TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Partitionneur_base.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 <Connectivite_som_elem.h>
18#include <Partitionneur_base.h>
19#include <communications.h>
20#include <Array_tools.h>
21#include <TRUSTLists.h>
22#include <ArrOfBit.h>
23#include <Domaine.h>
24#include <Param.h>
25
26Implemente_base_32_64(Partitionneur_base_32_64,"Partitionneur_base",Objet_U_With_Params);
27// XD partitionneur_deriv objet_u partitionneur_deriv INHERITS_BRACE not_set
28// XD attr nb_parts entier nb_parts OPT The number of non empty parts that must be generated (generally equal to the
29// XD_CONT number of processors in the parallel run).
30
31template <typename _SIZE_>
33{
34 exit();
35 return os;
36}
37
38template <typename _SIZE_>
40{
41}
42
43/*! @brief corrige la partition pour que l'element 0 du domaine initial se trouve sur le premier sous-domaine de la partition.
44 *
45 * On echange le premier sous-domaine et celui qui contient l'element 0.
46 *
47 */
48template <typename _SIZE_>
50{
51 Cerr << "Correction of the splitting to put the element 0 on processor 0." << finl;
52 int pe_to_xchange = elem_part[0];
53 envoyer_broadcast(pe_to_xchange, 0);
54 if (pe_to_xchange == 0)
55 {
56 Cerr << " No correction to be made" << finl;
57 return;
58 }
59
60 Cerr << " Exchange of parts 0 and " << pe_to_xchange << finl;
61 const int_t n = elem_part.size_reelle();
62 for (int_t i = 0; i < n; i++)
63 {
64 const int pe = elem_part[i];
65 if (pe == 0)
66 elem_part[i] = pe_to_xchange;
67 else if (pe == pe_to_xchange)
68 elem_part[i] = 0;
69 }
70
71}
72
73namespace
74{
75/*! @brief construction (taille et contenu) du tableau elements avec pour chaque face du bord donne, l'indice de l'element du domaine adjacent
76 *
77 * a cette face.
78 *
79 * @param (som_elem) connectivite sommet-elements du domaine, calculee a l'aide de construire_connectivite_som_elem
80 * @param (faces) les faces du bord a traiter (pour chaque face, indices des sommets)
81 * @param (nom_faces) un nom de bord a imprimer en cas d'erreur
82 * @param (elements) le tableau a remplir.
83 */
84template <typename _SIZE_>
85void chercher_elems_voisins_faces(const Static_Int_Lists_32_64<_SIZE_>& som_elem,
86 const IntTab_T<_SIZE_>& faces,
87 const Nom& nom_faces,
88 ArrOfInt_T<_SIZE_>& elements)
89{
90 using int_t = _SIZE_;
91 using SmallArrOfTID_t = SmallArrOfTID_T<_SIZE_>;
92
93 const int_t nb_faces = faces.dimension(0);
94 elements.resize_array(nb_faces);
95 if (nb_faces == 0)
96 return;
97 const int nb_som_faces = faces.dimension_int(1);
98 SmallArrOfTID_t une_face(nb_som_faces);
99 SmallArrOfTID_t voisins;
100 for (int_t i = 0; i < nb_faces; i++)
101 {
102 for (int j = 0; j < nb_som_faces; j++)
103 une_face[j] = faces(i, j);
104 find_adjacent_elements(som_elem, une_face, voisins);
105 const int nb_voisins = voisins.size_array();
106 if (nb_voisins != 1)
107 {
108 Cerr << "Error in chercher_elems_voisins_faces : the face " << i
109 << "\n of boundary " << nom_faces << " has " << nb_voisins
110 << " neighboring elements with the indices : " << voisins << finl;
112 }
113 elements[i] = voisins[0];
114 }
115}
116}
117
118/*! @brief Calcul d'un graphe de connectivite entre les elements lies par des faces periodiques.
119 *
120 * Si l'element i est voisin de l'element j par une face periodique, alors il existe
121 * k tel que graph(i,k)==j et il existe k2 tel que graph(j,k2)==i.
122 *
123 * @param (domaine) le domaine a traiter
124 * @param (liste_bords_periodiques) liste des noms des bords periodiques. ATTENTION: on suppose que les faces des bords periodiques sont rangees selon la convention des bords periodiques. Voir check_faces_periodiques().
125 * @param (som_elem) la connectivite sommets-elements pour le domaine donnee.
126 * @param (graph) On y stocke le resultat. Valeur de retour: nombre d'elements dans le graphe (egal au nombre de faces periodiques)
127 */
128template <typename _SIZE_>
131 const Static_Int_Lists_t& som_elem, const int_t my_offset,
132 Static_Int_Lists_t& graph)
133{
134 const Noms& liste_bords_periodiques = domaine.bords_perio();
135 const int_t nb_elem = domaine.nb_elem();
136
137 // Pour chaque element, combient a-t-il de faces periodiques ?
138 ArrOfInt_t nb_faces_perio(nb_elem);
139 // Liste de correspondances element0 <=> element1
140 // entre l'element voisin d'une face et l'element voisin de la face periodique opposee
141 IntTab_t correspondances(0,2);
142
143 // Premiere etape: remplissage de nb_faces_perio et correspondances
144 // Parcours des bords periodiques
145 const int nb_bords = domaine.nb_bords();
146 for (int i_bord = 0; i_bord < nb_bords; i_bord++)
147 {
148 const Bord_t& bord = domaine.bord(i_bord);
149 if (!liste_bords_periodiques.contient_(bord.le_nom()))
150 continue;
151 Cerr << " Checking of the boundary " << bord.le_nom();
152 {
153 ArrOfDouble delta;
154 ArrOfDouble erreur;
155 const int ok = Reordonner_faces_periodiques_32_64<_SIZE_>::check_faces_periodiques(domaine.bord(i_bord), delta, erreur);
156 const int d = delta.size_array();
157 Cerr << " Delta = ";
158 for (int i = 0; i < d; i++) Cerr << delta[i] << " ";
159 Cerr << " Error = ";
160 for (int i = 0; i < d; i++) Cerr << erreur[i] << " ";
161 Cerr << finl;
162 if (!ok)
163 {
164 Cerr << "You need to use the Declarer_bord_perio keyword on the periodic boundaries." << finl;
165 Cerr << "See the reference manual to use this keyword on your data file." << finl;
166 exit();
167 }
168 }
169 ArrOfInt_t elems_voisins;
170 chercher_elems_voisins_faces<_SIZE_>(som_elem, bord.faces().les_sommets(), bord.le_nom(), elems_voisins);
171
172 // Parcours des faces du bord periodique, 2 a 2.
173 // On suppose que les faces apparaissent dans l'ordre:
174 // d'abord toutes les faces d'une extremite du domaine,
175 // puis, dans le meme ordre, les faces de l'autre extremite.
176 assert(bord.nb_faces() % 2 == 0); // Nombre pair, forcement
177 const int_t nb_faces = bord.nb_faces() / 2;
178 for (int_t i = 0; i < nb_faces; i++)
179 {
180 // Les indices des deux elements "voisins" par la face periodique:
181 int_t elem0 = elems_voisins[i];
182 int_t elem1 = elems_voisins[i+nb_faces]; // Indice de la face perio correspondante
183
184 ++nb_faces_perio[elem0 - my_offset*(elem0 >= my_offset)];
185 ++nb_faces_perio[elem1 - my_offset*(elem1 >= my_offset)];
186 if (elem0 == elem1)
187 {
188 Cerr << "Error in calculer_correspondance_faces_perio: the faces " << i
189 << " and " << i + nb_faces
190 << "\n of the boundary " << bord.le_nom()
191 << " are neighbors of the same element " << elem0 << finl;
192 }
193 const int_t n = correspondances.dimension(0);
194 correspondances.resize(n+1, 2);
195 correspondances(n, 0) = elem0;
196 correspondances(n, 1) = elem1;
197 }
198 }
199
200 // Deuxieme etape:
201 // Construction de "graph" a partir du tableau correspondances.
202 graph.set_list_sizes(nb_faces_perio);
203 // On recycle le tableau nb_faces_perio pour stocker le nombre
204 // d'elements deja remplis dans chaque liste:
205 nb_faces_perio = 0;
206 const int_t n = correspondances.dimension(0);
207 for (int_t i = 0; i < n; i++)
208 {
209 const int_t elem0 = correspondances(i, 0),
210 elem1 = correspondances(i, 1);
211
212 const int_t j0 = nb_faces_perio[elem0 - my_offset*(elem0 >= my_offset)]++;
213 graph.set_value(elem0 - my_offset*(elem0 >= my_offset), j0, elem1);
214 const int_t j1 = nb_faces_perio[elem1 - my_offset*(elem1 >= my_offset)]++;
215 graph.set_value(elem1 - my_offset*(elem1 >= my_offset), j1, elem0);
216 }
217 Cerr << " There is " << n*2 << " periodic connections." << finl;
218 return n * 2;
219}
220
221/*! @brief Modifie elem_part pour assurer les proprietes suivantes : 1) Les elements possedant un sommet de bord sont associes
222 *
223 * a un processeur possedant une face de bord adjacente a ce sommet.
224 * 2) Si un processeur possede un sommet periodique reel, il
225 * possede forcement le renum_som_perio associe (donc un element
226 * qui possede ce sommet et un face periodique).
227 * Cette propriete est indispensable pour le periodique (existence
228 * de renum_som_perio pour tous les sommets).
229 * Pour les autres bords, cette correction est peut-etre inutile, mais
230 * pas sur. Sans cette correction, il peut exister des sommets de bord
231 * isoles (un processeur possede un sommet de bord mais aucune face).
232 * Si on cherche les sommets de bord en parcourant les faces de bord,
233 * c'est faux. Avec cette correction, cet algorithme est correct.
234 *
235 */
236template <typename _SIZE_>
239 const ArrOfInt_t& renum_som_perio,
240 const Static_Int_Lists_t& som_elem,
241 BigIntVect_& elem_part)
242{
243 using ArrOfBit_t = ArrOfBit_32_64<_SIZE_>;
244
245 const int_t nb_som_tot = domaine.nb_som_tot();
246 const int_t nb_elem = domaine.nb_elem();
247 const int_t nb_elem_tot = domaine.nb_elem_tot();
248 const Noms& liste_bords_perio = domaine.bords_perio();
249
250 // Premiere etape :
251 // Marquage des sommets de bord :
252 ArrOfBit_t sommet_bord(nb_som_tot);
253 ArrOfBit_t sommet_bord_perio(nb_som_tot);
254 sommet_bord = 0;
255 sommet_bord_perio = 0;
256 // element_bord indique si l'element est adjacent a une face de bord
257 ArrOfBit_t element_bord(nb_elem_tot);
258 // element_bord_perio indique si l'element est adjacent a une face de bord periodique
259 ArrOfBit_t element_bord_perio(nb_elem_tot);
260 element_bord = 0;
261 element_bord_perio = 0;
262
263 const int nb_bords = domaine.nb_bords();
264 for (int i_bord = 0; i_bord < nb_bords; i_bord++)
265 {
266 const Bord_t& bord = domaine.bord(i_bord);
267 const IntTab_t& faces_sommets = bord.faces().les_sommets();
268 const int_t nb_faces_bord = faces_sommets.dimension(0);
269 const int nb_som_face = faces_sommets.dimension_int(1);
270 ArrOfInt_t elems_voisins;
271 const bool is_perio = (liste_bords_perio.contient_(bord.le_nom()));
272
273 chercher_elems_voisins_faces(som_elem, faces_sommets, bord.le_nom(), elems_voisins);
274
275 // Pour chaque element voisin des faces du bord, on marque cet element.
276 // On associe a chaque sommet de bord l'indice de la partie la plus
277 // petite qui contient une face de bord adjacente au sommet.
278 for (int_t i_face = 0; i_face < nb_faces_bord; i_face++)
279 {
280 const int_t elem_voisin = elems_voisins[i_face];
281 element_bord.setbit(elem_voisin);
282 if (is_perio)
283 element_bord_perio.setbit(elem_voisin);
284 for (int i_som = 0; i_som < nb_som_face; i_som++)
285 {
286 const int_t som = faces_sommets(i_face, i_som);
287 sommet_bord.setbit(som);
288 if (is_perio)
289 sommet_bord_perio.setbit(som);
290 }
291 }
292 }
293
294 // Deuxieme etape:
295 // Parcours des elements qui n'ont pas de face de bord mais qui ont
296 // des sommets de bord:
297 // On construit pour chaque sommet de bord de l'element, la liste des
298 // "parties autorisees"
299 // Si le sommet renum_som_perio est adjacent a une face de bord periodique,
300 // les parties autorisees sont celles qui possedent une face periodique
301 // adjacente au sommet.
302 // Sinon, c'est les parties contenant une face de bord adjacente au sommet
303 // On calcule l'intersection de ces listes et si l'element n'est pas dans
304 // une partie autorisee, on en choisit une et on le met dedans.
305 int_t count = 0;
306 {
307 BigArrOfInt_ parties_autorisees, tmp;
308
309 const IntTab_t& elements = domaine.les_elems();
310 const int nb_som_elem = elements.dimension_int(1);
311 for (int_t elem = 0; elem < nb_elem; elem++)
312 {
313 // L'element a-t-il un sommet periodique ?
314 bool has_som_perio = false;
315 int isom;
316 for (isom = 0; isom < nb_som_elem; isom++)
317 if (sommet_bord_perio[elements(elem, isom)])
318 has_som_perio = true;
319 // Boucle sur les sommets de l'element:
320 parties_autorisees.resize_array(0);
321 int nb_sommets_bord = 0; // Nombre de sommets de bord de l'element
322 for (isom = 0; isom < nb_som_elem; isom++)
323 {
324 const int_t som = elements(elem, isom);
325 // Ne traiter que les sommets de bord perio si l'element a un bord perio,
326 // sinon ne traiter que les sommets de bord.
327 if (has_som_perio && !sommet_bord_perio[som])
328 continue;
329 if (!sommet_bord[som])
330 continue;
331
332 nb_sommets_bord++;
333 // On met dans tmp la liste des parties associees aux elements de bord adjacents
334 {
335 tmp.resize_array(0);
336 const int_t renum_som = renum_som_perio[som];
337 const int_t n = som_elem.get_list_size(renum_som);
338 for (int_t i = 0; i < n; i++)
339 {
340 const int_t elem2 = som_elem(renum_som, i);
341 int_t test;
342 if (has_som_perio)
343 test = element_bord_perio[elem2];
344 else
345 test = element_bord[elem2];
346 if (test)
347 {
348 const int p = elem_part[elem2];
349 tmp.append_array(p);
350 }
351 }
352 array_trier_retirer_doublons(tmp);
353 }
354 // Calcul de l'intersection entre tmp et parties_autorisees
355 if (parties_autorisees.size_array() > 0)
356 array_calculer_intersection(parties_autorisees, tmp);
357 else
358 parties_autorisees = tmp;
359 }
360 if (nb_sommets_bord > 0)
361 {
362 // Est-ce que l'element appartient a une partie autorisee ?
363 const int_t n = parties_autorisees.size_array();
364 if (n == 0)
365 {
366 Cerr << "Partitionneur_base_32_64<_SIZE_>::corriger_sommets_bord : Error. No part authorized because of the periodicity for the mesh element " << elem << finl;
367 elem_part[elem] = -1;
368 }
369 else
370 {
371 int_t i;
372 const int p = elem_part[elem];
373 for (i = 0; i < n; i++)
374 if (parties_autorisees[i] == p)
375 break;
376 if (i >= n)
377 {
378 // Il faut affecter une autre partie:
379 elem_part[elem] = parties_autorisees[0];
380 count++;
381 }
382 }
383 }
384 }
385 Cerr << "Partitionneur_base_32_64<_SIZE_>::corriger_sommets_bord : " << count << " modified elements" << finl;
386 }
387 return count;
388}
389
390/*! @brief applique des corrections a elem_part pour que le multi-periodique soit correct :
391 *
392 * Si un sommet appartient a plusieurs frontieres periodiques,
393 * tous les elements adjacents sont rattaches au meme processeur.
394 *
395 */
396template <typename _SIZE_>
399 const ArrOfInt_t& renum_som_perio,
400 const Static_Int_Lists_t& som_elem,
401 BigIntVect_& elem_part)
402{
403 const int_t nb_som = domaine.nb_som();
404 const int_t nb_elem = domaine.nb_elem();
405 const Noms& liste_bords_perio = domaine.bords_perio();
406
407 // Pour chaque sommet periodique, selectionner une partie a laquelle il appartient
408 // (la plus petite parmi les parties des elements periodiques adjacents)
409 // Initialise a -1
410 BigArrOfInt_ partie_associee(nb_som);
411 partie_associee= -1;
412 // Pour chaque sommet, a quel(s) bords periodiques appartient-il
413 // (somme de 2^n ou n est l'indice du nom du bord dans la liste des bords periodiques)
414 // Initialise a 0
415 BigArrOfInt_ marqueur_bord(nb_som);
416
417 int deux_puissance_i_bord = 1;
418 for (auto& itr : liste_bords_perio)
419 {
420 const Bord_t& bord = domaine.bord(itr);
421 const IntTab_t& faces_sommets = bord.faces().les_sommets();
422 const int_t nb_faces_bord = faces_sommets.dimension(0);
423 const int nb_som_face = faces_sommets.dimension_int(1);
424 ArrOfInt_t elems_voisins;
425 chercher_elems_voisins_faces<_SIZE_>(som_elem, faces_sommets, bord.le_nom(), elems_voisins);
426 for (int_t i_face = 0; i_face < nb_faces_bord; i_face++)
427 {
428 const int_t elem_voisin = elems_voisins[i_face];
429 const int part = elem_part[elem_voisin];
430 for (int i_som = 0; i_som < nb_som_face; i_som++)
431 {
432 const int_t som = faces_sommets(i_face, i_som);
433 const int old_part = partie_associee[som];
434 if (old_part < 0 || old_part > part)
435 partie_associee[som] = part;
436 marqueur_bord[som] |= deux_puissance_i_bord; // Bitwise OR operator
437 }
438 }
439 deux_puissance_i_bord *= 2;
440 if (deux_puissance_i_bord > 65536)
441 {
442 // De toutes facons, plus de 3 frontieres periodiques, c'est hautement suspect...
443 Cerr << "Error in Partitionneur_base_32_64<_SIZE_>::corriger_multiperiodique : there is too many periodic boundaries." << finl;
444 exit();
445 }
446 }
447
448 // Transformer marqueur_bord:
449 // 1 si le sommet appartient a plusieurs bords periodiques,
450 // 0 sinon
451 for (int_t sommet = 0; sommet < nb_som; sommet++)
452 {
453 // Compter le nombre de bits a 1 dans le marqueur
454 const int marq = marqueur_bord[sommet];
455 int n = 0;
456 for (int x = 1; x < marq; x = x * 2)
457 {
458 if (marq & x) // bitwise AND
459 n++;
460 }
461 // Marqueur a 1 si le sommet appartient a plusieurs bords
462 marqueur_bord[sommet] = (n > 1);
463 }
464 // Deuxieme etape: affecter les elements adjacents a un sommet multiperiodique
465 // a la partie associee au sommet renum_som_perio de ce sommet.
466 const IntTab_t& les_elems = domaine.les_elems();
467 const int nb_som_elem = les_elems.dimension_int(1);
468 int_t count = 0;
469 for (int_t elem = 0; elem < nb_elem; elem++)
470 {
471 // Cet int vaudra -1 si aucun sommet de l'element est periodique,
472 // sinon, c'est la plus petite des parties associees aux sommets periodiques
473 int new_part = -1;
474 for (int isom = 0; isom < nb_som_elem; isom++)
475 {
476 const int_t sommet = les_elems(elem, isom);
477 if (marqueur_bord[sommet])
478 {
479 // Ce sommet appartient a plusieurs frontieres periodiques
480 const int_t renum = renum_som_perio[sommet];
481 const int part = partie_associee[renum];
482 assert(marqueur_bord[renum]);
483 assert(part > -1);
484 if (new_part < 0 || new_part > part)
485 new_part = part;
486 }
487 }
488 if (new_part >= 0 && new_part != elem_part[elem])
489 {
490 count++;
491 elem_part[elem] = new_part;
492 }
493 }
494 Cerr << "Partitionneur_base_32_64<_SIZE_>::corriger_multiperiodique : " << count << " modified elements" << finl;
495
496 // Add another criteria to fix some problem when building renum_som_perio in parallel:
497 // Check every periodic nodes are surrounded by elements on the same parts
498 SmallArrOfTID_T<_SIZE_> node(2);
499 int_t another_count=0;
500 bool err=false; // never changed later??
501 for (int_t som=0; som<nb_som; som++)
502 {
503 // Periodic nodes:
504 node[0]=som;
505 node[1]=renum_som_perio[som];
506 if (node[0]!=node[1])
507 {
508 // Loop on each element surrounding the nodes
509 IntLists part(2);
510 for (int i=0; i<2; i++)
511 {
512 for (int_t i_elem=0; i_elem<som_elem.get_list_size(node[i]); i_elem++)
513 {
514 int_t elem = som_elem(node[i],i_elem);
515 part[i].add_if_not(elem_part[elem]);
516 }
517 }
518 // Check if same number:
519 if (part[0].size()!=part[1].size())
520 {
521 Cerr << "Warning: Not the same number of parts around the periodic nodes " << node[0] << " and " << node[1] << " !" << finl;
522 Cerr << "We try to fix:" << finl;
523 int smaller = ( part[0].size() < part[1].size() ? 0 : 1);
524 int bigger = 1 - smaller;
525 int first_part = part[smaller][0]; // Take arbitrary the first part of the smallest list
526 for (int i=0; i<part[bigger].size(); i++)
527 {
528 int i_part = part[bigger][i];
529 if (!part[smaller].contient(i_part))
530 {
531 // i_part -> first_part on all elements surrounding the node with more parts:
532 for (int_t i_elem=0; i_elem<som_elem.get_list_size(node[bigger]); i_elem++)
533 {
534 int_t elem = som_elem(node[bigger],i_elem);
535 if (elem_part[elem] == i_part)
536 {
537 elem_part[elem] = first_part;
538 another_count++;
539 Cerr << "Element " << elem << " moved from part " << i_part << " to " << first_part << finl;
540 }
541 }
542 }
543 }
544 }
545 else
546 {
547 // Check if same parts around the 2 nodes:
548 for (int i=0; i<part[0].size(); i++)
549 {
550 int i_part = part[0][i];
551 if (!part[1].contient(i_part))
552 {
553 // Implement an algorithm as just above ?
554 Cerr << "Warning: different parts around the periodic nodes " << node[0] << " and " << node[1] << " !" << finl;
555 //for (int j=0;j<2;j++)
556 // for (int k=0;k<part[j].size();k++)
557 // Cerr << "node " << j << " part " << part[j][k] << finl;
558 Cerr << "We try to fix:" << finl;
559 // Look for the j_part not in the part[1] list:
560 for (int j=0; j<part[1].size(); j++)
561 {
562 int j_part = part[1][j];
563 if (!part[0].contient(j_part))
564 {
565 // Choice between i_part and j_part:
566 // We take i_part arbitrary so j_part -> i_part
567 for (int_t i_elem=0; i_elem<som_elem.get_list_size(node[1]); i_elem++)
568 {
569 int_t elem = som_elem(node[1],i_elem);
570 if (elem_part[elem] == j_part)
571 {
572 elem_part[elem] = i_part;
573 Cerr << "Element " << elem << " moved from part " << j_part << " to " << i_part << finl;
574 another_count++;
575 }
576 }
577 }
578 }
579 }
580 }
581 }
582 }
583 }
584 if (err)
585 {
586 Cerr << "Error in Partitionneur_base_32_64<_SIZE_>::corriger_multiperiodique" << finl;
587 Cerr << "It will create possible problems for creation of renum_som_perio array." << finl;
588 Cerr << "Contact TRUST support or change the partition options." << finl;
589 exit();
590 }
591 count+=another_count;
592 Cerr << "Partitionneur_base_32_64<_SIZE_>::corriger_multiperiodique : plus " << another_count << " another modified elements" << finl;
593 return count;
594}
595
596/*! @brief corrige la partition elem_part pour qu'un element i se trouve sur la meme partition elem_part[i] que tous les elements auxquels il est lie dans le graphe
597 *
598 * (elements d'indices graph_elements_perio(i, j) pour tout j).
599 *
600 * @param (graph_elements_perio) graphe calcule par la methode calculer_graphe_connexions_periodiques
601 * @param (elem_part) pour chaque element, a quelle partie appartient-il. Valeur de retour: nombre d'elements dont la partition a ete corrigee.
602 */
603template <typename _SIZE_>
606 const Static_Int_Lists_t& som_elem,
607 const Domaine_t& domaine,
608 BigIntVect_& elem_part)
609{
610 // Algorithme: parcours de tous les elements dans l'ordre.
611 // Pour chaque element, associer aux autres elements lies la partie a laquelle appartient
612 // l'element courant. Comme le graphe est symetrique, si un element a deja ete traite,
613 // on ne change rien les fois suivantes. Donc un seul passage suffit.
614 const Noms& liste_bords_periodiques = domaine.bords_perio();
615 const int_t n = graph_elements_perio.get_nb_lists(); //elem_part.size_array();
616 //assert(n == graph_elements_perio.get_nb_lists());
617 int_t count = 0;
618 for (int_t i = 0; i < n; i++)
619 {
620 const int_t m = graph_elements_perio.get_list_size(i);
621 const int part = elem_part[i];
622 for (int_t j = 0; j < m; j++)
623 {
624 const int_t elem2 = graph_elements_perio(i,j);
625 if (elem_part[elem2] != part)
626 {
627 elem_part[elem2] = part;
628 count++;
629 }
630 }
631 }
632 Cerr << "Partitionneur_base_32_64<_SIZE_>::corriger_bords_avec_graphe : " << count
633 << " modified periodic elements" << finl;
634
635 const int_t nb_sommets_reels = domaine.nb_som();
636 ArrOfInt_t renum_som_perio(nb_sommets_reels);
637 // Initialisation du tableau renum_som_perio
638 for (int_t i = 0; i < nb_sommets_reels; i++)
639 renum_som_perio[i] = i;
640 bool parallel_algo = Process::is_parallel();
642 parallel_algo /* pas d'espace virtuel en sequentiel */);
643
644 if (liste_bords_periodiques.size() > 1)
645 count += corriger_multiperiodique(domaine, renum_som_perio, som_elem, elem_part);
646 count += corriger_sommets_bord(domaine, renum_som_perio, som_elem, elem_part);
647 return count;
648}
649
650/*! @brief Calcul des graphes de connectivite elements periodiques et appel a corriger_periodique_avec_graphe.
651 *
652 * (Methode a utiliser quand on ne dispose
653 * pas encore du graphe de de connectivite, si on a le graphe sous la main,
654 * appeler directement corriger_periodique_avec_graphe)
655 *
656 */
657template <typename _SIZE_>
659 const int_t my_offset,
660 BigIntVect_& elem_part)
661{
662 Cerr << "Correction of the splitting for the periodicity" << finl;
663 Static_Int_Lists_t som_elem;
664 Cerr << " Construction of the connectivity som_elem" << finl;
665 construire_connectivite_som_elem(dom.nb_som_tot(),
666 dom.les_elems(),
667 som_elem,
668 1 /* inclure les elements virtuels */);
669 Cerr << " Construction of graph connectivity for periodic elements" << finl;
670 Static_Int_Lists_t graph_elements_perio;
672 som_elem,
673 my_offset,
674 graph_elements_perio);
675 const int_t count = corriger_bords_avec_graphe(graph_elements_perio,
676 som_elem,
677 dom,
678 elem_part);
679 Cerr << "corriger_bords_avec_liste : we have corrected " << count << " elements all in all." << finl;
680}
681
682
683
684template class Partitionneur_base_32_64<int>;
685#if INT_is_64_ == 2
687#endif
688
689
IntTab_t & les_elems()
Definition Domaine.h:129
int_t nb_som_tot() const
Renvoie le nombre total de sommets du domaine i.e. le nombre de sommets reels et virtuels sur le proc...
Definition Domaine.h:123
const IntTab_t & les_sommets() const
Renvoie le tableau des sommets de toutes les faces.
Definition Faces.h:74
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Frontiere.h:49
int_t nb_faces() const
Renvoie le nombre de faces de la frontiere.
Definition Frontiere.h:59
const Faces_t & faces() const
Definition Frontiere.h:54
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
int contient_(const char *const ch) const
Definition Noms.cpp:60
Inherits from Objet_U, adds the very common method set_param for the Objet_U hierarchy.
virtual void set_param(Param &) const
Definition Objet_U.h:135
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
Classe de base des partitionneurs de domaine (pour decouper un maillage avant un calcul parallele).
TRUSTArray< int, _SIZE_ > BigArrOfInt_
static int_t corriger_bords_avec_graphe(const Static_Int_Lists_t &graph_elements_perio, const Static_Int_Lists_t &som_elem, const Domaine_t &domaine, BigIntVect_ &elem_part)
corrige la partition elem_part pour qu'un element i se trouve sur la meme partition elem_part[i] que ...
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...
ArrOfInt_T< _SIZE_ > ArrOfInt_t
static int_t corriger_sommets_bord(const Domaine_t &domaine, const ArrOfInt_t &renum_som_perio, const Static_Int_Lists_t &som_elem, BigIntVect_ &elem_part)
Modifie elem_part pour assurer les proprietes suivantes : 1) Les elements possedant un sommet de bord...
TRUSTVect< int, _SIZE_ > BigIntVect_
Domaine_32_64< _SIZE_ > Domaine_t
Bord_32_64< _SIZE_ > Bord_t
static int_t corriger_multiperiodique(const Domaine_t &domaine, const ArrOfInt_t &renum_som_perio, const Static_Int_Lists_t &som_elem, BigIntVect_ &elem_part)
applique des corrections a elem_part pour que le multi-periodique soit correct :
IntTab_T< _SIZE_ > IntTab_t
Static_Int_Lists_32_64< _SIZE_ > Static_Int_Lists_t
static int_t calculer_graphe_connexions_periodiques(const Domaine_t &domaine, const Static_Int_Lists_t &som_elem, const int_t my_offset, Static_Int_Lists_t &graph)
Calcul d'un graphe de connectivite entre les elements lies par des faces periodiques.
static bool is_parallel()
Definition Process.cpp:110
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...
static void renum_som_perio(const Domaine_32_64< _SIZE_ > &dom, ArrOfInt_T< _SIZE_ > &renum_som_perio, bool calculer_espace_virtuel)
Classe de base des flux de sortie.
Definition Sortie.h:52
Cette classe permet de stocker des listes d'entiers accessibles en temps constant.
void set_value(int_t i_liste, int_t i_element, int_t valeur)
affecte la "valeur" au j-ieme element de la i-ieme liste avec 0 <= i < get_nb_lists() et 0 <= j < get...
int_t get_list_size(int_t i_liste) const
renvoie le nombre d'elements de la liste i
void set_list_sizes(const ArrOfInt_t &sizes)
detruit les listes existantes et en cree de nouvelles.
int_t get_nb_lists() const
renvoie le nombre de listes stockees
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
int size() const
Definition TRUSTLists.h:86
int dimension_int(int d) const
Definition TRUSTTab.tpp:152
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size_reelle() const
Definition TRUSTVect.tpp:27