TRUST 1.9.8_beta
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Partitionneur_Tranche.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
16#include <Reordonner_faces_periodiques.h>
17#include <Partitionneur_Tranche.h>
18#include <TRUSTArray.h>
19#include <Domaine.h>
20#include <Param.h>
21
22Implemente_instanciable_32_64(Partitionneur_Tranche_32_64, "Partitionneur_Tranche", Partitionneur_base_32_64<_T_>);
23// XD partitionneur_tranche partitionneur_deriv tranche INHERITS_BRACE This algorithm will create a geometrical
24// XD_CONT partitionning by slicing the mesh in the two or three axis directions, based on the geometric center of each
25// XD_CONT mesh element. nz must be given if dimension=3. Each slice contains the same number of elements (slices don\'t
26// XD_CONT have the same geometrical width, and for VDF meshes, slice boundaries are generally not flat except if the
27// XD_CONT number of mesh elements in each direction is an exact multiple of the number of slices). First, nx slices in
28// XD_CONT the X direction are created, then each slice is split in ny slices in the Y direction, and finally, each part
29// XD_CONT is split in nz slices in the Z direction. The resulting number of parts is nx*ny*nz. If one particular
30// XD_CONT direction has been declared periodic, the default slicing (0, 1, 2, ..., n-1)is replaced by (0, 1, 2, ...
31// XD_CONT n-1, 0), each of the two \'0\' slices having twice less elements than the other slices.
32// XD attr tranches listentierf tranches OPT Partitioned by nx in the X direction, ny in the Y direction, nz in the Z
33// XD_CONT direction. Works only for structured meshes. No warranty for unstructured meshes.
34
35
36template <typename _SIZE_>
38{
39 Cerr << "Partitionneur_Tranche_32_64<_SIZE_>::printOn invalid\n" << finl;
41 return os;
42}
43
44/*! @brief La syntaxe est { Tranches nx ny [ nz ] }
45 */
46template <typename _SIZE_>
48{
49 if (!ref_domaine_)
50 {
51 Cerr << " Error: the domain has not been associated" << finl;
53 }
54 param.ajouter_arr_size_predefinie("tranches",&nb_tranches_,Param::REQUIRED);
55
56}
57
58/*! @brief La syntaxe est { Tranches nx ny [ nz ] }
59 */
60template <typename _SIZE_>
62{
63
64 // used to be done in readOn
65 if (min_array(nb_tranches_)<1)
66 {
67 Cerr << "Error for the cutting domain tool (Tranche) specifications : " <<finl;
68 Cerr<< " the number of slice must be greater than 0 for each direction. " << finl;
70 }
71}
72
73/*! @brief Premiere etape d'initialisation du partitionneur: on associe un domaine.
74 *
75 */
76template <typename _SIZE_>
78{
79 ref_domaine_ = domaine;
80 nb_tranches_.resize(domaine.dimension);
81 nb_tranches_ = -1;
82}
83
84/*! @brief Deuxieme etape d'initialisation: on definit le nombre de tranches.
85 *
86 * (on peut utiliser readOn a la place).
87 *
88 */
89template <typename _SIZE_>
90void Partitionneur_Tranche_32_64<_SIZE_>::initialiser(const ArrOfInt& nb_tranches)
91{
92
93 assert(ref_domaine_);
94 assert(nb_tranches.size_array() == nb_tranches_.size_array());
95 assert(min_array(nb_tranches) > 0);
96
97 nb_tranches_ = nb_tranches;
98}
99
100/*! @brief Remplissage du tableau directions perio a partir des noms des bords periodiques.
101 *
102 * Pour 0 <= i < Objet_U::dimension directions_perio[i] vaut 1 s'il
103 * existe un bord periodique pour lequel le vecteur delta est dirige dans la direction i.
104 *
105 */
106template <typename _SIZE_>
108 ArrOfInt& directions_perio)
109{
110 Cerr << "Search of periodic directions of domain " << domaine.le_nom() << finl;
111 const int dim = Objet_U::dimension;
112 const Noms& liste_bords_perio = domaine.bords_perio();
113
114 directions_perio.resize_array(dim);
115 directions_perio = 0;
116 for (auto& itr : liste_bords_perio)
117 {
118 int num_bord = 0;
119 const Nom& nom_bord = itr;
120 const int nb_bords = domaine.nb_bords();
121 while (num_bord < nb_bords)
122 {
123 if (domaine.bord(num_bord).le_nom() == nom_bord)
124 break;
125 num_bord++;
126 }
127 if (num_bord == nb_bords)
128 {
129 Cerr << "Error in Partitionneur_Tranche_32_64<_SIZE_>::chercher_direction_perio\n"
130 << " boundary not found : " << nom_bord << finl;
132 }
133 ArrOfDouble delta;
134 ArrOfDouble erreur;
135 const double epsilon = Objet_U::precision_geom;
136 Reordonner_faces_periodiques_32_64<_SIZE_>::check_faces_periodiques(domaine.bord(num_bord), delta, erreur);
137 int count = 0;
138 for (int j = 0; j < dim; j++)
139 {
140 if (std::abs(delta[j]) > epsilon)
141 {
142 directions_perio[j]++;
143 Cerr << " Boundary : " << nom_bord << " periodic direction : " << j << finl;
144 count++;
145 }
146 }
147 if (count != 1)
148 {
149 Cerr << "Error in Partitionneur_Tranche_32_64<_SIZE_>::chercher_direction_perio\n"
150 << " periodic direction not found for the boundary " << nom_bord
151 << "\n Vector delta found between faces twin : " << delta
152 << "\n with a maximum error : " << erreur << finl;
154 }
155 }
156 if (max_array(directions_perio) > 1)
157 {
158 Cerr << "Error in Partitionneur_Tranche_32_64<_SIZE_>::chercher_direction_perio\n"
159 << " several boundaries have the same periodic direction" << finl;
161 }
162}
163
164template <typename _SIZE_>
166{
167 using DoubleTab_t = DoubleTab_T<_SIZE_>;
168
169 assert(ref_domaine_);
170 assert(nb_tranches_[0] > 0);
171
172 const Domaine_t& dom = ref_domaine_.valeur();
173 const int_t nb_elem = dom.nb_elem();
174
175 const int dim = Objet_U::dimension;
176
177 // Pour chaque dimension d'espace, cette direction est-elle
178 // une direction de periodicite
179 ArrOfInt directions_perio;
180 this->chercher_direction_perio(dom, directions_perio);
181
182 // Centre de gravite des elements:
183 Cerr << "Calculation of centers of gravity of the elements" << finl;
184 DoubleTab_t coord_g;
185 dom.calculer_centres_gravite(coord_g);
186 assert(coord_g.dimension(0) == nb_elem);
187 assert(coord_g.dimension(1) == dim);
188
189 Cerr << "Moving of centers of gravity" << finl;
190 // Deplacement des coordonnees pour qu'il y ait une vraie relation d'ordre
191 // dans chaque direction (en VDF, eviter les coordonnees identiques)
192 {
193 for (int_t i = 0; i < nb_elem; i++)
194 {
195 double x = coord_g(i,0);
196 double y = coord_g(i,1);
197 double z = (dim == 3) ? coord_g(i,2) : 0.;
198 coord_g(i,0) = x + y*1e-6 + z*1e-12;
199 coord_g(i,1) = y + x*1e-6 + z*1e-12;
200 if (dim == 3)
201 coord_g(i,2) = z + x*1e-6 + y*1e-12;
202 }
203 }
204
205 // Nombre d'elements dans chaque partie
206 // (initialisation: une partie contenant nb_elem elements)
207 SmallArrOfTID_T<_SIZE_> nb_elem_part(1);
208 nb_elem_part= nb_elem;
209
210 // Dans l'ordre croissant des parties, liste des elements
211 // contenus dans la partie
212 // (exemple:
213 // de 0..nb_elem_part[0]-1 (elements de la partie 0)
214 // de nb_elem_part[0]..nb_elem_part[0]+nb_elem_part[1]-1 (partie 1)
215 // Initialisation: une seule grosse partie, tous les elements
216 ArrOfInt_t listes_elem(nb_elem);
217 for (int_t i = 0; i < nb_elem; i++)
218 listes_elem[i] = i;
219
220 SmallArrOfTID_T<_SIZE_> new_nb_elem_part;
221
222 // Index utilise pour trier les elements
223 ArrOfInt_t index;
224
225 // Algorithme: on cree nb_tranches[0] tranches dans la direction x,
226 // chaque tranche compte le meme nombre d'elements du domaine.
227 // Puis on prend chacune de ces tranches et on la decoupe en nb_tranches[1]
228 // parties dans la direction y, elles aussi equilibrees.
229 // Enfin, on prend chacune des parties obtenues et on la coupe en nb_tranches[2]
230 // parties dans la direction z.
231 // Attention: si le domaine n'est pas un parallelipipede, le decoupage
232 // n'est pas forcement cartesien:
233 // ------------------
234 // | | |
235 // |-------| |
236 // | |--------| <- les coins des tranches ne coincident pas forcement
237 // ------------------
238
239 for (int direction = 0; direction < dim; direction++)
240 {
241 // Nombre de tranches a creer dans cette direction
242 const int nb_tranches = nb_tranches_[direction];
243
244 int_t index_debut_partie = 0;
245 new_nb_elem_part.resize_array(0);
246 const int nb_parts = nb_elem_part.size_array();
247
248 Cerr << "The mesh contains " << nb_parts << " parts. ";
249 Cerr << "Splitting in the direction " << direction << finl;
250
251 // Boucle sur les parties deja creees. On divise chaque partie
252 // en nb_tranches sous-parties:
253 for (int part = 0; part < nb_parts; part++)
254 {
255 Cerr << " Splitting of subpart " << part << finl;
256 // Extraction de la liste des elements de cette partie:
257 // on fait pointer le tableau index vers une sous-partie de listes_elem
258 const int_t nb_elem_partie = nb_elem_part[part];
259 assert(index_debut_partie >= 0 && index_debut_partie + nb_elem_partie <= nb_elem);
260 index.ref_data(listes_elem.addr()+index_debut_partie, nb_elem_partie);
261 // Tri des elements de cette partie dans l'ordre croissant
262 // de la coordonnee (index pointe sur une partie de liste_elem, on trie
263 // donc en realite une partie du tableau liste_elem)
264 std::sort(index.begin(), index.end(), [&](int_t a, int_t b)
265 {
266 return ( coord_g(a,direction)<coord_g(b,direction) );
267 });
268
269 // Si cette direction est periodique, permutation circulaire de
270 // nb_elem_partie/(nb_tranches*2) elements pour que les elements de l'extremite
271 // se retrouvent sur la meme partie que ceux de l'extremite opposee
272 if (directions_perio[direction])
273 {
274 ArrOfInt_t copie(nb_elem_partie);
275 copie.inject_array(index);
276 int_t j = nb_elem_partie/(nb_tranches*2);
277 for (int i = 0; i < nb_elem_partie; i++)
278 {
279 index[j++] = copie[i];
280 if (j >= nb_elem_partie)
281 j = 0;
282 }
283 }
284 // Construction d'une partition en nb_tranches parties, par
285 // ordre croissant des coordonnees
286 {
287 int_t n = 0;
288 for (int i = 0; i < nb_tranches; i++)
289 {
290 // All the cast because nb_elem_partie * (i+1) > 2^31 for big meshes
291 const long long new_n0 = (long long)nb_elem_partie * (long long)(i+1) / (long long)nb_tranches;
292 assert(new_n0 < std::numeric_limits<_SIZE_>::max());
293 const int_t new_n = (int_t)new_n0;
294 new_nb_elem_part.append_array(new_n - n);
295 n = new_n;
296 }
297 }
298 index_debut_partie += nb_elem_partie;
299 }
300
301 nb_elem_part = new_nb_elem_part;
302 }
303
304 // Partition initiale du domaine: au depart tout dans 0
305 elem_part.resize(nb_elem);
306 elem_part = 0;
307 // Construction de elem_part
308 const int nb_parts = nb_elem_part.size_array();
309 int_t index_fin = 0, i = 0;
310 for (int part = 0; part < nb_parts; part++)
311 {
312 index_fin += nb_elem_part[part];
313 for (; i < index_fin; i++)
314 {
315 const int_t elem = listes_elem[i];
316 elem_part[elem] = part;
317 }
318 }
319
320 if (ref_domaine_->bords_perio().size() > 0)
321 this->corriger_bords_avec_liste(dom, 0, elem_part);
322
323 Cerr << "Correction elem0 on processor 0" << finl;
324 this->corriger_elem0_sur_proc0(elem_part);
325}
326
327
329#if INT_is_64_ == 2
331#endif
332
void calculer_centres_gravite(DoubleTab_t &xp) const
Calcule les centres de gravites des elements du domaine.
Definition Domaine.h:503
int_t nb_elem() const
Definition Domaine.h:131
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
virtual void set_param(Param &) const
Definition Objet_U.h:135
static int dimension
Definition Objet_U.h:99
static double precision_geom
Definition Objet_U.h:86
virtual const Nom & le_nom() const
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Objet_U.cpp:319
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter_arr_size_predefinie(const char *keyword, const ArrOfInt *value, Param::Nature nat=Param::OPTIONAL)
Register an ArrOfInt whose size has already been fixed.
Definition Param.cpp:411
@ REQUIRED
Definition Param.h:115
Partitionneur de domaine en tranches paralleles aux directions de l'espace.
void validate_params() const override
La syntaxe est { Tranches nx ny [ nz ] }.
static void chercher_direction_perio(const Domaine_t &domaine, ArrOfInt &directions_perio)
Remplissage du tableau directions perio a partir des noms des bords periodiques.
void associer_domaine(const Domaine_t &domaine) override
Premiere etape d'initialisation du partitionneur: on associe un domaine.
Domaine_32_64< _SIZE_ > Domaine_t
void construire_partition(BigIntVect_ &elem_part, int &nb_parts_tot) const override
void initialiser(const ArrOfInt &nb_tranches)
Deuxieme etape d'initialisation: on definit le nombre de tranches.
TRUSTVect< int, _SIZE_ > BigIntVect_
Classe de base des partitionneurs de domaine (pour decouper un maillage avant un calcul parallele).
static void corriger_bords_avec_liste(const Domaine_t &dom, const int_t my_offset, BigIntVect_ &elem_part)
Calcul des graphes de connectivite elements periodiques et appel a corriger_periodique_avec_graphe.
static void corriger_elem0_sur_proc0(BigIntVect_ &elem_part)
corrige la partition pour que l'element 0 du domaine initial se trouve sur le premier sous-domaine de...
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static int check_faces_periodiques(const Frontiere_32_64< _SIZE_ > &frontiere, ArrOfDouble &vecteur_delta, ArrOfDouble &erreur, bool verbose=false)
essaie de verifier si les faces du bord num_bord sont ordonnees suivant la convention des faces perio...
Classe de base des flux de sortie.
Definition Sortie.h:52
void append_array(_TYPE_ valeur)
Iterator_ end()
Definition TRUSTArray.h:112
_SIZE_ size_array() const
_TYPE_ * addr()
TRUSTArray & inject_array(const TRUSTArray &source, _SIZE_ nb_elements=-1, _SIZE_ first_element_dest=0, _SIZE_ first_element_source=0)
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Iterator_ begin()
Definition TRUSTArray.h:111
virtual void ref_data(_TYPE_ *ptr, _SIZE_ size)
void resize(_SIZE_, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTVect.tpp:91