Arcane  v3.15.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
SplitSDMeshPartitioner.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* SplitSDMeshPartitioner.cc
9
10 Partitioneur de maillage reprenant le fonctionnement (simplifié) de SplitSD
11 utilisé à Dassault Aviation et développé à l'ONERA par EB en 1996-99
12*/
13/*---------------------------------------------------------------------------*/
14/*---------------------------------------------------------------------------*/
15
16//#define DEBUG_PARTITIONER
17
18
19#include "arcane/utils/PlatformUtils.h"
20#include "arcane/utils/ArcanePrecomp.h"
21#include "arcane/utils/Convert.h"
22#include "arcane/utils/Array.h"
23
24#include "arcane/core/ISubDomain.h"
25#include "arcane/core/IParallelMng.h"
27#include "arcane/core/IPrimaryMesh.h"
28#include "arcane/core/Properties.h"
29#include "arcane/core/ItemGroup.h"
30#include "arcane/core/Service.h"
31#include "arcane/core/Timer.h"
32#include "arcane/core/FactoryService.h"
33#include "arcane/core/ItemPrinter.h"
34#include "arcane/core/IItemFamily.h"
35#include "arcane/core/MeshVariable.h"
36#include "arcane/core/VariableBuildInfo.h"
37#include "arcane/std/MeshPartitionerBase.h"
38#include "arcane/std/SplitSDMeshPartitioner.h"
39
40#include <map>
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45namespace Arcane
46{
47
48/*---------------------------------------------------------------------------*/
49/*---------------------------------------------------------------------------*/
50SplitSDMeshPartitioner::
51SplitSDMeshPartitioner(const ServiceBuildInfo& sbi)
52: ArcaneSplitSDMeshPartitionerObject(sbi)
53, m_poids_aux_mailles(VariableBuildInfo(sbi.mesh(),"MeshPartitionerCellsWeight",IVariable::PNoDump|IVariable::PNoRestore))
54{
55 info() << "SplitSDMeshPartitioner::SplitSDMeshPartitioner(...)";
56}
57
58/*---------------------------------------------------------------------------*/
59/*---------------------------------------------------------------------------*/
60
61void SplitSDMeshPartitioner::
62partitionMesh(bool initial_partition)
63{
64 info() << "Equilibrage de charge avec SplitSDMeshPartitioner";
65
66 // on ne supporte pas les contraintes
67 // car on utilise le maillage Arcane pour les parcours frontaux,
68 // il n'est donc pas prévu pour le moment de tenir compte des groupes
69 // de mailles associées aux contraintes
70 _initArrayCellsWithConstraints();
71 if (haveConstraints())
72 throw FatalErrorException("SplitSDMeshPartitioner: On ne supporte pas les contraintes avec SplitSD");
73
74 // initialisation des structures internes
75
76 StrucInfoProc* InfoProc = NULL;/* structure décrivant le processeur sur lequel tourne l'application */
77 StructureBlocEtendu* Domaine = NULL;/* structure décrivant sommairement le bloc, c.a.d. la partie de la topologie localisée sur ce processeur */
78 StrucMaillage* Maillage = NULL;/* structure décrivant sommairement le maillage global */
79
80 // initialisation des données propres au partitionneur, m_cells_weight doit être calculé
82
83 // processus itératif de rééquilibrage de charge par déplacement d'éléments d'un sous-domaine à l'autre
84 Equilibrage(InfoProc, Domaine, Maillage);
85
86 // on vide les structures
88}
89/*---------------------------------------------------------------------------*/
90/*---------------------------------------------------------------------------*/
91void SplitSDMeshPartitioner::
93{
94 info() << "SplitSDMeshPartitioner::init("<<initial_partition<<",...)";
95
96 ISubDomain* sd = subDomain();
97 IParallelMng* pm = sd->parallelMng();
98
99 /* Initialisation memoire de InfoProc */
100 InfoProc = new StrucInfoProc();
101
102 InfoProc->me = sd->subDomainId();
103 InfoProc->nbSubDomain = pm->commSize();
104 InfoProc->m_service = this;
105 // MPI_Comm_dup(MPI_COMM_WORLD,&InfoProc->Split_Comm); /* Attribution d'un communicateur propre à notre partitioneur */
106 InfoProc->Split_Comm = *(MPI_Comm*)getCommunicator();
107 initConstraints();
108
109 // initialisation des poids aux mailles
110 initPoids(initial_partition);
111#if 0
112 if (!initial_partition){
113 info() << "Initialize new owners";
114 // Initialise le new owner pour le cas où il n'y a pas besoin de rééquilibrer
115 IMesh* mesh = this->mesh();
116 VariableItemInteger& cells_new_owner = mesh->itemsNewOwner(IK_Cell);
118 Cell cell = *icell;
119 cells_new_owner[icell] = cell.owner();
120 }
121 changeOwnersFromCells();
122 cells_new_owner.synchronize();
123 }
124#endif
125
126 /* Initialisation memoire de Domaine */
128
129 Domaine->NbIntf = 0;
130 Domaine->Intf = NULL;
131 Domaine->NbElements = 0;
132 Domaine->PoidsDom = 0.0;
133
134 MAJDomaine(Domaine);
135
136 /* Initialisation memoire de Maillage */
137 Maillage = new StrucMaillage();
138
139 Maillage->NbElements = 0;
140 Maillage->NbDomainesMax = pm->commSize();
141 Maillage->NbDomainesPleins = 0;
142 Maillage->ListeDomaines = NULL;
143 Maillage->NbProcsVides = 0;
144 Maillage->Poids = 0.0;
145
146 // on ne met à jour que sur le processeur maitre (le 0) la structure, en fonction de Domaine
147 MAJMaillageMaitre(InfoProc, Domaine, Maillage);
148}
149/*---------------------------------------------------------------------------*/
150/*---------------------------------------------------------------------------*/
151void SplitSDMeshPartitioner::
152initPoids(bool initial_partition)
153{
154 ARCANE_UNUSED(initial_partition);
155
156 /* récupération du poids aux mailles pour qu'il suivent les cellules */
157 IMesh* mesh = this->mesh();
158 CellGroup own_cells = mesh->ownCells();
159// if (initial_partition || m_cells_weight.empty())
160// ENUMERATE_CELL(iitem,own_cells){
161// const Cell& cell = *iitem
162// m_poids_aux_mailles[cell] = 1.0;
163// }
164// else{
165// Integer nb_weight = nbCellWeight();
166 SharedArray<float> cell_weights = cellsWeightsWithConstraints(1, true); // 1 poids seulement
168 m_poids_aux_mailles[iitem] = cell_weights[iitem.index()];
169 }
170}
171/*---------------------------------------------------------------------------*/
172/*---------------------------------------------------------------------------*/
173void SplitSDMeshPartitioner::
175{
176 info() << "SplitSDMeshPartitioner::fin(...)";
177 LibereInfoProc(InfoProc);
178 LibereDomaine(Domaine);
179 LibereMaillage(Maillage);
180
181 delete InfoProc;
182 delete Domaine ;
183 delete Maillage;
184
185 InfoProc = NULL;
186 Domaine = NULL;
187 Maillage = NULL;
188}
189/*---------------------------------------------------------------------------*/
190/*---------------------------------------------------------------------------*/
191void SplitSDMeshPartitioner::
192MAJDomaine(StructureBlocEtendu* Domaine)
193{
194 debug() <<" ----------------------------------------";
195 debug() << "SplitSDMeshPartitioner::MAJDomaine(...)";
196
197 LibereDomaine(Domaine);
198
199 int me = subDomain()->subDomainId();
200
201 // remplissage de Domaine->Intf, listes de noeuds par sous-domaine voisin
202
203 IMesh* mesh = this->mesh();
204 FaceGroup all_faces = mesh->allFaces(); // faces sur ce processeur
205 debug() << " all_faces.size() = =" <<all_faces.size();
206
207 std::map<int, SharedArray<Face> > vois_faces; // liste des faces par sous-domaine voisin
208
210 const Face face = *i_item;
211 if (!face.isSubDomainBoundary()){
212 int id1 = face.backCell().owner();
213 int id2 = face.frontCell().owner();
214
215 if (id1 != id2){ // cas du voisinage avec un autre domaine
216 int idv = -1; // numéro du voisin
217 if (id1==me)
218 idv = id2;
219 else if (id2==me)
220 idv = id1;
221 else
222 continue;
223 // info() << "idv = "<<idv<< " pour la face " <<face.uniqueId();
224
225 // on ajoute l'indice de la face pour un sous-domaine
227 v_face.add(face);
228
229 } // end if (id1 != id2)
230 } // end if (!face.isBoundary())
231 } // end ENUMERATE_FACE
232
233 UniqueArray<int> filtreNoeuds(mesh->nodeFamily()->maxLocalId());
234 filtreNoeuds.fill(0); // initialisation du filtre
235 int marque = 0;
236
237 // pour chacun des sous-domaines voisins, on recherche les noeuds dans l'interface
238 // en évitant les doublons à l'aide du filtre sur le noeuds
239
240 Domaine->NbIntf = arcaneCheckArraySize(vois_faces.size());
241
242 // les mailles sur ce proc (sans les mailles fantomes)
243 Domaine->NbElements = mesh->ownCells().size();
244
245 // calcul du poids total d'un domaine => utilisation m_poids_aux_mailles
246 Domaine->PoidsDom = 0.0;
247 CellGroup own_cells = mesh->ownCells();
249 Cell cell = *iitem;
250 Domaine->PoidsDom += m_poids_aux_mailles[cell];
251 }
252
253#ifdef ARCANE_DEBUG
254 info() << "Domaine->NbIntf = "<<Domaine->NbIntf;
255 info() << "Domaine->NbElements = "<<Domaine->NbElements;
256 info() << "Domaine->PoidsDom = "<<Domaine->PoidsDom;
257#endif
258
259 Domaine->Intf = new StructureInterface[Domaine->NbIntf];
260 unsigned int ind = 0;
261 for (std::map<int, SharedArray<Face> >::iterator iter_vois = vois_faces.begin();
262 iter_vois!=vois_faces.end(); ++iter_vois) {
263
264 marque+=1;
265
266 Domaine->Intf[ind].NoDomVois = (*iter_vois).first;
267 Array<Face> &v_face = (*iter_vois).second;
268
269#ifdef ARCANE_DEBUG
270 info() << "Domaine->Intf["<<ind<<"].NoDomVois = "<<Domaine->Intf[ind].NoDomVois;
271 info() << " v_face.size() = "<<v_face.size();
272#endif
273
274 for (int i = 0; i<v_face.size(); i++){
275 const Face& face = v_face[i];
276// info() << " v_face["<<i<<"].uniqueId() = " << face.uniqueId()
277// << ", backCell: "<<face.backCell().owner() <<", frontCell: "<< face.frontCell().owner();
278
279 for( Integer z=0; z<face.nbNode(); ++z ){
280 const Node node = face.node(z);
281 Integer node_local_id = node.localId();
283 Domaine->Intf[ind].ListeNoeuds.add(node);
285 }
286 }
287
288 }// end for iter_face
289#ifdef ARCANE_DEBUG
290 info() << " ListeNoeuds.size() = "<<Domaine->Intf[ind].ListeNoeuds.size();
291#endif
292
293 ind+=1;
294 } // end for iter_vois
295
296#ifdef ARCANE_DEBUG
297 info() << "MAJDomaine => ";
298 AfficheDomaine(1,Domaine);
299 info() <<" ----------------------------------------";
300#endif
301}
302/*---------------------------------------------------------------------------*/
303/*---------------------------------------------------------------------------*/
304void SplitSDMeshPartitioner::
306{
307 // prérequis: avoir fait un MAJDomaine avant de venir ici
308
309#ifdef ARCANE_DEBUG
310 info() << "SplitSDMeshPartitioner::MAJMaillageMaitre(...)";
311 LibereMaillage(Maillage);
312#endif
313
314 void* TabTMP; /* tableau pour les communications Domaine => Maillage->ListeDomaines[*] */
315 int TailleTab; /* taille du tableau TabTMP (en octets) */
316 int iDom; /* indice de boucle sur les domaines */
317
318 /* on concentre l'information dans TabTMP */
319 TailleTab = TailleDom(Domaine);
320 TabTMP = malloc ((size_t) TailleTab);
321
322 PackDom(InfoProc, Domaine, TabTMP, TailleTab, InfoProc->Split_Comm);
323
324
325 /* on fait les envois vers le maitre, pour tous les domaines
326 (sauf le maitre qui fait juste une copie) */
327 if (InfoProc->me == 0){
328#ifdef DEBUG
329 info()<<" ***************************";
330 info()<<" * Avant MAJMaillageMaitre *";
331 AfficheMaillage (Maillage);
332 info()<<" ***************************";
333#endif
334
335 if (Maillage->ListeDomaines == NULL){
336 Maillage->ListeDomaines = new StrucListeDomMail[InfoProc->nbSubDomain];
337 for (iDom=0; iDom<InfoProc->nbSubDomain; iDom++){
338 Maillage->ListeDomaines[iDom].NbElements = 0;
339 Maillage->ListeDomaines[iDom].Poids = 0;
340 Maillage->ListeDomaines[iDom].NbVoisins = 0;
341 Maillage->ListeDomaines[iDom].ListeVoisins = NULL;
342 }
343 } /* end if Maillage->ListeDomaines == NULL */
344
345 UnpackDom(TabTMP, TailleTab, InfoProc->Split_Comm, &Maillage->ListeDomaines[0]);
346 }
347 else { /* cas où ce n'est pas le maitre */
348 EnvoieMessage(InfoProc, 0, TAG_MAILLAGEMAITRE, TabTMP, TailleTab);
349 }
350
351 /* libération */
352 free (TabTMP);
353 TabTMP = NULL;
354
355 /* --------- */
356 /* Réception */
357 /* --------- */
358
359 /* le maitre recoit toute les infos des autres noeuds (que lui même) */
360 if (InfoProc->me == 0){
361 Maillage->NbDomainesPleins = 0; /* on va compter le nombre de domaines pleins */
362 Maillage->NbProcsVides = 0; /* on va compter le nombre de domaines vides */
363 Maillage->Poids = 0.0; // poids total
364 Maillage->NbElements = 0; // nombre d'éléments total dans le maillage
365
366 /* on met les numéros les plus petits à la fin pour les utiliser en premier */
367 for (iDom=InfoProc->nbSubDomain-1; iDom>=0; iDom--){
368 if (iDom != 0){
369
370 TailleTab = 0; /* car on ne connait pas encore la taille */
371 TabTMP = RecoitMessage(InfoProc, iDom, TAG_MAILLAGEMAITRE, &TailleTab);
372
373 UnpackDom(TabTMP, TailleTab, InfoProc->Split_Comm, &Maillage->ListeDomaines[iDom]);
374
375 free ((void*) TabTMP); TabTMP = NULL;
376 }
377
378 /* on compte le nombre de domaines pleins et vides */
379 if (Maillage->ListeDomaines[iDom].NbElements != 0)
380 Maillage->NbDomainesPleins += 1;
381 else
382 Maillage->NbProcsVides += 1;
383
384 Maillage->Poids += Maillage->ListeDomaines[iDom].Poids;
385 Maillage->NbElements += Maillage->ListeDomaines[iDom].NbElements;
386 }
387
388#ifdef ARCANE_DEBUG
389 info()<<" ***************************";
390 info()<<" * Apres MAJMaillageMaitre *";
391#ifdef DEBUG
392 AfficheMaillage (Maillage);
393#endif
394 info()<<" ***************************";
395 verifMaillageMaitre(Maillage);
396#endif
397 } /* end if me == maitre */
398
399}
400/*---------------------------------------------------------------------------*/
401/*---------------------------------------------------------------------------*/
402void SplitSDMeshPartitioner::
403verifMaillageMaitre(StrucMaillage* Maillage)
404{
405#ifdef ARCANE_DEBUG
406 info()<<" on entre dans verifMaillageMaitre";
407
408 StrucListeDomMail* ListeDomaines = Maillage->ListeDomaines;
409 int NbDomaines = Maillage->NbDomainesPleins;
410
411 for (int iDom=0; iDom<NbDomaines; iDom++){
412 for (int j=0; j<ListeDomaines[iDom].NbVoisins; j++){
413
414 int NbNoeudsInterface = ListeDomaines[iDom].ListeVoisins[j].NbNoeudsInterface;
415 int iVois = ListeDomaines[iDom].ListeVoisins[j].NoDomVois;
416
417 // recherche si le voisin existe et si le nombre de noeuds est identiques
418 int k;
419 for (k=0; k<ListeDomaines[iVois].NbVoisins && ListeDomaines[iVois].ListeVoisins[k].NoDomVois != iDom; k++)
420 { }
421 if (k==ListeDomaines[iVois].NbVoisins){
422 printf("on ne trouve pas le numéro de voisin \n");
423 printf("pour info: iDom = %d, iVois = %d\n",iDom,iVois);
424 perror() << "verifMaillageMaitre en erreur sur le voisinage !!!";
425 }
426
427 if (ListeDomaines[iVois].ListeVoisins[k].NbNoeudsInterface != NbNoeudsInterface){
428 printf("on ne trouve pas le même nombre de noeuds entre les voisins \n");
429 printf("pour info: iDom = %d, iVois = %d, NbNoeudsInterface %d != %d\n"
430 ,iDom,iVois,NbNoeudsInterface,ListeDomaines[iVois].ListeVoisins[k].NbNoeudsInterface);
431 perror() << "verifMaillageMaitre en erreur sur le nombre de noeuds !!!";
432 }
433 }
434 }
435
436 info()<<" on sort de verifMaillageMaitre";
437#else
438 ARCANE_UNUSED(Maillage);
439#endif
440}
441/*---------------------------------------------------------------------------*/
442/*---------------------------------------------------------------------------*/
443void SplitSDMeshPartitioner::
444MAJDeltaGlobal(StrucInfoProc* InfoProc, StrucMaillage* Maillage, double tolerance)
445{
446 StrucListeDomMail* ListeDomaines = Maillage->ListeDomaines;
447 int NbDomaines = Maillage->NbDomainesPleins;
448
449 int i;
450 int iDomDep; /* indice du domaine trop plein qui sert de départ aux parcours frontaux */
451 double PoidsMoyen;
452
453 int tailleFP;
454 int tailleFS;
455
456 int* FrontPrec; // front de noeuds du graphe (domaines)
457 int* FrontSuiv;
458 int* FrontTMP;
459 /* pour chacun des noeuds du graphe, donne le noeud précédent.
460 Cela va permettre depuis un noeud donné lors du parcours frontal de trouver un cheminement vers le noeuds de départ */
461 int* ListeNoeudsPrec;
462
463 int* FiltreDomaine; /* pour marquer les domaines à marqueDomVu, marqueDomNonVu ou marqueDomVide */
464 int marqueDomVu = 1;
465 int marqueDomNonVu = 0;
466 int marqueDomVide = -1; // normallement, il n'y e a pas
467
468 double* PoidsSave;
469
470#ifdef ARCANE_DEBUG
471 info()<<" ------------------------------------";
472 info()<<" on entre dans MAJDeltaGlobal, tolerance = "<<tolerance;
473 info()<<" ------------------------------------";
474 info()<<" ......... Maillage Initial ...........";
475 AfficheListeDomaines(ListeDomaines,NbDomaines);
476#endif
477
478 if (NbDomaines==0){
479 info()<<" SplitSDMeshPartitioner::MAJDeltaGlobal : NbDomaines nul !";
480 return;
481 }
482 if (Maillage->NbDomainesPleins<=1){
483#ifdef ARCANE_DEBUG
484 info()<<" \n = on sort de MAJDeltaGlobal sans rien faire (NbDomainesPleins = "<<Maillage->NbDomainesPleins;
485 info()<<" ------------------------------------";
486#endif
487 return;
488 }
489
490 FiltreDomaine = (int*) malloc ((size_t) NbDomaines*sizeof(int));
491 CHECK_IF_NOT_NULL(FiltreDomaine);
492
493 /* on met à zero tous les Delta par sécurité */
494 for (i=0; i<NbDomaines; i++)
495 for (int j=0; j<ListeDomaines[i].NbVoisins; j++)
496 ListeDomaines[i].ListeVoisins[j].Delta = 0.0;
497
498 /*
499 on décale le nombre de noeuds de chacun des domaines de manière à avoir
500 une somme totale <= 0
501 */
502
503 for (i=0; i<NbDomaines; i++){
504 if (ListeDomaines[i].NbElements != 0)
506 else
508 }
509
510 PoidsSave = (double*) malloc ((size_t) NbDomaines*sizeof(double));
511 CHECK_IF_NOT_NULL(PoidsSave);
512
513 /* la valeur moyenne */
514 PoidsMoyen = Maillage->Poids/(double)Maillage->NbDomainesMax;
515
516 /* on fait le décalage */
517 for (i=0; i<NbDomaines; i++){
518 /* on met de côté le poids */
519 PoidsSave[i] = ListeDomaines[i].Poids;
520
522 ListeDomaines[i].Poids -= PoidsMoyen;
523 }
524
525#ifdef DEBUG
526 info()<<" Après Poids -= PoidsMoyen";
527 AfficheListeDomaines(ListeDomaines,NbDomaines);
528#endif
529
530 /* initialisation mémoire au plus large */
531 FrontPrec = (int*) malloc ((size_t) (NbDomaines-1)*sizeof(int));
532 CHECK_IF_NOT_NULL(FrontPrec);
533 FrontSuiv = (int*) malloc ((size_t) (NbDomaines-1)*sizeof(int));
534 CHECK_IF_NOT_NULL(FrontSuiv);
535
536 ListeNoeudsPrec = (int*) malloc ((size_t) (NbDomaines)*sizeof(int));
537 CHECK_IF_NOT_NULL(ListeNoeudsPrec);
538
539 for (iDomDep=0; iDomDep<NbDomaines; iDomDep++){
540#ifdef DEBUG
541 info()<<" ListeDomaines[iDomDep = "<<iDomDep<<"].Poids = "<<ListeDomaines[iDomDep].Poids;
542#endif
543
544 /* on ne prend comme départ que les domaines étant au dessus de la moyenne en poids
545 (donc > 0 maintenant) */
546 if (ListeDomaines[iDomDep].Poids > tolerance){
547 /* DANS CE QUI SUIT, UN NOEUD EST UN DOMAINE, IL S'AGIT D'UN NOEUD DU GRAPHE */
548
549 /* on initialise les domaines qui ont été vu précédemment à non vu */
550 for (i=0; i<NbDomaines; i++)
551 if (FiltreDomaine[i] == marqueDomVu)
553
554 /* on marque le noeud actuel comme étant vu */
556
557 /* initialisation du front de départ */
558 tailleFS = 1;
560
561#ifdef DEBUG
562 info()<<" FrontSuiv[0] = "<<iDomDep;
563#endif
564
565 /* initialisation du noeud de départ (pas de noeud précédent) */
567
568 /* boucle tant que le noeud de départ est trop gros (poids>0) */
569 while (ListeDomaines[iDomDep].Poids > tolerance){
570#ifdef DEBUG
571 info()<<" while (ListeDomaines["<<iDomDep<<"].Poids = "<<ListeDomaines[iDomDep].Poids<<" > "<<tolerance;
572#endif
573
574 /* on permute les fronts suivant et précédents */
579 tailleFS = 0; /* le front suivant est désormais vide */
580
581 /* cas où le domaine de départ n'a pas réussi à dispercer son surplus sur
582 les autre domaines, et que l'on a vu tout ce que l'on pouvait */
583 if (tailleFP == 0){
584 fatal()<<" partitionner/MAJDeltaGlobal: on ne trouve plus de domaine alors que l'on n'a pas terminé !!!";
585 }
586
587 /*
588 on progresse d'un front
589 */
590
591 /* boucle sur les noeuds du front précédent */
592 for (int iFP=0; iFP<tailleFP; iFP++){
593 int iDom = FrontPrec[iFP];
594
595 /* boucle sur les voisins du noeud */
596 for (int iVois=0; iVois<ListeDomaines[iDom].NbVoisins; iVois++){
597 int iDomVois = ListeDomaines[iDom].ListeVoisins[iVois].NoDomVois;
599 /* on marque ce noeud */
602#ifdef DEBUG
603 info()<<" FrontSuiv["<<tailleFS<<"] = "<<iDomVois;
604#endif
606 }
607 }
608 } /* end for iFD<tailleFP */
609
610
611 /*
612 on décharge le noeud de base sur les noeuds du front suivant
613 */
614
615 /* boucle sur les noeuds du front suivant */
616 for (int iFS=0; iFS<tailleFS; iFS++){
617 int iDom = FrontSuiv[iFS];
618
619#ifdef DEBUG
620 info()<<" ListeDomaines["<<iDom<<"].Poids = "<<ListeDomaines[iDom].Poids;
621#endif
622
623 /* on ne donne qu'aux noeuds déficitaires */
624 if (ListeDomaines[iDom].Poids < 0.0){
625 /* on ne donne pas plus que ce que l'on a */
626 double don = MIN(-ListeDomaines[iDom].Poids, ListeDomaines[iDomDep].Poids);
627
628 /* cas où il y a un don */
629 if (don > 0.0){
630 int iDomTmp;
631 int iDomTmpPrec;
632
633 ListeDomaines[iDom].Poids += don;
634 ListeDomaines[iDomDep].Poids -= don;
635
636 //fprintf(stdout," don = %f\n",don);
637
638 /* on remonte tout le chemin pour mettre à jour le Delta
639 entre les noeuds iDomTmp et iDomTmpPrec */
640 iDomTmp = iDom;
642 while (iDomTmpPrec != -1){
643 /* on incrémente le Delta de don entre iDomTmpPrec et iDomTmp */
644 MAJDelta(don,iDomTmpPrec,iDomTmp,ListeDomaines);
645 /* de même (au signe pret) pour l'interface réciproque */
646 MAJDelta(-don,iDomTmp,iDomTmpPrec,ListeDomaines);
647
648 /* on remonte d'un cran en arrière sur le chemin */
651
652 } /* end while iDomTmpPrec != -1 */
653
654 }/* end if don != 0 */
655 } /* end if NbNoeuds < 0, pour le domaine du front */
656 } /* end for iFD<tailleFP */
657 // AfficheListeDomaines(ListeDomaines,NbDomaines);
658
659 } /* end while Poids > tolerance */
660 } /* end if Poids > tolerance */
661 } /* end for iDomDep<NbDomaines */
662
663
664 /* on remet les valeurs en place */
665 for (i=0; i<NbDomaines; i++)
666 ListeDomaines[i].Poids = PoidsSave[i];
667
668 free((void*) FrontPrec); FrontPrec = NULL;
669 free((void*) FrontSuiv); FrontSuiv = NULL;
670 free((void*) ListeNoeudsPrec); ListeNoeudsPrec = NULL;
671 free((void*) FiltreDomaine); FiltreDomaine = NULL;
672 free((void*) PoidsSave); PoidsSave = NULL;
673
674#ifdef ARCANE_DEBUG
675 info()<<" ......... Maillage Final ...........";
676 AfficheListeDomaines(ListeDomaines,NbDomaines);
677 info()<<" = on sort de MAJDeltaGlobal =";
678 info()<<" ------------------------------------";
679#endif
680}
681/*---------------------------------------------------------------------------*/
682/*---------------------------------------------------------------------------*/
683void SplitSDMeshPartitioner::
684MAJDelta(double ajout, int iDom, int iVois, StrucListeDomMail* ListeDomaines)
685{
686 int j;
687 for (j=0;
688 j<ListeDomaines[iDom].NbVoisins
689 &&
690 ListeDomaines[iDom].ListeVoisins[j].NoDomVois != iVois;
691 j++)
692 {}
693
694 if (j == ListeDomaines[iDom].NbVoisins)
695 {
696 info()<<"on ne trouve pas le numéro de voisin";
697 info()<<"pour info: ajout = "<<ajout<<", iDom = "<<iDom<<", iVois = "<<iVois;
698 pfatal()<<"Erreur dans Partitionner/MAJDelta, pas de voisin !";
699 }
700
701 /* on fait le décalage */
702 ListeDomaines[iDom].ListeVoisins[j].Delta += ajout;
703}
704
705/*---------------------------------------------------------------------------*/
706/*---------------------------------------------------------------------------*/
707double SplitSDMeshPartitioner::
708CalculDeltaMin(StrucMaillage* Maillage, double deltaMin, int iterEquilibrage, int NbMaxIterEquil)
709{
710 // le but : limiter le deltaMin pour qu'il ne soit pas trop petit les premières fois
711 // dans le cas où les transferts sont importants.
712 // En effet, cela a tendance à morceler les domaines ce qui se répercute par de moins bonnes perf
713 // (plus d'attentes lors des communications)
714
715 debug()<<" on entre dans SplitSDMeshPartitioner::CalculDeltaMin, deltaMin = "<<deltaMin
716 << ", iterEquilibrage = " <<iterEquilibrage
717 << ", NbMaxIterEquil = " <<NbMaxIterEquil;
718 if (arcaneIsDebug())
719 AfficheMaillage (Maillage);
720
721 double deltaAjuste = deltaMin;
722
723 // recherche du plus grand Delta sur les interfaces
724 double deltaMaxItf = 0.0;
725 // idem pour la somme des deltas par domaine, ramené au poid du domaine (donc un ratio)
726 double ratioDeltaMax = 0.0;
727
728 StrucListeDomMail* ListeDomaines = Maillage->ListeDomaines;
729 int NbDomaines = Maillage->NbDomainesPleins;
730
731 for (int iDom=0; iDom<NbDomaines; iDom++){
732 double deltaTotalDom = 0.0;
733 for (int j=0; j<ListeDomaines[iDom].NbVoisins; j++){
734 double delta = ListeDomaines[iDom].ListeVoisins[j].Delta;
736 if (delta > 0.0) deltaTotalDom += delta;
737 }
738 double ratio = 0.0;
739 if (ListeDomaines[iDom].Poids>0.0)
740 ratio = deltaTotalDom/ ListeDomaines[iDom].Poids;
742 }
743
744 double poidsMoy = Maillage->Poids/(double)Maillage->NbDomainesMax;
745
746 // heuristique pour limiter deltaAjuste
747 if (ratioDeltaMax>0.9)
748 deltaAjuste = poidsMoy/3.0;
749 else if (ratioDeltaMax>0.5)
751
752 // pour ne pas avoir plus petit que le min qui semble raisonnable et qui est paramétré par le cas .plt
754
755#if defined(ARCANE_DEBUG) || defined(DEBUG_PARTITIONER)
756 // que représente ce delta / poids moy ? tout ou une faible proportion ?
758
759 info()<<" deltaMaxItf = "<<deltaMaxItf;
760 info()<<" ratioDeltaMax = "<<ratioDeltaMax;
761 info()<<" poidsMoy = "<<poidsMoy;
762 info()<<" proportion = "<<proportion;
763 info()<<" deltaAjuste = "<<deltaAjuste;
764#endif
765
766 return deltaAjuste;
767}
768/*---------------------------------------------------------------------------*/
769/*---------------------------------------------------------------------------*/
770void SplitSDMeshPartitioner::
772{
773 int iDom; // indice pour les boucles
774 int indDomCharge = -1; // le domaine dont on va extraire des éléments
775 int indDomVois = -1; // le domaine qui va recevoir depuis indDomCharge
776
777 double deltaMin; // on ne fera le transfert que pour un poids minimum.
778 // desequilibre-maximal (0.01) dans fichier .plt => maxImbalance()
779 deltaMin = Maillage->Poids/(double)Maillage->NbDomainesMax*maxImbalance()/6.0; // on prend comme valeur maxImbalance/6 de la moyenne (donc 0.1 par défaut)
780
781 double poidsMax = 0; // pour la recherche du domaine le plus chargé
782
783 void* TabTMP; /* pour transférer les infos sur les procs choisis et le Delta du maître vers les autres procs */
784
785 int NbAppelsAEquil2Dom = -1;
786
787 int iterEquilibrage = 0;
788 int NbMaxIterEquil = 5; // phase d'équilibrage global. TODO voir s'il faut faire évoluer cette valeur (la paramétrer)
789
790 double tolConnexite = 0.1; // un sous-domaine non connexe plus petit de tolConnexite*taille_moyenne, sera transféré
791
792
793#ifdef ARCANE_DEBUG
794 info()<<" -------------------------------------";
795 info()<<" on entre dans SplitSDMeshPartitioner::Equilibrage, deltaMin = "<<deltaMin;
796#endif
797
798 int TailleTMP = TailleEquil();
799 TabTMP = malloc((size_t)TailleTMP);
800 CHECK_IF_NOT_NULL(TabTMP);
801
802 /* on se limite à NbMaxIter itérations */
804 int* FiltreDomaine;
805 int marqueDomVu = 1;
806 int marqueDomNonVu = 0;
807
810 poidsMax = 0;
811 indDomCharge = -1;
812
813
814 int* MasqueDesNoeuds = GetMasqueDesNoeuds(InfoProc);
815 int* MasqueDesElements = GetMasqueDesElements(InfoProc);
816 int marqueVu = 0;
817 int marqueNonVu = 0;
818
819 IPrimaryMesh* mesh = this->mesh()->toPrimaryMesh();
820
821 /* sur le maître */
822 if (InfoProc->me == 0){
823 info()<<" SplitSDMeshPartitioner::Equilibrage de la charge (iteration No "<<iterEquilibrage<<")";
824
825 /* MAJ des Delta sur les interfaces de la description des domaines sur le maître */
826 MAJDeltaGlobal(InfoProc, Maillage, deltaMin); // ex GetDeltaNoeuds
827
828 // calcul un deltaMin en fonction des transferts locaux
829 double deltaAjuste = CalculDeltaMin(Maillage, deltaMin, iterEquilibrage, NbMaxIterEquil);
830
831 /* on va marquer les domaines vu (ou vide) */
832 FiltreDomaine = (int*) calloc ((size_t) Maillage->NbDomainesMax, sizeof(int));
833 CHECK_IF_NOT_NULL(FiltreDomaine);
834
835 // pour les domaines vides
836 for (iDom=0; iDom<Maillage->NbDomainesMax; iDom++)
837 if (Maillage->ListeDomaines[iDom].NbElements == 0)
839
840 // boucle tant que l'on trouve un domaine sur lequel faire un transfert
841 do {
842
843 /* on recherche le plus chargé des domaines restant */
844 indDomCharge = -1;
845 poidsMax = 0;
846
847 for (iDom=0; iDom<Maillage->NbDomainesMax; iDom++)
848 if (FiltreDomaine[iDom] == marqueDomNonVu && Maillage->ListeDomaines[iDom].Poids > poidsMax){
849 poidsMax = Maillage->ListeDomaines[iDom].Poids;
851 }
852
853#ifdef ARCANE_DEBUG
854 info()<<"indDomCharge = "<<indDomCharge<<"; poidsMax = "<<poidsMax;
855#endif
856
857 if (indDomCharge != -1) {
858 /* on ne veut plus le retrouver */
860
861 /* on choisi 2 domaines pour effectuer le déplacement de l'interface entre les 2 */
862
863 /* pour ce domaine chargé, on regarde vers quel autre domaine il pourrait
864 y avoir transfert de noeuds */
865 for (int i=0; i<Maillage->ListeDomaines[indDomCharge].NbVoisins; i++){
866 indDomVois = Maillage->ListeDomaines[indDomCharge].ListeVoisins[i].NoDomVois;
867
868
869 /* on se limite aux transferts dont le DeltaNoeuds>deltaNoeudsMin */
870 if (Maillage->ListeDomaines[indDomCharge].ListeVoisins[i].Delta > deltaAjuste){
871#if defined(ARCANE_DEBUG) || defined(DEBUG_PARTITIONER)
872 info()<<" Equilibrage ("<<iterEquilibrage<<") pour le couple indDomCharge = "<<indDomCharge<<"; indDomVois = "<<indDomVois
873 <<"; Delta = "<<Maillage->ListeDomaines[indDomCharge].ListeVoisins[i].Delta;
874#endif
875
876 /* on diffuse l'information à tous les processeurs */
877 PackEquil(InfoProc, indDomCharge, indDomVois, Maillage->ListeDomaines[indDomCharge].ListeVoisins[i].Delta,
878 TabTMP, TailleTMP, InfoProc->Split_Comm);
879
880 TabTMP = DiffuseMessage(InfoProc, 0, TabTMP, TailleTMP);
881
882 // change la marque pour chaque appel (ce qui permet de libérer les noeuds)
883 marqueVu+=1;
884
885 // équilibrage entre 2 domaines
888 Maillage->ListeDomaines[indDomCharge].ListeVoisins[i].Delta);
890
891 } /* end if Delta > deltaAjuste */
892 } /* end for i<NbVoisins */
893
894 }// end if indDomCharge != -1
895 } while (indDomCharge != -1);
896
897 indDomVois = -1; /* pour informer que l'on arete, indDomCharge == -1 et indDomVois == -1 */
898 double DeltaNul = 0.0;
899 PackEquil(InfoProc, indDomCharge, indDomVois, DeltaNul, TabTMP, TailleTMP, InfoProc->Split_Comm);
900
901 TabTMP = DiffuseMessage(InfoProc, 0, TabTMP, TailleTMP);
902
903 free((void*) FiltreDomaine);
905
906
907#ifdef ARCANE_DEBUG
908 info()<<" NbAppelsAEquil2Dom = "<<NbAppelsAEquil2Dom;
909#endif
910
911 } /* end if me == 0 */
912 else {
913 double Delta;
914
915 do {
916 TabTMP = DiffuseMessage(InfoProc, 0, TabTMP, TailleTMP);
917 UnpackEquil(TabTMP, TailleTMP, InfoProc->Split_Comm, &indDomCharge, &indDomVois, &Delta);
918
919 if (indDomCharge != -1){
920 // change la marque pour chaque appel
921 marqueVu+=1;
922
923 // équilibrage entre 2 domaines
927 }
928
929 } while(indDomCharge != -1);
930
931 } /* end else if me == 0 */
932
933 // synchro dans le cas où il y a eu des modifs
935 // libération des noeuds dans les interfaces
936 LibereDomaine(Domaine);
937
938#ifdef ARCANE_DEBUG
939 info() << "cells_new_owner.synchronize() et changeOwnersFromCells()";
940#endif
941 // on ne fait la synchro que pour une unique série d'appels à Equil2Dom
943 cells_new_owner.synchronize();
944 changeOwnersFromCells();
945 // effectue le transfert effectif des données d'un proc à l'autre, sans compactage des données
946 bool compact = mesh->properties()->getBool("compact");
947 mesh->properties()->setBool("compact", false);
948 mesh->exchangeItems();
949 mesh->properties()->setBool("compact", compact);
950
951 // MAJ du Domaine
952 MAJDomaine(Domaine);
953
954 /* on remet à jour la structure Maillage->ListeDomaines */
955 MAJMaillageMaitre(InfoProc,Domaine,Maillage);
956 } // end if NbAppelsAEquil2Dom
957
958 free((void*)MasqueDesNoeuds);
960 free((void*)MasqueDesElements);
962
963 AfficheEquilMaillage(Maillage);
964
965 // Rend les domaines connexes autant que possible suivant une tolérance
966 // (on accepte des partie non connexes à condition que leur taille soit > tol*taille_moyenne)
967 marqueVu+=1;
968 ConnexifieDomaine(InfoProc, Domaine, Maillage, tolConnexite);
969
970 AfficheEquilMaillage(Maillage);
971
972 } /* end while (iterEquilibrage<NbMaxIterEquil && NbAppelsAEquil2Dom!=0) */
973
974 free(TabTMP);
975 TabTMP = nullptr;
976
977 debug()<<" nombre d'iterations pour equilibrage = "<<iterEquilibrage<<" / "<<NbMaxIterEquil<<" max ";
978 debug()<<" = on sort de SplitSDMeshPartitioner::Equilibrage";
979 debug()<<" -------------------------------------";
980}
981
982/*---------------------------------------------------------------------------*/
983/*---------------------------------------------------------------------------*/
984
985void SplitSDMeshPartitioner::
986Equil2Dom(int* MasqueDesNoeuds, int* MasqueDesElements, int marqueVu, int marqueNonVu,
988 int indDomCharge, int indDomVois, double Delta)
989{
990 ARCANE_UNUSED(Maillage);
991
992 debug()<<" on entre dans Equil2Dom (indDomCharge:"<<indDomCharge<<", indDomVois:"<<indDomVois<<", Delta:"<<Delta;
993
994 // tableau des éléments sélectionnés pour être déplacé
996
997 if (InfoProc->me == indDomCharge){
998 int iIntf = 0;
999 /* l'interface entre les deux domaines existe-t-elle encore ? */
1000 for (iIntf=0;
1001 iIntf<Domaine->NbIntf
1002 && Domaine->Intf[iIntf].NoDomVois != indDomVois;
1003 iIntf++)
1004 { }
1005
1006 if (iIntf==Domaine->NbIntf){
1007#if defined(ARCANE_DEBUG) || defined(DEBUG_PARTITIONER)
1008 pinfo()<<"### l'interface a disparu ### entre "<<indDomCharge<< " et " <<indDomVois;
1009#endif
1010 }
1011 else {
1012 // sélection des éléments par un parcour frontal depuis l'interface entre les 2 sous-domaines.
1013 SelectElements(MasqueDesNoeuds, MasqueDesElements,
1016
1017 }
1018
1019 // marquage pour déplacement des données arcane
1020 IPrimaryMesh* mesh = this->mesh()->toPrimaryMesh();
1022
1023 for (int i=0; i<ListeElements.size(); i++){
1024 const Cell item = ListeElements[i];
1026 }
1027
1028 } // end if me == indDomCharge
1029#ifdef ARCANE_DEBUG
1030 else {
1031 info() << "SelectElements et autres operations sur les processeurs "<<indDomCharge<<" et " <<indDomVois;
1032 }
1033
1034 info()<<" on sort de Equil2Dom";
1035#endif
1036}
1037/*---------------------------------------------------------------------------*/
1038/*---------------------------------------------------------------------------*/
1039void SplitSDMeshPartitioner::
1040SelectElements(int* MasqueDesNoeuds, int* MasqueDesElements, int marqueVu, int marqueNonVu,
1043{
1044#ifdef ARCANE_DEBUG
1045 info()<<"SplitSDMeshPartitioner::SelectElements(Domaine, Delta = "<<Delta<<", indDomVois = "<<indDomVois<<")";
1046 info()<<" Domaine->NbElements = " << Domaine->NbElements;
1047 info()<<" Domaine->PoidsDom = " << Domaine->PoidsDom;
1048#endif
1049
1050 if (Delta <= 0.0){
1051 perror() << "Delta <= 0 !!!";
1052 }
1053
1054 IMesh* mesh = this->mesh();
1055
1056 if (Delta>=Domaine->PoidsDom){
1057#ifdef ARCANE_DEBUG
1058 pinfo()<<" Tout le domaine est sélectionné sur le domaine "<<subDomain()->subDomainId()
1059 <<", avec SelectElements, PoidsDom = " << Domaine->PoidsDom
1060 <<", Delta = "<<Delta;
1061#endif
1062 // cas où tout le domaine est demandé
1063 // ce proceseur va se retrouver vide ! à moins qu'il n'y ait un transfert depuis un autre proc qui compense la perte
1064 CellGroup own_cells = mesh->ownCells();
1066 const Cell item = *i_item;
1067 //MasqueDesElements[item.localId()] = marqueVu;
1068 ListeElements.add(item);
1069 }
1070 } else {
1071 // cas où il faut sélectionner un sous-ensemble
1072
1073 int iIntf; /* indice de l'interface pour le voisin indDomVois */
1074 int NbFrontsMax;
1075 int NbFronts;
1076 int* IndFrontsNoeuds;
1077 int* IndFrontsElements;
1078
1079 for (iIntf=0; iIntf<Domaine->NbIntf && Domaine->Intf[iIntf].NoDomVois != indDomVois; iIntf++)
1080 { }
1081
1082 if (iIntf==Domaine->NbIntf) {
1083 pfatal()<<" SelectElements ne trouve pas l'interface parmis les voisins !!!";
1084 }
1085
1086 NbFrontsMax = Domaine->NbElements / 2;
1087
1088 /* les noeuds pris dans les fronts */
1090
1091 /* les éléments pris dans les fronts */
1093
1094 IndFrontsNoeuds = (int*) malloc ((size_t) (NbFrontsMax+1)*sizeof(int));
1095 CHECK_IF_NOT_NULL(IndFrontsNoeuds);
1096
1097 IndFrontsElements = (int*) malloc ((size_t) (NbFrontsMax+1)*sizeof(int));
1098 CHECK_IF_NOT_NULL(IndFrontsElements);
1099
1100 /* front de départ pour le parcours */
1101 NbFronts = 1;
1102
1103 /* on met comme front de départ la liste des noeuds dans l'interface */
1104 for (int i=0; i<Domaine->Intf[iIntf].ListeNoeuds.size(); i++)
1105 FrontsNoeuds.add(Domaine->Intf[iIntf].ListeNoeuds[i]);
1106
1107 IndFrontsNoeuds[0] = 0;
1108 IndFrontsNoeuds[1] = Domaine->Intf[iIntf].ListeNoeuds.size();
1109 IndFrontsElements[0] = 0;
1110 IndFrontsElements[1] = 0;
1111
1112 // on marque les mailles fantomes comme étant déjà vues
1113 int me = subDomain()->subDomainId();
1114 CellGroup all_cells = mesh->allCells(); // éléments sur ce processeur (mailles fantomes comprises)
1116 const Cell cell = *i_item;
1117 if (cell.owner() != me)
1119 }
1120
1121 // on marque les éléments déjà sélectionné
1122 for (int i=0; i<ListeElements.size(); i++){
1123 const Cell cell = ListeElements[i];
1125 }
1126
1127
1128 int retPF;
1129 // Parcour Frontal pour un poids Delta demandé
1130 retPF = ParcoursFrontalDelta (MasqueDesNoeuds, MasqueDesElements,
1132 Delta,
1136
1137 /* le dernier front est un front incomplet, on le concatène à l'avant dernier pour le lissage */
1138 if (NbFronts>1){
1141 NbFronts-=1;
1142 }
1143
1144 /* on fait le lissage du front dans le cas où l'on n'a pas sélectionné tout le domaine
1145 et que le ParcoursFrontal s'est bien déroulé (n'est pas bloqué) */
1146 if (FrontsNoeuds.size() < Domaine->NbElements && retPF == 0)
1147 LissageDuFront(MasqueDesNoeuds, MasqueDesElements,
1149 NbFronts,
1152
1153
1154 free((void*)IndFrontsNoeuds); IndFrontsNoeuds = NULL;
1156 }
1157
1158 info()<<" en sortie: ListeElements.size() = "<<ListeElements.size();
1159}
1160/*---------------------------------------------------------------------------*/
1161/*---------------------------------------------------------------------------*/
1162int SplitSDMeshPartitioner::
1163ParcoursFrontalDelta (int* MasqueDesNoeuds, int* MasqueDesElements,
1164 int marqueVu, int marqueNonVu,
1165 double Delta,
1166 int *pNbFronts, int NbFrontsMax,
1169{
1170#ifdef ARCANE_DEBUG
1171 info()<<" = on entre dans ParcoursFront : (NbFronts = "<<*pNbFronts<<", NbFrontsMax = "<<NbFrontsMax<<")";
1172 info()<<" FrontsNoeuds.size() = "<<FrontsNoeuds.size();
1173 info()<<" FrontsElements.size() = "<<FrontsElements.size();
1174#endif
1175
1176 int IndFn = 0; /* indices sur les tableaux [Ind]FrontsNoeuds */
1177 int IndFe = 0; /* indices sur les tableaux [Ind]FrontsElements */
1178 double PoidsActuel = 0.0;
1179 bool bloque = false;
1180
1181 /* on marque les noeuds et les éléments déjà dans les fronts (pour ne pas les avoir deux fois) */
1184 }
1185
1188 }
1189
1190 /* on met dans le front initial les noeuds liés aux éléments de ce même front
1191 si cela n'a pas été fait */
1193 //info()<<" Initialisation à partir de "<<IndFrontsElements[*pNbFronts]<<" éléments";
1194 for (int ielm=0; ielm<IndFrontsElements[*pNbFronts]; ielm++){
1195 const Cell cell = FrontsElements[ielm];
1196 PoidsActuel += m_poids_aux_mailles[cell];
1197
1198 for (int iepn = 0; iepn < cell.nbNode(); iepn++){
1199 const Node nodeVois = cell.node(iepn); // noeud voisin // int NoeudVoisin
1200
1201 /* pour chaques nouveau noeud, on l'insère dans le nouveau front*/
1202 if (MasqueDesNoeuds[nodeVois.localId()] == marqueNonVu){
1204 IndFn+=1;
1205 MasqueDesNoeuds[nodeVois.localId()] = marqueVu;
1206 }
1207 } /* end for iepn */
1208 }
1209 /* on met les noeuds dans le dernier front existant */
1211 }
1212
1213 /*----------------------------------------------------------------*/
1214 /* boucle jusqu'à ce que l'on ait vu assez de noeuds ou de fronts */
1215 /*----------------------------------------------------------------*/
1216 do {
1217 /* pour chaques noeuds du front précédent, on regarde les éléments qu'il possède */
1218 for (int in = IndFrontsNoeuds[*pNbFronts-1];
1220 in++) {
1221 const Node node = FrontsNoeuds[in]; // noeud du front précédent // int Noeud
1222
1223 /* on évite de s'arrêter sans avoir tous les éléments liés,
1224 on risquerait d'avoir un élément relié par un seul noeud ! */
1225 for (int inpe = 0; inpe < node.nbCell(); inpe++){
1226 const Cell cell = node.cell(inpe); //élément lié à ce noeud //int Element
1227
1228 /* pour ce nouvel élément, on l'insère dans le nouveau front
1229 et on regarde les noeuds qu'il possède */
1230 if (MasqueDesElements[cell.localId()] == marqueNonVu) {
1231 FrontsElements.add(cell);
1232 IndFe+=1;
1234
1235 PoidsActuel += m_poids_aux_mailles[cell];
1236
1237 for (int iepn = 0; iepn < cell.nbNode(); iepn++){
1238 const Node nodeVois = cell.node(iepn); // noeud voisin // int NoeudVoisin
1239
1240 /* pour chaques nouveau noeud, on l'insère dans le nouveau front*/
1241 if (MasqueDesNoeuds[nodeVois.localId()] == marqueNonVu){
1243 IndFn+=1;
1244 MasqueDesNoeuds[nodeVois.localId()] = marqueVu;
1245 } /* end if MasqueDesNoeuds == marqueNonVu */
1246 } /* end for iepn */
1247 } /* end if MasqueDesElements == marqueNonVu */
1248 } /* end for inpe */
1249 } /* end for in */
1250
1251 /* test du cas où cela se bloquerait */
1253 bloque = true;
1254 }
1255
1256 *pNbFronts += 1;
1259
1260 }
1261 while (*pNbFronts<NbFrontsMax && PoidsActuel<Delta && !bloque);
1262
1263
1264#ifdef ARCANE_DEBUG
1265 info()<<" NbFronts = "<<*pNbFronts;
1266 info()<<" Delta = "<<Delta;
1267 info()<<" PoidsActuel = "<<PoidsActuel;
1268 info()<<" NbNoeuds = "<<IndFrontsNoeuds[*pNbFronts];
1269 info()<<" NbElements = "<<IndFrontsElements[*pNbFronts];
1270 info()<<" bloque = "<<(bloque?"VRAI":"FAUX");
1271
1272 if (!(*pNbFronts<NbFrontsMax)){
1273 info()<<" = on arete apres avoir obtenu le nombre maximum de fronts "<<NbFrontsMax;
1274 }
1275 else if (!(PoidsActuel<Delta)){
1276 info()<<" = on arete apres avoir obtenu le poids desire "<<PoidsActuel;
1277 }
1278 else if (bloque){
1279 info()<<" = on est bloque (non connexe ?) =";
1280 }
1281 else{
1282 info()<<" = on arete parce que l'on a tout vu =";
1283 }
1284 info()<<" = on sort de ParcoursFront . =";
1285#endif
1286
1287 return ((bloque)?1:0);
1288}
1289/*---------------------------------------------------------------------------*/
1290/*---------------------------------------------------------------------------*/
1291
1292void SplitSDMeshPartitioner::
1293LissageDuFront (int* MasqueDesNoeuds, int* MasqueDesElements,
1294 int marqueVu, int marqueNonVu,
1295 int NbFronts,
1298{
1299 ARCANE_UNUSED(IndFrontsElements);
1300
1301 debug()<<" on entre dans LissageDuFront : NbFronts = "<<NbFronts;
1302
1303 int NbElementsAjoutes = 0;
1304
1306
1307 /* Récupération des éléments pris dans le dernier front de noeuds */
1309 const Node node = FrontsNoeuds[IndFn]; // noeud du front précédent // int Noeud
1310
1311 for (int inpe = 0; inpe < node.nbCell(); inpe++){
1312 const Cell cell = node.cell(inpe); //élément lié à ce noeud //int Element
1313
1314 /* si cet élément est non-vu */
1315 if (MasqueDesElements[cell.localId()] == marqueNonVu){
1316 /* on cherche si tous les noeuds de cet élément sont marqués vu */
1317 int iepn;
1318 for (iepn = 0; iepn < cell.nbNode() && MasqueDesNoeuds[cell.node(iepn).localId()] == marqueVu; iepn++)
1319 { }
1320 /* cas où tous les noeuds sont marqués */
1321 if (iepn == cell.nbNode()){
1322 /* on ajoute l'élément au dernier front */
1323
1324 FrontsElements.add(cell);
1327 }
1328 else {
1329 /* on marque l'élement */
1330 MasqueDesElements[cell.localId()] = marqueVu; // pour ne pas le reprendre tout de suite
1331 ElementsALiberer.add(cell);
1332 }
1333
1334 } /* end if Element non vu */
1335 } /* end for inpe ... */
1336 } /* end for IndFn ... */
1337
1338 // on remet à marqueNonVu ceux que l'on a marqué juste pour ne les voir qu'une fois
1339 for (int i=0; i<ElementsALiberer.size(); i++)
1341
1342#ifdef ARCANE_DEBUG
1343 info()<<" on sort de LissageDuFront ("<<NbElementsAjoutes<<" elements ajoutes)";
1344#endif
1345}
1346/*---------------------------------------------------------------------------*/
1347/*---------------------------------------------------------------------------*/
1348void SplitSDMeshPartitioner::
1350 double tolConnexite)
1351{
1352#ifdef ARCANE_DEBUG
1353 info()<<" on entre dans ConnexifieDomaine, tolConnexite = "<<tolConnexite;
1354#endif
1355
1356 int* MasqueDesNoeuds = GetMasqueDesNoeuds(InfoProc);
1357 int* MasqueDesElements = GetMasqueDesElements(InfoProc);
1358 int marqueVu = 1;
1359 int marqueNonVu = 0;
1360
1361 // Maillage->NbElements n'est connu que sur le maitre !
1362// double tailleMoy = (double)Maillage->NbElements / (double)Maillage->NbDomainesMax;
1363 double tailleMoy = (double)Domaine->NbElements;
1364
1365 // on marque les mailles fantomes comme étant déjà vues
1366 int me = InfoProc->me;
1367 IPrimaryMesh* mesh = this->mesh()->toPrimaryMesh();
1368 CellGroup all_cells = mesh->allCells(); // éléments sur ce processeur (mailles fantomes comprises)
1369
1371 Cell cell = *i_item;
1372 if (cell.owner() != me)
1374 } // end ENUMERATE_CELL
1375
1376 int NbElementsVus = 0;
1377 int NbElementsAVoir = Domaine->NbElements;
1378#ifdef ARCANE_DEBUG
1379 info()<<" NbElementsAVoir = "<<NbElementsAVoir;
1380#endif
1381
1382 int NbFrontsMax;
1383 int NbFronts;
1384 int* IndFrontsNoeuds;
1385 int* IndFrontsElements;
1386
1387 NbFrontsMax = Domaine->NbElements / 2;
1388
1389 /* les noeuds pris dans les fronts */
1391
1392 /* les éléments pris dans les fronts */
1394
1395 IndFrontsNoeuds = (int*) malloc ((size_t) (NbFrontsMax+1)*sizeof(int));
1396 CHECK_IF_NOT_NULL(IndFrontsNoeuds);
1397
1398 IndFrontsElements = (int*) malloc ((size_t) (NbFrontsMax+1)*sizeof(int));
1399 CHECK_IF_NOT_NULL(IndFrontsElements);
1400
1401
1402 /* on boucle de manière à voir tous les éléments du domaine */
1404
1405 FrontsNoeuds.clear();
1407
1408 /* recherche d'un éléments non vu (il est mis dans le premier front) */
1409 //TODO à optimiser ?
1410 bool trouve = false;
1412 const Cell cell = *i_item;
1413 if (!trouve && MasqueDesElements[cell.localId()] == marqueNonVu){
1414 FrontsElements.add(cell);
1415 trouve = true;
1416 }
1417 }
1418 if (!trouve){
1419 pfatal()<<"ConnexifieDomaine est bloqué lors de la recherche d'un élément de départ";
1420 }
1421
1422 NbFronts = 1;
1423 IndFrontsNoeuds[0] = 0;
1424 IndFrontsNoeuds[1] = 0;
1425 IndFrontsElements[0] = 0;
1426 IndFrontsElements[1] = 1;
1427
1428 /* recherche de l'ensemble connexe d'éléments non vus associé */
1429 ParcoursFrontalDelta (MasqueDesNoeuds, MasqueDesElements,
1431 Domaine->PoidsDom,
1435
1436 /* on met de côté cet ensemble d'éléments */
1438
1440#ifdef ARCANE_DEBUG
1441 info()<<" NbElementsVus+="<<FrontsElements.size();
1442#endif
1443
1444 } /* end while (NbElementsVus < NbElementsAVoir) */
1445
1446 // nombre de composantes transférées
1447 int nbCCTransf = 0;
1448
1449 /* s'il y a plus d'une composante connexe */
1450 if (ListeFrontsElements.size() > 1){
1451
1452#ifdef ARCANE_DEBUG
1453 info()<<" NbComposantesConnexes = "<<ListeFrontsElements.size();
1454#endif
1455
1456 // analyse du nombre de domaines en dessous du seuil
1457 int nbDomEnDessous = 0;
1458 int plusGrosseCC = 0; // plus grosse composante connexe
1459
1461#ifdef ARCANE_DEBUG
1462 info()<< " seuil = "<<seuil;
1463#endif
1464
1465 for (int i=0; i<ListeFrontsElements.size(); i++){
1468 if (FrontsElements.size()<seuil)
1469 nbDomEnDessous+=1;
1470 }
1471
1472#ifdef ARCANE_DEBUG
1473 info()<< " nbDomEnDessous = "<<nbDomEnDessous;
1474#endif
1475
1476 // pour éviter de prendre toutes les composantes
1477 if (nbDomEnDessous == ListeFrontsElements.size()){
1478#ifdef ARCANE_DEBUG
1479 info() <<" seuil abaissé à "<< plusGrosseCC;
1480#endif
1482 }
1483
1484 // pour chacune des composante de taille < seuil, on fait le transfert vers un voisin
1486 for (int i=0; i<ListeFrontsElements.size(); i++){
1488 if (FrontsElements.size()<seuil){
1489 nbCCTransf += 1;
1490
1491 // recherche du sous-domaine voisin ayant un max de face en commun
1492 int indDomVois = getDomVoisMaxFace(FrontsElements, me);
1493
1494 // on affecte les cellules à ce voisin
1495 for (int j=0; j<FrontsElements.size(); j++){
1496 const Cell item = FrontsElements[j];
1498 }
1499
1500 } // if FrontsElements.size()<seuil
1501 } // end for i<ListeFrontsElements.size()
1502#ifdef ARCANE_DEBUG
1503 info() << " Nombre de composantes transférées : "<<nbCCTransf;
1504#endif
1505
1506 } // end if ListeFrontsElements.size() > 1
1507
1508 /* libérations mémoire */
1509 free((void*) IndFrontsNoeuds);
1511 free((void*) IndFrontsElements);
1513
1514 free((void*)MasqueDesNoeuds);
1516 free((void*)MasqueDesElements);
1518
1519
1520 // on ne fait la synchro que si l'un des sous-domaines à fait une modif
1521 // faire la somme sur tous les proc de nbCCTransf
1522
1523 int nbCCTransfMin = 0;
1524 int nbCCTransfMax = 0;
1525 int nbCCTransfSum = 0;
1526 Int32 procMin = 0;
1527 Int32 procMax = 0;
1528
1529 ISubDomain* sd = subDomain();
1530 IParallelMng* pm = sd->parallelMng();
1531
1533
1534 bool synchroNecessaire = (nbCCTransfSum > 0);
1535#if defined(ARCANE_DEBUG) || defined(DEBUG_PARTITIONER)
1536 info()<<" ConnexifieDomaine: nbCCTransfSum = "<<nbCCTransfSum;
1537#endif
1538
1539 if (synchroNecessaire){
1540#ifdef ARCANE_DEBUG
1541 info()<<" on fait la synchronisation";
1542#endif
1543 // on ne fait la synchro que pour une unique série d'appels à Equil2Dom
1545 cells_new_owner.synchronize();
1546 changeOwnersFromCells();
1547 // effectue le transfert effectif des données d'un proc à l'autre, sans compactage des données
1548 bool compact = mesh->properties()->getBool("compact");
1549 mesh->properties()->setBool("compact", false);
1550 mesh->exchangeItems();
1551 mesh->properties()->setBool("compact", compact);
1552
1553 // MAJ du Domaine
1554 MAJDomaine(Domaine);
1555
1556 /* on remet à jour la structure Maillage->ListeDomaines */
1557 MAJMaillageMaitre(InfoProc,Domaine,Maillage);
1558 }
1559#ifdef ARCANE_DEBUG
1560 info()<<" on sort de ConnexifieDomaine";
1561#endif
1562}
1563/*---------------------------------------------------------------------------*/
1564/*---------------------------------------------------------------------------*/
1565int SplitSDMeshPartitioner::
1566getDomVoisMaxFace(Arcane::Array<Arcane::Cell>& ListeElements, int me)
1567{
1568 int indDomVois = -1;
1569
1570 // nombre de face par sous-domaine voisin
1571 std::map<int,int> indVois_nbFace;
1572
1573 for (int i=0; i<ListeElements.size(); i++){
1574 const Cell cell = ListeElements[i];
1575
1576 for (int j=0;j<cell.nbFace(); j++){
1577 const Face face = cell.face(j);
1578
1579 if (!face.isSubDomainBoundary()){
1580 int id1 = face.backCell().owner();
1581 int id2 = face.frontCell().owner();
1582
1583 if (id1 == me && id2 != me)
1584 indVois_nbFace[id2]+=1;
1585 else if (id1 != me && id2 == me)
1586 indVois_nbFace[id1]+=1;
1587 }
1588 }
1589 }
1590
1591 // recherche du plus grand nombre de faces
1592 int maxNbFaces = 0;
1593 std::map<int,int>::iterator iter;
1594 for (iter = indVois_nbFace.begin();
1595 iter != indVois_nbFace.end();
1596 ++iter){
1597 int nbFaces = (*iter).second;
1598 if (nbFaces>maxNbFaces){
1600 indDomVois = (*iter).first;
1601 }
1602 }
1603
1604 if (indDomVois == -1)
1605 pfatal()<<"indDomVois toujours à -1 !!!";
1606
1607#ifdef ARCANE_DEBUG
1608 pinfo()<<" getDomVoisMaxFace, me = "<<me<<", ListeElements.size() = "<<ListeElements.size()
1609 <<", indDomVois = "<<indDomVois<<", maxNbFaces = "<<maxNbFaces;
1610#endif
1611 return indDomVois;
1612}
1613/*---------------------------------------------------------------------------*/
1614/*---------------------------------------------------------------------------*/
1615int* SplitSDMeshPartitioner::
1616GetMasqueDesNoeuds(StrucInfoProc* InfoProc)
1617{
1618 int* MasqueDesNoeuds = NULL;
1619
1620 IMesh* mesh = this->mesh();
1621 // recherche des plus grand id
1622 int maxNodeLocalId = 0;
1623
1624 NodeGroup all_nodes = mesh->allNodes();
1626 const Node node = *i_item;
1628 }
1629#ifdef ARCANE_DEBUG
1630 info() << "SplitSDMeshPartitioner::GetMasqueDesNoeuds(), maxNodeLocalId = "<<maxNodeLocalId;
1631#endif
1632
1633 /* allocation et initialisation à 0 du masque */
1634 MasqueDesNoeuds = (int*) calloc ((size_t)(maxNodeLocalId+1), sizeof(int));
1635 CHECK_IF_NOT_NULL(MasqueDesNoeuds);
1636
1637 return MasqueDesNoeuds;
1638}
1639/*---------------------------------------------------------------------------*/
1640/*---------------------------------------------------------------------------*/
1641int* SplitSDMeshPartitioner::
1642GetMasqueDesElements(StrucInfoProc* InfoProc)
1643{
1644 int* MasqueDesElements = NULL;
1645
1646 IMesh* mesh = this->mesh();
1647 // recherche des plus grand id
1648 int maxCellLocalId = 0;
1649
1650 CellGroup all_cells = mesh->allCells(); // éléments sur ce processeur (mailles fantomes comprises)
1652 const Cell cell = *i_item;
1654 }
1655
1656#ifdef ARCANE_DEBUG
1657 info() << "SplitSDMeshPartitioner::GetMasqueDesElements(), maxCellLocalId = "<<maxCellLocalId;
1658#endif
1659
1660 /* allocation et initialisation à 0 du masque */
1661 MasqueDesElements = (int*) calloc ((size_t)(maxCellLocalId+1), sizeof(int));
1662 CHECK_IF_NOT_NULL(MasqueDesElements);
1663
1664 return MasqueDesElements;
1665}
1666/*---------------------------------------------------------------------------*/
1667/*---------------------------------------------------------------------------*/
1668
1669void SplitSDMeshPartitioner::
1670LibereInfoProc(StrucInfoProc* &InfoProc)
1671{
1672 ARCANE_UNUSED(InfoProc);
1673}
1674
1675/*---------------------------------------------------------------------------*/
1676/*---------------------------------------------------------------------------*/
1677
1678void SplitSDMeshPartitioner::
1679LibereDomaine(StructureBlocEtendu* &Domaine)
1680{
1681#ifdef ARCANE_DEBUG
1682 info()<<"LibereDomaine(...)";
1683#endif
1684
1685 if (Domaine->NbIntf != 0){
1686 if (Domaine->Intf != NULL){
1687 for (int i=0; i<Domaine->NbIntf; i++)
1688 Domaine->Intf[i].ListeNoeuds.clear();
1689 delete [] Domaine->Intf;
1690 Domaine->Intf = NULL;
1691 }
1692 }
1693
1694 Domaine->NbIntf = 0;
1695 Domaine->NbElements = 0;
1696 Domaine->PoidsDom = 0.0;
1697}
1698/*---------------------------------------------------------------------------*/
1699/*---------------------------------------------------------------------------*/
1700void SplitSDMeshPartitioner::
1701LibereMaillage(StrucMaillage* &Maillage)
1702{
1703#ifdef ARCANE_DEBUG
1704 info()<<"LibereMaillage(...)";
1705#endif
1706
1707 if (Maillage->NbElements != 0){
1708 if (Maillage->ListeDomaines != NULL){
1709 for (int i=0; i<Maillage->NbDomainesMax; i++){
1710 if (Maillage->ListeDomaines[i].ListeVoisins != NULL){
1711 delete [] Maillage->ListeDomaines[i].ListeVoisins;
1712 Maillage->ListeDomaines[i].ListeVoisins = NULL;
1713 }
1714 }
1715 delete [] Maillage->ListeDomaines;
1716 Maillage->ListeDomaines = NULL;
1717 }
1718 }
1719 Maillage->NbElements = 0;
1720 Maillage->Poids = 0.0;
1721 Maillage->NbDomainesPleins = 0;
1722 Maillage->NbProcsVides = 0;
1723}
1724/*---------------------------------------------------------------------------*/
1725/*---------------------------------------------------------------------------*/
1726void SplitSDMeshPartitioner::
1727AfficheDomaine (int NbDom, StructureBlocEtendu* Domaine)
1728{
1729 int i;
1730 int idom;
1731
1732 for (idom=0; idom<NbDom; idom++) {
1733 info()<<" --------------------";
1734 info()<<" --- Domaine ("<<idom<<") ---";
1735 info()<<" --------------------";
1736
1737 if (Domaine == NULL){
1738 info()<<" Domaine vide ! (pointeur NULL)";
1739 }
1740 else if (Domaine[idom].NbElements == 0) {
1741 info()<<" Domaine vide ! (pas d'éléments)";
1742 }
1743 else {
1744 info()<<" NbElements = "<<Domaine[idom].NbElements;
1745 info()<<" PoidsDom = "<<Domaine[idom].PoidsDom;
1746 info()<<" Interfaces (NbIntf = "<<Domaine[idom].NbIntf<<") :";
1747 for (i=0; i<Domaine[idom].NbIntf; i++) {
1748 info()<<" ("<<i<<") NoDomVois = "<<Domaine[idom].Intf[i].NoDomVois
1749 <<", nb de noeuds "<<Domaine[idom].Intf[i].ListeNoeuds.size();
1750 }
1751
1752 } /* end else if 'domaine vide' */
1753 } /* end for idom */
1754}
1755/*---------------------------------------------------------------------------*/
1756/*---------------------------------------------------------------------------*/
1757void SplitSDMeshPartitioner::
1758AfficheMaillage (StrucMaillage* Maillage)
1759{
1760 info()<<" ----------------";
1761 info()<<" --- Maillage ---";
1762 info()<<" ----------------";
1763 if (Maillage==NULL){
1764 info()<<" structure Maillage vide !";
1765 }
1766 else {
1767 info()<<" NbElements (total) = "<<Maillage->NbElements;
1768 info()<<" Poids (total) = "<<Maillage->Poids;
1769 info()<<" NbDomainesMax = "<<Maillage->NbDomainesMax;
1770 info()<<" NbDomainesPleins = "<<Maillage->NbDomainesPleins;
1771 info()<<" NbProcsVides = "<<Maillage->NbProcsVides;
1772
1773 if (Maillage->ListeDomaines == NULL) {
1774 info()<<" Maillage.ListeDomaines == NULL";
1775 }
1776 else {
1777 AfficheListeDomaines(Maillage->ListeDomaines,Maillage->NbDomainesMax);
1778 }
1779
1780 } /* else if Maillage==NULL */
1781}
1782/*---------------------------------------------------------------------------*/
1783/*---------------------------------------------------------------------------*/
1784void SplitSDMeshPartitioner::
1785AfficheListeDomaines(StrucListeDomMail* ListeDomaines, int NbDomaines)
1786{
1787 info()<<" ListeDomaines :";
1788 for (int i=0; i<NbDomaines; i++) {
1789 info()<<" ("<<i<<") NbElements = "<<ListeDomaines[i].NbElements<<"; Poids = "<<ListeDomaines[i].Poids;
1790 info()<<" ("<<i<<") NbVoisins = "<<ListeDomaines[i].NbVoisins<<"; ListeVoisins :";
1791 for (int j=0; j<ListeDomaines[i].NbVoisins; j++) {
1792 info()<<" ("<<i<<") NoDomVois = "<<ListeDomaines[i].ListeVoisins[j].NoDomVois
1793 <<"; NbNoeudsInterface = "<<ListeDomaines[i].ListeVoisins[j].NbNoeudsInterface
1794 <<"; Delta = "<<ListeDomaines[i].ListeVoisins[j].Delta;
1795 }
1796 }
1797}
1798/*---------------------------------------------------------------------------*/
1799/*---------------------------------------------------------------------------*/
1800void SplitSDMeshPartitioner::
1801AfficheEquilMaillage(StrucMaillage* Maillage)
1802{
1803 info()<<" AfficheEquilMaillage(...)";
1804
1805 double poidsMin = 0.0;
1806 double poidsMax = 0.0;
1807
1808 if(Maillage->ListeDomaines != NULL){
1809
1810 poidsMin = Maillage->ListeDomaines[0].Poids;
1811
1812 for (int i=0; i<Maillage->NbDomainesMax; i++){
1813 double poidsDom = Maillage->ListeDomaines[i].Poids;
1814
1815 if (poidsDom > poidsMax)
1816 poidsMax = poidsDom;
1817 if (poidsDom < poidsMin)
1818 poidsMin = poidsDom;
1819 }
1820
1821 info()<<" INFO equilibrage / noeuds : max : "<<poidsMax<<", min : "<<poidsMin
1822 <<", max/moy = "<<poidsMax/(Maillage->Poids/(double)Maillage->NbDomainesMax);
1823 }
1824 else{
1825 info()<<"AfficheEquilMaillage : Maillage->ListeDomaines == NULL";
1826 }
1827
1828}
1829/*---------------------------------------------------------------------------*/
1830/*---------------------------------------------------------------------------*/
1851void* SplitSDMeshPartitioner::RecoitMessage (StrucInfoProc* InfoProc, int FromProc, int Tag, int *pTailleTMP)
1852{
1853 void *TabTMP;
1854 int ierror; /* retour d'erreur sur lib MPI */
1855 MPI_Status status; /* pour les communication MPI */
1856
1857
1858 if (*pTailleTMP <= 0)
1859 {
1860 /* pour récupérer l'info sur la taille des tableaux qui vont suivre,
1861 on attend qu'un message soit arrivé */
1863 Tag,
1864 InfoProc->Split_Comm,
1865 &status);
1866
1867 if (ierror != MPI_SUCCESS)
1868 {
1869 InfoProc->m_service->pfatal()<<"Problème sur "<<InfoProc->me<<" de communication en provenance de "
1870 <<FromProc<<", lors de MPI_Probe";
1871 }
1872
1873 /* récupération de la taille du message | tableau */
1874 ierror = MPI_Get_count (&status,
1875 MPI_PACKED,
1876 pTailleTMP);
1877
1878 if (ierror != MPI_SUCCESS) {
1879 InfoProc->m_service->pfatal()<<"Problème sur "<<InfoProc->me<<" de communication en provenance de "
1880 <<FromProc<<", lors de MPI_Get_count";
1881 }
1882 } /* end if *pTailleTMP <= 0 */
1883
1884 /* allocation pour le tableau tampon */
1885 if (*pTailleTMP > 0)
1886 {
1887 TabTMP = malloc ((size_t) *pTailleTMP);
1888 CHECK_IF_NOT_NULL(TabTMP);
1889 }
1890 else
1891 TabTMP = NULL;
1892
1893 /* réception du message */
1895 *pTailleTMP,
1896 MPI_PACKED,
1897 FromProc,
1898 Tag,
1899 InfoProc->Split_Comm,
1900 &status);
1901
1902 if (ierror != MPI_SUCCESS) {
1903 InfoProc->m_service->pfatal()<<"Problème sur "<<InfoProc->me<<" de communication en provenance de "
1904 <<FromProc<<", lors de MPI_Recv";
1905 }
1906
1907 return (TabTMP);
1908}
1909
1910/*---------------------------------------------------------------------------*/
1911/*---------------------------------------------------------------------------*/
1928void SplitSDMeshPartitioner::EnvoieMessage(StrucInfoProc* InfoProc, int ToProc, int Tag, void* TabTMP, int TailleTMP)
1929{
1930 int ierror; /* retour d'erreur sur les fonctions MPI */
1931
1932 ierror = MPI_Send ((void *) TabTMP,
1933 TailleTMP,
1934 MPI_PACKED,
1935 ToProc,
1936 Tag,
1937 InfoProc->Split_Comm);
1938
1939 if (ierror != MPI_SUCCESS) {
1940 InfoProc->m_service->pfatal()<<"Problème sur "<<InfoProc->me<<" de communication vers "
1941 <<ToProc<<", lors de MPI_Send";
1942 }
1943
1944
1945}
1946
1947/*---------------------------------------------------------------------------*/
1948/*---------------------------------------------------------------------------*/
1949// /**
1950// Fonction qui se charge d'envoyer un tableau avec une communication non bloquante.
1951
1952// {\em Remarque:} La taille du tableau est en octets.
1953
1954// @memo Envoi d'un message non-bloquants.
1955// @param InfoProc (I) structure décrivant le processeur sur lequel tourne l'application.
1956// @param ToProc (I) noeud de calcul de destination.
1957// @param Tag (I) marque pour différencier les messages.
1958// @param TabTMP (I) tableau qui est envoyé.
1959// @param TailleTMP (I) taille de TabTMP (en octets).
1960// @return (MPI\_Request*) prequest : pointeur sur une structure propre à MPI pour la gestion du message.
1961// @see
1962// @author Eric Brière de l'Isle, ONERA, DRIS/SRL
1963// @version Création Décembre 1998
1964// */
1965// MPI_Request* EnvoieIMessage(StrucInfoProc* InfoProc, int ToProc, int Tag, void* TabTMP, int TailleTMP)
1966// {
1967// int ierror;
1968// MPI_Request *prequest;
1969
1970// prequest = (MPI_Request*) malloc(sizeof(MPI_Request));
1971// CHECK_IF_NOT_NULL(prequest);
1972
1973// ierror = MPI_Isend ((void *) TabTMP,
1974// TailleTMP,
1975// MPI_PACKED,
1976// ToProc,
1977// Tag,
1978// InfoProc->Split_Comm,
1979// prequest);
1980
1981// if (ierror != MPI_SUCCESS) {
1982// InfoProc->m_service->pfatal()<<"Problème sur "<<InfoProc->me<<" de communication vers "
1983// <<ToProc<<", lors de MPI_Isend";
1984// }
1985
1986// return prequest;
1987
1988// }
1989
1990/*---------------------------------------------------------------------------*/
1991/*---------------------------------------------------------------------------*/
2008void* SplitSDMeshPartitioner::DiffuseMessage(StrucInfoProc* InfoProc, int FromProc, void* TabTMP, int TailleTMP)
2009{
2010 int ierror; /* retour d'erreur sur les fonctions MPI */
2011
2012 if (TailleTMP<=0) {
2013 InfoProc->m_service->pfatal()<<"DiffuseMessage depuis "<<InfoProc->me<<", il est nécessaire que la taille du tableau soit connue !!!\n";
2014 }
2015
2016
2017 if (InfoProc->me != FromProc)
2018 {
2019 if (TabTMP == NULL)
2020 {
2021 TabTMP = malloc ((size_t) TailleTMP);
2022 CHECK_IF_NOT_NULL(TabTMP);
2023 }
2024 } /* end if me != FromProc */
2025
2026
2027 /* diffusion du tableau TabTMP */
2029 TailleTMP,
2030 MPI_PACKED,
2031 FromProc,
2032 InfoProc->Split_Comm);
2033
2034 if (ierror != MPI_SUCCESS) {
2035 InfoProc->m_service->pfatal()<<"Problème sur "<<InfoProc->me<<" depuis "
2036 <<FromProc<<", lors de MPI_Bcast";
2037 }
2038
2039 return (TabTMP);
2040
2041}
2042/*---------------------------------------------------------------------------*/
2043/*---------------------------------------------------------------------------*/
2054Integer SplitSDMeshPartitioner::
2055TailleDom(StructureBlocEtendu* Domaine)
2056{
2057 size_t s = (2+2*Domaine->NbIntf)*sizeof(int)+sizeof(double);
2058 return arcaneCheckArraySize(s);
2059}
2060
2061/*---------------------------------------------------------------------------*/
2062/*---------------------------------------------------------------------------*/
2075void SplitSDMeshPartitioner::
2077 int TailleTMP, MPI_Comm comm)
2078{
2079 int position = 0; // initialisation pour mettre dans le tableau au début
2080 int ier;
2081
2082 ier = MPI_Pack(&Domaine->NbElements, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2083 CHECK_MPI_PACK_ERR(ier);
2084
2085 ier = MPI_Pack(&Domaine->PoidsDom, 1, MPI_DOUBLE, TabTMP, TailleTMP, &position, comm);
2086 CHECK_MPI_PACK_ERR(ier);
2087
2088 ier = MPI_Pack(&Domaine->NbIntf, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2089 CHECK_MPI_PACK_ERR(ier);
2090
2091 for (int i=0; i<Domaine->NbIntf; i++){
2092 ier = MPI_Pack(&Domaine->Intf[i].NoDomVois, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2093 CHECK_MPI_PACK_ERR(ier);
2094
2095 int NbNoeuds = Domaine->Intf[i].ListeNoeuds.size();
2096 ier = MPI_Pack(&NbNoeuds, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2097 CHECK_MPI_PACK_ERR(ier);
2098 }
2099}
2100/*---------------------------------------------------------------------------*/
2101/*---------------------------------------------------------------------------*/
2114void SplitSDMeshPartitioner::UnpackDom(void* TabTMP, int TailleTMP, MPI_Comm comm, StrucListeDomMail* DomMail)
2115{
2116 int position = 0; // initialisation pour prendre au début du tableau
2117
2118 MPI_Unpack(TabTMP, TailleTMP, &position, &DomMail->NbElements, 1, MPI_INT, comm);
2119 MPI_Unpack(TabTMP, TailleTMP, &position, &DomMail->Poids, 1, MPI_DOUBLE, comm);
2120 MPI_Unpack(TabTMP, TailleTMP, &position, &DomMail->NbVoisins, 1, MPI_INT, comm);
2121
2122 DomMail->ListeVoisins = new StrucListeVoisMail[DomMail->NbVoisins];
2123
2124 for (int i=0; i<DomMail->NbVoisins; i++){
2125 MPI_Unpack(TabTMP, TailleTMP, &position, &DomMail->ListeVoisins[i].NoDomVois, 1, MPI_INT, comm);
2126 MPI_Unpack(TabTMP, TailleTMP, &position, &DomMail->ListeVoisins[i].NbNoeudsInterface, 1, MPI_INT, comm);
2127 DomMail->ListeVoisins[i].Delta = 0.0;
2128 }
2129}
2130
2131/*---------------------------------------------------------------------------*/
2132/*---------------------------------------------------------------------------*/
2137int SplitSDMeshPartitioner::TailleEquil()
2138{
2139 return 2*sizeof(int) + sizeof(double);
2140}
2141/*---------------------------------------------------------------------------*/
2142/*---------------------------------------------------------------------------*/
2146void SplitSDMeshPartitioner::PackEquil(StrucInfoProc* InfoProc, int indDomCharge, int indDomVois, double Delta, void* TabTMP, int TailleTMP, MPI_Comm comm)
2147{
2148 int position = 0; // initialisation pour mettre dans le tableau au début
2149 int ier;
2150 ier = MPI_Pack(&indDomCharge, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2151 CHECK_MPI_PACK_ERR(ier);
2152
2153 ier = MPI_Pack(&indDomVois, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2154 CHECK_MPI_PACK_ERR(ier);
2155
2156 ier = MPI_Pack(&Delta, 1, MPI_DOUBLE, TabTMP, TailleTMP, &position, comm);
2157 CHECK_MPI_PACK_ERR(ier);
2158}
2159/*---------------------------------------------------------------------------*/
2160/*---------------------------------------------------------------------------*/
2164void SplitSDMeshPartitioner::UnpackEquil(void* TabTMP, int TailleTMP, MPI_Comm comm, int* indDomCharge, int* indDomVois, double* Delta)
2165{
2166 int position = 0; // initialisation pour prendre au début du tableau
2168 MPI_Unpack(TabTMP, TailleTMP, &position, indDomVois, 1, MPI_INT, comm);
2169 MPI_Unpack(TabTMP, TailleTMP, &position, Delta, 1, MPI_DOUBLE, comm);
2170}
2171
2172/*---------------------------------------------------------------------------*/
2173/*---------------------------------------------------------------------------*/
2174
2176 ServiceProperty("SplitSD",ST_SubDomain),
2179
2180ARCANE_REGISTER_SERVICE_SPLITSDMESHPARTITIONER(SplitSD,SplitSDMeshPartitioner);
2181
2182/*---------------------------------------------------------------------------*/
2183/*---------------------------------------------------------------------------*/
2184
2185} // End namespace Arcane
2186
2187/*---------------------------------------------------------------------------*/
2188/*---------------------------------------------------------------------------*/
Types et macros pour itérer sur les entités du maillage.
#define ENUMERATE_FACE(name, group)
Enumérateur générique d'un groupe de faces.
#define ENUMERATE_CELL(name, group)
Enumérateur générique d'un groupe de mailles.
#define ENUMERATE_NODE(name, group)
Enumérateur générique d'un groupe de noeuds.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro pour déclarer une interface lors de l'enregistrement d'un service.
Maille d'un maillage.
Definition Item.h:1178
Face face(Int32 i) const
i-ème face de la maille
Definition Item.h:1255
Int32 nbFace() const
Nombre de faces de la maille.
Definition Item.h:1252
Face d'une maille.
Definition Item.h:932
Cell frontCell() const
Maille devant la face (maille nulle si aucune)
Definition Item.h:1604
bool isSubDomainBoundary() const
Indique si la face est au bord du sous-domaine (i.e nbCell()==1)
Definition Item.h:1025
Cell backCell() const
Maille derrière la face (maille nulle si aucune)
Definition Item.h:1598
virtual IItemFamily * nodeFamily()=0
Retourne la famille des noeuds.
virtual CellGroup ownCells()=0
Groupe de toutes les mailles propres au domaine.
virtual FaceGroup allFaces()=0
Groupe de toutes les faces.
virtual NodeGroup allNodes()=0
Groupe de tous les noeuds.
virtual CellGroup allCells()=0
Groupe de toutes les mailles.
Interface d'un partitionneur de maillage.
Interface d'un partitionneur de maillage.
virtual IPrimaryMesh * toPrimaryMesh()=0
Retourne l'instance sous la forme d'un IPrimaryMesh.
virtual Properties * properties()=0
Propriétés associées à ce maillage.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual void computeMinMaxSum(char val, char &min_val, char &max_val, char &sum_val, Int32 &min_rank, Int32 &max_rank)=0
Calcule en une opération la somme, le min, le max d'une valeur.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual void exchangeItems()=0
Change les sous-domaines propriétaires des entités.
virtual VariableItemInt32 & itemsNewOwner(eItemKind kind)=0
Variable contenant l'identifiant du sous-domaine propriétaire.
Interface du gestionnaire d'un sous-domaine.
Definition ISubDomain.h:74
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:768
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:765
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:210
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
Definition Item.h:229
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:149
Noeud d'un maillage.
Definition Item.h:564
Cell cell(Int32 i) const
i-ème maille du noeud
Definition Item.h:1568
Int32 nbCell() const
Nombre de mailles connectées au noeud.
Definition Item.h:643
Propriétés de création d'un service.
Partitioneur de maillage inspiré de la bibliothèque SplitSD, développé initialement à l'ONERA pour Da...
Exception lorsqu'une erreur fatale est survenue.
TraceMessage pfatal() const
Flot pour un message d'erreur fatale en parallèle.
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Integer arcaneCheckArraySize(unsigned long long size)
Vérifie que size peut être converti dans un 'Integer' pour servir de taille à un tableau....
bool arcaneIsDebug()
Vrai si la macro ARCANE_DEBUG est définie.
Definition Misc.cc:80
@ IK_Cell
Entité de maillage de genre maille.
StrucListeVoisMail * ListeVoisins
StrucListeDomMail * ListeDomaines
StructureInterface * Intf
Arcane::UniqueArray< Arcane::Node > ListeNoeuds