TrioCFD 1.9.8
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 de la liste des sommets du sous-domaine "partie".
53 *
54 * C'est l'ensemble des sommets des elements appartenant a ce sous-domaine.
55 * On ne traite que les elements reels.
56 *
57 * @param (nb_sommets) nombre de sommets du domaine globale
58 * @param (les_elems)
59 * @param (elem_part) tableau de decoupage (pour chaque element i du domaine global, elem_part[i] est le numero du sous-domaine auquel il est affecte)
60 * @param (partie) le numero du sous-domaine a construire
61 * @param (liste_sommets) en sortie : liste des sommets du sous-domaine: liste_sommets[i] est l'indice dans le domaine_globale du i-ieme sommet du sous-domaine. Les indices sont classes dans l'ordre croissant.
62 * @param (liste_inverse_sommets) en sortie : on lui donne la taille nb_sommets et on l'initialise. liste_inverse_sommet[i] est l'indice du sommet dans le sous-domaine ou -1 si le sommet i n'est pas dans le sous-domaine)
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 // Algorithme : on parcourt les elements: pour les elements de la partie,
79 // on marque les sommets de l'element par un drapeau.
80 // Puis on fait une boucle sur les sommets, et ceux dont le drapeau
81 // est mis sont mis dans la liste.
82
83 // D'abord, on compte les sommets de la partie et on
84 // remplit drapeau_sommet
85 ArrOfBit_32_64<_SIZE_> drapeau_sommet(nb_sommets);
86
87 drapeau_sommet = 0;
88 // Nombre de sommets de la partie "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 // Si le drapeau n'etait pas mis, cela fait un sommet de plus
100 if (! bit)
101 nb_sommets_part++;
102 }
103 }
104 }
105 //sommets a ajouter a cause de 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)) //le sommet est demande par ce proc
110 nb_sommets_part++; //si on ne l'a pas deja, on le rajoute
111
112 // Remplissage de liste_sommets et liste_inverse_sommets
113 liste_sommets.resize_array(0); // On oublie les valeurs precedentes
114 liste_sommets.resize_array(nb_sommets_part);
115
116 liste_inverse_sommets.resize_array(0); // On oublie les valeurs precedentes
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/*! Remplissage du tableau des coordonnees des sommets d'une partie
133 * a partir des coordonnees des sommets du domaine complet (sommets_glob)
134 * et de la liste des sommets de la partie (liste_sommets)
135 * On cree sommets_loc comme suit:
136 * sommets_loc.dimension(0) = liste_sommets.size_array()
137 * sommets_loc.dimension(1) = sommets_glob.dimension(1)
138 *
139 * Parametre: sommets_glob
140 * Signification: les coordonnees des sommets du domaine global
141 * Parametre: liste_sommets
142 * Signification: les indices des sommets de sommets_glob a copier
143 * dans 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/*! Construction du tableau elems des elements de la partie "part".
164 * elems(i, j) sera le nouveau numero du sommet j de l'element i
165 * dans la partie part. On utilise la liste_inverse pour obtenir les
166 * nouveaux numeros des sommets.
167 * Les elements du domaine local sont crees dans l'ordre croissant de
168 * leur indice dans le domaine global.
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 // Premier passage: comptage du nombre d'elements de la partie
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 // Deuxieme passage: remplissage du tableau
190 for (int i_elem = 0; i_elem < nb_elem_part; i_elem++)
191 {
192 int_t elem = liste_elements[i_elem];
193
194 // Nouveau numero de l'element dans la partie
195 liste_inverse_elements[elem] = i_elem;
196 // Copie de l'element avec traduction du numero des sommets en
197 // numero local dans le sous-domaine
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 Pour une liste de "faces" du domaine globale, compter le nombre de faces incluses dans la partie "part" et les copier dans la structure
217 *
218 * faces_partie en remplacant les numeros de sommets par les numeros locaux
219 * dans le sous-domaine.
220 * L'ordre des faces est conserve (si une face apparait avant une autre dans
221 * la liste du domaine complet et si elles sont toutes les deux dans la sous-partie,
222 * alors leur ordre est conserve). C'est important pour le periodique
223 * (hypothese qu'il y a correspondance entre la face i et la face i+n/2 du bord
224 * periodique).
225 * Attention: la condition pour qu'une face soit incluse est "la face appartient
226 * a un element de la partie voisine". La condition "les sommets des faces sont
227 * des sommets de joint" n'est PAS suffisante.
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 // La liste des faces du tableau faces_sommets a inclure dans le sous-domaine
244 ArrOfInt_T<_SIZE_> liste_faces;
245
246 // Premier passage : on cherche les faces a inclure
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 // Deuxieme passage : stockage des faces et conversion des numeros
261 // de sommets des faces en numeros locaux dans le sous-domaine.
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 Pour chaque PE mentionne dans le tableau "voisins", si un joint avec ce pe n'existe par encore dans le domaine,
283 * ajoute un joint et initialise ce joint avec "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 // Ces joints n'auront pas de sommets communs. Met le flag d'initialisation a 1.
308 joint.set_joint_item(JOINT_ITEM::SOMMET).set_items_communs();
309 }
310 }
311}
312
313
314/*! @brief A partir d'une liste de sommets de depart (liste_sommets_depart), on parcourt les elements voisins de ces sommets (si epaisseur <= 1),
315 *
316 * puis les voisins de ces elements (voisins par un sommet de l'element) si epaisseur <= 2,
317 * puis les voisins des voisins si epaisseur <= 3, etc
318 * Les elements appartenant a la "partie_a_ignorer" ne sont pas parcourus.
319 * Les indices des elements parcourus sont ranges dans liste_elements_trouves.
320 * Cette methode a ete codee pour construire_elements_distants_ssdom()
321 */
322template <typename _SIZE_>
323void DomaineCutter_32_64<_SIZE_>::parcourir_epaisseurs_elements(SmallArrOfTID_t liste_sommets_depart, /* par valeur car on va la modifier */
324 const int partie_a_ignorer, /* ne pas parcourir les elems de cette partie */
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 // Marquage des sommets de depart et construction d'une liste de sommets uniques
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 // Boucle sur les epaisseurs successives d'elements autour des sommets de joint.
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 // Parcours des elements voisins de ce sommet :
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; // Cet element a deja ete visite
371 // Numero de domaine de l'element voisin:
372 const int part = elem_part[elem];
373 if (part == partie_a_ignorer)
374 continue; // Ne traiter que les elements des autres parties
375
376 liste_elements_trouves.append_array(elem);
377 elements_parcourus.setbit(elem);
378
379 // Ajout a la prochaine liste de sommets a traiter les sommets de cet 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/*! Pour les trois fonctions suivantes :
396 * Remplissage des frontieres de la partie associee a un processeur.
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 Constructions des raccords de la sous_partie a partir des raccords du domaine global.
425 *
426 * Les Raccord_local_homogene sont transformes en Raccord_distant_homogene.
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 // Rappel : les bords internes sont des "frontieres" a l'interieur du domaine
467 // (par exemple une plaque d'epaisseur nulle dans l'ecoulement)
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 // Premier passage : on cherche les faces a inclure
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 // Deuxieme passage : stockage des faces et conversion des numeros
539 // de sommets des faces en numeros locaux dans le sous-domaine.
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 calcul et remplissage de domaine_partie.
561 *
562 * joint(i).set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants()
563 * (liste des elements distants).
564 * Eventuellement, de nouveaux joints sont crees.
565 * Historique: methode codee en janvier 2006 par B.Mathieu. Je croyais que c'etait
566 * trop complique de determiner les elements distants au moment du scatter et j'ai
567 * fini par trouver comment faire. Du coup la methode ci-dessous n'est plus utilisee
568 * en temps normal. En cas de probleme, on peut la reactiver (option 'print_more_info' de Decouper):
569 * en theorie elle donne exactement le meme resultat que l'algorithme code dans Scatter::calculer_espace_distant_elements.
570 * Attention, elle ne fait rien de special pour le bords periodiques...
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 // Premiere etape: chercher les elements virtuels de la sous-partie
585 // (elements des autres parties situes dans l'epaisseur de joint en partant
586 // des sommets de joint).
587 SmallArrOfTID_t elements_virtuels;
588 {
589 // Construction d'un tableau contenant tous les sommets de tous les 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, // Sommets de depart
606 partie, /* ignorer les elements de la partie locale */
607 elements_virtuels);
608 }
609 const int nb_elements_virtuels = elements_virtuels.size_array();
610 // Construire la liste des numeros de domaines voisins et ajouter les joints manquants:
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 // Pour chaque partie voisine, chercher les elements distants:
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 // Liste des sommets des elements virtuels de la partie voisine:
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 // Recherche des elements voisins de cette liste:
646 SmallArrOfTID_t elements_distants;
647 parcourir_epaisseurs_elements(sommets_depart,
648 partie_voisine, /* ignorer les elements de la partie voisine */
649 elements_distants);
650
651 // Retirer de la liste les elements qui ne sont pas dans la partie locale:
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 // Traduire les indices des elements en indices locaux sur le sous-domaine.
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 // Trier les elements dans l'ordre croissant des indices
675 elements_distants.ordonne_array();
676 // Stocker la liste des elements distants dans le 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 Creation des joints et construction des listes et des tableaux de sommets joints pour tous les joints de
683 *
684 * la partie part. Les sommets du joint avec le "PEvoisin" sont
685 * les sommets de la partie "part" qui sont aussi un sommet d'un
686 * element appartenant au PEvoisin.
687 * Les joints apparaissent dans la liste dans l'ordre croissant des PEs.
688 * Note: Les faces que l'on va creer ensuite utilisent forcement
689 * des sommets que l'on va trouver ici.
690 * Propriete : Les sommets du joint sont classes dans l'ordre croissant
691 * de leur numero local, donc dans l'ordre croissant de
692 * leur numero global (voir 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 // Liste de sommets de joint (toutes parties confondues, un sommet peut
707 // apparaitre plusieurs fois dans le tableau, une fois par pe voisin au maximum)
708 // C'est le numero global du sommet
709 ArrsOfInt_T<_SIZE_> joints_sommets(parts);
710
711 // Algorithme : boucle sur les sommets de la partie.
712 // Pour chaque sommet du sous-domaine "p", on cherche les PEs auxquels appartiennent
713 // les elements voisins du sommet, et, s'il y a un PE voisin different de "p",
714 // on ajoute ce sommet aux joints avec ces PEs.
715
716 const int nb_sommets = liste_sommets.size_array();
717
718 // i = indice local du sommet dans le sous-domaine
719 for (int i_sommet = 0; i_sommet < nb_sommets; i_sommet++)
720 {
721 // Numero global du sommet
722 int_t sommet = liste_sommets[i_sommet];
723 // Boucle sur les elements voisins du sommet 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 // Faut-il ajouter ce sommet aux sommets du joint avec le PEvoisin ?
730 if (PEvoisin != partie)
731 joints_sommets[PEvoisin].append_array(sommet);
732 }
733 //boucle sur les procs connectes au sommet par un raccord
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 // Creation des joints : dans l'ordre croissant du PE voisin
744 for (int PEvoisin = 0; PEvoisin < parts; PEvoisin++)
745 {
746 ArrOfInt_t& sommets = joints_sommets[PEvoisin];
747 if (sommets.size_array() > 0)
748 {
749 // Trier les sommets de joint par ordre croissant de l'indice global
750 // (donc toutes les listes sur les processeurs voisins seront ordonnees
751 // de la meme facon) et retirer les doublons
752 array_trier_retirer_doublons(sommets);
753 const int nb_sommets2 = Process::check_int_overflow(sommets.size_array());
754
755 // On cree un nouveau 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 // Remplissage du tableau (transformation en indice local de sommet)
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/*! Recherche des faces de joints (faces adjacentes a deux elements appartenant
779 * a deux processeurs differents).
780 * On suppose que les sommets des joints ont ete construits.
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 // Premiere etape: reperage des "elements de joint" (elements de la "partie"
793 // possedant un sommet de joint), et marquage des sommets de joint
794 SmallArrOfTID_t liste_elements_joint;
795 ArrOfBit drapeaux_sommets_joints(nb_sommets_ssdom);
796 {
797 // Pour l'instant, on utilise les joints en const...
798 const Joints& joints_partie = domaine_partie.faces_joint();
799 drapeaux_sommets_joints = 0;
800
801 // Marqueurs: pour chaque element du sous-domaine, est-il deja dans la liste ?
802 ArrOfBit drapeaux_elements(nb_elem_ssdom);
803 drapeaux_elements = 0;
804 // Boucle sur tous les sommets de joint
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 // Marquage du sommet de joint dans le sous-domaine
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 // On ajoute l'element a la liste d'elements joint s'il est dans ma partie
823 // et s'il n'est pas encore dans la liste.
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 // Deuxieme etape: pour chaque element de joint, construction de ses
833 // faces et on regarde si la face a un element voisin dans une autre partie.
834 // Si oui, c'est une face de joint
835
836 // Tableau des indices des sommets de toutes les faces de joint
837 // (tous joints confondus, indices de sommets dans le sous-domaine)
838 IntTab faces_joints;
839 // Pour chaque face de joint, numero du sous-domaine voisin par cette face
840 ArrOfInt faces_pe_voisins;
841 // Pour chaque processeur, nombre de faces de joint avec ce proc.
842 // (on initialise a zero)
843 ArrOfInt nb_faces_joints(nb_parties_);
844 {
845 // Indices des sommets des faces sur l'element de reference
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 // Sommets des elements du maillage global
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 // Boucle sur les elements de joint
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 // Indice de l'element dans le domaine global
869 const int_t i_elem_global = liste_elements_joint[i_elem_joint];
870 // Boucle sur les faces de l'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 // Construction de la 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 // Indice du sommet dans le sous-domaine
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 // Le sommet est-il sur un joint ?
900 if (drapeaux_sommets_joints[i_som_local] == 0)
901 face_ok = 0; // Non => cette face n'est pas sur un joint
902 }
903 }
904 }
905 }
906 // Premier test pour eliminer tout de suite la face
907 // si tous ses sommets ne sont pas des sommets de joint.
908 if (face_ok)
909 {
910 // Recherche des elements voisins de cette face
911 find_adjacent_elements(som_elem_, une_face, elements_voisins);
912 // Recherche d'un element voisin qui n'est pas dans ma partie
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 // J'ai une face de joint, je l'ajoute au tableau
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 // Troisieme etape: ajout des faces dans les joints
947 {
948 // Le type des faces de joint
949 const Domaine_t& domaine_globale = ref_domaine_.valeur();
950 const Type_Face& type_face_joint = domaine_globale.type_elem()->type_face();
951 // On va modifier les 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 // *suite* : tableau de dimension 2 meme s'il n'y a pas de 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 // Typage des faces et allocation memoire
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 // Remplissage du tableau de faces
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 annule toutes les references et vide les tableaux
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 // Premier passage : comptage
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 // Deuxieme passage : remplissage
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 Prepare les structures de donnees pour la construction des sous-domaines en fonction d'un decoupage fourni dans elem_part.
1133 *
1134 * @param (domaine_global) le domaine a decouper (doit avoir un domaine). On prend une ref a ce domaine (il doit donc rester valide).
1135 * @param (elem_part) pour chaque element, numero du sous-domaine auquel il appartient, avec 0 <= elem_part[i] < nb_parts. Attention, on prend une ref a ce tableau, on ne fait pas une copie local. Le tableau doit continuer a exister jusqu'a ce qu'on a fini d'utiliser DomaineCutter.
1136 * @param (nb_parts) nombre total de sous-domaines
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 /* inclure les elems virtuels */);
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 Remplit la structure "correspondance" et le "sous_domaine" pour la partie "part".
1178 *
1179 * On cherche les sommets qui appartiennent a la sous-partie,
1180 * on calcule les tableaux de renumerotation des sommets et des elements entre numero
1181 * global et numero local (structure correspondance), on remplit les structures de
1182 * sous_domaine (sommets, elements, frontieres, joints, etc).
1183 * Attention: sous_domaine doit etre un objet vierge (ne pas contenir de domaine)
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 // L'objet doit etre initialise:
1192 assert(nb_parties_ >= 0);
1193 // sous_domaine vide
1194 assert(sous_domain.nb_elem() == 0);
1195 // Numero de partie valide
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 du sous_domaine
1206 // sous_domaine.reset(); /* reset n'existe pas encore... */
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 // Cet algorithme sequentiel n'est pas utilise en temps normal, sauf si
1248 // on veut tester l'algorithme parallele dans Scatter.cpp
1249 // voir CHECK_ALGO_ESPACE_VIRTUEL dans Scatter.cpp (Benoit Mathieu) et/ou option 'print_more_info' dans Decouper
1250 construire_elements_distants_ssdom(part, correspondance.liste_sommets_, correspondance.liste_inverse_elements_, sous_domain);
1251 }
1252 else
1253 {
1254 // Initialiser des joints vides (sinon assert en debug car les joints ne sont pas initialises)
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 de tous les sous-domaines du calcul et ecriture sur disque des fichiers basename_000n.
1272 *
1273 * Domaines pour 0 <= n < nb_parties_.
1274 * Si des "sous-domaines" sont definies (dans le champ domaine.ss_domaines()),
1275 * on genere aussi un fichier par sous-domaine.
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 // On affiche quelques informations...
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 numerotation:
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 // Ecritures des fichiers sous-domaines .ssz
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 // Un fichier par sous-domaine, dans chaque fichier on trouve toutes les parties...
1570 // Si on est en train d'ecrire la premiere partie, on efface le fichier
1571 IOS_OPEN_MODE mode;
1572 if (i_part == 0)
1573 mode = ios::out; // Premiere partie, on ecrase le fichier
1574 else
1575 mode = (ios::out | ios::app); // Mode append
1576
1577 // Boucle sur les sous-domaines
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 des elements du sous-domaine qui sont dans le sous-domaine:
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 // Le fichier sous-domaines est toujours en 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 forcer a ne pas changer la 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
Classe outil permettant de generer des sous-domaines pour un calcul parallele a partir d'un domaine d...
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 de tous les sous-domaines du calcul et ecriture sur disque des fichiers basename_000n.
void reset()
annule toutes les references et vide les tableaux
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)
Prepare les structures de donnees pour la construction des sous-domaines en fonction d'un decoupage f...
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
Remplit la structure "correspondance" et le "sous_domaine" pour la partie "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
classe Domaine_32_64 un Domaine est un maillage compose d'un ensemble d'elements geometriques de meme...
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 &)
Type les elements du domaine avec le nom passe en parametre.
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
Renvoie le nombre total de sommets du domaine i.e. le nombre de sommets reels et virtuels sur le proc...
Definition Domaine.h:123
int_t nb_som() const
Renvoie le nombre de sommets du domaine.
Definition Domaine.h:121
const Noms & bords_perio() const
Definition Domaine.h:278
void nommer(const Nom &nom) override
Donne un nom a l'Objet_U Methode virtuelle a surcharger.
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
virtual int get_tab_faces_sommets_locaux(IntTab &faces_som_local) const
remplit le tableau faces_som_local(i,j) qui donne pour 0 <= i < nb_faces() et 0 <= j < nb_som_face(i)...
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
void typer(const Motcle &)
Type les faces.
Definition Faces.cpp:390
const IntTab_t & les_sommets() const
Renvoie le tableau des sommets de toutes les 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
Donne un nom a la frontiere.
Definition Frontiere.cpp:74
void typer_faces(const Motcle &)
Type les faces de la frontiere.
Definition Frontiere.cpp:96
int_t nb_faces() const
Renvoie le nombre de faces de la frontiere.
Definition Frontiere.h:59
void associer_domaine(const Domaine_t &)
Associe la frontiere au domaine dont elle depend.
Definition Frontiere.cpp:63
const Faces_t & faces() const
Definition Frontiere.h:54
void add(const Frontiere_32_64 &)
Ajoute les sommets (et faces) de la frontiere passee en parametre a l'objet (Frontiere_32_64).
Classe Groupe_Face La classe sert a representer une selection de faces lu dans le fichier med.
void affecte_epaisseur(int ep)
Definition Joint.h:48
const Joint_Items_t & joint_item(JOINT_ITEM type) const
Renvoie les informations de joint pour le type demande.
Definition Joint.cpp:128
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)
Renvoie les informations de joint pour un type d'item geometrique donne, pour remplissage des structu...
Definition Joint.cpp:103
int PEvoisin() const
Definition Joint.h:49
const ArrOfInt_t & items_communs() const
Definition Joint_Items.h:44
ArrOfInt_t & set_items_communs()
Renvoie le tableau items_communs_ pour le remplir.
const ArrOfInt_t & items_distants() const
Voir items_distants_.
ArrOfInt_t & set_items_distants()
Renvoie le tableau items_distants_ pour le remplir Voir Scatter::calculer_espace_distant,...
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
Nom nom_me(int, const char *prefix=0, int without_padding=0) const
Insere _prefix000n (n=me() ou nproc()) dans un nom de fichier (par ex:toto.
Definition Nom.cpp:387
Nom & prefix(const char *const)
Definition Nom.cpp:329
Un tableau de chaine de caracteres (VECT(Nom)).
Definition Noms.h:26
classe Objet_U Cette classe est la classe de base des Objets de TRUST
Definition Objet_U.h:73
static int dimension
Definition Objet_U.h:99
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
Base class for polyedrons and polygons. Connectivity is stored in descending mode:
static int check_int_overflow(trustIdType)
Definition Process.cpp:428
static double mp_max(double)
Definition Process.cpp:376
static bool is_parallel()
Definition Process.cpp:110
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
Definition Process.cpp:86
Cette classe est a la classe C++ ofstream ce que la classe Sortie est a la classe C++ ostream Elle re...
Definition SFichier.h:27
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)
Classe de base des flux de sortie.
Definition Sortie.h:52
void set_bin(bool bin) override
Change le mode d'ecriture du fichier.
Definition Sortie.cpp:255
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
int_t nb_elem_tot() const
Cette classe permet de stocker des listes d'entiers accessibles en temps constant.
void set_value(int_t i_liste, int_t i_element, int_t valeur)
affecte la "valeur" au j-ieme element de la i-ieme liste avec 0 <= i < get_nb_lists() et 0 <= j < get...
int_t get_list_size(int_t i_liste) const
renvoie le nombre d'elements de la liste i
void set_list_sizes(const ArrOfInt_t &sizes)
detruit les listes existantes et en cree de nouvelles.
int_t get_nb_lists() const
renvoie le nombre de listes stockees
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
_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")