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