TrioCFD 1.9.9_beta
TrioCFD documentation
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// XD attr declare_only rien declare_only OPT flag if added will only add the periodic boundary without calling
40// XD_CONT corriger_frontiere_periodique
41
42template <typename _SIZE_>
44{
45 return is;
46}
47
48template <typename _SIZE_>
50{
51 return os;
52}
53
54/*! @brief Main routine recording the periodic boundaries in the domain and performing the appropriate reordering of the faces
55 */
56template <typename _SIZE_>
58{
59 Domaine_t& dom = this->domaine();
60 const int_t dim = dom.coord_sommets().dimension(1);
61 int direction_perio_set;
62 if (direction_perio_.size_array() == 0)
63 {
64 direction_perio_set=0;
65 Cerr << "No direction given, searching periodicity direction automatically:" << finl;
67 }
68 else
69 {
70 direction_perio_set=1;
71 if (direction_perio_.size_array() != dim)
72 {
73 Cerr << "Error in Declarer_bord_perio::interpreter: direction should be of size "
74 << dim << finl;
75 this->exit();
76 }
77 }
78 Cerr << "Searching and moving periodicity nodes for domain " << dom.le_nom() << " boundary " << nom_bord_ << finl;
80 Bord_t& bord = dom.bord(nom_bord_);
81 IntTab_t& faces = bord.faces().les_sommets();
82 const double epsilon = Objet_U::precision_geom;
84 if (!ok)
85 {
86 if (direction_perio_set)
87 Cerr << "May be you give a wrong vector for the DIRECTION option" << finl;
88 else
89 Cerr << "May be you could use the DIRECTION option to specify the vector of periodicity" << finl;
90 Cerr << "for the keyword:" << finl;
91 Cerr << "Declarer_bord_perio { Domaine " << dom.le_nom() << " Bord " << nom_bord_ << " } " << finl;
92 this->exit();
93 }
94}
95
96template <typename _SIZE_>
98{
99 bool declare_only = false;
100
101 Nom nom_dom;
102 Param param(this->que_suis_je());
103 param.ajouter("domaine", &nom_dom, Param::REQUIRED);
104 param.ajouter("bord", &nom_bord_, Param::REQUIRED);
105 param.ajouter("direction", &direction_perio_);
106 param.ajouter("fichier_post", &nom_fichier_post_);
107 param.ajouter_flag("declare_only", &declare_only);
109
110 if (this->nproc() > 1)
111 {
112 Cerr << "Error in Declarer_bord_perio::interpreter():\n"
113 << " this function must be run in sequential before mesh splitting." << finl;
114 this->barrier();
115 this->exit();
116 }
117
118 this->associer_domaine(nom_dom);
119
120 if(!declare_only)
122
123 // Register 'bord' in the list of periodic boundary of the domain:
124 Domaine_t& dom = this->domaine();
125 dom.bords_perio().add(nom_bord_);
126
127 return is;
128}
129
130
131/*! @brief For each vertex of the periodic boundary, its opposite vertex is searched in the + or - vecteur_perio direction and within a search_radius.
132 *
133 * Among the pair of vertices formed, the one located in the +vecteur_perio direction is moved
134 * to align it with the other vertex.
135 * Exits with an error if vertices are too far from their associated vertex.
136 */
137template <typename _SIZE_>
139{
140 if (Process::nproc() > 1)
141 {
142 Cerr << "Error in Declarer_bord_perio_32_64::corriger_coordonnees_sommets_perio\n"
143 << " this algorithm is sequential (use it before Decouper)" << finl;
146 }
147
148 Domaine_t& dom = this->domaine();
149 Domaine_bord_t domaine_bord;
150 domaine_bord.construire_domaine_bord(dom, nom_bord_);
151 const ArrOfInt_t& renum_som = domaine_bord.get_renum_som();
152 const DoubleTab_t& som_bord = domaine_bord.les_sommets();
153 Octree_Double_t octree;
154 octree.build_nodes(som_bord, 0 /* do not include virtual nodes */);
155
156 const double epsilon_initial = dom.epsilon();
157 if (epsilon_initial == 0.)
158 {
159 Cerr << "Error in Declarer_bord_perio_32_64::corriger_coordonnees_sommets_perio\n"
160 << " dom.epsilon = 0." << finl;
162 }
163
164 int error_flag = 0;
165
166 const int_t nb_som_bord = som_bord.dimension(0);
167 const int dim = static_cast<int>(som_bord.dimension(1));
168 // Array containing the displacement applied to the vertices (for post-processing)
169 DoubleTab_t delta(nb_som_bord, dim);
170 // Array to detect periodicity errors: vertices associated more than once
171 ArrOfBit_t marker(nb_som_bord);
172 marker = 0;
173 // Temporary array for the octree:
174 ArrOfInt_t nodes_list;
175
176 DoubleTab_t& sommets_src = dom.les_sommets();
177 ArrOfDouble coord(dim);
178 for (int_t som = 0; som < nb_som_bord; som++)
179 {
180 if (marker.testsetbit(som))
181 continue; // Vertex already processed
182
183 // Search for the opposite vertex in both directions (-1. and +1.)
184 double facteur;
185 int_t som2 = -1;
186 // Search for the vertex in an increasingly large radius starting from epsilon:
187 double epsilon = epsilon_initial;
188 do
189 {
190 for (facteur = -1.; facteur < 1.5; facteur += 2.)
191 {
192 for (int i = 0; i < dim; i++)
193 coord[i] = som_bord(som, i) + facteur * direction_perio_[i];
194 octree.search_elements_box(coord, epsilon, nodes_list);
195 som2 = octree.search_nodes_close_to(coord, som_bord, nodes_list, epsilon);
196 if (som2 >= 0)
197 break;
198 }
199 if (som2 >= 0)
200 break;
201 // Vertex not found, retry with a larger search radius
202 epsilon *= 4.;
203 }
204 while (1);
205 if (marker.testsetbit(som2))
206 {
207 Cerr << "Error in Declarer_bord_perio_32_64::corriger_coordonnees_sommets_perio\n"
208 << " Coordinate " << coord
209 << " Closest point [ " << som_bord(som2, 0) << " " << som_bord(som2, 0) << " "
210 << ((dim==3)?som_bord(som2, 0):0.) << " ] already used for another point" << finl;
211 error_flag = 1;
212 }
213 else
214 {
215 // Move the vertex pointed to by vecteur_perio:
216 const int_t som_ref = som;
217 const int_t som_deplace = som2;
218 // Index of the vertex to move in the source domain:
219 const int_t s = renum_som[som_deplace];
220 // Displacement
221 for (int i = 0; i < dim; i++)
222 {
223 double old_x = som_bord(som_deplace, i);
224 double new_x = som_bord(som_ref, i) + facteur * direction_perio_[i];
225 sommets_src(s, i) = new_x;
226 delta(som_deplace, i) = new_x - old_x;
227 }
228 }
229 }
230
231 if (nom_fichier_post_ != "??")
232 {
233 if (!std::is_same<_SIZE_, int>::value)
234 {
235 Cerr << "Declarer_bord_perio_64 - option 'fichier_post' is not implemented yet for 64b domains!" << finl;
236 Cerr << "Remove the attribute or contact TRUST support." << finl;
237 Process::exit(-1);
238 }
239#if INT_is_64_ != 2
240 //Domaine dom2;
241 Cerr << "Writing node displacement into file: " << nom_fichier_post_ << finl;
242 OWN_PTR(Format_Post_base) fichier_post;
243 fichier_post.typer("FORMAT_POST_LATA");
244 fichier_post->initialize(nom_fichier_post_, 1 /* binaire */, "SIMPLE");
245 Format_Post_base& post = fichier_post.valeur();
246 post.ecrire_entete(0., 0 /*reprise*/, 1 /* premier post */);
247 post.ecrire_domaine(domaine_bord, 1 /* premier_post */);
248 post.ecrire_temps(0.);
249 Noms unites;
250 unites.add("m");
251 unites.add("m");
252 if (dim==3) unites.add("m");
253 Noms compos;
254 compos.add("dx");
255 compos.add("dy");
256 if (dim==3) compos.add("dz");
257 post.ecrire_champ(domaine_bord,
258 unites, compos, -1 /* write all components */,
259 0., /* time */
260 "vitesse", domaine_bord.le_nom(), "SOM","vector", delta);
261 int fin=1;
262 post.finir(fin);
263#endif
264 }
265
266 Cerr << "Max of node displacement (m): " << max_abs_array(delta) << finl;
267 if (error_flag)
268 {
269 Cerr << "Could not correct node coordinates. Aborting." << finl;
271 }
272}
273
274template class Declarer_bord_perio_32_64<int>;
275#if INT_is_64_ == 2
277#endif
int testsetbit(int_t i) const
Returns the value of bit e, then sets bit e to 1.
Definition ArrOfBit.h:85
This interpreter must be used in sequential (before mesh splitting) if the opposite vertices of a 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()
For each vertex of the periodic boundary, its opposite vertex is searched in the + or - vecteur_perio...
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
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
double epsilon() const
virtual void construire_domaine_bord(const Domaine_t &source, const Nom &nom_bord)
builds the domain by calling extraire_domaine_bord()
virtual const ArrOfInt_t & get_renum_som() const
returns renum_som (for each vertex of domaine_bord, index of the same vertex in the domain)
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
const IntTab_t & les_sommets() const
Returns the array of vertices of all faces.
Definition Faces.h:74
Base class for post-processing output formats for fields (lata, med, cgns, lml, single_lata).
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)
Writing a field to the post-processing file.
virtual int ecrire_temps(const double temps)
Starts writing a time step.
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)
Writing a mesh.
const Faces_t & faces() const
Definition Frontiere.h:54
Class Interprete_geometrique_base.
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
An array of character strings (VECT(Nom)).
Definition Noms.h:26
friend class Entree
Definition Objet_U.h:71
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
static double precision_geom
Definition Objet_U.h:81
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
static int_t search_nodes_close_to(double x, double y, double z, const DoubleTab_t &coords, ArrOfInt_t &node_list, double epsilon)
Non-member method. Searches among the vertices in node_list for those within a distance.
void build_nodes(const DoubleTab_t &coords, const bool include_virtual, const double epsilon=0.)
builds an octree containing the points with coordinates coords.
int_t search_elements_box(double xmin, double ymin, double zmin, double xmax, double ymax, double zmax, ArrOfInt_t &elements) const
searches for all elements or points potentially having a non-empty intersection with the given box.
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()
Returns the number of processors in the current group. See Comm_Group::nproc() and PE_Groups::current...
Definition Process.cpp:102
static void barrier()
Synchronizes all processors in the current group (waits until all processors have reached the barrier...
Definition Process.cpp:133
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
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)
Reorders the "faces" array according to the periodic face convention: First the faces of one end,...
Base class for output streams.
Definition Sortie.h:52
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133