TRUST 1.9.8_beta
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Declarer_bord_perio.cpp
1/****************************************************************************
2* Copyright (c) 2026, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15#include <Reordonner_faces_periodiques.h>
16#include <Declarer_bord_perio.h>
17#include <Format_Post_base.h>
18#include <Synonyme_info.h>
19#include <Octree_Double.h>
20#include <Domaine_bord.h>
21#include <ArrOfBit.h>
22#include <Param.h>
23
24Implemente_instanciable_32_64(Declarer_bord_perio_32_64,"Declarer_bord_perio",Interprete_geometrique_base_32_64<_T_>);
25Add_synonym(Declarer_bord_perio,"Corriger_frontiere_periodique");
26Add_synonym(Declarer_bord_perio_64,"Corriger_frontiere_periodique_64");
27
28// XD declarer_bord_perio interprete corriger_frontiere_periodique BRACE The Declarer_bord_perio keyword is mandatory to
29// XD_CONT first define the periodic boundaries, to reorder the faces and eventually fix unaligned nodes of these
30// XD_CONT boundaries. Faces on one side of the periodic domain are put first, then the faces on the opposite side, in
31// XD_CONT the same order. It must be run in sequential before mesh splitting.
32// XD attr domaine chaine domaine REQ Name of domain.
33// XD attr bord chaine bord REQ the name of the boundary (which must contain two opposite sides of the domain)
34// XD attr direction list direction OPT defines the periodicity direction vector (a vector that points from one node on
35// XD_CONT one side to the opposite node on the other side). This vector must be given if the automatic algorithm fails,
36// XD_CONT that is:NL2 - when the node coordinates are not perfectly periodic NL2 - when the periodic direction is not
37// XD_CONT aligned with the normal vector of the boundary faces
38// XD attr fichier_post chaine fichier_post OPT .
39
40template <typename _SIZE_>
42{
43 return is;
44}
45
46template <typename _SIZE_>
48{
49 return os;
50}
51
52/*! @brief Main routine recording the periodic boundaries in the domain and performing the appropriate reordering of the faces
53 */
54template <typename _SIZE_>
56{
57 Domaine_t& dom = this->domaine();
58 const int_t dim = dom.coord_sommets().dimension(1);
59 int direction_perio_set;
60 if (direction_perio_.size_array() == 0)
61 {
62 direction_perio_set=0;
63 Cerr << "No direction given, searching periodicity direction automatically:" << finl;
65 }
66 else
67 {
68 direction_perio_set=1;
69 if (direction_perio_.size_array() != dim)
70 {
71 Cerr << "Error in Declarer_bord_perio::interpreter: direction should be of size "
72 << dim << finl;
73 this->exit();
74 }
75 }
76 Cerr << "Searching and moving periodicity nodes for domain " << dom.le_nom() << " boundary " << nom_bord_ << finl;
78 Bord_t& bord = dom.bord(nom_bord_);
79 IntTab_t& faces = bord.faces().les_sommets();
80 const double epsilon = Objet_U::precision_geom;
82 if (!ok)
83 {
84 if (direction_perio_set)
85 Cerr << "May be you give a wrong vector for the DIRECTION option" << finl;
86 else
87 Cerr << "May be you could use the DIRECTION option to specify the vector of periodicity" << finl;
88 Cerr << "for the keyword:" << finl;
89 Cerr << "Declarer_bord_perio { Domaine " << dom.le_nom() << " Bord " << nom_bord_ << " } " << finl;
90 this->exit();
91 }
92}
93
94template <typename _SIZE_>
96{
97 bool declare_only = false;
98
99 Nom nom_dom;
100 Param param(this->que_suis_je());
101 param.ajouter("domaine", &nom_dom, Param::REQUIRED);
102 param.ajouter("bord", &nom_bord_, Param::REQUIRED);
103 param.ajouter("direction", &direction_perio_);
104 param.ajouter("fichier_post", &nom_fichier_post_);
105 param.ajouter_flag("declare_only", &declare_only);
107
108 if (this->nproc() > 1)
109 {
110 Cerr << "Error in Declarer_bord_perio::interpreter():\n"
111 << " this function must be run in sequential before mesh splitting." << finl;
112 this->barrier();
113 this->exit();
114 }
115
116 this->associer_domaine(nom_dom);
117
118 if(!declare_only)
120
121 // Register 'bord' in the list of periodic boundary of the domain:
122 Domaine_t& dom = this->domaine();
123 dom.bords_perio().add(nom_bord_);
124
125 return is;
126}
127
128
129/*! @brief Pour chaque sommet du bord periodique, on cherche son sommet oppose dans la direction + ou - vecteur_perio et dans un rayon search_radius.
130 *
131 * Parmi le couple de sommets forme, on deplace celui qui se trouve en +vecteur_perio
132 * pour le mettre en face de l'autre sommet.
133 * Exit en cas d'erreur (si les sommets sont trop eloignes de leur sommet associe)
134 */
135template <typename _SIZE_>
137{
138 if (Process::nproc() > 1)
139 {
140 Cerr << "Error in Declarer_bord_perio_32_64::corriger_coordonnees_sommets_perio\n"
141 << " this algorithm is sequential (use it before Decouper)" << finl;
144 }
145
146 Domaine_t& dom = this->domaine();
147 Domaine_bord_t domaine_bord;
148 domaine_bord.construire_domaine_bord(dom, nom_bord_);
149 const ArrOfInt_t& renum_som = domaine_bord.get_renum_som();
150 const DoubleTab_t& som_bord = domaine_bord.les_sommets();
151 Octree_Double_t octree;
152 octree.build_nodes(som_bord, 0 /* do not include virtual nodes */);
153
154 const double epsilon_initial = dom.epsilon();
155 if (epsilon_initial == 0.)
156 {
157 Cerr << "Error in Declarer_bord_perio_32_64::corriger_coordonnees_sommets_perio\n"
158 << " dom.epsilon = 0." << finl;
160 }
161
162 int error_flag = 0;
163
164 const int_t nb_som_bord = som_bord.dimension(0);
165 const int dim = static_cast<int>(som_bord.dimension(1));
166 // Un tableau contenant le deplacement applique aux sommets (pour postraitement)
167 DoubleTab_t delta(nb_som_bord, dim);
168 // Un tableau pour detecter les erreurs de periodicite: sommets associes plusieurs fois
169 ArrOfBit_t marker(nb_som_bord);
170 marker = 0;
171 // Tableau temporaire pour l'octree:
172 ArrOfInt_t nodes_list;
173
174 DoubleTab_t& sommets_src = dom.les_sommets();
175 ArrOfDouble coord(dim);
176 for (int_t som = 0; som < nb_som_bord; som++)
177 {
178 if (marker.testsetbit(som))
179 continue; // Sommet deja traite
180
181 // Cherche le sommet oppose dans les deux directions (-1. et +1.)
182 double facteur;
183 int_t som2 = -1;
184 // Recherche du sommet dans un rayon de plus en plus grand en commencant par epsilon:
185 double epsilon = epsilon_initial;
186 do
187 {
188 for (facteur = -1.; facteur < 1.5; facteur += 2.)
189 {
190 for (int i = 0; i < dim; i++)
191 coord[i] = som_bord(som, i) + facteur * direction_perio_[i];
192 octree.search_elements_box(coord, epsilon, nodes_list);
193 som2 = octree.search_nodes_close_to(coord, som_bord, nodes_list, epsilon);
194 if (som2 >= 0)
195 break;
196 }
197 if (som2 >= 0)
198 break;
199 // Sommet non trouve, on recommence avec un rayon de recherche plus grand
200 epsilon *= 4.;
201 }
202 while (1);
203 if (marker.testsetbit(som2))
204 {
205 Cerr << "Error in Declarer_bord_perio_32_64::corriger_coordonnees_sommets_perio\n"
206 << " Coordinate " << coord
207 << " Closest point [ " << som_bord(som2, 0) << " " << som_bord(som2, 0) << " "
208 << ((dim==3)?som_bord(som2, 0):0.) << " ] already used for another point" << finl;
209 error_flag = 1;
210 }
211 else
212 {
213 // On deplace le sommet vers lequel pointe vecteur_perio:
214 const int_t som_ref = som;
215 const int_t som_deplace = som2;
216 // Indice du sommet a deplacer dans le domaine source:
217 const int_t s = renum_som[som_deplace];
218 // Deplacement
219 for (int i = 0; i < dim; i++)
220 {
221 double old_x = som_bord(som_deplace, i);
222 double new_x = som_bord(som_ref, i) + facteur * direction_perio_[i];
223 sommets_src(s, i) = new_x;
224 delta(som_deplace, i) = new_x - old_x;
225 }
226 }
227 }
228
229 if (nom_fichier_post_ != "??")
230 {
231 if (!std::is_same<_SIZE_, int>::value)
232 {
233 Cerr << "Declarer_bord_perio_64 - option 'fichier_post' is not implemented yet for 64b domains!" << finl;
234 Cerr << "Remove the attribute or contact TRUST support." << finl;
235 Process::exit(-1);
236 }
237#if INT_is_64_ != 2
238 //Domaine dom2;
239 Cerr << "Writing node displacement into file: " << nom_fichier_post_ << finl;
240 OWN_PTR(Format_Post_base) fichier_post;
241 fichier_post.typer("FORMAT_POST_LATA");
242 fichier_post->initialize(nom_fichier_post_, 1 /* binaire */, "SIMPLE");
243 Format_Post_base& post = fichier_post.valeur();
244 post.ecrire_entete(0., 0 /*reprise*/, 1 /* premier post */);
245 post.ecrire_domaine(domaine_bord, 1 /* premier_post */);
246 post.ecrire_temps(0.);
247 Noms unites;
248 unites.add("m");
249 unites.add("m");
250 if (dim==3) unites.add("m");
251 Noms compos;
252 compos.add("dx");
253 compos.add("dy");
254 if (dim==3) compos.add("dz");
255 post.ecrire_champ(domaine_bord,
256 unites, compos, -1 /* ecrire toutes les composantes */,
257 0., /* temps */
258 "vitesse", domaine_bord.le_nom(), "SOM","vector", delta);
259 int fin=1;
260 post.finir(fin);
261#endif
262 }
263
264 Cerr << "Max of node displacement (m): " << max_abs_array(delta) << finl;
265 if (error_flag)
266 {
267 Cerr << "Could not correct node coordinates. Aborting." << finl;
269 }
270}
271
272template class Declarer_bord_perio_32_64<int>;
273#if INT_is_64_ == 2
275#endif
int testsetbit(int_t i) const
Renvoie la valeur du bit e, puis met le bit e a 1.
Definition ArrOfBit.h:85
Cet interprete doit etre utilise en sequentiel (avant decoupage) si les sommets opposes d'un bord per...
ArrOfBit_32_64< _SIZE_ > ArrOfBit_t
DoubleTab_T< _SIZE_ > DoubleTab_t
void adapt_som_and_faces()
Main routine recording the periodic boundaries in the domain and performing the appropriate reorderin...
Entree & interpreter_(Entree &is) override
Octree_Double_32_64< _SIZE_ > Octree_Double_t
Domaine_32_64< _SIZE_ > Domaine_t
Domaine_bord_32_64< _SIZE_ > Domaine_bord_t
ArrOfInt_T< _SIZE_ > ArrOfInt_t
void corriger_coordonnees_sommets_perio()
Pour chaque sommet du bord periodique, on cherche son sommet oppose dans la direction + ou - vecteur_...
Bord_32_64< _SIZE_ > Bord_t
DoubleTab_t & les_sommets()
Definition Domaine.h:113
Bord_t & bord(int i)
Definition Domaine.h:193
const DoubleTab_t & coord_sommets() const
Definition Domaine.h:112
const Noms & bords_perio() const
Definition Domaine.h:278
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
double epsilon() const
virtual void construire_domaine_bord(const Domaine_t &source, const Nom &nom_bord)
construit le domaine en appelant extraire_domaine_bord()
virtual const ArrOfInt_t & get_renum_som() const
renvoie renum_som (pour chaque sommet du domaine_bord, indice du meme sommet dans le domaine)
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
const IntTab_t & les_sommets() const
Renvoie le tableau des sommets de toutes les faces.
Definition Faces.h:74
Classe de base des formats de postraitements pour les champs (lata, med, cgns, lml,...
virtual int finir(const int est_le_dernier_post)
virtual int ecrire_champ(const Domaine &domaine, const Noms &unite_, const Noms &noms_compo, int ncomp, double temps_, const Nom &id_du_champ, const Nom &id_du_domaine, const Nom &localisation, const Nom &nature, const DoubleTab &data)
Ecriture d'un champ dans le fichier de postraitement.
virtual int ecrire_temps(const double temps)
Commence l'ecriture d'un pas de temps.
virtual int ecrire_entete(const double temps_courant, const int reprise, const int est_le_premier_post)
virtual int ecrire_domaine(const Domaine &domaine, const int est_le_premier_post)
Ecriture d'un maillage.
const Faces_t & faces() const
Definition Frontiere.h:54
classe Interprete_geometrique_base .
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
Un tableau de chaine de caracteres (VECT(Nom)).
Definition Noms.h:26
friend class Entree
Definition Objet_U.h:76
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
static double precision_geom
Definition Objet_U.h:86
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
static int_t search_nodes_close_to(double x, double y, double z, const DoubleTab_t &coords, ArrOfInt_t &node_list, double epsilon)
Methode hors classe Cherche parmi les sommets de la liste node_list ceux qui sont a une.
void build_nodes(const DoubleTab_t &coords, const bool include_virtual, const double epsilon=0.)
construit un octree contenant les points de coordonnees coords.
int_t search_elements_box(double xmin, double ymin, double zmin, double xmax, double ymax, double zmax, ArrOfInt_t &elements) const
cherche tous les elements ou points ayant potentiellement une intersection non vide avec la boite don...
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter_flag(const char *keyword, const bool *value)
Register a boolean flag whose mere presence switches it to true.
Definition Param.cpp:474
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
@ REQUIRED
Definition Param.h:115
int lire_avec_accolades_depuis(Entree &is)
Parse the parameter block { ... } from is.
Definition Param.cpp:32
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
static void barrier()
Synchronise tous les processeurs du groupe courant (attend que tous les processeurs soient arrives a ...
Definition Process.cpp:136
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static void chercher_direction_perio(ArrOfDouble &direction_perio, const Domaine_32_64< _SIZE_ > &dom, const Nom &bord)
static int reordonner_faces_periodiques(const Domaine_32_64< _SIZE_ > &domaine, IntTab_T< _SIZE_ > &faces, const ArrOfDouble &direction_perio, const double epsilon)
Reordonne le tableau "faces" selon la convention des faces periodiques: D'abord les faces d'une extre...
Classe de base des flux de sortie.
Definition Sortie.h:52
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133