TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
DomaineCutter.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 <DomaineCutter.h>
17#include <ArrOfBit.h>
18#include <Domaine.h>
19#include <Connectivite_som_elem.h>
20#include <SFichierBin.h>
21#include <Array_tools.h>
22#include <Scatter.h>
23#include <TRUSTArrays.h>
24#include <Sous_Domaine.h>
25#include <Sparskit.h>
26#include <Poly_geom_base.h>
27#include <Sortie_Brute.h>
28#include <TRUSTVect.h>
29#include <FichierHDFPar.h>
30#include <communications.h>
31
32Implemente_instanciable_32_64(DomaineCutter_32_64,"DomaineCutter",Objet_U);
33
34template<typename _SIZE_>
36{
37 Process::exit("Error : DomaineCutter_32_64<_SIZE_>::printOn should not be used.");
38 return os;
39}
40
41template<typename _SIZE_>
43{
44 Process::exit("Error : DomaineCutter_32_64<_SIZE_>::readOn should not be used.");
45 return s;
46}
47
48
49namespace // anonymous namespace
50{
51
52/*! @brief Creation of the vertex list of sub-domain "partie".
53 *
54 * This is the set of vertices of elements belonging to this sub-domain.
55 * Only real elements are processed.
56 *
57 * @param (nb_sommets) number of vertices of the global domain
58 * @param (les_elems)
59 * @param (elem_part) partitioning array (for each element i of the global domain, elem_part[i] is the number of the sub-domain to which it is assigned)
60 * @param (partie) the number of the sub-domain to build
61 * @param (liste_sommets) on output: list of vertices of the sub-domain: liste_sommets[i] is the index in domaine_globale of the i-th vertex of the sub-domain. Indices are sorted in ascending order.
62 * @param (liste_inverse_sommets) on output: sized to nb_sommets and initialized. liste_inverse_sommet[i] is the index of the vertex in the sub-domain, or -1 if vertex i is not in the sub-domain)
63 */
64template<typename _SIZE_>
65void construire_liste_sommets_sousdomaine(const _SIZE_ nb_sommets,
66 const IntTab_T<_SIZE_>& les_elems,
67 const ArrOfInt_T<_SIZE_>& liste_elements,
68 const int i_part,
69 const Static_Int_Lists_32_64<_SIZE_> *som_raccord,
70 SmallArrOfTID_T<_SIZE_>& liste_sommets,
71 BigArrOfInt_T<_SIZE_>& liste_inverse_sommets)
72{
73 using int_t = _SIZE_;
74
75 const int nb_elem_part = Process::check_int_overflow(liste_elements.size_array());
76 const int_t nb_sommets_par_element = les_elems.dimension(1);
77
78 // Algorithm: iterate over elements; for elements of the part,
79 // mark the vertices of the element with a flag.
80 // Then iterate over vertices, and those whose flag is set
81 // are added to the list.
82
83 // First, count the vertices of the part and
84 // fill drapeau_sommet
85 ArrOfBit_32_64<_SIZE_> drapeau_sommet(nb_sommets);
86
87 drapeau_sommet = 0;
88 // Number of vertices of part "part"
89 int nb_sommets_part = 0;
90 for (int i_elem = 0; i_elem < nb_elem_part; i_elem++)
91 {
92 const int_t elem = liste_elements[i_elem];
93 for (int j = 0; j < nb_sommets_par_element; j++)
94 {
95 int_t sommet = les_elems(elem, j);
96 if (sommet>-1)
97 {
98 int bit = drapeau_sommet.testsetbit(sommet);
99 // If the flag was not set, this is one more vertex
100 if (! bit)
101 nb_sommets_part++;
102 }
103 }
104 }
105 //vertices to add due to som_raccord
106 if (som_raccord)
107 for (int s = 0; s < som_raccord->get_nb_lists(); s++)
108 for (int_t i = 0; i < som_raccord->get_list_size(s); i++)
109 if ((*som_raccord)(s, i) == i_part && !drapeau_sommet.testsetbit(s)) //the vertex is requested by this proc
110 nb_sommets_part++; //if we don't already have it, add it
111
112 // Fill liste_sommets and liste_inverse_sommets
113 liste_sommets.resize_array(0); // Forget previous values
114 liste_sommets.resize_array(nb_sommets_part);
115
116 liste_inverse_sommets.resize_array(0); // Forget previous values
117 liste_inverse_sommets.resize_array(nb_sommets,RESIZE_OPTIONS::NOCOPY_NOINIT);
118 liste_inverse_sommets = -1;
119
120 int n = 0;
121 for (int_t i = 0; i < nb_sommets; i++)
122 {
123 if (drapeau_sommet[i])
124 {
125 liste_sommets[n] = i;
126 liste_inverse_sommets[i] = n;
127 n++;
128 }
129 }
130}
131
132/*! Fill the vertex coordinate array of a part
133 * from the vertex coordinates of the complete domain (sommets_glob)
134 * and the list of vertices of the part (liste_sommets).
135 * sommets_loc is created as follows:
136 * sommets_loc.dimension(0) = liste_sommets.size_array()
137 * sommets_loc.dimension(1) = sommets_glob.dimension(1)
138 *
139 * Parameter: sommets_glob
140 * Meaning: the coordinates of the vertices of the global domain
141 * Parameter: liste_sommets
142 * Meaning: the indices of the vertices of sommets_glob to copy
143 * into sommets_loc.
144 */
145template<typename _SIZE_>
146void remplir_coordsommets_sous_domaine(const DoubleTab_T<_SIZE_>& sommets_glob,
147 const SmallArrOfTID_T<_SIZE_>& liste_sommets,
148 DoubleTab& sommets_loc)
149{
150 using int_t = _SIZE_;
151 const int nb_som = liste_sommets.size_array();
152 const int dim = sommets_glob.dimension_int(1);
153 sommets_loc.resize(nb_som, dim);
154
155 for (int i = 0; i < nb_som; i++)
156 {
157 int_t indice = liste_sommets[i];
158 for (int j = 0; j < dim; j++)
159 sommets_loc(i, j) = sommets_glob(indice, j);
160 }
161}
162
163/*! Build the elems array of elements of part "part".
164 * elems(i, j) will be the new number of vertex j of element i
165 * in part. The liste_inverse is used to obtain the
166 * new vertex numbers.
167 * The elements of the local domain are created in ascending order of
168 * their index in the global domain.
169 */
170template<typename _SIZE_>
171void construire_elems_sous_domaine(const IntTab_T<_SIZE_>& elems_domaine_globale,
172 const ArrOfInt_T<_SIZE_>& liste_elements,
173 const BigArrOfInt_T<_SIZE_>& liste_inverse_sommets,
174 IntTab& elems_domaine_locale,
175 BigArrOfInt_T<_SIZE_>& liste_inverse_elements)
176{
177 using int_t = _SIZE_;
178
179 const int_t nb_elem_tot = elems_domaine_globale.dimension_tot(0);
180 const int nb_sommets_par_element = elems_domaine_globale.dimension_int(1);
181
182 liste_inverse_elements.resize(nb_elem_tot,RESIZE_OPTIONS::NOCOPY_NOINIT);
183 liste_inverse_elements = -1;
184
185 // First pass: count the number of elements in the part
186 const int nb_elem_part = Process::check_int_overflow(liste_elements.size_array());
187 elems_domaine_locale.resize(nb_elem_part, nb_sommets_par_element);
188
189 // Second pass: fill the array
190 for (int i_elem = 0; i_elem < nb_elem_part; i_elem++)
191 {
192 int_t elem = liste_elements[i_elem];
193
194 // New element number in the part
195 liste_inverse_elements[elem] = i_elem;
196 // Copy the element with vertex numbers translated to
197 // local numbers in the sub-domain
198 for (int i = 0; i < nb_sommets_par_element; i++)
199 {
200 int_t sommet = elems_domaine_globale(elem, i);
201 if (sommet<0)
202 {
203 assert(sommet == -1); // Polytopes
204 elems_domaine_locale(i_elem, i) = -1;
205 }
206 else
207 {
208 int new_num = liste_inverse_sommets[sommet];
209 assert(new_num >= 0);
210 elems_domaine_locale(i_elem, i) = new_num;
211 }
212 }
213 }
214}
215
216/*! @brief For a list of "faces" of the global domain, count the number of faces included in part "part" and copy them into the structure
217 *
218 * faces_partie by replacing vertex numbers with local numbers
219 * in the sub-domain.
220 * The order of faces is preserved (if a face appears before another in
221 * the list of the complete domain and both are in the sub-part,
222 * their order is preserved). This is important for periodicity
223 * (assumption that there is a correspondence between face i and face i+n/2 of the
224 * periodic boundary).
225 * Note: the condition for a face to be included is "the face belongs
226 * to an element of the neighboring part". The condition "the vertices of the faces are
227 * joint vertices" is NOT sufficient.
228 */
229template<typename _SIZE_>
230void construire_liste_faces_sous_domaine(const ArrOfInt_T<_SIZE_>& elements_voisins,
231 const BigIntVect_T<_SIZE_>& elem_part,
232 const int partie,
233 const IntTab_T<_SIZE_>& faces_sommets,
234 const BigArrOfInt_T<_SIZE_>& liste_inverse_sommets,
235 IntTab& faces_sommets_partie)
236{
237 using int_t = _SIZE_;
238
239 const int_t nb_faces = faces_sommets.dimension(0);
240 const int nb_sommets_par_face = faces_sommets.dimension_int(1);
241
242 assert(elements_voisins.size_array() == nb_faces);
243 // List of faces from the faces_sommets array to include in the sub-domain
244 ArrOfInt_T<_SIZE_> liste_faces;
245
246 // First pass: look for faces to include
247 {
248 for (int_t i = 0; i < nb_faces; i++)
249 {
250 int_t elem = elements_voisins[i];
251 const int part = elem_part[elem];
252 if (part == partie)
253 liste_faces.append_array(i);
254 }
255 }
256
257 const int nb_faces_part = Process::check_int_overflow(liste_faces.size_array());
258 faces_sommets_partie.resize(nb_faces_part, nb_sommets_par_face);
259
260 // Second pass: store the faces and convert vertex numbers
261 // to local numbers in the sub-domain.
262 for (int i = 0; i < nb_faces_part; i++)
263 {
264 const int_t i_face = liste_faces[i];
265 for (int j = 0; j < nb_sommets_par_face; j++)
266 {
267 int_t sommet = faces_sommets(i_face, j);
268 if (sommet>-1)
269 {
270 int new_num = liste_inverse_sommets[sommet];
271 assert(new_num >= 0);
272 faces_sommets_partie(i, j) = new_num;
273 }
274 else
275 faces_sommets_partie(i, j) = -1;
276 }
277 }
278}
279
280} // end anonymous NS
281
282/*! @brief For each PE listed in the "voisins" array, if a joint with that pe does not yet exist in the domain,
283 * add a joint and initialize it with "epaisseur".
284 */
285template <typename _SIZE_>
286void DomaineCutter_32_64<_SIZE_>::ajouter_joints(Domaine32& domaine, const ArrOfInt& voisins) const
287{
288 Joints& joints = domaine.faces_joint();
289
290 const int n = voisins.size_array();
291 for (int i = 0; i < n; i++)
292 {
293 const int pe = voisins[i];
294 int j = 0;
295 const int nb_joints = joints.size();
296 for (; j < nb_joints; j++)
297 if (joints[j].PEvoisin() == pe)
298 break;
299 if (j == nb_joints)
300 {
301 Cerr << " Adding of a new joint : " << pe << finl;
302 Joint& joint = joints.add(Joint());
303 joint.nommer(Nom("Joint_")+Nom(pe));
304 joint.associer_domaine(domaine);
305 joint.affecte_epaisseur(epaisseur_joint_);
306 joint.affecte_PEvoisin(pe);
307 // These joints will have no common vertices. Set the initialization flag to 1.
308 joint.set_joint_item(JOINT_ITEM::SOMMET).set_items_communs();
309 }
310 }
311}
312
313
314/*! @brief Starting from a list of vertices (liste_sommets_depart), iterate over neighboring elements of these vertices (if epaisseur <= 1),
315 *
316 * then the neighbors of these elements (sharing a vertex with the element) if epaisseur <= 2,
317 * then the neighbors of the neighbors if epaisseur <= 3, etc.
318 * Elements belonging to "partie_a_ignorer" are not visited.
319 * The indices of the visited elements are stored in liste_elements_trouves.
320 * This method was written for construire_elements_distants_ssdom()
321 */
322template <typename _SIZE_>
323void DomaineCutter_32_64<_SIZE_>::parcourir_epaisseurs_elements(SmallArrOfTID_t liste_sommets_depart, /* by value since we will modify it */
324 const int partie_a_ignorer, /* do not traverse elements of this partition */
325 SmallArrOfTID_t& liste_elements_trouves) const
326{
327 const Domaine_t& domaine = ref_domaine_.valeur();
328 const IntTab_t& elements = domaine.les_elems();
329 const BigIntVect_t& elem_part = ref_elem_part_.valeur();
330 const int_t nb_sommets = som_elem_.get_nb_lists();
331 const int_t nb_elements = elements.dimension_tot(0);
332 const int nb_som_elem = elements.dimension_int(1);
333
334 liste_elements_trouves.resize_array(0);
335
336 ArrOfBit_32_64<_SIZE_> sommets_parcourus(nb_sommets);
337 ArrOfBit_32_64<_SIZE_> elements_parcourus(nb_elements);
338 SmallArrOfTID_t new_liste;
339
340 sommets_parcourus = 0;
341 elements_parcourus = 0;
342
343 {
344 // Mark the starting vertices and build a list of unique vertices
345 const int sz_liste = liste_sommets_depart.size_array();
346 for (int i = 0; i < sz_liste; i++)
347 {
348 const int_t sommet = liste_sommets_depart[i];
349 if (sommet>-1)
350 if (!sommets_parcourus.testsetbit(sommet))
351 new_liste.append_array(sommet);
352 }
353 }
354
355 // Loop over successive layers of elements around the joint vertices.
356 for (int ep = 1; ep <= epaisseur_joint_; ep++)
357 {
358 liste_sommets_depart = new_liste;
359 new_liste.resize_array(0);
360 const int sz_liste = liste_sommets_depart.size_array();
361 for (int i_sommet = 0; i_sommet < sz_liste; i_sommet++)
362 {
363 const int_t sommet = liste_sommets_depart[i_sommet];
364 // Iterate over elements neighboring this vertex:
365 const int nb_elems_voisins = Process::check_int_overflow(som_elem_.get_list_size(sommet));
366 for (int i_elem = 0; i_elem < nb_elems_voisins; i_elem++)
367 {
368 const int_t elem = som_elem_(sommet, i_elem);
369 if (elements_parcourus[elem])
370 continue; // This element has already been visited
371 // Domain number of the neighboring element:
372 const int part = elem_part[elem];
373 if (part == partie_a_ignorer)
374 continue; // Only process elements from other parts
375
376 liste_elements_trouves.append_array(elem);
377 elements_parcourus.setbit(elem);
378
379 // Add to the next list of vertices to process the vertices of this element:
380 for (int i = 0; i < nb_som_elem; i++)
381 {
382 const int_t sommet2 = elements(elem, i);
383 if (sommet2>-1)
384 {
385 if (sommets_parcourus.testsetbit(sommet2) == 0)
386 new_liste.append_array(sommet2);
387 }
388 }
389 }
390 }
391 }
392}
393
394
395/*! For the following three functions:
396 * Fill the boundaries of the part associated with a processor.
397 */
398template<typename _SIZE_>
399void DomaineCutter_32_64<_SIZE_>::construire_faces_bords_ssdom(const BigArrOfInt_T<_SIZE_>& liste_inverse_sommets,
400 const int partie,
401 Domaine32& domaine_partie) const
402{
403 const Domaine_t& domaine = ref_domaine_.valeur();
404 int i_fr = 0;
405 ArrOfInt_t elements_voisins;
406 for(const auto& itr: domaine.faces_bord())
407 {
408 const Frontiere_t& frontiere = itr;
409 Frontiere& front_partie = domaine_partie.faces_bord().add(Bord());
410 front_partie.nommer(frontiere.le_nom());
411 front_partie.associer_domaine(domaine_partie);
412 front_partie.faces().typer(frontiere.faces().type_face());
413 voisins_bords_.copy_list_to_array(i_fr, elements_voisins);
414 construire_liste_faces_sous_domaine(elements_voisins,
415 ref_elem_part_.valeur(),
416 partie,
417 frontiere.faces().les_sommets(),
418 liste_inverse_sommets,
419 front_partie.faces().les_sommets());
420 i_fr++;
421 }
422}
423
424/*! @brief Builds the connections of the sub-partition from the connections of the global domain.
425 *
426 * Raccord_local_homogene objects are transformed into Raccord_distant_homogene objects.
427 */
428template<typename _SIZE_>
429void DomaineCutter_32_64<_SIZE_>::construire_faces_raccords_ssdom(const BigArrOfInt_t& liste_inverse_sommets,
430 const int partie,
431 Domaine32& domaine_partie) const
432{
433 const Domaine_t& domaine = ref_domaine_.valeur();
434 int i_fr = domaine.nb_bords();
435 ArrOfInt_t elements_voisins;
436 for(const auto& itr: domaine.faces_raccord())
437 {
438 const Frontiere_t& frontiere = itr;
439 Raccord& raccord_partie = domaine_partie.faces_raccord().add(Raccord());
440 Nom type_raccord = frontiere.que_suis_je();
441 // Strip away a potential "_64" suffix since we are now building a reduced 32b dom.
442 type_raccord.prefix("_64");
443 if (type_raccord == "Raccord_local_homogene")
444 type_raccord = "Raccord_distant_homogene";
445 raccord_partie.typer(type_raccord);
446 Frontiere& front_partie = raccord_partie.valeur();
447 front_partie.nommer(frontiere.le_nom());
448 front_partie.associer_domaine(domaine_partie);
449 front_partie.faces().typer(frontiere.faces().type_face());
450 voisins_bords_.copy_list_to_array(i_fr, elements_voisins);
451 construire_liste_faces_sous_domaine(elements_voisins,
452 ref_elem_part_.valeur(),
453 partie,
454 frontiere.faces().les_sommets(),
455 liste_inverse_sommets,
456 front_partie.faces().les_sommets());
457 i_fr++;
458 }
459}
460
461template<typename _SIZE_>
462void DomaineCutter_32_64<_SIZE_>::construire_frontieres_internes_ssdom(const BigArrOfInt_t& liste_inverse_sommets,
463 const int partie,
464 Domaine32& domaine_partie) const
465{
466 // Reminder: internal boundaries are "frontiers" inside the domain
467 // (for example a zero-thickness plate in the flow)
468 const Domaine_t& domaine = ref_domaine_.valeur();
469 int i_fr = domaine.nb_bords()+domaine.nb_raccords();
470 ArrOfInt_t elements_voisins;
471 for(const auto& itr: domaine.bords_int())
472 {
473 const Frontiere_t& frontiere = itr;
474 Frontiere& front_partie = domaine_partie.bords_int().add(Bord_Interne());
475 front_partie.nommer(frontiere.le_nom());
476 front_partie.associer_domaine(domaine_partie);
477 front_partie.faces().typer(frontiere.faces().type_face());
478 voisins_bords_.copy_list_to_array(i_fr, elements_voisins);
479 construire_liste_faces_sous_domaine(elements_voisins,
480 ref_elem_part_.valeur(),
481 partie,
482 frontiere.faces().les_sommets(),
483 liste_inverse_sommets,
484 front_partie.faces().les_sommets());
485 i_fr++;
486 }
487}
488
489template<typename _SIZE_>
490void DomaineCutter_32_64<_SIZE_>::construire_groupe_faces_ssdom(const BigArrOfInt_t& liste_inverse_sommets,
491 const int partie,
492 Domaine32& domaine_partie) const
493{
494 using Groupe_Faces_t = Groupe_Faces_32_64<_SIZE_>;
495
496 const Domaine_t& domaine = ref_domaine_.valeur();
497 Static_Int_Lists_t voisins;
498 const int nb_groupe_faces = domaine.nb_groupes_faces();
499 ArrOfInt_T<_SIZE_> nb_faces(nb_groupe_faces);
500 for (int i = 0; i < nb_groupe_faces; i++)
501 nb_faces[i] = domaine.groupe_faces(i).nb_faces();
502 voisins.set_list_sizes(nb_faces);
503 const int nb_som_face = domaine.frontiere(0).faces().nb_som_faces();
504 SmallArrOfTID_t une_face(nb_som_face), elements_voisins;
505
506 const BigIntVect_t& elem_part = ref_elem_part_.valeur();
507
508 for (int grp = 0; grp < nb_groupe_faces; grp++)
509 {
510 const Groupe_Faces_t& groupe_faces = domaine.groupe_faces(grp);
511 Groupe_Faces& groupe_partie = domaine_partie.groupes_faces().add(Groupe_Faces());
512 groupe_partie.nommer(groupe_faces.le_nom());
513 groupe_partie.associer_domaine(domaine_partie);
514 groupe_partie.faces().typer(groupe_faces.faces().type_face());
515 const IntTab_t& faces_sommets = groupe_faces.faces().les_sommets();
516 IntTab& faces_sommets_partie = groupe_partie.faces().les_sommets();
517
518 ArrOfInt_t liste_faces;
519 // First pass: look for faces to include
520 const IntTab_t& faces = groupe_faces.les_sommets_des_faces();
521 const int_t n = nb_faces[grp];
522 for (int_t j = 0; j < n; j++)
523 {
524 for (int k = 0; k < nb_som_face; k++)
525 une_face[k] = faces(j, k);
526 find_adjacent_elements(som_elem_, une_face, elements_voisins);
527
528 if (elements_voisins.size_array() == 1 && elem_part[elements_voisins[0]] == partie) liste_faces.append_array(j);
529
530 if (elements_voisins.size_array() == 2)
531 if (elem_part[elements_voisins[0]] == partie || elem_part[elements_voisins[1]] == partie)
532 liste_faces.append_array(j);
533 }
534
535 const int nb_faces_part = Process::check_int_overflow(liste_faces.size_array());
536 faces_sommets_partie.resize(nb_faces_part, nb_som_face);
537
538 // Second pass: store the faces and convert vertex numbers
539 // to local numbers in the sub-domain.
540 for (int i = 0; i < nb_faces_part; i++)
541 {
542 const int_t i_face = liste_faces[i];
543 for (int j = 0; j < nb_som_face; j++)
544 {
545 int_t sommet = faces_sommets(i_face, j);
546 if (sommet>-1)
547 {
548 int new_num = liste_inverse_sommets[sommet];
549 assert(new_num >= 0);
550 faces_sommets_partie(i, j) = new_num;
551 }
552 else
553 faces_sommets_partie(i, j) = -1;
554 }
555 }
556 }
557}
558
559
560/*! @brief Compute and fill domaine_partie.
561 *
562 * joint(i).set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants()
563 * (list of distant elements).
564 * New joints may be created.
565 * History: method coded in January 2006 by B.Mathieu. The original belief was that
566 * determining distant elements during scatter would be too complex. Eventually a way
567 * was found. As a result this method is no longer used in normal operation. In case of
568 * problems, it can be re-enabled (option 'print_more_info' in Decouper):
569 * in theory it gives exactly the same result as the algorithm in Scatter::calculer_espace_distant_elements.
570 * Note: it does nothing special for periodic boundaries...
571 */
572template<typename _SIZE_>
573void DomaineCutter_32_64<_SIZE_>::construire_elements_distants_ssdom(const int partie,
574 const SmallArrOfTID_t& liste_sommets,
575 const BigArrOfInt_t& liste_inverse_elements,
576 Domaine32& domaine_partie) const
577{
578 const Domaine_t& domaine = ref_domaine_.valeur();
579 const IntTab_t& elements = domaine.les_elems();
580 const BigIntVect_t& elem_part = ref_elem_part_.valeur();
581 const int_t nb_elem = elements.dimension(0);
582 const int_t nb_som_elem = elements.dimension(1);
583
584 // First step: look for virtual elements of the sub-part
585 // (elements of other parts located within the joint thickness starting
586 // from the joint vertices).
587 SmallArrOfTID_t elements_virtuels;
588 {
589 // Build an array containing all the vertices of all the joints
590 SmallArrOfTID_t sommets_joint;
591
592 const int nb_joints = domaine_partie.nb_joints();
593 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
594 {
595 const ArrOfInt& sommets = domaine_partie.joint(i_joint).joint_item(JOINT_ITEM::SOMMET).items_communs();
596 const int n = sommets.size_array();
597 for (int i = 0; i < n; i++)
598 {
599 const int sommet_local = sommets[i];
600 const int_t sommet_global = liste_sommets[sommet_local];
601 sommets_joint.append_array(sommet_global);
602 }
603 }
604
605 parcourir_epaisseurs_elements(sommets_joint, // Starting vertices
606 partie, /* ignore elements of the local partition */
607 elements_virtuels);
608 }
609 const int nb_elements_virtuels = elements_virtuels.size_array();
610 // Build the list of neighboring domain numbers and add missing joints:
611 ArrOfInt parties_voisines;
612 {
613 for (int i = 0; i < nb_elements_virtuels; i++)
614 {
615 const int_t elem = elements_virtuels[i];
616 const int part = elem_part[elem];
617 parties_voisines.append_array(part);
618 }
619 array_trier_retirer_doublons(parties_voisines);
620 ajouter_joints(domaine_partie, parties_voisines);
621 }
622
623 // For each neighboring part, look for distant elements:
624 const int nb_parties_voisines = parties_voisines.size_array();
625 SmallArrOfTID_t sommets_depart;
626
627 for (int i_part = 0; i_part < nb_parties_voisines; i_part++)
628 {
629 const int partie_voisine = parties_voisines[i_part];
630 sommets_depart.resize_array(0);
631 // List of vertices of the virtual elements of the neighboring part:
632 for (int i_elem = 0; i_elem < nb_elements_virtuels; i_elem++)
633 {
634 const int_t elem = elements_virtuels[i_elem];
635 if (elem_part(elem) == partie_voisine)
636 {
637 for (int i = 0; i < nb_som_elem; i++)
638 {
639 const int_t som = elements(elem, i);
640 sommets_depart.append_array(som);
641 }
642 }
643 }
644
645 // Search for elements neighboring this list:
646 SmallArrOfTID_t elements_distants;
647 parcourir_epaisseurs_elements(sommets_depart,
648 partie_voisine, /* ignore elements of the neighboring part */
649 elements_distants);
650
651 // Remove from the list the elements that are not in the local part:
652 {
653 int count = 0;
654 const int n = elements_distants.size_array();
655 for (int i = 0; i < n; i++)
656 {
657 const int_t elem = elements_distants[i];
658 if (elem_part[elem] == partie && elem < nb_elem)
659 elements_distants[count++] = elem;
660 }
661 elements_distants.resize_array(count);
662 }
663 // Translate element indices to local indices on the sub-domain.
664 const int n = elements_distants.size_array();
665 ArrOfInt elem_dist_loc(n);
666 {
667 for (int i = 0; i < n; i++)
668 {
669 const int_t elem = elements_distants[i];
670 const int renum = liste_inverse_elements[elem];
671 elem_dist_loc[i] = renum;
672 }
673 }
674 // Sort elements in ascending order of indices
675 elements_distants.ordonne_array();
676 // Store the list of distant elements in the joint
677 Joint& joint = domaine_partie.joint_of_pe(partie_voisine);
678 joint.set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants() = elem_dist_loc;
679 }
680}
681
682/*! @brief Create joints and build vertex lists and arrays for all joints of
683 *
684 * part. The vertices of the joint with "PEvoisin" are
685 * the vertices of part "part" that are also a vertex of an
686 * element belonging to PEvoisin.
687 * Joints appear in the list in ascending order of PEs.
688 * Note: The faces to be created next necessarily use
689 * vertices found here.
690 * Property: The vertices of the joint are sorted in ascending order
691 * of their local number, hence in ascending order of
692 * their global number (see Remplir_Numeros_Sommets)
693 */
694template<typename _SIZE_>
695void DomaineCutter_32_64<_SIZE_>::construire_sommets_joints_ssdom(const SmallArrOfTID_t& liste_sommets,
696 const BigArrOfInt_t& liste_inverse_sommets,
697 const int partie,
698 const Static_Int_Lists_t* som_raccord,
699 Domaine32& domaine_partie) const
700{
701 Joints& les_joints = domaine_partie.faces_joint();
702
703 const int parts = nb_parties_;
704 const BigIntVect_t& elem_part = ref_elem_part_.valeur();
705
706 // List of joint vertices (across all parts; a vertex may appear
707 // multiple times in the array, at most once per neighboring pe).
708 // This is the global vertex number.
709 ArrsOfInt_T<_SIZE_> joints_sommets(parts);
710
711 // Algorithm: loop over the vertices of the part.
712 // For each vertex of sub-domain "p", look for the PEs to which
713 // the neighboring elements of the vertex belong, and, if there is a neighboring PE
714 // different from "p", add this vertex to the joints with those PEs.
715
716 const int nb_sommets = liste_sommets.size_array();
717
718 // i = local index of the vertex in the sub-domain
719 for (int i_sommet = 0; i_sommet < nb_sommets; i_sommet++)
720 {
721 // Global vertex number
722 int_t sommet = liste_sommets[i_sommet];
723 // Loop over the elements neighboring vertex i
724 int nb_elements_voisins = Process::check_int_overflow(som_elem_.get_list_size(sommet));
725 for (int i = 0; i < nb_elements_voisins; i++)
726 {
727 int_t elem = som_elem_(sommet, i);
728 int PEvoisin = elem_part[elem];
729 // Should this vertex be added to the joint vertices with PEvoisin?
730 if (PEvoisin != partie)
731 joints_sommets[PEvoisin].append_array(sommet);
732 }
733 //loop over procs connected to the vertex by a connection
734 if (som_raccord)
735 for (int_t i = 0; i < som_raccord->get_list_size(sommet); i++)
736 {
737 int part_num = Process::check_int_overflow((*som_raccord)(sommet, i));
738 if (part_num != partie)
739 joints_sommets[part_num].append_array(sommet);
740 }
741 }
742
743 // Create joints: in ascending order of the neighboring PE
744 for (int PEvoisin = 0; PEvoisin < parts; PEvoisin++)
745 {
746 ArrOfInt_t& sommets = joints_sommets[PEvoisin];
747 if (sommets.size_array() > 0)
748 {
749 // Sort joint vertices in ascending order of global index
750 // (so all lists on neighboring processors will be sorted
751 // in the same way) and remove duplicates
752 array_trier_retirer_doublons(sommets);
753 const int nb_sommets2 = Process::check_int_overflow(sommets.size_array());
754
755 // Create a new joint
756 Joint& joint = les_joints.add(Joint());
757 Nom nom_joint("Joint_");
758 Nom nom_numero(PEvoisin);
759 nom_joint+=nom_numero;
760 joint.nommer(nom_joint);
761 joint.affecte_epaisseur(epaisseur_joint_);
762 joint.associer_domaine(domaine_partie);
763 joint.affecte_PEvoisin(PEvoisin);
764 ArrOfInt& sommets_locaux = joint.set_joint_item(JOINT_ITEM::SOMMET).set_items_communs();
765 sommets_locaux.resize_array(nb_sommets2);
766 // Fill the array (convert to local vertex index)
767 for (int i = 0; i < nb_sommets2; i++)
768 {
769 const int_t indice_global = sommets[i];
770 const int indice_local = liste_inverse_sommets[indice_global];
771 assert(indice_local >= 0);
772 sommets_locaux[i] = indice_local;
773 }
774 }
775 }
776}
777
778/*! Search for joint faces (faces adjacent to two elements belonging
779 * to two different processors).
780 * It is assumed that the joint vertices have already been built.
781 */
782template<typename _SIZE_>
783void DomaineCutter_32_64<_SIZE_>::construire_faces_joints_ssdom(const int partie,
784 const DomaineCutter_Correspondance_t& correspondance,
785 Domaine32& domaine_partie) const
786{
787 const int nb_sommets_ssdom = domaine_partie.nb_som();
788 const int nb_elem_ssdom = domaine_partie.nb_elem();
789 const SmallArrOfTID_t& liste_sommets = correspondance.liste_sommets_;
790 const BigArrOfInt_t& liste_inverse_elements = correspondance.liste_inverse_elements_;
791
792 // First step: identify "joint elements" (elements of "partie"
793 // having a joint vertex), and mark the joint vertices
794 SmallArrOfTID_t liste_elements_joint;
795 ArrOfBit drapeaux_sommets_joints(nb_sommets_ssdom);
796 {
797 // For now, use joints as const...
798 const Joints& joints_partie = domaine_partie.faces_joint();
799 drapeaux_sommets_joints = 0;
800
801 // Markers: for each element of the sub-domain, is it already in the list?
802 ArrOfBit drapeaux_elements(nb_elem_ssdom);
803 drapeaux_elements = 0;
804 // Loop over all joint vertices
805 const int nb_joints = joints_partie.size();
806 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
807 {
808 const Joint& joint = joints_partie[i_joint];
809 const ArrOfInt& sommets_du_joint = joint.joint_item(JOINT_ITEM::SOMMET).items_communs();
810 const int n = sommets_du_joint.size_array();
811 for (int i = 0; i < n; i++)
812 {
813 const int i_sommet_local = sommets_du_joint[i];
814 const int_t i_sommet_global = liste_sommets[i_sommet_local];
815 const int nb_elem_voisins = Process::check_int_overflow(som_elem_.get_list_size(i_sommet_global));
816 // Mark the joint vertex in the sub-domain
817 drapeaux_sommets_joints.setbit(i_sommet_local);
818 for (int j = 0; j < nb_elem_voisins; j++)
819 {
820 const int_t i_elem_global = som_elem_(i_sommet_global, j);
821 const int i_elem_local = liste_inverse_elements[i_elem_global];
822 // Add the element to the joint element list if it is in my part
823 // and if it is not yet in the list.
824 if (i_elem_local >= 0)
825 if (! drapeaux_elements.testsetbit(i_elem_local))
826 liste_elements_joint.append_array(i_elem_global);
827 }
828 }
829 }
830 }
831
832 // Second step: for each joint element, build its faces and check
833 // if the face has a neighboring element in another part.
834 // If so, it is a joint face.
835
836 // Array of vertex indices of all joint faces
837 // (across all joints, vertex indices in the sub-domain)
838 IntTab faces_joints;
839 // For each joint face, the number of the neighboring sub-domain through this face
840 ArrOfInt faces_pe_voisins;
841 // For each processor, number of joint faces with that proc.
842 // (initialized to zero)
843 ArrOfInt nb_faces_joints(nb_parties_);
844 {
845 // Indices of face vertices on the reference element
846 IntTab faces_element_reference;
847 const Elem_geom_base& type_elem = domaine_partie.type_elem().valeur();
848 int is_regular = type_elem.get_tab_faces_sommets_locaux(faces_element_reference);
849 // Overload for polytope meshes
850 if (!is_regular)
851 ref_cast(Poly_geom_base,type_elem).get_tab_faces_sommets_locaux(faces_element_reference,0);
852
853 int nb_faces_elem = faces_element_reference.dimension(0);
854 const int nb_sommets_par_face = faces_element_reference.dimension(1);
855 faces_joints.resize(0, nb_sommets_par_face); // Voir *suite*
856 const BigArrOfInt_t& liste_inverse_sommets = correspondance.liste_inverse_sommets_;
857 const BigIntVect_t& elem_part = ref_elem_part_.valeur();
858 // Vertices of the elements of the global mesh
859 const Domaine_t& domaine = ref_domaine_.valeur();
860 const IntTab_t& elem_som = domaine.les_elems();
861 SmallArrOfTID_t une_face(nb_sommets_par_face);
862 SmallArrOfTID_t elements_voisins;
863
864 // Loop over joint elements
865 const int nb_elem_joints = liste_elements_joint.size_array();
866 for (int i_elem_joint = 0; i_elem_joint < nb_elem_joints; i_elem_joint++)
867 {
868 // Index of the element in the global domain
869 const int_t i_elem_global = liste_elements_joint[i_elem_joint];
870 // Loop over the faces of the element
871 if (!is_regular)
872 {
873 int loc_idx = liste_inverse_elements[i_elem_global];
874 ref_cast(Poly_geom_base,type_elem).get_tab_faces_sommets_locaux(faces_element_reference, loc_idx);
875 nb_faces_elem = faces_element_reference.dimension(0);
876 while ( faces_element_reference(nb_faces_elem-1,0) == -1)
877 nb_faces_elem--;
878 }
879 for (int i_face = 0; i_face < nb_faces_elem; i_face++)
880 {
881 // Build the face
882 int face_ok = 1;
883 for (int i = 0; i < nb_sommets_par_face; i++)
884 {
885 const int i_ref = faces_element_reference(i_face, i);
886 if (i_ref<0)
887 une_face[i] = i_ref;
888 else
889 {
890 const int_t i_som = elem_som(i_elem_global, i_ref);
891 une_face[i] = i_som;
892 // Index of the vertex in the sub-domain
893
894 if (i_som>-1)
895 {
896 const int i_som_local = liste_inverse_sommets[i_som];
897 if(i_som_local>0)
898 {
899 // Is the vertex on a joint?
900 if (drapeaux_sommets_joints[i_som_local] == 0)
901 face_ok = 0; // No => this face is not on a joint
902 }
903 }
904 }
905 }
906 // First test to quickly reject the face
907 // if not all its vertices are joint vertices.
908 if (face_ok)
909 {
910 // Search for neighboring elements of this face
911 find_adjacent_elements(som_elem_, une_face, elements_voisins);
912 // Search for a neighboring element that is not in my part
913 const int nb_elem_voisins = elements_voisins.size_array();
914 int PEvoisin = -1, i=0;
915 for (; i < nb_elem_voisins; i++)
916 {
917 const int_t i_elem_glob = elements_voisins[i];
918 PEvoisin = elem_part[i_elem_glob];
919 if (PEvoisin != partie)
920 break;
921 }
922 if (i < nb_elem_voisins)
923 {
924 // I have a joint face, add it to the array
925 faces_pe_voisins.append_array(PEvoisin);
926 const int n = faces_joints.dimension(0);
927 faces_joints.resize(n+1, nb_sommets_par_face);
928 for (int j = 0; j < nb_sommets_par_face; j++)
929 {
930 const int_t i_som_global = une_face[j];
931 if (i_som_global>-1)
932 {
933 const int i_som_local = liste_inverse_sommets[i_som_global];
934 faces_joints(n, j) = i_som_local;
935 }
936 else
937 faces_joints(n, j) = -1;
938 }
939 nb_faces_joints[PEvoisin]++;
940 }
941 }
942 }
943 }
944 }
945
946 // Third step: add the faces to the joints
947 {
948 // The type of joint faces
949 const Domaine_t& domaine_globale = ref_domaine_.valeur();
950 const Type_Face& type_face_joint = domaine_globale.type_elem()->type_face();
951 // Modify the joints:
952 Joints& joints_partie = domaine_partie.faces_joint();
953 const int nb_joints = joints_partie.size();
954 const int nb_faces_joints_tot = faces_joints.dimension(0);
955 // *continued*: 2D array even if there are no faces
956 const int nb_sommets_par_face = faces_joints.dimension(1);
957
958 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
959 {
960 // Face type and memory allocation
961 Joint& joint = joints_partie[i_joint];
962 joint.typer_faces(type_face_joint);
963 joint.faces().les_sommets().resize(0, nb_sommets_par_face);
964 const int PE_voisin = joint.PEvoisin();
965 const int nb_faces = nb_faces_joints[PE_voisin];
966 joint.dimensionner(nb_faces);
967 // Fill the face array
968 IntTab& faces = joint.faces().les_sommets();
969 int k = 0;
970 for (int i = 0; i < nb_faces_joints_tot; i++)
971 {
972 const int face_pe = faces_pe_voisins[i];
973 if (face_pe == PE_voisin)
974 {
975 for (int j = 0; j < nb_sommets_par_face; j++)
976 faces(k, j) = faces_joints(i,j);
977 k++;
978 }
979 }
980 }
981 }
982}
983
984/*! @brief cancels all references and empties the arrays
985 */
986template<typename _SIZE_>
988{
989 ref_domaine_.reset();
990 ref_elem_part_.reset();
991 nb_parties_ = -1;
992 epaisseur_joint_ = -1;
993 som_elem_.reset();
994}
995
996namespace // anonymous NS
997{
998
999template<typename _SIZE_>
1000void calculer_listes_elements_sous_domaines(const BigIntVect_T<_SIZE_>& elem_part,
1001 const int nb_parts,
1002 const _SIZE_ nbelem,
1003 Static_Int_Lists_32_64<_SIZE_>& liste_elems_sous_domaines)
1004{
1005 using int_t = _SIZE_;
1006
1007 ArrOfInt_T<_SIZE_> sizes(nb_parts);
1008 // First pass: counting
1009 for (int_t i = 0; i < nbelem; i++)
1010 {
1011 const int part = elem_part[i];
1012 sizes[part]++;
1013 }
1014 liste_elems_sous_domaines.set_list_sizes(sizes);
1015 // Second pass: filling
1016 sizes = 0;
1017 for (int_t i = 0; i < nbelem; i++)
1018 {
1019 const int part = elem_part[i];
1020 const int_t index = sizes[part]++;
1021 liste_elems_sous_domaines.set_value(part, index, i);
1022 }
1023}
1024
1025template<typename _SIZE_>
1026void calculer_elements_voisins_bords(const Domaine_32_64<_SIZE_>& domaine,
1027 const Static_Int_Lists_32_64<_SIZE_>& som_elem,
1028 Static_Int_Lists_32_64<_SIZE_>& voisins,const BigIntVect_T<_SIZE_>& elem_part,
1029 const bool permissif, Noms& bords_a_pb_)
1030{
1031 using int_t = _SIZE_;
1032 using ArrOfInt_t = ArrOfInt_T<_SIZE_>;
1033 using SmallArrOfTID_t = SmallArrOfTID_T<_SIZE_>;
1034
1035 const int nb_front = domaine.nb_front_Cl();
1036 ArrOfInt_t nb_faces(nb_front);
1037 for (int i = 0; i < nb_front; i++)
1038 nb_faces[i] = domaine.frontiere(i).nb_faces();
1039 voisins.set_list_sizes(nb_faces);
1040 const int nb_som_face = domaine.frontiere(0).faces().nb_som_faces();
1041 SmallArrOfTID_t une_face(nb_som_face);
1042 SmallArrOfTID_t elems_voisins;
1043
1044 for (int i = 0; i < nb_front; i++)
1045 {
1046 int drap=0;
1047 const IntTab_T<_SIZE_>& faces = domaine.frontiere(i).les_sommets_des_faces();
1048 const int_t n = nb_faces[i];
1049 for (int_t j = 0; j < n; j++)
1050 {
1051 for (int k = 0; k < nb_som_face; k++)
1052 une_face[k] = faces(j, k);
1053 find_adjacent_elements(som_elem, une_face, elems_voisins);
1054 const int n_voisins = elems_voisins.size_array();
1055 if (n_voisins != 1)
1056 {
1057 if (drap==0)
1058 {
1059 if (permissif)
1060 Cerr << "Message from DomaineCutter.cpp : calculer_elements_voisins_bords\n"
1061 << " boundary face "<< domaine.frontiere(i).le_nom()<<" with " << n_voisins << " neighbors." << finl;
1062 else
1063 Cerr << "Error in DomaineCutter.cpp : calculer_elements_voisins_bords\n"
1064 << " boundary face "<< domaine.frontiere(i).le_nom()<<" with " << n_voisins << " neighbors." << finl;
1065 bords_a_pb_.add( domaine.frontiere(i).le_nom());
1066 if (elems_voisins.size_array()==0) Process::exit();
1067 }
1068 drap=1;
1069 if (elem_part[elems_voisins[1]]==1)
1070 elems_voisins[0]=elems_voisins[1];
1071 if (!permissif)
1072 Process::exit();
1073 }
1074 voisins.set_value(i, j, elems_voisins[0]);
1075 }
1076 }
1077}
1078
1079/*! @brief Build the name of the ".
1080 *
1081 * Domaines" file for a given proc and a domain. If partie == -1 a single filename is returned. For example
1082 * DOM.Zones
1083 * instead of
1084 * DOM_0001.Zones
1085 */
1086void construire_nom_fichier_sous_domaine(const Nom& basename,
1087 const int partie, const int nb_parties_,
1088 const int original_proc,
1089 Nom& fichier)
1090{
1091 fichier = basename;
1092
1093 if (partie > 100000)
1094 {
1095 Cerr << "Error while generating filename: nb_parties_ too large" << finl;
1096 Process::exit();
1097 }
1098 char s[30];
1099 // single file name for all procs (HDF5)
1100 // the number of parts is still included in the file name
1101 // (make_PAR.data needs to know how many domaines there are)
1102 if (partie < 0)
1103 {
1104 if (nb_parties_ > 10000)
1105 snprintf(s, 30, "_p%05d.Zones", (int)nb_parties_);
1106 else
1107 snprintf(s, 30, "_p%04d.Zones",(int) nb_parties_);
1108 }
1109 else
1110 {
1111 if (nb_parties_ > 10000)
1112 {
1113 if(original_proc < 0)
1114 snprintf(s, 30, "_%05d.Zones", (int)partie);
1115 else
1116 snprintf(s, 30, "_%05d_%d.Zones", (int)partie, (int)original_proc);
1117 }
1118 else
1119 {
1120 if(original_proc < 0)
1121 snprintf(s, 30, "_%04d.Zones", (int)partie);
1122 else
1123 snprintf(s, 30, "_%04d_%d.Zones", (int)partie, (int)original_proc);
1124 }
1125 }
1126 fichier += Nom(s);
1127}
1128
1129}// end anonymous NS
1130
1131
1132/*! @brief Prepares the data structures for building sub-domains based on a partitioning provided in elem_part.
1133 *
1134 * @param (domaine_global) the domain to partition (must have a domain). A reference to this domain is stored (it must remain valid).
1135 * @param (elem_part) for each element, the number of the sub-domain to which it belongs, with 0 <= elem_part[i] < nb_parts. Note: a reference to this array is stored, not a local copy. The array must continue to exist until DomaineCutter is no longer used.
1136 * @param (nb_parts) total number of sub-domains
1137 * @param (les_faces)
1138 * @param (epaisseur_joint)
1139 */
1140template<typename _SIZE_>
1142 const BigIntVect_t& elem_part,
1143 const int nb_parts,
1144 const int epaisseur_joint,
1145 const bool permissif)
1146{
1147 assert(nb_parts >= 0);
1148 assert(elem_part.size_array() == domaine_global.nb_elem_tot());
1149 assert(max_array(elem_part) < nb_parts);
1150 if (min_array(elem_part)<0)
1151 {
1152 Cerr << "Error in DomaineCutter_32_64<_SIZE_>::initialiser" << finl;
1153 Cerr << "The built partition has a default." << finl;
1154 Cerr << "Try to change the partition tool or try changing some partitioning options." << finl;
1155 Cerr << "Contact TRUST support if you are still unsuccessful with your tries." << finl;
1156 Process::exit();
1157 }
1158 reset();
1159
1160 ref_domaine_ = domaine_global;
1161 ref_elem_part_ = elem_part;
1162 nb_parties_ = nb_parts;
1163 epaisseur_joint_ = epaisseur_joint;
1164
1165 const IntTab_t& elems = domaine_global.les_elems();
1166 const int_t nb_som = domaine_global.nb_som_tot();
1167 construire_connectivite_som_elem(nb_som, elems, som_elem_,
1168 1 /* include virtual elements */);
1169
1170 Cerr << "Search of neighboring elements of boundary faces" << finl;
1171 calculer_elements_voisins_bords(domaine_global, som_elem_, voisins_bords_,elem_part,permissif,bords_a_pb_);
1172 Cerr << "Construction of lists of elements per subdomain" << finl;
1173 calculer_listes_elements_sous_domaines(elem_part, nb_parts, elems.dimension(0), liste_elems_sous_domaines_);
1174 //calculer_listes_elements_sous_domaines(elem_part, nb_parts, liste_elems_sous_domaines_);
1175}
1176
1177/*! @brief Fills the "correspondance" structure and the "sous_domaine" for part "part".
1178 *
1179 * Look for the vertices belonging to the sub-part,
1180 * compute the renumbering arrays for vertices and elements between global
1181 * and local numbers (correspondance structure), fill the sub_domaine structures
1182 * (vertices, elements, boundaries, joints, etc).
1183 * Note: sous_domaine must be an empty object (not containing a domain)
1184 */
1185template<typename _SIZE_>
1187 Domaine32& sous_domain, const Static_Int_Lists_t *som_raccord) const
1188{
1189 using Poly_geom_base_t = Poly_geom_base_32_64<_SIZE_>;
1190
1191 // The object must be initialized:
1192 assert(nb_parties_ >= 0);
1193 // sous_domaine empty
1194 assert(sous_domain.nb_elem() == 0);
1195 // Valid part number
1196 assert(part >= 0 && part < nb_parties_);
1197
1198 correspondance.partie_ = part;
1199
1200 const Domaine_t& domain = ref_domaine_.valeur();
1201
1202 ArrOfInt_t elements_sous_partie;
1203 liste_elems_sous_domaines_.copy_list_to_array(part, elements_sous_partie);
1204
1205 // Preparation of sous_domaine
1206 // sous_domaine.reset(); /* reset does not exist yet... */
1207 sous_domain.nommer(domain.le_nom());
1208 if (sub_type(Poly_geom_base_t, domain.type_elem().valeur()))
1209 {
1210 const Poly_geom_base_t& dom_as_poly = ref_cast(Poly_geom_base_t,domain.type_elem().valeur());
1211 dom_as_poly.build_reduced(sous_domain.type_elem(), elements_sous_partie);
1212 }
1213 else
1214 {
1215 // Funny! We need to build the 32b elem type from its 64b version ...!
1216 Nom el_nam = domain.type_elem()->que_suis_je();
1217 el_nam.prefix("_64");
1218 sous_domain.typer(el_nam);
1219 }
1220 sous_domain.type_elem()->associer_domaine(sous_domain);
1221
1222 // Copy names of periodic boundaries:
1223 sous_domain.bords_perio() = domain.bords_perio();
1224
1225 construire_liste_sommets_sousdomaine(domain.nb_som_tot(), domain.les_elems(), elements_sous_partie, part,
1226 som_raccord, correspondance.liste_sommets_ /* write */,
1227 correspondance.liste_inverse_sommets_ /* write */);
1228
1229 remplir_coordsommets_sous_domaine(domain.coord_sommets(), correspondance.liste_sommets_, sous_domain.les_sommets() /* write */);
1230 construire_elems_sous_domaine(domain.les_elems(), elements_sous_partie, correspondance.liste_inverse_sommets_, sous_domain.les_elems() /* write */,
1231 correspondance.liste_inverse_elements_ /* write */);
1232
1233 const SmallArrOfTID_t& l_som = correspondance.liste_sommets_;
1234 const BigArrOfInt_t& l_inv_som = correspondance.liste_inverse_sommets_;
1235 construire_faces_bords_ssdom(l_inv_som, part, sous_domain);
1236 construire_faces_raccords_ssdom(l_inv_som, part, sous_domain);
1237 construire_frontieres_internes_ssdom(l_inv_som, part, sous_domain);
1238 construire_groupe_faces_ssdom(l_inv_som, part, sous_domain);
1239 construire_sommets_joints_ssdom(l_som, l_inv_som, part, som_raccord, sous_domain);
1240 construire_faces_joints_ssdom(part, correspondance, sous_domain);
1241
1242 //if som_raccord is used (for DecouperMulti), then construire_elements_distants_ssdom()
1243 //can lead to the creation of empty joints -> it must not be called
1244 int compute_items_distants = Decouper_t::print_more_infos_ && !som_raccord; // To print NbElemDist informations
1245 if (compute_items_distants)
1246 {
1247 // This sequential algorithm is not used in normal operation, unless
1248 // testing the parallel algorithm in Scatter.cpp.
1249 // see CHECK_ALGO_ESPACE_VIRTUEL in Scatter.cpp (Benoit Mathieu) and/or option 'print_more_info' in Decouper
1250 construire_elements_distants_ssdom(part, correspondance.liste_sommets_, correspondance.liste_inverse_elements_, sous_domain);
1251 }
1252 else
1253 {
1254 // Initialize empty joints (otherwise assert in debug mode since joints are not initialized)
1255 for (int ij = 0; ij < sous_domain.nb_joints(); ij++)
1256 {
1257 Joint& joint = sous_domain.joint(ij);
1258 joint.set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants();
1259 }
1260 }
1262}
1263
1264
1265template<typename _SIZE_>
1266void DomaineCutter_32_64<_SIZE_>::writeData(const Domaine& sous_domaine, Sortie& os) const
1267{
1268 os << sous_domaine;
1269}
1270
1271/*! @brief Generation of all sub-domains of the computation and writing to disk of the files basename_000n.
1272 *
1273 * Domains for 0 <= n < nb_parties_.
1274 * If "sous-domaines" are defined (in the domain.ss_domaines() field),
1275 * a file is also generated per sub-domain.
1276 *
1277 * WARNING: this method might change elem_part!!! (if 'reorder' option was specified)
1278 */
1279template<typename _SIZE_>
1280void DomaineCutter_32_64<_SIZE_>::ecrire_domaines(const Nom& basename, const DomainesFileOutputType format,
1281 const int reorder, const Static_Int_Lists_t* som_raccord)
1282{
1283 assert(nb_parties_ >= 0);
1284 BigIntVect_t& elem_part = ref_elem_part_.valeur();
1285 const Domaine_t& domaine = ref_domaine_.valeur();
1286 const int_t nbelem = domaine.nb_elem();
1287 DomaineCutter_Correspondance_t dc_correspondance;
1288
1289 // Needed for HDF5 Domaines output:
1290#ifdef MPI_
1291 FichierHDFPar fic_hdf;
1292#else
1293 FichierHDF fic_hdf;
1294#endif
1295 Nom nom_fichier_hdf5(basename);
1296 nom_fichier_hdf5+=Nom(".Zones");
1297 nom_fichier_hdf5 = nom_fichier_hdf5.nom_me(nb_parties_, "p", 1);
1298
1299 // Build temp arrays to eventually reorder the partition numbering
1300 ArrOfInt ia(nb_parties_+1), ja;
1301
1302 int nnz=0;
1303 ia[0]=1;
1304
1305 //To detect my parts (when running in parallel)
1306 ArrOfInt myDomaines(nb_parties_);
1307 myDomaines = 0;
1308 ArrsOfInt otherProcDomaines(Process::nproc());
1309
1310 //if some domains are splitted between multiple procs,
1311 //we assign consecutive indices to each of its fragment
1312 //(reading the .Zones files during Scatter will be more efficient)
1313 // Possible values for domaines_index[part]:
1314 // -2 : means that part is detained by multiple procs but not by me
1315 // -1 : means that part is detained by a single proc
1316 // i >=0 : means that my proc detains the i-th fragment of part
1317 ArrOfInt domaines_index(nb_parties_);
1318 domaines_index = -2;
1319
1320 Cerr << "Generation of " << nb_parties_ << " parts:" << finl;
1321 IntVect EdgeCut(nb_parties_);
1322 ArrsOfInt Neighbours(nb_parties_);
1323 // 2 loops if reorder=1
1324 for (int loop=0; loop<1+reorder; loop++)
1325 {
1326 if (reorder)
1327 {
1328 Cerr << "====================================" << finl;
1329 if (loop==0)
1330 Cerr << "FIRST PASS, analyzing the partition:" << finl;
1331 else
1332 Cerr << "SECOND PASS, after reordering the partition:" << finl;
1333 Cerr << "====================================" << finl;
1334 }
1335
1336 if(loop == reorder)
1337 {
1338 // check to see which part is shared between multiple processors:
1339 // 1- everyone sends the number of the parts that belong to them to the master process
1340 // 2- master process will assign a unique positive number to each fragment of a shared domain
1341 // 3- if a part is owned by a single process, it is indicated with the index -1
1342 // 4- the master process scatters the indices to all the proc
1343 ArrsOfInt domaines_indices(Process::nproc());
1344
1345 for(int_t i=0; i < nbelem; i++)
1346 {
1347 const int part = elem_part[i];
1348 myDomaines[part] = 1;
1349 }
1350
1351 for(int p=0; p<Process::nproc(); p++)
1352 {
1353 if(p==0)
1354 otherProcDomaines[p] = myDomaines;
1355 else
1356 {
1357 otherProcDomaines[p].resize_array(nb_parties_);
1358 otherProcDomaines[p] = 0;
1359 }
1360 }
1362 {
1363 for(int p=0; p<Process::nproc(); p++)
1364 {
1365 domaines_indices[p].resize_array(nb_parties_);
1366 domaines_indices[p] = -2;
1367 if(p!=0)
1368 recevoir(otherProcDomaines[p], p, 0, p+2001);
1369 }
1370
1371 for(int part=0; part<nb_parties_; part++)
1372 {
1373 int s = 0;
1374 for(int proc=0; proc < Process::nproc(); proc++)
1375 {
1376 if(otherProcDomaines[proc][part])
1377 domaines_indices[proc][part] = s++;
1378 }
1379
1380 if(s<=1)
1381 {
1382 if(s==0) //empty part: master process will write it
1383 myDomaines[part] = 1;
1384
1385 //part is detained by a single proc
1386 for(int proc=0; proc < Process::nproc(); proc++)
1387 domaines_indices[proc][part] = -1;
1388 }
1389 }
1390
1391 for(int p=0; p<Process::nproc(); p++)
1392 {
1393 if(p==0)
1394 domaines_index = domaines_indices[p];
1395 else
1396 envoyer(domaines_indices[p], 0, p, p+2002);
1397 }
1398 }
1399 else
1400 {
1401 envoyer(myDomaines, Process::me(), 0, Process::me()+2001);
1402 recevoir(domaines_index, 0, Process::me(), Process::me()+2002);
1403 }
1404
1405 if (format == DomainesFileOutputType::HDF5_SINGLE) // create HDF5 file only once!
1406 {
1407 fic_hdf.create(nom_fichier_hdf5);
1409 {
1410 // creating datasets
1411 Noms dataset_names;
1413 {
1414 for(int part=0; part<nb_parties_; part++)
1415 {
1416 if(domaines_index[part] == -1)
1417 {
1418 std::string dname = "/zone_" + std::to_string(part);
1419 Nom dataset_name(dname);
1420 dataset_names.add(dataset_name);
1421 }
1422 else
1423 {
1424 for(int proc=0; proc < Process::nproc(); proc++)
1425 {
1426 if(domaines_indices[proc][part] >=0)
1427 {
1428 std::string dname = "/zone_" + std::to_string(part) + "_" + std::to_string(domaines_indices[proc][part]);
1429 Nom dataset_name(dname);
1430 dataset_names.add(dataset_name);
1431 }
1432 }
1433 }
1434 }
1435 }
1436
1437 // estimation of an upper bound of the datasets' size
1438 int ipart = 0;
1439 while(!myDomaines[ipart]) ipart++;
1440 Domaine32 dom_tmp;
1441 construire_sous_domaine(ipart, dc_correspondance, dom_tmp);
1442 Sortie_Brute os_tmp;
1443 writeData(dom_tmp, os_tmp);
1444 double sz_ = (double)os_tmp.get_size();
1445 sz_ *= 1.5;
1446 sz_ = Process::mp_max(sz_);
1447 envoyer_broadcast(dataset_names,0);
1448 long sz_l = lround(sz_);
1449 fic_hdf.create_datasets(dataset_names, sz_l);
1450 }
1451 }
1452 }
1453 for (int i_part = 0; i_part < nb_parties_; i_part++)
1454 {
1455 if(!myDomaines[i_part])
1456 continue;
1457
1458 assert(domaines_index[i_part] > -2);
1459 Cerr << " Construction of part number " << i_part << finl;
1460 if(domaines_index[i_part] >= 0)
1461 Cerr << "This part is shared between multiple processors" << finl;
1462
1463 Domaine32 sous_domaine;
1464 construire_sous_domaine(i_part, dc_correspondance, sous_domaine, som_raccord);
1465 // Print some information...
1466 {
1467 const Joints& joints = sous_domaine.faces_joint();
1468 const int nb_joints = joints.size();
1469 Cerr << " Number of nodes : " << sous_domaine.nb_som() << finl;
1470 Cerr << " Number of elements : " << sous_domaine.nb_elem() << finl;
1471 Cerr << " Number of joints : " << nb_joints << finl;
1472 // char s[200];
1473 int nbfaces_total=0;
1474 int nbelemdist_total=0;
1475 int nbsom_total=0;
1476 Neighbours[i_part].resize_array(0);
1477 Neighbours[i_part].resize_array(nb_joints);
1478 for (int i = 0; i < nb_joints; i++)
1479 {
1480 const Joint& joint = joints[i];
1481 const int pe = joint.PEvoisin();
1482 Neighbours[i_part][i] = pe;
1483 const int nbsom = joint.joint_item(JOINT_ITEM::SOMMET).items_communs().size_array();
1484 nbsom_total+=nbsom;
1485 const int nbfaces = joint.nb_faces();
1486 nbfaces_total+=nbfaces;
1487 const int nbelemdist = joint.joint_item(JOINT_ITEM::ELEMENT).items_distants().size_array();
1488 nbelemdist_total+=nbelemdist;
1489 Cerr<< " Joint "<<i<<" PeVoisin "<<pe<<" NbSommets "<<nbsom<<" NbFaces "<<nbfaces;
1490 if (Decouper_t::print_more_infos_) Cerr <<" NbElemDist "<<nbelemdist;
1491 Cerr<<finl;
1492 }
1493 Cerr<<" Total: NbSommets "<<nbsom_total<<" NbFaces "<<nbfaces_total;
1494 if (Decouper_t::print_more_infos_) Cerr<<" NbElemDist "<<nbelemdist_total;
1495 EdgeCut(i_part)=nbfaces_total;
1496 Cerr<<finl;
1497
1498 }
1499 if (reorder && loop==0)
1500 {
1501 const Joints& joints = sous_domaine.faces_joint();
1502 const int nb_joints = joints.size();
1503 // Resize ja:
1504 ja.resize_array(nnz+nb_joints+1);
1505 // Fortran numbering:
1506 ja[nnz]=i_part+1;
1507 nnz++;
1508 ia[i_part+1]=ia[i_part]+1;
1509 for (int i = 0; i < nb_joints; i++)
1510 {
1511 const int pe = joints[i].PEvoisin();
1512 ja[nnz] = pe+1;
1513 nnz++;
1514 ia[i_part+1]++;
1515 }
1516 }
1517 else
1518 {
1519 // Write .Zones file(s):
1520 if (format == DomainesFileOutputType::BINARY_MULTIPLE)
1521 {
1522 Nom nom_fichier(basename);
1523 nom_fichier+=Nom(".Zones");
1524 //nom_fichier = nom_fichier.nom_me(i_part);
1525 construire_nom_fichier_sous_domaine(basename,i_part, nb_parties_, domaines_index[i_part], nom_fichier);
1526 Cerr << "Writing part " << i_part << " into the "
1527 << (format == DomainesFileOutputType::BINARY_MULTIPLE ? "binary" : "ascii")
1528 << " file " << nom_fichier << finl;
1529 SFichier os;
1530 os.set_bin(1);
1531
1532 //
1533 // Even for big computations, Zones files can always be written in 32b.
1534 //
1535 os.set_64b(false);
1536
1537 const int ok = os.ouvrir(nom_fichier);
1538 if (!ok)
1539 Process::exit("DomaineCutter_32_64<_SIZE_>::ecrire_domaines : Error while opening file!");
1540 writeData(sous_domaine, os);
1541 }
1542 else if (format == DomainesFileOutputType::HDF5_SINGLE)
1543 {
1544 Sortie_Brute os_hdf;
1545 writeData(sous_domaine, os_hdf);
1546
1547 std::string dname = "/zone_" + std::to_string(i_part);
1548 if(domaines_index[i_part] >=0)
1549 dname += std::string("_") + std::to_string(domaines_index[i_part]);
1550 Nom datasetname(dname);
1552 fic_hdf.fill_dataset(datasetname, os_hdf);
1553 else
1554 fic_hdf.create_and_fill_dataset_SW(datasetname, os_hdf);
1555 }
1556 else
1557 {
1558 Cerr << "DomaineCutter_32_64<_SIZE_>::ecrire_domaines : Unsupported output file type!" << finl;
1559 Process::exit(1);
1560 }
1561 }
1562
1563 // Write sub-domain .ssz files
1564 const LIST(OBS_PTR(Sous_Domaine_t)) & liste_sous_domaines = domaine.ss_domaines();
1565 const int nb_sous_domaines = liste_sous_domaines.size();
1566 if (nb_sous_domaines>0)
1567 {
1568 Cerr << " Writing of files .ssz ..." << finl;
1569 // One file per sub-domain, each file contains all parts...
1570 // If writing the first part, erase the file
1571 IOS_OPEN_MODE mode;
1572 if (i_part == 0)
1573 mode = ios::out; // First part, overwrite the file
1574 else
1575 mode = (ios::out | ios::app); // Append mode
1576
1577 // Loop over sub-domains
1578 const BigArrOfInt_t& liste_inverse_elements = dc_correspondance.liste_inverse_elements_;
1579
1580 for (int i_sous_domaine = 0; i_sous_domaine < nb_sous_domaines; i_sous_domaine++)
1581 {
1582 // Indices of the sub-domain elements that are in the sub-domain:
1583 const Sous_Domaine_t& sous_dom = liste_sous_domaines[i_sous_domaine];
1584 ArrOfInt elements;
1585 {
1586 for (int_t i = 0; i < sous_dom.nb_elem_tot(); i++)
1587 {
1588 const int_t i_elem_global = sous_dom[i];
1589 const int i_elem_local = liste_inverse_elements[i_elem_global];
1590 if (i_elem_local >= 0)
1591 elements.append_array(i_elem_local);
1592 }
1593 }
1594 Nom nom_fichier(sous_dom.le_nom() + Nom(".ssz"));
1595 Cerr << " Subarea " << i_sous_domaine
1596 << " file_name " << nom_fichier
1597 << " nb_elements in this part " << elements.size_array()
1598 << finl;
1599 // The sub-domain file is always in ascii
1600 SFichier os;
1601 const int ok = os.ouvrir(nom_fichier, mode);
1602 if (!ok)
1603 {
1604 Cerr << "DomaineCutter_32_64<_SIZE_>::ecrire_domaines :\n Error while opening file"
1605 << nom_fichier << finl;
1606 exit();
1607 }
1608 os << elements;
1609 }
1610 }
1611 }
1612 if (reorder && loop==0)
1613 {
1614 // Reduce the bandwith of a the matrix connectivity between parts:
1615 // ToDo force not to change partition 0!
1616 ArrOfInt riord(nb_parties_+1);
1617 ArrOfInt levels(nb_parties_+1);
1618 ArrOfInt mask(nb_parties_+1);
1619 int maskval = 1;
1620 for (int i_part=0 ; i_part<nb_parties_+1; i_part++)
1621 mask[i_part] = maskval;
1622 int init=1;
1623 int nlev;
1624 F77NAME(PERPHN)(&nb_parties_, ja.addr(), ia.addr(), &init, mask.addr(), &maskval, &nlev, riord.addr(), levels.addr());
1625
1626 // Renumber the elem_part array:
1627 ArrOfInt renum(nb_parties_);
1628 for (int i_part=0; i_part < nb_parties_; i_part++)
1629 renum[riord[i_part]-1]=i_part;
1630 int_t size=elem_part.size_reelle();
1631 for (int_t i=0; i<size; i++)
1632 elem_part[i]=renum[elem_part[i]];
1633 elem_part.echange_espace_virtuel();
1634 // Rebuild the liste_elems_sous_domaines_
1635 liste_elems_sous_domaines_.reset();
1636 calculer_listes_elements_sous_domaines(elem_part, nb_parties_, nbelem, liste_elems_sous_domaines_);
1637 }
1638
1639 /*
1640 // Print statistics exactly as Fluent:
1641 // http://combust.hit.edu.cn:8080/fluent/Fluent60_help/html/ug/node984.htm
1642 Cerr << ">> Partitions:" << finl;
1643 Cerr << "
1644 P Cells I-Cells Cell Ratio Faces I-Faces Face Ratio Neighbors" << finl;
1645
1646 0 134 10 0.075 217 10 0.046 1
1647 1 137 19 0.139 222 19 0.086 2
1648 2 134 19 0.142 218 19 0.087 2
1649 3 137 10 0.073 223 10 0.045 1
1650 Cerr << "------" << finl;
1651 Cerr << "Partition count = " << nb_parties_ << finl;
1652 Cerr << "Cell variation = (134 - 138)
1653 Cerr << "Mean cell variation = ( -1.1% - 1.1%)
1654 Cerr << "Intercell variation = (10 - 19)
1655 Cerr << "Intercell ratio variation = ( 7.3% - 14.2%);
1656 Cerr << "Global intercell ratio = 10.7%
1657 Cerr << "Face variation = (217 - 223)
1658 Cerr << "Interface variation = (10 - 19)
1659 Cerr << "Interface ratio variation = ( 4.5% - 8.7%)
1660 Cerr << "Global interface ratio = 3.4%
1661 Cerr << "Neighbor variation = (1 - 2) */
1662 }
1663
1664 // if my part is shared with other procs, then my whole part may contain joints that I don't have
1665 // calling mp_sum wouldn't be correct though, because the shared joints would be counted several times
1666 // so we need to gather neighbours of each part
1667 if (Decouper_t::print_more_infos_) // involves communication: do it only if requested
1668 {
1670 {
1671 for(int proc=1; proc<Process::nproc(); proc++)
1672 {
1673 for(int i_part=0; i_part<nb_parties_; i_part++)
1674 {
1675 if(otherProcDomaines[proc][i_part])
1676 {
1677 ArrOfInt tmp_neighbours;
1678 recevoir(tmp_neighbours, proc, 0, proc+2003);
1679 for(int i=0; i<tmp_neighbours.size_array(); i++)
1680 Neighbours[i_part].append_array(tmp_neighbours[i]);
1681 }
1682 }
1683 ArrOfInt tmp_edge_cut(nb_parties_);
1684 tmp_edge_cut = 0;
1685 recevoir(tmp_edge_cut, proc, 0, proc+2008);
1686
1687 for(int i_part=0; i_part<nb_parties_; i_part++)
1688 EdgeCut(i_part) += tmp_edge_cut[i_part];
1689 }
1690
1691 Cout << "\nQuality of partitioning --------------------------------------------" << finl;
1692 int total_edge_cut = 0;
1693 for (int i_part=0; i_part<nb_parties_; i_part++)
1694 total_edge_cut+=EdgeCut(i_part);
1695 Cout << "Total number of edge-cut (faces shared by processes) : " << total_edge_cut << finl;
1696 if (total_edge_cut>0)
1697 {
1698 double mean_edgecut_domaine = total_edge_cut / nb_parties_;
1699 int max_edgecut_domaine = local_min_vect(EdgeCut);
1700 int min_edgecut_domaine = local_max_vect(EdgeCut);
1701
1702 double load_imbalance = double(max_edgecut_domaine / mean_edgecut_domaine);
1703 Cout << "Number of edge-cut per Domaine (min/mean/max) : " << min_edgecut_domaine << " / "
1704 << (int) (mean_edgecut_domaine) << " / " << max_edgecut_domaine << " Load imbalance: " << load_imbalance
1705 << "\n" << finl;
1706 }
1707
1708 int mean_neighbours = 0;
1709 int min_neighbours = nb_parties_;
1710 int max_neighbours = 0;
1711 for (int i_part = 0; i_part < nb_parties_; i_part++)
1712 {
1713 array_trier_retirer_doublons(Neighbours[i_part]);
1714 int nb_neighbours = Neighbours[i_part].size_array();
1715 mean_neighbours += nb_neighbours;
1716 if(nb_neighbours < min_neighbours) min_neighbours = nb_neighbours;
1717 if(nb_neighbours > max_neighbours) max_neighbours = nb_neighbours;
1718 }
1719
1720 mean_neighbours/=nb_parties_;
1721 if (mean_neighbours>0)
1722 {
1723 double load_imbalance = double(max_neighbours / mean_neighbours);
1724 Cout << "Number of neighbours per Domaine (min/mean/max) : " << min_neighbours << " / "
1725 << (int) (mean_neighbours) << " / " <<max_neighbours << " Load imbalance: " << load_imbalance
1726 << "\n" << finl;
1727 }
1728 }
1729 else
1730 {
1731 for(int i_part=0; i_part < nb_parties_; i_part++)
1732 if(myDomaines[i_part])
1733 envoyer(Neighbours[i_part], Process::me(), 0, Process::me()+2003);
1734 envoyer(EdgeCut, Process::me(), 0, Process::me()+2008);
1735 }
1736 }
1737
1738 if (format == DomainesFileOutputType::HDF5_SINGLE)
1739 fic_hdf.close();
1740}
1741
1742template class DomaineCutter_32_64<int>;
1743#if INT_is_64_ == 2
1745#endif
static int print_more_infos_
Definition Decouper.h:60
Tool class to generate sub-domains for a parallel computation from a starting domain (domaine_global)...
Domaine_32_64< _SIZE_ > Domaine_t
BigArrOfInt_T< _SIZE_ > BigArrOfInt_t
BigIntVect_T< _SIZE_ > BigIntVect_t
void ecrire_domaines(const Nom &basename, const DomainesFileOutputType format, const int reorder, const Static_Int_Lists_t *som_raccord=nullptr)
Generation of all sub-domains of the computation and writing to disk of the files basename_000n.
void reset()
cancels all references and empties the arrays
IntTab_T< _SIZE_ > IntTab_t
void initialiser(const Domaine_t &domaine_global, const BigIntVect_t &elem_part, const int nb_parts, const int epaisseur_joint, const bool permissif=false)
Prepares the data structures for building sub-domains based on a partitioning provided in elem_part.
Domaine_32_64< int > Domaine32
void construire_sous_domaine(const int part, DomaineCutter_Correspondance_t &correspondance, Domaine32 &sous_domaine, const Static_Int_Lists_t *som_raccord=nullptr) const
Fills the "correspondance" structure and the "sous_domaine" for part "part".
SmallArrOfTID_T< _SIZE_ > SmallArrOfTID_t
Static_Int_Lists_32_64< _SIZE_ > Static_Int_Lists_t
DomaineCutter_Correspondance_32_64< _SIZE_ > DomaineCutter_Correspondance_t
TRUSTArray< _SIZE_, _SIZE_ > ArrOfInt_t
Sous_Domaine_32_64< _SIZE_ > Sous_Domaine_t
class Domaine_32_64 A Domain is a mesh composed of a set of geometric elements of the same type.
Definition Domaine.h:62
int_t nb_elem_tot() const
Definition Domaine.h:132
DoubleTab_t & les_sommets()
Definition Domaine.h:113
int nb_joints() const
Definition Domaine.h:259
IntTab_t & les_elems()
Definition Domaine.h:129
int_t nb_elem() const
Definition Domaine.h:131
Joint_t & joint(int i)
Definition Domaine.h:261
void typer(const Nom &)
Sets the element type of the domain using the name passed as parameter.
Definition Domaine.h:457
const DoubleTab_t & coord_sommets() const
Definition Domaine.h:112
Joints_t & faces_joint()
Definition Domaine.h:265
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
int_t nb_som() const
Returns the number of vertices of the domain.
Definition Domaine.h:121
const Noms & bords_perio() const
Definition Domaine.h:278
void nommer(const Nom &nom) override
Assigns a name to the Objet_U. Virtual method to override.
const Nom & le_nom() const override
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
virtual int get_tab_faces_sommets_locaux(IntTab &faces_som_local) const
Fills faces_som_local(i,j) giving for 0 <= i < nb_faces() and 0 <= j < nb_som_face(i) the local verte...
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
void typer(const Motcle &)
Sets the type of the faces.
Definition Faces.cpp:382
const IntTab_t & les_sommets() const
Returns the array of vertices of all faces.
Definition Faces.h:74
Parallel collective version of FichierHDF, to be used for all concurrent reading/writing on HDF files...
This abstract class provides all the functionalities to open and manipulate HDF files and related con...
Definition FichierHDF.h:47
void fill_dataset(Nom dataset_name, Sortie_Brute &sortie)
virtual void create_and_fill_dataset_SW(Nom datasetname, Sortie_Brute &sortie)
void create_datasets(Noms dataset_names, long length)
Definition FichierHDF.h:74
virtual void close()
virtual void create(Nom filename)
void nommer(const Nom &) override
Gives a name to the boundary.
Definition Frontiere.cpp:74
void typer_faces(const Motcle &)
Sets the type of the boundary faces.
Definition Frontiere.cpp:96
int_t nb_faces() const
Returns the number of faces of the boundary.
Definition Frontiere.h:59
void associer_domaine(const Domaine_t &)
Associates the boundary to the domain it belongs to.
Definition Frontiere.cpp:63
const Faces_t & faces() const
Definition Frontiere.h:54
void add(const Frontiere_32_64 &)
Adds the vertices (and faces) of the given boundary to this object (Frontiere_32_64).
Groupe_Face class — represents a selection of faces read from a med file.
void affecte_epaisseur(int ep)
Definition Joint.h:48
const Joint_Items_t & joint_item(JOINT_ITEM type) const
Returns the joint information for the requested type (read-only).
Definition Joint.cpp:131
void affecte_PEvoisin(int num)
Definition Joint.h:47
void dimensionner(int)
Definition Joint.cpp:76
Joint_Items_t & set_joint_item(JOINT_ITEM type)
Returns the joint information for a given geometric item type, for filling the structures.
Definition Joint.cpp:104
int PEvoisin() const
Definition Joint.h:49
const ArrOfInt_t & items_communs() const
Definition Joint_Items.h:44
ArrOfInt_t & set_items_communs()
Returns the items_communs_ array for filling.
const ArrOfInt_t & items_distants() const
Returns the items_distants_ array (read-only). See items_distants_.
ArrOfInt_t & set_items_distants()
Returns the items_distants_ array for filling.
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
Nom nom_me(int, const char *prefix=0, int without_padding=0) const
Inserts _prefix000n (n=me() or nproc()) into a file name (e.g. toto.titi) to produce toto_prefix000n....
Definition Nom.cpp:380
Nom & prefix(const char *const)
Definition Nom.cpp:324
An array of character strings (VECT(Nom)).
Definition Noms.h:26
Base class for TRUST objects (Objet_U).
Definition Objet_U.h:68
static int dimension
Definition Objet_U.h:94
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
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
Base class for polyedrons and polygons. Connectivity is stored in descending mode:
static int check_int_overflow(trustIdType)
Definition Process.cpp:437
static double mp_max(double)
Definition Process.cpp:379
static bool is_parallel()
Definition Process.cpp:108
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 int me()
Returns the rank of the local processor in the current communication group. See Comm_Group::rank() an...
Definition Process.cpp:122
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
static int je_suis_maitre()
Returns 1 if on the master processor of the current group (i.e. me() == 0), 0 otherwise.
Definition Process.cpp:82
SFichier is to the C++ ofstream class what Sortie is to the C++ ostream class.
Definition SFichier.h:29
static void trier_les_joints(Joints &joints)
Sort joints by increasing neighbor proc number.
Definition Scatter.cpp:712
This derived class of Sortie stacks whatever it receives in an internal binary buffer.
unsigned get_size() const
virtual int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::out)
Base class for output streams.
Definition Sortie.h:52
void set_bin(bool bin) override
Changes the write mode of the file.
Definition Sortie.cpp:252
const Nom & le_nom() const override
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
int_t nb_elem_tot() const
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
_TYPE_ * addr()
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
virtual _SIZE_ dimension_tot(int) const
void resize(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTArray.h:156
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_tot(int) const override
Definition TRUSTTab.tpp:160
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size_reelle() const
Definition TRUSTVect.tpp:27
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")