TrioCFD 1.9.9_beta
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 Corrects the partition so that element 0 of the initial domain is on the first sub-domain of the partition.
44 *
45 * The first sub-domain and the one containing element 0 are swapped.
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 Builds (size and content) the elements array with, for each face of the given boundary, the index of the adjacent domain element.
76 *
77 * @param som_elem Vertex-element connectivity for the domain, computed using construire_connectivite_som_elem.
78 * @param faces The faces of the boundary to process (for each face, indices of the vertices).
79 * @param nom_faces A boundary name to print in case of error.
80 * @param elements The array to fill.
81 */
82template <typename _SIZE_>
83void chercher_elems_voisins_faces(const Static_Int_Lists_32_64<_SIZE_>& som_elem,
84 const IntTab_T<_SIZE_>& faces,
85 const Nom& nom_faces,
86 ArrOfInt_T<_SIZE_>& elements)
87{
88 using int_t = _SIZE_;
89 using SmallArrOfTID_t = SmallArrOfTID_T<_SIZE_>;
90
91 const int_t nb_faces = faces.dimension(0);
92 elements.resize_array(nb_faces);
93 if (nb_faces == 0)
94 return;
95 const int nb_som_faces = faces.dimension_int(1);
96 SmallArrOfTID_t une_face(nb_som_faces);
97 SmallArrOfTID_t voisins;
98 for (int_t i = 0; i < nb_faces; i++)
99 {
100 for (int j = 0; j < nb_som_faces; j++)
101 une_face[j] = faces(i, j);
102 find_adjacent_elements(som_elem, une_face, voisins);
103 const int nb_voisins = voisins.size_array();
104 if (nb_voisins != 1)
105 {
106 Cerr << "Error in chercher_elems_voisins_faces : the face " << i
107 << "\n of boundary " << nom_faces << " has " << nb_voisins
108 << " neighboring elements with the indices : " << voisins << finl;
110 }
111 elements[i] = voisins[0];
112 }
113}
114}
115
116/*! @brief Computes a connectivity graph between elements connected by periodic faces.
117 *
118 * If element i is a neighbour of element j through a periodic face, then there exists
119 * k such that graph(i,k)==j and there exists k2 such that graph(j,k2)==i.
120 *
121 * @param domaine The domain to process.
122 * @param som_elem Vertex-element connectivity for the given domain. WARNING: periodic boundary faces are assumed to be ordered according to the periodic boundary convention. See check_faces_periodiques().
123 * @param my_offset Global element offset for this process.
124 * @param graph Where the result is stored. Return value: number of elements in the graph (equal to the number of periodic faces).
125 */
126template <typename _SIZE_>
129 const Static_Int_Lists_t& som_elem, const int_t my_offset,
130 Static_Int_Lists_t& graph)
131{
132 const Noms& liste_bords_periodiques = domaine.bords_perio();
133 const int_t nb_elem = domaine.nb_elem();
134
135 // For each element, how many periodic faces does it have?
136 ArrOfInt_t nb_faces_perio(nb_elem);
137 // List of correspondences element0 <=> element1
138 // between the element adjacent to a face and the element adjacent to the opposite periodic face
139 IntTab_t correspondances(0,2);
140
141 // First step: fill nb_faces_perio and correspondances
142 // Loop over periodic boundaries
143 const int nb_bords = domaine.nb_bords();
144 for (int i_bord = 0; i_bord < nb_bords; i_bord++)
145 {
146 const Bord_t& bord = domaine.bord(i_bord);
147 if (!liste_bords_periodiques.contient_(bord.le_nom()))
148 continue;
149 Cerr << " Checking of the boundary " << bord.le_nom();
150 {
151 ArrOfDouble delta;
152 ArrOfDouble erreur;
153 const int ok = Reordonner_faces_periodiques_32_64<_SIZE_>::check_faces_periodiques(domaine.bord(i_bord), delta, erreur);
154 const int d = delta.size_array();
155 Cerr << " Delta = ";
156 for (int i = 0; i < d; i++) Cerr << delta[i] << " ";
157 Cerr << " Error = ";
158 for (int i = 0; i < d; i++) Cerr << erreur[i] << " ";
159 Cerr << finl;
160 if (!ok)
161 {
162 Cerr << "You need to use the Declarer_bord_perio keyword on the periodic boundaries." << finl;
163 Cerr << "See the reference manual to use this keyword on your data file." << finl;
164 exit();
165 }
166 }
167 ArrOfInt_t elems_voisins;
168 chercher_elems_voisins_faces<_SIZE_>(som_elem, bord.faces().les_sommets(), bord.le_nom(), elems_voisins);
169
170 // Loop over the periodic boundary faces, two by two.
171 // It is assumed that faces appear in the order:
172 // first all faces from one end of the domain,
173 // then, in the same order, the faces from the other end.
174 assert(bord.nb_faces() % 2 == 0); // Even count, necessarily
175 const int_t nb_faces = bord.nb_faces() / 2;
176 for (int_t i = 0; i < nb_faces; i++)
177 {
178 // Indices of the two elements "neighbouring" through the periodic face:
179 int_t elem0 = elems_voisins[i];
180 int_t elem1 = elems_voisins[i+nb_faces]; // Index of the corresponding periodic face
181
182 ++nb_faces_perio[elem0 - my_offset*(elem0 >= my_offset)];
183 ++nb_faces_perio[elem1 - my_offset*(elem1 >= my_offset)];
184 if (elem0 == elem1)
185 {
186 Cerr << "Error in calculer_correspondance_faces_perio: the faces " << i
187 << " and " << i + nb_faces
188 << "\n of the boundary " << bord.le_nom()
189 << " are neighbors of the same element " << elem0 << finl;
190 }
191 const int_t n = correspondances.dimension(0);
192 correspondances.resize(n+1, 2);
193 correspondances(n, 0) = elem0;
194 correspondances(n, 1) = elem1;
195 }
196 }
197
198 // Second step:
199 // Build "graph" from the correspondances array.
200 graph.set_list_sizes(nb_faces_perio);
201 // Reuse the nb_faces_perio array to store the number
202 // of elements already filled in each list:
203 nb_faces_perio = 0;
204 const int_t n = correspondances.dimension(0);
205 for (int_t i = 0; i < n; i++)
206 {
207 const int_t elem0 = correspondances(i, 0),
208 elem1 = correspondances(i, 1);
209
210 const int_t j0 = nb_faces_perio[elem0 - my_offset*(elem0 >= my_offset)]++;
211 graph.set_value(elem0 - my_offset*(elem0 >= my_offset), j0, elem1);
212 const int_t j1 = nb_faces_perio[elem1 - my_offset*(elem1 >= my_offset)]++;
213 graph.set_value(elem1 - my_offset*(elem1 >= my_offset), j1, elem0);
214 }
215 Cerr << " There is " << n*2 << " periodic connections." << finl;
216 return n * 2;
217}
218
219/*! @brief Modifies elem_part to ensure the following properties: 1) Elements that have a boundary vertex are associated
220 *
221 * with a processor that owns an adjacent boundary face.
222 * 2) If a processor owns a real periodic vertex, it necessarily
223 * also owns the associated renum_som_perio (hence an element
224 * that has this vertex and a periodic face).
225 * This property is essential for periodicity (existence
226 * of renum_som_perio for all vertices).
227 * For other boundaries, this correction may be unnecessary, but
228 * this is not certain. Without this correction, isolated boundary
229 * vertices can exist (a processor owns a boundary vertex but no face).
230 * If boundary vertices are searched by scanning boundary faces,
231 * the result is wrong. With this correction, that algorithm is correct.
232 *
233 */
234template <typename _SIZE_>
237 const ArrOfInt_t& renum_som_perio,
238 const Static_Int_Lists_t& som_elem,
239 BigIntVect_& elem_part)
240{
241 using ArrOfBit_t = ArrOfBit_32_64<_SIZE_>;
242
243 const int_t nb_som_tot = domaine.nb_som_tot();
244 const int_t nb_elem = domaine.nb_elem();
245 const int_t nb_elem_tot = domaine.nb_elem_tot();
246 const Noms& liste_bords_perio = domaine.bords_perio();
247
248 // First step:
249 // Mark boundary vertices:
250 ArrOfBit_t sommet_bord(nb_som_tot);
251 ArrOfBit_t sommet_bord_perio(nb_som_tot);
252 sommet_bord = 0;
253 sommet_bord_perio = 0;
254 // element_bord indicates whether the element is adjacent to a boundary face
255 ArrOfBit_t element_bord(nb_elem_tot);
256 // element_bord_perio indicates whether the element is adjacent to a periodic boundary face
257 ArrOfBit_t element_bord_perio(nb_elem_tot);
258 element_bord = 0;
259 element_bord_perio = 0;
260
261 const int nb_bords = domaine.nb_bords();
262 for (int i_bord = 0; i_bord < nb_bords; i_bord++)
263 {
264 const Bord_t& bord = domaine.bord(i_bord);
265 const IntTab_t& faces_sommets = bord.faces().les_sommets();
266 const int_t nb_faces_bord = faces_sommets.dimension(0);
267 const int nb_som_face = faces_sommets.dimension_int(1);
268 ArrOfInt_t elems_voisins;
269 const bool is_perio = (liste_bords_perio.contient_(bord.le_nom()));
270
271 chercher_elems_voisins_faces(som_elem, faces_sommets, bord.le_nom(), elems_voisins);
272
273 // For each element neighbouring the boundary faces, mark that element.
274 // Associate to each boundary vertex the index of the smallest part
275 // that contains an adjacent boundary face.
276 for (int_t i_face = 0; i_face < nb_faces_bord; i_face++)
277 {
278 const int_t elem_voisin = elems_voisins[i_face];
279 element_bord.setbit(elem_voisin);
280 if (is_perio)
281 element_bord_perio.setbit(elem_voisin);
282 for (int i_som = 0; i_som < nb_som_face; i_som++)
283 {
284 const int_t som = faces_sommets(i_face, i_som);
285 sommet_bord.setbit(som);
286 if (is_perio)
287 sommet_bord_perio.setbit(som);
288 }
289 }
290 }
291
292 // Second step:
293 // Loop over elements that have no boundary face but do have
294 // boundary vertices:
295 // For each boundary vertex of the element, build the list of
296 // "allowed parts":
297 // If the renum_som_perio vertex is adjacent to a periodic boundary face,
298 // the allowed parts are those that own a periodic face adjacent to the vertex.
299 // Otherwise, they are the parts containing an adjacent boundary face.
300 // Compute the intersection of these lists and if the element does not belong
301 // to an allowed part, choose one and assign it.
302 int_t count = 0;
303 {
304 BigArrOfInt_ parties_autorisees, tmp;
305
306 const IntTab_t& elements = domaine.les_elems();
307 const int nb_som_elem = elements.dimension_int(1);
308 for (int_t elem = 0; elem < nb_elem; elem++)
309 {
310 // Does the element have a periodic vertex?
311 bool has_som_perio = false;
312 int isom;
313 for (isom = 0; isom < nb_som_elem; isom++)
314 if (sommet_bord_perio[elements(elem, isom)])
315 has_som_perio = true;
316 // Loop over element vertices:
317 parties_autorisees.resize_array(0);
318 int nb_sommets_bord = 0; // Number of boundary vertices of the element
319 for (isom = 0; isom < nb_som_elem; isom++)
320 {
321 const int_t som = elements(elem, isom);
322 // Process only periodic boundary vertices if the element has a periodic boundary,
323 // otherwise process only boundary vertices.
324 if (has_som_perio && !sommet_bord_perio[som])
325 continue;
326 if (!sommet_bord[som])
327 continue;
328
329 nb_sommets_bord++;
330 // Put in tmp the list of parts associated with adjacent boundary elements
331 {
332 tmp.resize_array(0);
333 const int_t renum_som = renum_som_perio[som];
334 const int_t n = som_elem.get_list_size(renum_som);
335 for (int_t i = 0; i < n; i++)
336 {
337 const int_t elem2 = som_elem(renum_som, i);
338 int_t test;
339 if (has_som_perio)
340 test = element_bord_perio[elem2];
341 else
342 test = element_bord[elem2];
343 if (test)
344 {
345 const int p = elem_part[elem2];
346 tmp.append_array(p);
347 }
348 }
349 array_trier_retirer_doublons(tmp);
350 }
351 // Compute the intersection between tmp and parties_autorisees
352 if (parties_autorisees.size_array() > 0)
353 array_calculer_intersection(parties_autorisees, tmp);
354 else
355 parties_autorisees = tmp;
356 }
357 if (nb_sommets_bord > 0)
358 {
359 // Does the element belong to an allowed part?
360 const int_t n = parties_autorisees.size_array();
361 if (n == 0)
362 {
363 Cerr << "Partitionneur_base_32_64<_SIZE_>::corriger_sommets_bord : Error. No part authorized because of the periodicity for the mesh element " << elem << finl;
364 elem_part[elem] = -1;
365 }
366 else
367 {
368 int_t i;
369 const int p = elem_part[elem];
370 for (i = 0; i < n; i++)
371 if (parties_autorisees[i] == p)
372 break;
373 if (i >= n)
374 {
375 // Another part must be assigned:
376 elem_part[elem] = parties_autorisees[0];
377 count++;
378 }
379 }
380 }
381 }
382 Cerr << "Partitionneur_base_32_64<_SIZE_>::corriger_sommets_bord : " << count << " modified elements" << finl;
383 }
384 return count;
385}
386
387/*! @brief Applies corrections to elem_part so that multi-periodicity is correct:
388 *
389 * If a vertex belongs to several periodic boundaries,
390 * all adjacent elements are assigned to the same processor.
391 *
392 */
393template <typename _SIZE_>
396 const ArrOfInt_t& renum_som_perio,
397 const Static_Int_Lists_t& som_elem,
398 BigIntVect_& elem_part)
399{
400 const int_t nb_som = domaine.nb_som();
401 const int_t nb_elem = domaine.nb_elem();
402 const Noms& liste_bords_perio = domaine.bords_perio();
403
404 // For each periodic vertex, select a part to which it belongs
405 // (the smallest among the parts of the adjacent periodic elements)
406 // Initialised to -1
407 BigArrOfInt_ partie_associee(nb_som);
408 partie_associee= -1;
409 // For each vertex, to which periodic boundary(ies) does it belong?
410 // (sum of 2^n where n is the index of the boundary name in the periodic boundary list)
411 // Initialised to 0
412 BigArrOfInt_ marqueur_bord(nb_som);
413
414 int deux_puissance_i_bord = 1;
415 for (auto& itr : liste_bords_perio)
416 {
417 const Bord_t& bord = domaine.bord(itr);
418 const IntTab_t& faces_sommets = bord.faces().les_sommets();
419 const int_t nb_faces_bord = faces_sommets.dimension(0);
420 const int nb_som_face = faces_sommets.dimension_int(1);
421 ArrOfInt_t elems_voisins;
422 chercher_elems_voisins_faces<_SIZE_>(som_elem, faces_sommets, bord.le_nom(), elems_voisins);
423 for (int_t i_face = 0; i_face < nb_faces_bord; i_face++)
424 {
425 const int_t elem_voisin = elems_voisins[i_face];
426 const int part = elem_part[elem_voisin];
427 for (int i_som = 0; i_som < nb_som_face; i_som++)
428 {
429 const int_t som = faces_sommets(i_face, i_som);
430 const int old_part = partie_associee[som];
431 if (old_part < 0 || old_part > part)
432 partie_associee[som] = part;
433 marqueur_bord[som] |= deux_puissance_i_bord; // Bitwise OR operator
434 }
435 }
436 deux_puissance_i_bord *= 2;
437 if (deux_puissance_i_bord > 65536)
438 {
439 // In any case, more than 3 periodic boundaries is highly suspicious...
440 Cerr << "Error in Partitionneur_base_32_64<_SIZE_>::corriger_multiperiodique : there is too many periodic boundaries." << finl;
441 exit();
442 }
443 }
444
445 // Transform marqueur_bord:
446 // 1 if the vertex belongs to several periodic boundaries,
447 // 0 otherwise
448 for (int_t sommet = 0; sommet < nb_som; sommet++)
449 {
450 // Count the number of bits set to 1 in the marker
451 const int marq = marqueur_bord[sommet];
452 int n = 0;
453 for (int x = 1; x < marq; x = x * 2)
454 {
455 if (marq & x) // bitwise AND
456 n++;
457 }
458 // Marker is 1 if the vertex belongs to several boundaries
459 marqueur_bord[sommet] = (n > 1);
460 }
461 // Second step: assign elements adjacent to a multi-periodic vertex
462 // to the part associated with the renum_som_perio vertex of that vertex.
463 const IntTab_t& les_elems = domaine.les_elems();
464 const int nb_som_elem = les_elems.dimension_int(1);
465 int_t count = 0;
466 for (int_t elem = 0; elem < nb_elem; elem++)
467 {
468 // This int will be -1 if no vertex of the element is periodic,
469 // otherwise it is the smallest of the parts associated with the periodic vertices
470 int new_part = -1;
471 for (int isom = 0; isom < nb_som_elem; isom++)
472 {
473 const int_t sommet = les_elems(elem, isom);
474 if (marqueur_bord[sommet])
475 {
476 // This vertex belongs to several periodic boundaries
477 const int_t renum = renum_som_perio[sommet];
478 const int part = partie_associee[renum];
479 assert(marqueur_bord[renum]);
480 assert(part > -1);
481 if (new_part < 0 || new_part > part)
482 new_part = part;
483 }
484 }
485 if (new_part >= 0 && new_part != elem_part[elem])
486 {
487 count++;
488 elem_part[elem] = new_part;
489 }
490 }
491 Cerr << "Partitionneur_base_32_64<_SIZE_>::corriger_multiperiodique : " << count << " modified elements" << finl;
492
493 // Add another criteria to fix some problem when building renum_som_perio in parallel:
494 // Check every periodic nodes are surrounded by elements on the same parts
495 SmallArrOfTID_T<_SIZE_> node(2);
496 int_t another_count=0;
497 bool err=false; // never changed later??
498 for (int_t som=0; som<nb_som; som++)
499 {
500 // Periodic nodes:
501 node[0]=som;
502 node[1]=renum_som_perio[som];
503 if (node[0]!=node[1])
504 {
505 // Loop on each element surrounding the nodes
506 IntLists part(2);
507 for (int i=0; i<2; i++)
508 {
509 for (int_t i_elem=0; i_elem<som_elem.get_list_size(node[i]); i_elem++)
510 {
511 int_t elem = som_elem(node[i],i_elem);
512 part[i].add_if_not(elem_part[elem]);
513 }
514 }
515 // Check if same number:
516 if (part[0].size()!=part[1].size())
517 {
518 Cerr << "Warning: Not the same number of parts around the periodic nodes " << node[0] << " and " << node[1] << " !" << finl;
519 Cerr << "We try to fix:" << finl;
520 int smaller = ( part[0].size() < part[1].size() ? 0 : 1);
521 int bigger = 1 - smaller;
522 int first_part = part[smaller][0]; // Take arbitrary the first part of the smallest list
523 for (int i=0; i<part[bigger].size(); i++)
524 {
525 int i_part = part[bigger][i];
526 if (!part[smaller].contient(i_part))
527 {
528 // i_part -> first_part on all elements surrounding the node with more parts:
529 for (int_t i_elem=0; i_elem<som_elem.get_list_size(node[bigger]); i_elem++)
530 {
531 int_t elem = som_elem(node[bigger],i_elem);
532 if (elem_part[elem] == i_part)
533 {
534 elem_part[elem] = first_part;
535 another_count++;
536 Cerr << "Element " << elem << " moved from part " << i_part << " to " << first_part << finl;
537 }
538 }
539 }
540 }
541 }
542 else
543 {
544 // Check if same parts around the 2 nodes:
545 for (int i=0; i<part[0].size(); i++)
546 {
547 int i_part = part[0][i];
548 if (!part[1].contient(i_part))
549 {
550 // Implement an algorithm as just above ?
551 Cerr << "Warning: different parts around the periodic nodes " << node[0] << " and " << node[1] << " !" << finl;
552 //for (int j=0;j<2;j++)
553 // for (int k=0;k<part[j].size();k++)
554 // Cerr << "node " << j << " part " << part[j][k] << finl;
555 Cerr << "We try to fix:" << finl;
556 // Look for the j_part not in the part[1] list:
557 for (int j=0; j<part[1].size(); j++)
558 {
559 int j_part = part[1][j];
560 if (!part[0].contient(j_part))
561 {
562 // Choice between i_part and j_part:
563 // We take i_part arbitrary so j_part -> i_part
564 for (int_t i_elem=0; i_elem<som_elem.get_list_size(node[1]); i_elem++)
565 {
566 int_t elem = som_elem(node[1],i_elem);
567 if (elem_part[elem] == j_part)
568 {
569 elem_part[elem] = i_part;
570 Cerr << "Element " << elem << " moved from part " << j_part << " to " << i_part << finl;
571 another_count++;
572 }
573 }
574 }
575 }
576 }
577 }
578 }
579 }
580 }
581 if (err)
582 {
583 Cerr << "Error in Partitionneur_base_32_64<_SIZE_>::corriger_multiperiodique" << finl;
584 Cerr << "It will create possible problems for creation of renum_som_perio array." << finl;
585 Cerr << "Contact TRUST support or change the partition options." << finl;
586 exit();
587 }
588 count+=another_count;
589 Cerr << "Partitionneur_base_32_64<_SIZE_>::corriger_multiperiodique : plus " << another_count << " another modified elements" << finl;
590 return count;
591}
592
593/*! @brief Corrects elem_part so that element i is on the same partition elem_part[i] as all elements connected to it in the graph
594 *
595 * (elements with indices graph_elements_perio(i, j) for all j).
596 *
597 * @param graph_elements_perio Graph computed by calculer_graphe_connexions_periodiques.
598 * @param som_elem Vertex-element connectivity.
599 * @param domaine The domain.
600 * @param elem_part For each element, which part it belongs to. Return value: number of elements whose partition was corrected.
601 */
602template <typename _SIZE_>
605 const Static_Int_Lists_t& som_elem,
606 const Domaine_t& domaine,
607 BigIntVect_& elem_part)
608{
609 // Algorithm: loop over all elements in order.
610 // For each element, assign to all linked elements the part to which the current
611 // element belongs. Since the graph is symmetric, if an element has already been
612 // processed, nothing is changed on subsequent passes. One pass is sufficient.
613 const Noms& liste_bords_periodiques = domaine.bords_perio();
614 const int_t n = graph_elements_perio.get_nb_lists(); //elem_part.size_array();
615 //assert(n == graph_elements_perio.get_nb_lists());
616 int_t count = 0;
617 for (int_t i = 0; i < n; i++)
618 {
619 const int_t m = graph_elements_perio.get_list_size(i);
620 const int part = elem_part[i];
621 for (int_t j = 0; j < m; j++)
622 {
623 const int_t elem2 = graph_elements_perio(i,j);
624 if (elem_part[elem2] != part)
625 {
626 elem_part[elem2] = part;
627 count++;
628 }
629 }
630 }
631 Cerr << "Partitionneur_base_32_64<_SIZE_>::corriger_bords_avec_graphe : " << count
632 << " modified periodic elements" << finl;
633
634 const int_t nb_sommets_reels = domaine.nb_som();
635 ArrOfInt_t renum_som_perio(nb_sommets_reels);
636 // Initialise the renum_som_perio array
637 for (int_t i = 0; i < nb_sommets_reels; i++)
638 renum_som_perio[i] = i;
639 bool parallel_algo = Process::is_parallel();
641 parallel_algo /* no virtual space in sequential */);
642
643 if (liste_bords_periodiques.size() > 1)
644 count += corriger_multiperiodique(domaine, renum_som_perio, som_elem, elem_part);
645 count += corriger_sommets_bord(domaine, renum_som_perio, som_elem, elem_part);
646 return count;
647}
648
649/*! @brief Computes the periodic element connectivity graphs and calls corriger_periodique_avec_graphe.
650 *
651 * (Method to use when the connectivity graph is not yet available;
652 * if the graph is already at hand, call corriger_periodique_avec_graphe directly.)
653 *
654 */
655template <typename _SIZE_>
657 const int_t my_offset,
658 BigIntVect_& elem_part)
659{
660 Cerr << "Correction of the splitting for the periodicity" << finl;
661 Static_Int_Lists_t som_elem;
662 Cerr << " Construction of the connectivity som_elem" << finl;
663 construire_connectivite_som_elem(dom.nb_som_tot(),
664 dom.les_elems(),
665 som_elem,
666 1 /* include virtual elements */);
667 Cerr << " Construction of graph connectivity for periodic elements" << finl;
668 Static_Int_Lists_t graph_elements_perio;
670 som_elem,
671 my_offset,
672 graph_elements_perio);
673 const int_t count = corriger_bords_avec_graphe(graph_elements_perio,
674 som_elem,
675 dom,
676 elem_part);
677 Cerr << "corriger_bords_avec_liste : we have corrected " << count << " elements all in all." << finl;
678}
679
680
681
682template class Partitionneur_base_32_64<int>;
683#if INT_is_64_ == 2
685#endif
686
687
IntTab_t & les_elems()
Definition Domaine.h:129
int_t nb_som_tot() const
Returns the total number of vertices of the domain i.e. the number of real and virtual vertices on th...
Definition Domaine.h:123
const IntTab_t & les_sommets() const
Returns the array of vertices of all faces.
Definition Faces.h:74
const Nom & le_nom() const override
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
Definition Frontiere.h:49
int_t nb_faces() const
Returns the number of faces of the boundary.
Definition Frontiere.h:59
const Faces_t & faces() const
Definition Frontiere.h:54
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
An array of character strings (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:130
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
Base class for domain partitioners (for splitting a mesh before a parallel computation).
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)
Corrects elem_part so that element i is on the same partition elem_part[i] as all elements connected ...
static void corriger_bords_avec_liste(const Domaine_t &dom, const int_t my_offset, BigIntVect_ &elem_part)
Computes the periodic element connectivity graphs and calls corriger_periodique_avec_graphe.
static void corriger_elem0_sur_proc0(BigIntVect_ &elem_part)
Corrects the partition so that element 0 of the initial domain is on the first sub-domain of the part...
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)
Modifies elem_part to ensure the following properties: 1) Elements that have a boundary vertex are as...
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)
Applies corrections to elem_part so that multi-periodicity is 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)
Computes a connectivity graph between elements connected by periodic faces.
static bool is_parallel()
Definition Process.cpp:108
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
static int check_faces_periodiques(const Frontiere_32_64< _SIZE_ > &frontiere, ArrOfDouble &vecteur_delta, ArrOfDouble &erreur, bool verbose=false)
Tries to verify whether the faces on boundary num_bord are ordered according to the periodic face con...
static void renum_som_perio(const Domaine_32_64< _SIZE_ > &dom, ArrOfInt_T< _SIZE_ > &renum_som_perio, bool calculer_espace_virtuel)
Base class for output streams.
Definition Sortie.h:52
This class allows storing lists of integers accessible in constant time.
void set_value(int_t i_liste, int_t i_element, int_t valeur)
Assigns "valeur" to the j-th element of the i-th list with 0 <= i < get_nb_lists() and 0 <= j < get_l...
int_t get_list_size(int_t i_liste) const
Returns the number of elements in list i.
void set_list_sizes(const ArrOfInt_t &sizes)
Destroys existing lists and creates new ones.
int_t get_nb_lists() const
Returns the number of stored lists.
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