Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
SplitSDMeshPartitioner.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 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 (C) 2000-2024 */
9/* */
10/* Mesh partitioner reproducing the (simplified) functionality of SplitSD */
11/* used at Dassault Aviation and developed at ONERA by EB in 1996-99 */
12/*---------------------------------------------------------------------------*/
13/*---------------------------------------------------------------------------*/
14
15//#define DEBUG_PARTITIONER
16
17#include "arcane/utils/PlatformUtils.h"
18#include "arcane/utils/ArcanePrecomp.h"
19#include "arcane/utils/Convert.h"
20#include "arcane/utils/Array.h"
21
22#include "arcane/core/ISubDomain.h"
23#include "arcane/core/IParallelMng.h"
25#include "arcane/core/IPrimaryMesh.h"
26#include "arcane/core/Properties.h"
27#include "arcane/core/ItemGroup.h"
28#include "arcane/core/Service.h"
29#include "arcane/core/Timer.h"
30#include "arcane/core/FactoryService.h"
31#include "arcane/core/ItemPrinter.h"
32#include "arcane/core/IItemFamily.h"
33#include "arcane/core/MeshVariable.h"
34#include "arcane/core/VariableBuildInfo.h"
35#include "arcane/std/MeshPartitionerBase.h"
36#include "arcane/std/SplitSDMeshPartitioner.h"
37
38#include <map>
39
40/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------*/
42
43namespace Arcane
44{
45
46/*---------------------------------------------------------------------------*/
47/*---------------------------------------------------------------------------*/
48SplitSDMeshPartitioner::
49SplitSDMeshPartitioner(const ServiceBuildInfo& sbi)
51, m_poids_aux_mailles(VariableBuildInfo(sbi.mesh(), "MeshPartitionerCellsWeight", IVariable::PNoDump | IVariable::PNoRestore))
52{
53 info() << "SplitSDMeshPartitioner::SplitSDMeshPartitioner(...)";
54}
55
56/*---------------------------------------------------------------------------*/
57/*---------------------------------------------------------------------------*/
58
59void SplitSDMeshPartitioner::
60partitionMesh(bool initial_partition)
61{
62 info() << "Load balancing with SplitSDMeshPartitioner";
63
64 // we do not support constraints
65 // because we use the Arcane mesh for frontal sweeps,
66 // it is therefore not planned for the moment to take into account groups
67 // of cells associated with constraints
68 _initArrayCellsWithConstraints();
69 if (haveConstraints())
70 throw FatalErrorException("SplitSDMeshPartitioner: Constraints are not supported with SplitSD");
71
72 // initialization of internal structures
73
74 StrucInfoProc* InfoProc = NULL; /* structure describing the processor on which the application runs */
75 StructureBlocEtendu* Domaine = NULL; /* structure summarizing the block, i.e., the part of the topology localized on this processor */
76 StrucMaillage* Maillage = NULL; /* structure summarizing the global mesh */
77
78 // initialization of partitioner-specific data, m_cells_weight must be calculated
79 init(initial_partition, InfoProc, Domaine, Maillage);
80
81 // iterative load balancing process by moving elements from one subdomain to another
82 Equilibrage(InfoProc, Domaine, Maillage);
83
84 // we clear the structures
85 fin(InfoProc, Domaine, Maillage);
86}
87/*---------------------------------------------------------------------------*/
88/*---------------------------------------------------------------------------*/
89void SplitSDMeshPartitioner::
90init(bool initial_partition, StrucInfoProc*& InfoProc, StructureBlocEtendu*& Domaine, StrucMaillage*& Maillage)
91{
92 info() << "SplitSDMeshPartitioner::init(" << initial_partition << ",...)";
93
94 ISubDomain* sd = subDomain();
95 IParallelMng* pm = sd->parallelMng();
96
97 /* Memory initialization of InfoProc */
98 InfoProc = new StrucInfoProc();
99
100 InfoProc->me = sd->subDomainId();
101 InfoProc->nbSubDomain = pm->commSize();
102 InfoProc->m_service = this;
103 // MPI_Comm_dup(MPI_COMM_WORLD,&InfoProc->Split_Comm); /* Assignment of a communicator specific to our partitioner */
104 InfoProc->Split_Comm = *(MPI_Comm*)getCommunicator();
105 initConstraints();
106
107 // initialization of cell weights
108 initPoids(initial_partition);
109#if 0
110 if (!initial_partition){
111 info() << "Initialize new owners";
112 // Initialise the new owner for the case where no rebalancing is needed
113 IMesh* mesh = this->mesh();
114 VariableItemInteger& cells_new_owner = mesh->itemsNewOwner(IK_Cell);
115 ENUMERATE_CELL(icell,mesh->ownCells()){
116 Cell cell = *icell;
117 cells_new_owner[icell] = cell.owner();
118 }
120 cells_new_owner.synchronize();
121 }
122#endif
123
124 /* Memory initialization of Domain */
125 Domaine = new StructureBlocEtendu();
126
127 Domaine->NbIntf = 0;
128 Domaine->Intf = NULL;
129 Domaine->NbElements = 0;
130 Domaine->PoidsDom = 0.0;
131
132 MAJDomaine(Domaine);
133
134 /* Memory initialization of Mesh */
135 Maillage = new StrucMaillage();
136
137 Maillage->NbElements = 0;
138 Maillage->NbDomainesMax = pm->commSize();
139 Maillage->NbDomainesPleins = 0;
140 Maillage->ListeDomaines = NULL;
141 Maillage->NbProcsVides = 0;
142 Maillage->Poids = 0.0;
143
144 // we only update the structure on the master processor (0), based on Domain
145 MAJMaillageMaitre(InfoProc, Domaine, Maillage);
146}
147/*---------------------------------------------------------------------------*/
148/*---------------------------------------------------------------------------*/
149void SplitSDMeshPartitioner::
150initPoids(bool initial_partition)
151{
152 ARCANE_UNUSED(initial_partition);
153
154 /* retrieval of cell weights so that they follow the cells */
155 IMesh* mesh = this->mesh();
156 CellGroup own_cells = mesh->ownCells();
157 // if (initial_partition || m_cells_weight.empty())
158 // ENUMERATE_CELL(iitem,own_cells){
159 // const Cell& cell = *iitem
160 // m_poids_aux_mailles[cell] = 1.0;
161 // }
162 // else{
163 // Integer nb_weight = nbCellWeight();
164 SharedArray<float> cell_weights = cellsWeightsWithConstraints(1, true); // 1 weight only
165 ENUMERATE_CELL (iitem, own_cells) {
166 m_poids_aux_mailles[iitem] = cell_weights[iitem.index()];
167 }
168}
169/*---------------------------------------------------------------------------*/
170/*---------------------------------------------------------------------------*/
171void SplitSDMeshPartitioner::
172fin(StrucInfoProc*& InfoProc, StructureBlocEtendu*& Domaine, StrucMaillage*& Maillage)
173{
174 info() << "SplitSDMeshPartitioner::fin(...)";
175 LibereInfoProc(InfoProc);
176 LibereDomaine(Domaine);
177 LibereMaillage(Maillage);
178
179 delete InfoProc;
180 delete Domaine;
181 delete Maillage;
182
183 InfoProc = NULL;
184 Domaine = NULL;
185 Maillage = NULL;
186}
187/*---------------------------------------------------------------------------*/
188/*---------------------------------------------------------------------------*/
189void SplitSDMeshPartitioner::
190MAJDomaine(StructureBlocEtendu* Domaine)
191{
192 debug() << " ----------------------------------------";
193 debug() << "SplitSDMeshPartitioner::MAJDomaine(...)";
194
195 LibereDomaine(Domaine);
196
197 int me = subDomain()->subDomainId();
198
199 // filling Domaine->Intf, lists of nodes per neighboring subdomain
200
201 IMesh* mesh = this->mesh();
202 FaceGroup all_faces = mesh->allFaces(); // faces on this processor
203 debug() << " all_faces.size() = =" << all_faces.size();
204
205 std::map<int, SharedArray<Face>> vois_faces; // list of faces per neighboring subdomain
206
207 ENUMERATE_FACE (i_item, all_faces) {
208 const Face face = *i_item;
209 if (!face.isSubDomainBoundary()) {
210 int id1 = face.backCell().owner();
211 int id2 = face.frontCell().owner();
212
213 if (id1 != id2) { // case of neighborhood with another domain
214 int idv = -1; // neighbor number
215 if (id1 == me)
216 idv = id2;
217 else if (id2 == me)
218 idv = id1;
219 else
220 continue;
221 // info() << "idv = "<<idv<< " for the face " <<face.uniqueId();
222
223 // we add the face index for a subdomain
224 SharedArray<Face>& v_face = vois_faces[idv];
225 v_face.add(face);
226
227 } // end if (id1 != id2)
228 } // end if (!face.isBoundary())
229 } // end ENUMERATE_FACE
230
231 UniqueArray<int> filtreNoeuds(mesh->nodeFamily()->maxLocalId());
232 filtreNoeuds.fill(0); // initialization of the filter
233 int marque = 0;
234
235 // for each neighboring subdomain, we search for nodes in the interface
236 // avoiding duplicates using the node filter
237
238 Domaine->NbIntf = arcaneCheckArraySize(vois_faces.size());
239
240 // cells on this proc (without ghost cells)
241 Domaine->NbElements = mesh->ownCells().size();
242
243 // calculation of the total weight of a domain => using m_cells_weight
244 Domaine->PoidsDom = 0.0;
245 CellGroup own_cells = mesh->ownCells();
246 ENUMERATE_CELL (iitem, own_cells) {
247 Cell cell = *iitem;
248 Domaine->PoidsDom += m_poids_aux_mailles[cell];
249 }
250
251#ifdef ARCANE_DEBUG
252 info() << "Domaine->NbIntf = " << Domaine->NbIntf;
253 info() << "Domaine->NbElements = " << Domaine->NbElements;
254 info() << "Domaine->PoidsDom = " << Domaine->PoidsDom;
255#endif
256
257 Domaine->Intf = new StructureInterface[Domaine->NbIntf];
258 unsigned int ind = 0;
259 for (std::map<int, SharedArray<Face>>::iterator iter_vois = vois_faces.begin();
260 iter_vois != vois_faces.end(); ++iter_vois) {
261
262 marque += 1;
263
264 Domaine->Intf[ind].NoDomVois = (*iter_vois).first;
265 Array<Face>& v_face = (*iter_vois).second;
266
267#ifdef ARCANE_DEBUG
268 info() << "Domaine->Intf[" << ind << "].NoDomVois = " << Domaine->Intf[ind].NoDomVois;
269 info() << " v_face.size() = " << v_face.size();
270#endif
271
272 for (int i = 0; i < v_face.size(); i++) {
273 const Face& face = v_face[i];
274 // info() << " v_face["<<i<<"].uniqueId() = " << face.uniqueId()
275 // << ", backCell: "<<face.backCell().owner() <<", frontCell: "<< face.frontCell().owner();
276
277 for (Integer z = 0; z < face.nbNode(); ++z) {
278 const Node node = face.node(z);
279 Integer node_local_id = node.localId();
280 if (filtreNoeuds[node_local_id] != marque) {
281 Domaine->Intf[ind].ListeNoeuds.add(node);
282 filtreNoeuds[node_local_id] = marque;
283 }
284 }
285
286 } // end for iter_face
287#ifdef ARCANE_DEBUG
288 info() << " ListeNoeuds.size() = " << Domaine->Intf[ind].ListeNoeuds.size();
289#endif
290
291 ind += 1;
292 } // end for iter_vois
293
294#ifdef ARCANE_DEBUG
295 info() << "MAJDomaine => ";
296 AfficheDomaine(1, Domaine);
297 info() << " ----------------------------------------";
298#endif
299}
300/*---------------------------------------------------------------------------*/
301/*---------------------------------------------------------------------------*/
302void SplitSDMeshPartitioner::
303MAJMaillageMaitre(StrucInfoProc* InfoProc, StructureBlocEtendu* Domaine, StrucMaillage* Maillage)
304{
305 // prerequisite: having done a MAJDomaine before coming here
306
307#ifdef ARCANE_DEBUG
308 info() << "SplitSDMeshPartitioner::MAJMaillageMaitre(...)";
309 LibereMaillage(Maillage);
310#endif
311
312 void* TabTMP; /* array for Domain => Mesh->ListeDomaines[*] communications */
313 int TailleTab; /* size of the TabTMP array (in bytes) */
314 int iDom; /* loop index over domains */
315
316 /* we concentrate the information in TabTMP */
317 TailleTab = TailleDom(Domaine);
318 TabTMP = malloc((size_t)TailleTab);
319
320 PackDom(InfoProc, Domaine, TabTMP, TailleTab, InfoProc->Split_Comm);
321
322 /* we send to the master, for all domains
323 (except the master which just copies) */
324 if (InfoProc->me == 0) {
325#ifdef DEBUG
326 info() << " ***************************";
327 info() << " * Before MAJMaillageMaitre *";
328 AfficheMaillage(Maillage);
329 info() << " ***************************";
330#endif
331
332 if (Maillage->ListeDomaines == NULL) {
333 Maillage->ListeDomaines = new StrucListeDomMail[InfoProc->nbSubDomain];
334 for (iDom = 0; iDom < InfoProc->nbSubDomain; iDom++) {
335 Maillage->ListeDomaines[iDom].NbElements = 0;
336 Maillage->ListeDomaines[iDom].Poids = 0;
337 Maillage->ListeDomaines[iDom].NbVoisins = 0;
338 Maillage->ListeDomaines[iDom].ListeVoisins = NULL;
339 }
340 } /* end if Maillage->ListeDomaines == NULL */
341
342 UnpackDom(TabTMP, TailleTab, InfoProc->Split_Comm, &Maillage->ListeDomaines[0]);
343 }
344 else { /* case where it is not the master */
345 EnvoieMessage(InfoProc, 0, TAG_MAILLAGEMAITRE, TabTMP, TailleTab);
346 }
347
348 /* release */
349 free(TabTMP);
350 TabTMP = NULL;
351
352 /* --------- */
353 /* Reception */
354 /* --------- */
355
356 /* the master receives all information from other nodes (including itself) */
357 if (InfoProc->me == 0) {
358 Maillage->NbDomainesPleins = 0; /* we will count the number of full domains */
359 Maillage->NbProcsVides = 0; /* we will count the number of empty domains */
360 Maillage->Poids = 0.0; // total weight
361 Maillage->NbElements = 0; // total number of elements in the mesh
362
363 /* we put the smallest numbers at the end to use them first */
364 for (iDom = InfoProc->nbSubDomain - 1; iDom >= 0; iDom--) {
365 if (iDom != 0) {
366
367 TailleTab = 0; /* because we do not yet know the size */
368 TabTMP = RecoitMessage(InfoProc, iDom, TAG_MAILLAGEMAITRE, &TailleTab);
369
370 UnpackDom(TabTMP, TailleTab, InfoProc->Split_Comm, &Maillage->ListeDomaines[iDom]);
371
372 free((void*)TabTMP);
373 TabTMP = NULL;
374 }
375
376 /* we count the number of full and empty domains */
377 if (Maillage->ListeDomaines[iDom].NbElements != 0)
378 Maillage->NbDomainesPleins += 1;
379 else
380 Maillage->NbProcsVides += 1;
381
382 Maillage->Poids += Maillage->ListeDomaines[iDom].Poids;
383 Maillage->NbElements += Maillage->ListeDomaines[iDom].NbElements;
384 }
385
386#ifdef ARCANE_DEBUG
387 info() << " ***************************";
388 info() << " * After MAJMaillageMaitre *";
389#ifdef DEBUG
390 AfficheMaillage(Maillage);
391#endif
392 info() << " ***************************";
393 verifMaillageMaitre(Maillage);
394#endif
395 } /* end if me == master */
396}
397/*---------------------------------------------------------------------------*/
398/*---------------------------------------------------------------------------*/
399void SplitSDMeshPartitioner::
400verifMaillageMaitre(StrucMaillage* Maillage)
401{
402#ifdef ARCANE_DEBUG
403 info() << " entering verifMaillageMaitre";
404
405 StrucListeDomMail* ListeDomaines = Maillage->ListeDomaines;
406 int NbDomaines = Maillage->NbDomainesPleins;
407
408 for (int iDom = 0; iDom < NbDomaines; iDom++) {
409 for (int j = 0; j < ListeDomaines[iDom].NbVoisins; j++) {
410
411 int NbNoeudsInterface = ListeDomaines[iDom].ListeVoisins[j].NbNoeudsInterface;
412 int iVois = ListeDomaines[iDom].ListeVoisins[j].NoDomVois;
413
414 // search if the neighbor exists and if the number of nodes is identical
415 int k;
416 for (k = 0; k < ListeDomaines[iVois].NbVoisins && ListeDomaines[iVois].ListeVoisins[k].NoDomVois != iDom; k++) {
417 }
418 if (k == ListeDomaines[iVois].NbVoisins) {
419 printf("we cannot find the neighbor number \n");
420 printf("for info: iDom = %d, iVois = %d\n", iDom, iVois);
421 perror() << "verifMaillageMaitre error on neighborhood !!!";
422 }
423
424 if (ListeDomaines[iVois].ListeVoisins[k].NbNoeudsInterface != NbNoeudsInterface) {
425 printf("we do not find the same number of nodes between neighbors \n");
426 printf("for info: iDom = %d, iVois = %d, NbNoeudsInterface %d != %d\n", iDom, iVois, NbNoeudsInterface, ListeDomaines[iVois].ListeVoisins[k].NbNoeudsInterface);
427 perror() << "verifMaillageMaitre error on number of nodes !!!";
428 }
429 }
430 }
431
432 info() << " leaving verifMaillageMaitre";
433#else
434 ARCANE_UNUSED(Maillage);
435#endif
436}
437/*---------------------------------------------------------------------------*/
438/*---------------------------------------------------------------------------*/
439void SplitSDMeshPartitioner::
440MAJDeltaGlobal(StrucInfoProc* InfoProc, StrucMaillage* Maillage, double tolerance)
441{
442 StrucListeDomMail* ListeDomaines = Maillage->ListeDomaines;
443 int NbDomaines = Maillage->NbDomainesPleins;
444
445 int i;
446 int iDomDep; /* index of the full domain that serves as the starting point for front sweeps */
447 double PoidsMoyen;
448
449 int tailleFP;
450 int tailleFS;
451
452 int* FrontPrec; // front of nodes of the graph (domains)
453 int* FrontSuiv;
454 int* FrontTMP;
455 /* for each node in the graph, gives the previous node.
456 This will allow, from a given node during the front sweep, to find a path back to the starting node */
457 int* ListeNoeudsPrec;
458
459 int* FiltreDomaine; /* to mark the domains as markedDomVu, markedDomNonVu, or markedDomVide */
460 int marqueDomVu = 1;
461 int marqueDomNonVu = 0;
462 int marqueDomVide = -1; // normally, there are none
463
464 double* PoidsSave;
465
466#ifdef ARCANE_DEBUG
467 info() << " ------------------------------------";
468 info() << " entering MAJDeltaGlobal, tolerance = " << tolerance;
469 info() << " ------------------------------------";
470 info() << " ......... Initial Mesh ...........";
471 AfficheListeDomaines(ListeDomaines, NbDomaines);
472#endif
473
474 if (NbDomaines == 0) {
475 info() << " SplitSDMeshPartitioner::MAJDeltaGlobal: NbDomaines is null!";
476 return;
477 }
478 if (Maillage->NbDomainesPleins <= 1) {
479#ifdef ARCANE_DEBUG
480 info() << " \n = exiting MAJDeltaGlobal without doing anything (NbDomainesPleins = " << Maillage->NbDomainesPleins;
481 info() << " ------------------------------------";
482#endif
483 return;
484 }
485
486 FiltreDomaine = (int*)malloc((size_t)NbDomaines * sizeof(int));
487 CHECK_IF_NOT_NULL(FiltreDomaine);
488
489 /* setting all Deltas to zero for safety */
490 for (i = 0; i < NbDomaines; i++)
491 for (int j = 0; j < ListeDomaines[i].NbVoisins; j++)
492 ListeDomaines[i].ListeVoisins[j].Delta = 0.0;
493
494 /*
495 shifting the number of nodes of each domain so that the total sum is <= 0
496 */
497
498 for (i = 0; i < NbDomaines; i++) {
499 if (ListeDomaines[i].NbElements != 0)
500 FiltreDomaine[i] = marqueDomNonVu;
501 else
502 FiltreDomaine[i] = marqueDomVide;
503 }
504
505 PoidsSave = (double*)malloc((size_t)NbDomaines * sizeof(double));
506 CHECK_IF_NOT_NULL(PoidsSave);
507
508 /* the average value */
509 PoidsMoyen = Maillage->Poids / (double)Maillage->NbDomainesMax;
510
511 /* performing the shift */
512 for (i = 0; i < NbDomaines; i++) {
513 /* saving the weight */
514 PoidsSave[i] = ListeDomaines[i].Poids;
515
516 if (FiltreDomaine[i] != marqueDomVide)
517 ListeDomaines[i].Poids -= PoidsMoyen;
518 }
519
520#ifdef DEBUG
521 info() << " After Poids -= PoidsMoyen";
522 AfficheListeDomaines(ListeDomaines, NbDomaines);
523#endif
524
525 /* memory initialization to the largest size */
526 FrontPrec = (int*)malloc((size_t)(NbDomaines - 1) * sizeof(int));
527 CHECK_IF_NOT_NULL(FrontPrec);
528 FrontSuiv = (int*)malloc((size_t)(NbDomaines - 1) * sizeof(int));
529 CHECK_IF_NOT_NULL(FrontSuiv);
530
531 ListeNoeudsPrec = (int*)malloc((size_t)(NbDomaines) * sizeof(int));
532 CHECK_IF_NOT_NULL(ListeNoeudsPrec);
533
534 for (iDomDep = 0; iDomDep < NbDomaines; iDomDep++) {
535#ifdef DEBUG
536 info() << " ListeDomaines[iDomDep = " << iDomDep << "].Poids = " << ListeDomaines[iDomDep].Poids;
537#endif
538
539 /* we only take domains above the average weight (so > 0 now) as starting points */
540 if (ListeDomaines[iDomDep].Poids > tolerance) {
541 /* BELOW, A NODE IS A DOMAIN; IT IS A NODE OF THE GRAPH */
542
543 /* initializing previously seen domains to non-seen */
544 for (i = 0; i < NbDomaines; i++)
545 if (FiltreDomaine[i] == marqueDomVu)
546 FiltreDomaine[i] = marqueDomNonVu;
547
548 /* marking the current node as seen */
549 FiltreDomaine[iDomDep] = marqueDomVu;
550
551 /* initialization of the starting front */
552 tailleFS = 1;
553 FrontSuiv[tailleFS - 1] = iDomDep;
554
555#ifdef DEBUG
556 info() << " FrontSuiv[0] = " << iDomDep;
557#endif
558
559 /* initialization of the starting node (no previous node) */
560 ListeNoeudsPrec[FrontSuiv[tailleFS - 1]] = -1;
561
562 /* loop while the starting node is too large (weight>0) */
563 while (ListeDomaines[iDomDep].Poids > tolerance) {
564#ifdef DEBUG
565 info() << " while (ListeDomaines[" << iDomDep << "].Poids = " << ListeDomaines[iDomDep].Poids << " > " << tolerance;
566#endif
567
568 /* swapping the following and preceding fronts */
569 FrontTMP = FrontPrec;
570 FrontPrec = FrontSuiv;
571 FrontSuiv = FrontTMP;
572 tailleFP = tailleFS;
573 tailleFS = 0; /* the following front is now empty */
574
575 /* case where the starting domain failed to disperse its surplus onto other domains, and we have seen everything we could */
576 if (tailleFP == 0) {
577 fatal() << " partitionner/MAJDeltaGlobal: no more domains found while not finished!!!";
578 }
579
580 /*
581 progressing one front
582 */
583
584 /* loop over the nodes of the preceding front */
585 for (int iFP = 0; iFP < tailleFP; iFP++) {
586 int iDom = FrontPrec[iFP];
587
588 /* loop over the neighbors of the node */
589 for (int iVois = 0; iVois < ListeDomaines[iDom].NbVoisins; iVois++) {
590 int iDomVois = ListeDomaines[iDom].ListeVoisins[iVois].NoDomVois;
591 if (FiltreDomaine[iDomVois] == marqueDomNonVu) {
592 /* marking this node */
593 FiltreDomaine[iDomVois] = marqueDomVu;
594 ListeNoeudsPrec[iDomVois] = iDom;
595#ifdef DEBUG
596 info() << " FrontSuiv[" << tailleFS << "] = " << iDomVois;
597#endif
598 FrontSuiv[tailleFS++] = iDomVois;
599 }
600 }
601 } /* end for iFP<tailleFP */
602
603 /*
604 discharging the base node onto the nodes of the following front
605 */
606
607 /* loop over the nodes of the following front */
608 for (int iFS = 0; iFS < tailleFS; iFS++) {
609 int iDom = FrontSuiv[iFS];
610
611#ifdef DEBUG
612 info() << " ListeDomaines[" << iDom << "].Poids = " << ListeDomaines[iDom].Poids;
613#endif
614
615 /* only giving to deficit nodes */
616 if (ListeDomaines[iDom].Poids < 0.0) {
617 /* not giving more than we have */
618 double don = MIN(-ListeDomaines[iDom].Poids, ListeDomaines[iDomDep].Poids);
619
620 /* case where there is a donation */
621 if (don > 0.0) {
622 int iDomTmp;
623 int iDomTmpPrec;
624
625 ListeDomaines[iDom].Poids += don;
626 ListeDomaines[iDomDep].Poids -= don;
627
628 //fprintf(stdout," donation = %f\n",don);
629
630 /* tracing back the entire path to update the Delta
631 between nodes iDomTmp and iDomTmpPrec */
632 iDomTmp = iDom;
633 iDomTmpPrec = ListeNoeudsPrec[iDomTmp];
634 while (iDomTmpPrec != -1) {
635 /* incrementing the Delta by donation between iDomTmpPrec and iDomTmp */
636 MAJDelta(don, iDomTmpPrec, iDomTmp, ListeDomaines);
637 /* similarly (with the opposite sign) for the reciprocal interface */
638 MAJDelta(-don, iDomTmp, iDomTmpPrec, ListeDomaines);
639
640 /* moving one step back along the path */
641 iDomTmp = iDomTmpPrec;
642 iDomTmpPrec = ListeNoeudsPrec[iDomTmp];
643
644 } /* end while iDomTmpPrec != -1 */
645
646 } /* end if don != 0 */
647 } /* end if NbNoeuds < 0, for the front domain */
648 } /* end for iFS<tailleFS */
649 // AfficheListeDomaines(ListeDomaines,NbDomaines);
650
651 } /* end while Poids > tolerance */
652 } /* end if Poids > tolerance */
653 } /* end for iDomDep<NbDomaines */
654
655 /* restoring the values */
656 for (i = 0; i < NbDomaines; i++)
657 ListeDomaines[i].Poids = PoidsSave[i];
658
659 free((void*)FrontPrec);
660 FrontPrec = NULL;
661 free((void*)FrontSuiv);
662 FrontSuiv = NULL;
663 free((void*)ListeNoeudsPrec);
664 ListeNoeudsPrec = NULL;
665 free((void*)FiltreDomaine);
666 FiltreDomaine = NULL;
667 free((void*)PoidsSave);
668 PoidsSave = NULL;
669
670#ifdef ARCANE_DEBUG
671 info() << " ......... Final Mesh ...........";
672 AfficheListeDomaines(ListeDomaines, NbDomaines);
673 info() << " = exiting MAJDeltaGlobal =";
674 info() << " ------------------------------------";
675#endif
676}
677/*---------------------------------------------------------------------------*/
678/*---------------------------------------------------------------------------*/
679void SplitSDMeshPartitioner::
680MAJDelta(double ajout, int iDom, int iVois, StrucListeDomMail* ListeDomaines)
681{
682 int j;
683 for (j = 0;
684 j < ListeDomaines[iDom].NbVoisins &&
685 ListeDomaines[iDom].ListeVoisins[j].NoDomVois != iVois;
686 j++) {
687 }
688
689 if (j == ListeDomaines[iDom].NbVoisins) {
690 info() << "could not find the neighbor number";
691 info() << "for info: addition = " << ajout << ", iDom = " << iDom << ", iVois = " << iVois;
692 pfatal() << "Error in Partitionner/MAJDelta, no neighbor found!";
693 }
694
695 /* performing the shift */
696 ListeDomaines[iDom].ListeVoisins[j].Delta += ajout;
697}
698
699/*---------------------------------------------------------------------------*/
700/*---------------------------------------------------------------------------*/
701double SplitSDMeshPartitioner::
702CalculDeltaMin(StrucMaillage* Maillage, double deltaMin, int iterEquilibrage, int NbMaxIterEquil)
703{
704 // the goal: limit deltaMin so that it is not too small the first time transfers are important.
705 // Indeed, this tends to fragment the domains, which results in poorer performance (more waiting during communications)
706
707 debug() << " entering SplitSDMeshPartitioner::CalculDeltaMin, deltaMin = " << deltaMin
708 << ", iterEquilibrage = " << iterEquilibrage
709 << ", NbMaxIterEquil = " << NbMaxIterEquil;
710 if (arcaneIsDebug())
711 AfficheMaillage(Maillage);
712
713 double deltaAjuste = deltaMin;
714
715 // searching for the largest Delta on the interfaces
716 double deltaMaxItf = 0.0;
717 // same for the sum of deltas per domain, normalized by the domain weight (so a ratio)
718 double ratioDeltaMax = 0.0;
719
720 StrucListeDomMail* ListeDomaines = Maillage->ListeDomaines;
721 int NbDomaines = Maillage->NbDomainesPleins;
722
723 for (int iDom = 0; iDom < NbDomaines; iDom++) {
724 double deltaTotalDom = 0.0;
725 for (int j = 0; j < ListeDomaines[iDom].NbVoisins; j++) {
726 double delta = ListeDomaines[iDom].ListeVoisins[j].Delta;
727 deltaMaxItf = MAX(delta, deltaMaxItf);
728 if (delta > 0.0)
729 deltaTotalDom += delta;
730 }
731 double ratio = 0.0;
732 if (ListeDomaines[iDom].Poids > 0.0)
733 ratio = deltaTotalDom / ListeDomaines[iDom].Poids;
734 ratioDeltaMax = MAX(ratio, ratioDeltaMax);
735 }
736
737 double poidsMoy = Maillage->Poids / (double)Maillage->NbDomainesMax;
738
739 // heuristic to limit deltaAjuste
740 if (ratioDeltaMax > 0.9)
741 deltaAjuste = poidsMoy / 3.0;
742 else if (ratioDeltaMax > 0.5)
743 deltaAjuste = deltaMaxItf / 10.0;
744
745 // to avoid being smaller than the minimum which seems reasonable and is parameterized by the .plt file
746 deltaAjuste = MAX(deltaMin, deltaAjuste);
747
748#if defined(ARCANE_DEBUG) || defined(DEBUG_PARTITIONER)
749 // what does this delta / average weight represent? all or a small proportion?
750 double proportion = deltaMaxItf / poidsMoy;
751
752 info() << " deltaMaxItf = " << deltaMaxItf;
753 info() << " ratioDeltaMax = " << ratioDeltaMax;
754 info() << " poidsMoy = " << poidsMoy;
755 info() << " proportion = " << proportion;
756 info() << " deltaAjuste = " << deltaAjuste;
757#endif
758
759 return deltaAjuste;
760}
761/*---------------------------------------------------------------------------*/
762/*---------------------------------------------------------------------------*/
763void SplitSDMeshPartitioner::
764Equilibrage(StrucInfoProc* InfoProc, StructureBlocEtendu* Domaine, StrucMaillage* Maillage)
765{
766 int iDom; // index for loops
767 int indDomCharge = -1; // the domain from which elements will be extracted
768 int indDomVois = -1; // the domain that will receive from indDomCharge
769
770 double deltaMin; // we will only perform the transfer for a minimum weight.
771 // maximum imbalance (0.01) in .plt file => maxImbalance()
772 deltaMin = Maillage->Poids / (double)Maillage->NbDomainesMax * maxImbalance() / 6.0; // we take maxImbalance/6 of the average as the value (so 0.1 by default)
773
774 double poidsMax = 0; // for searching the most loaded domain
775
776 void* TabTMP; /* to transfer info about the chosen procs and the master's Delta to the other procs */
777
778 int NbAppelsAEquil2Dom = -1;
779
780 int iterEquilibrage = 0;
781 int NbMaxIterEquil = 5; // global balancing phase. TODO see if this value needs to be changed (parameterize it)
782
783 double tolConnexite = 0.1; // a non-connected subdomain smaller than tolConnexite*average_size will be transferred
784
785#ifdef ARCANE_DEBUG
786 info() << " -------------------------------------";
787 info() << " entering SplitSDMeshPartitioner::Equilibrage, deltaMin = " << deltaMin;
788#endif
789
790 int TailleTMP = TailleEquil();
791 TabTMP = malloc((size_t)TailleTMP);
792 CHECK_IF_NOT_NULL(TabTMP);
793
794 /* limiting to NbMaxIter iterations */
795 while (iterEquilibrage < NbMaxIterEquil && NbAppelsAEquil2Dom != 0) {
796 int* FiltreDomaine;
797 int marqueDomVu = 1;
798 int marqueDomNonVu = 0;
799
800 iterEquilibrage += 1;
801 NbAppelsAEquil2Dom = 0;
802 poidsMax = 0;
803 indDomCharge = -1;
804
805 int* MasqueDesNoeuds = GetMasqueDesNoeuds(InfoProc);
806 int* MasqueDesElements = GetMasqueDesElements(InfoProc);
807 int marqueVu = 0;
808 int marqueNonVu = 0;
809
810 IPrimaryMesh* mesh = this->mesh()->toPrimaryMesh();
811
812 /* on the master */
813 if (InfoProc->me == 0) {
814 info() << " SplitSDMeshPartitioner::Equilibrage of the load (iteration No " << iterEquilibrage << ")";
815
816 /* updating Deltas on the domain description interfaces on the master */
817 MAJDeltaGlobal(InfoProc, Maillage, deltaMin); // e.g. GetDeltaNoeuds
818
819 // calculating a deltaMin based on local transfers
820 double deltaAjuste = CalculDeltaMin(Maillage, deltaMin, iterEquilibrage, NbMaxIterEquil);
821
822 /* marking the seen (or empty) domains */
823 FiltreDomaine = (int*)calloc((size_t)Maillage->NbDomainesMax, sizeof(int));
824 CHECK_IF_NOT_NULL(FiltreDomaine);
825
826 // for empty domains
827 for (iDom = 0; iDom < Maillage->NbDomainesMax; iDom++)
828 if (Maillage->ListeDomaines[iDom].NbElements == 0)
829 FiltreDomaine[iDom] = marqueDomVu;
830
831 // loop while we find a domain to transfer from
832 do {
833
834 /* searching for the most loaded of the remaining domains */
835 indDomCharge = -1;
836 poidsMax = 0;
837
838 for (iDom = 0; iDom < Maillage->NbDomainesMax; iDom++)
839 if (FiltreDomaine[iDom] == marqueDomNonVu && Maillage->ListeDomaines[iDom].Poids > poidsMax) {
840 poidsMax = Maillage->ListeDomaines[iDom].Poids;
841 indDomCharge = iDom;
842 }
843
844#ifdef ARCANE_DEBUG
845 info() << "indDomCharge = " << indDomCharge << "; poidsMax = " << poidsMax;
846#endif
847
848 if (indDomCharge != -1) {
849 /* we no longer want to find it */
850 FiltreDomaine[indDomCharge] = marqueDomVu;
851
852 /* choosing 2 domains to perform the interface movement between the 2 */
853
854 /* for this loaded domain, we look at which other domain there might be a node transfer */
855 for (int i = 0; i < Maillage->ListeDomaines[indDomCharge].NbVoisins; i++) {
856 indDomVois = Maillage->ListeDomaines[indDomCharge].ListeVoisins[i].NoDomVois;
857
858 /* we limit ourselves to transfers where DeltaNoeuds > deltaNoeudsMin */
859 if (Maillage->ListeDomaines[indDomCharge].ListeVoisins[i].Delta > deltaAjuste) {
860#if defined(ARCANE_DEBUG) || defined(DEBUG_PARTITIONER)
861 info() << " Balancing (" << iterEquilibrage << ") for the pair indDomCharge = " << indDomCharge << "; indDomVois = " << indDomVois
862 << "; Delta = " << Maillage->ListeDomaines[indDomCharge].ListeVoisins[i].Delta;
863#endif
864
865 /* We diffuse the information to all processors */
866 PackEquil(InfoProc, indDomCharge, indDomVois, Maillage->ListeDomaines[indDomCharge].ListeVoisins[i].Delta,
867 TabTMP, TailleTMP, InfoProc->Split_Comm);
868
869 TabTMP = DiffuseMessage(InfoProc, 0, TabTMP, TailleTMP);
870
871 // Change the mark for each call (which allows the nodes to be released)
872 marqueVu += 1;
873
874 // Balancing between 2 domains
875 Equil2Dom(MasqueDesNoeuds, MasqueDesElements, marqueVu, marqueNonVu,
876 InfoProc, Domaine, Maillage, indDomCharge, indDomVois,
877 Maillage->ListeDomaines[indDomCharge].ListeVoisins[i].Delta);
878 NbAppelsAEquil2Dom += 1;
879
880 } /* end if Delta > deltaAjuste */
881 } /* end for i<NbVoisins */
882
883 } // end if indDomCharge != -1
884 } while (indDomCharge != -1);
885
886 indDomVois = -1; /* to inform that we are stopping, indDomCharge == -1 and indDomVois == -1 */
887 double DeltaNul = 0.0;
888 PackEquil(InfoProc, indDomCharge, indDomVois, DeltaNul, TabTMP, TailleTMP, InfoProc->Split_Comm);
889
890 TabTMP = DiffuseMessage(InfoProc, 0, TabTMP, TailleTMP);
891
892 free((void*)FiltreDomaine);
893 FiltreDomaine = NULL;
894
895#ifdef ARCANE_DEBUG
896 info() << " NbAppelsAEquil2Dom = " << NbAppelsAEquil2Dom;
897#endif
898
899 } /* end if me == 0 */
900 else {
901 double Delta;
902
903 do {
904 TabTMP = DiffuseMessage(InfoProc, 0, TabTMP, TailleTMP);
905 UnpackEquil(TabTMP, TailleTMP, InfoProc->Split_Comm, &indDomCharge, &indDomVois, &Delta);
906
907 if (indDomCharge != -1) {
908 // Change the mark for each call
909 marqueVu += 1;
910
911 // Balancing between 2 domains
912 Equil2Dom(MasqueDesNoeuds, MasqueDesElements, marqueVu, marqueNonVu,
913 InfoProc, Domaine, Maillage, indDomCharge, indDomVois, Delta);
914 NbAppelsAEquil2Dom += 1;
915 }
916
917 } while (indDomCharge != -1);
918
919 } /* end else if me == 0 */
920
921 // Synchronization in the case where there have been modifications
922 if (NbAppelsAEquil2Dom) {
923 // Release of nodes in the interfaces
924 LibereDomaine(Domaine);
925
926#ifdef ARCANE_DEBUG
927 info() << "cells_new_owner.synchronize() et changeOwnersFromCells()";
928#endif
929 // We only perform synchronization for a single series of calls to Equil2Dom
930 VariableItemInt32& cells_new_owner = mesh->itemsNewOwner(IK_Cell);
931 cells_new_owner.synchronize();
933 // Performs the effective transfer of data from one proc to another, without data compaction
934 bool compact = mesh->properties()->getBool("compact");
935 mesh->properties()->setBool("compact", false);
936 mesh->exchangeItems();
937 mesh->properties()->setBool("compact", compact);
938
939 // Domain Update
940 MAJDomaine(Domaine);
941
942 /* We update the Maillage->ListeDomaines structure */
943 MAJMaillageMaitre(InfoProc, Domaine, Maillage);
944 } // end if NbAppelsAEquil2Dom
945
946 free((void*)MasqueDesNoeuds);
947 MasqueDesNoeuds = NULL;
948 free((void*)MasqueDesElements);
949 MasqueDesElements = NULL;
950
951 AfficheEquilMaillage(Maillage);
952
953 // Makes the domains connected as much as possible according to a tolerance
954 // (we accept non-connected parts provided their size is > tol*average_size)
955 marqueVu += 1;
956 ConnexifieDomaine(InfoProc, Domaine, Maillage, tolConnexite);
957
958 AfficheEquilMaillage(Maillage);
959
960 } /* end while (iterEquilibrage<NbMaxIterEquil && NbAppelsAEquil2Dom!=0) */
961
962 free(TabTMP);
963 TabTMP = nullptr;
964
965 debug() << " number of iterations for balancing = " << iterEquilibrage << " / " << NbMaxIterEquil << " max ";
966 debug() << " = we are exiting SplitSDMeshPartitioner::Equilibrage";
967 debug() << " -------------------------------------";
968}
969
970/*---------------------------------------------------------------------------*/
971/*---------------------------------------------------------------------------*/
972
973void SplitSDMeshPartitioner::
974Equil2Dom(int* MasqueDesNoeuds, int* MasqueDesElements, int marqueVu, int marqueNonVu,
975 StrucInfoProc* InfoProc, StructureBlocEtendu* Domaine, StrucMaillage* Maillage,
976 int indDomCharge, int indDomVois, double Delta)
977{
978 ARCANE_UNUSED(Maillage);
979
980 debug() << " we are entering Equil2Dom (indDomCharge:" << indDomCharge << ", indDomVois:" << indDomVois << ", Delta:" << Delta;
981
982 // array of elements selected to be moved
984
985 if (InfoProc->me == indDomCharge) {
986 int iIntf = 0;
987 /* Does the interface between the two domains still exist? */
988 for (iIntf = 0;
989 iIntf < Domaine->NbIntf && Domaine->Intf[iIntf].NoDomVois != indDomVois;
990 iIntf++) {
991 }
992
993 if (iIntf == Domaine->NbIntf) {
994#if defined(ARCANE_DEBUG) || defined(DEBUG_PARTITIONER)
995 pinfo() << "### the interface has disappeared ### between " << indDomCharge << " and " << indDomVois;
996#endif
997 }
998 else {
999 // selection of elements by a frontal traversal from the interface between the 2 sub-domains.
1000 SelectElements(MasqueDesNoeuds, MasqueDesElements,
1001 marqueVu, marqueNonVu,
1002 InfoProc, Domaine, Delta, indDomVois, ListeElements);
1003 }
1004
1005 // marking for arcane data transfer
1006 IPrimaryMesh* mesh = this->mesh()->toPrimaryMesh();
1007 VariableItemInt32& cells_new_owner = mesh->itemsNewOwner(IK_Cell);
1008
1009 for (int i = 0; i < ListeElements.size(); i++) {
1010 const Cell item = ListeElements[i];
1011 cells_new_owner[item] = indDomVois;
1012 }
1013
1014 } // end if me == indDomCharge
1015#ifdef ARCANE_DEBUG
1016 else {
1017 info() << "SelectElements and other operations on processors " << indDomCharge << " and " << indDomVois;
1018 }
1019
1020 info() << " we are exiting Equil2Dom";
1021#endif
1022}
1023/*---------------------------------------------------------------------------*/
1024/*---------------------------------------------------------------------------*/
1025void SplitSDMeshPartitioner::
1026SelectElements(int* MasqueDesNoeuds, int* MasqueDesElements, int marqueVu, int marqueNonVu,
1027 StrucInfoProc* InfoProc, StructureBlocEtendu* Domaine,
1028 double Delta, int indDomVois, Arcane::Array<Arcane::Cell>& ListeElements)
1029{
1030#ifdef ARCANE_DEBUG
1031 info() << "SplitSDMeshPartitioner::SelectElements(Domaine, Delta = " << Delta << ", indDomVois = " << indDomVois << ")";
1032 info() << " Domaine->NbElements = " << Domaine->NbElements;
1033 info() << " Domaine->PoidsDom = " << Domaine->PoidsDom;
1034#endif
1035
1036 if (Delta <= 0.0) {
1037 perror() << "Delta <= 0 !!!";
1038 }
1039
1040 IMesh* mesh = this->mesh();
1041
1042 if (Delta >= Domaine->PoidsDom) {
1043#ifdef ARCANE_DEBUG
1044 pinfo() << " All the domain is selected on domain " << subDomain()->subDomainId()
1045 << ", with SelectElements, PoidsDom = " << Domaine->PoidsDom
1046 << ", Delta = " << Delta;
1047#endif
1048 // case where the entire domain is requested
1049 // this processor will end up empty! unless there is a transfer from another proc that compensates for the loss
1050 CellGroup own_cells = mesh->ownCells();
1051 ENUMERATE_CELL (i_item, own_cells) {
1052 const Cell item = *i_item;
1053 //MasqueDesElements[item.localId()] = marqueVu;
1054 ListeElements.add(item);
1055 }
1056 }
1057 else {
1058 // case where a subset must be selected
1059
1060 int iIntf; /* interface index for neighbor indDomVois */
1061 int NbFrontsMax;
1062 int NbFronts;
1063 int* IndFrontsNoeuds;
1064 int* IndFrontsElements;
1065
1066 for (iIntf = 0; iIntf < Domaine->NbIntf && Domaine->Intf[iIntf].NoDomVois != indDomVois; iIntf++) {
1067 }
1068
1069 if (iIntf == Domaine->NbIntf) {
1070 pfatal() << " SelectElements cannot find the interface among the neighbors !!!";
1071 }
1072
1073 NbFrontsMax = Domaine->NbElements / 2;
1074
1075 /* nodes taken in the fronts */
1077
1078 /* elements taken in the fronts */
1079 Arcane::Array<Arcane::Cell>& FrontsElements(ListeElements);
1080
1081 IndFrontsNoeuds = (int*)malloc((size_t)(NbFrontsMax + 1) * sizeof(int));
1082 CHECK_IF_NOT_NULL(IndFrontsNoeuds);
1083
1084 IndFrontsElements = (int*)malloc((size_t)(NbFrontsMax + 1) * sizeof(int));
1085 CHECK_IF_NOT_NULL(IndFrontsElements);
1086
1087 /* starting front for the traversal */
1088 NbFronts = 1;
1089
1090 /* we use the list of nodes in the interface as the starting front */
1091 for (int i = 0; i < Domaine->Intf[iIntf].ListeNoeuds.size(); i++)
1092 FrontsNoeuds.add(Domaine->Intf[iIntf].ListeNoeuds[i]);
1093
1094 IndFrontsNoeuds[0] = 0;
1095 IndFrontsNoeuds[1] = Domaine->Intf[iIntf].ListeNoeuds.size();
1096 IndFrontsElements[0] = 0;
1097 IndFrontsElements[1] = 0;
1098
1099 // we mark the phantom cells as already seen
1100 int me = subDomain()->subDomainId();
1101 CellGroup all_cells = mesh->allCells(); // elements on this processor (including phantom cells)
1102 ENUMERATE_CELL (i_item, all_cells) {
1103 const Cell cell = *i_item;
1104 if (cell.owner() != me)
1105 MasqueDesElements[cell.localId()] = marqueVu;
1106 }
1107
1108 // we mark the already selected elements
1109 for (int i = 0; i < ListeElements.size(); i++) {
1110 const Cell cell = ListeElements[i];
1111 MasqueDesElements[cell.localId()] = marqueVu;
1112 }
1113
1114 int retPF;
1115 // Frontal Traversal for a requested Delta weight
1116 retPF = ParcoursFrontalDelta(MasqueDesNoeuds, MasqueDesElements,
1117 marqueVu, marqueNonVu,
1118 Delta,
1119 &NbFronts, NbFrontsMax,
1120 FrontsNoeuds, IndFrontsNoeuds,
1121 FrontsElements, IndFrontsElements);
1122
1123 /* the last front is an incomplete front, we concatenate it to the second to last for smoothing */
1124 if (NbFronts > 1) {
1125 IndFrontsNoeuds[NbFronts - 1] = IndFrontsNoeuds[NbFronts];
1126 IndFrontsElements[NbFronts - 1] = IndFrontsElements[NbFronts];
1127 NbFronts -= 1;
1128 }
1129
1130 /* we perform front smoothing in the case where we haven't selected the entire domain
1131 and the Frontal Traversal proceeded correctly (is not blocked) */
1132 if (FrontsNoeuds.size() < Domaine->NbElements && retPF == 0)
1133 LissageDuFront(MasqueDesNoeuds, MasqueDesElements,
1134 marqueVu, marqueNonVu,
1135 NbFronts,
1136 FrontsNoeuds, IndFrontsNoeuds,
1137 FrontsElements, IndFrontsElements);
1138
1139 free((void*)IndFrontsNoeuds);
1140 IndFrontsNoeuds = NULL;
1141 free((void*)IndFrontsElements);
1142 IndFrontsElements = NULL;
1143 }
1144
1145 info() << " exiting: ListeElements.size() = " << ListeElements.size();
1146}
1147/*---------------------------------------------------------------------------*/
1148/*---------------------------------------------------------------------------*/
1149int SplitSDMeshPartitioner::
1150ParcoursFrontalDelta(int* MasqueDesNoeuds, int* MasqueDesElements,
1151 int marqueVu, int marqueNonVu,
1152 double Delta,
1153 int* pNbFronts, int NbFrontsMax,
1154 Arcane::Array<Arcane::Node>& FrontsNoeuds, int* IndFrontsNoeuds,
1155 Arcane::Array<Arcane::Cell>& FrontsElements, int* IndFrontsElements)
1156{
1157#ifdef ARCANE_DEBUG
1158 info() << " = we are entering FrontalTraversal : (NbFronts = " << *pNbFronts << ", NbFrontsMax = " << NbFrontsMax << ")";
1159 info() << " FrontsNoeuds.size() = " << FrontsNoeuds.size();
1160 info() << " FrontsElements.size() = " << FrontsElements.size();
1161#endif
1162
1163 int IndFn = 0; /* indices on the [Ind]FrontsNoeuds arrays */
1164 int IndFe = 0; /* indices on the [Ind]FrontsElements arrays */
1165 double PoidsActuel = 0.0;
1166 bool bloque = false;
1167
1168 /* we mark the nodes and elements already in the fronts (to avoid duplicates) */
1169 for (IndFn = 0; IndFn < IndFrontsNoeuds[*pNbFronts]; IndFn++) {
1170 MasqueDesNoeuds[FrontsNoeuds[IndFn].localId()] = marqueVu;
1171 }
1172
1173 for (IndFe = 0; IndFe < IndFrontsElements[*pNbFronts]; IndFe++) {
1174 MasqueDesElements[FrontsElements[IndFe].localId()] = marqueVu;
1175 }
1176
1177 /* we put the nodes linked to the elements of this same front into the initial front
1178 if it hasn't been done */
1179 if (IndFrontsElements[*pNbFronts] > 0 && IndFrontsNoeuds[*pNbFronts] == 0) {
1180 //info()<<" Initialization from "<<IndFrontsElements[*pNbFronts]<<" elements";
1181 for (int ielm = 0; ielm < IndFrontsElements[*pNbFronts]; ielm++) {
1182 const Cell cell = FrontsElements[ielm];
1183 PoidsActuel += m_poids_aux_mailles[cell];
1184
1185 for (int iepn = 0; iepn < cell.nbNode(); iepn++) {
1186 const Node nodeVois = cell.node(iepn); // neighbor node // int NeighborNode
1187
1188 /* for each new node, we insert it into the new front*/
1189 if (MasqueDesNoeuds[nodeVois.localId()] == marqueNonVu) {
1190 FrontsNoeuds.add(nodeVois);
1191 IndFn += 1;
1192 MasqueDesNoeuds[nodeVois.localId()] = marqueVu;
1193 }
1194 } /* end for iepn */
1195 }
1196 /* we set the nodes in the last existing front */
1197 IndFrontsNoeuds[*pNbFronts] = IndFn;
1198 }
1199
1200 /*----------------------------------------------------------------*/
1201 /* loop until we have seen enough nodes or fronts */
1202 /*----------------------------------------------------------------*/
1203 do {
1204 /* for each node in the previous front, we look at the elements it possesses */
1205 for (int in = IndFrontsNoeuds[*pNbFronts - 1];
1206 in < IndFrontsNoeuds[*pNbFronts] && PoidsActuel < Delta;
1207 in++) {
1208 const Node node = FrontsNoeuds[in]; // node of the previous front // int Node
1209
1210 /* we avoid stopping without having all linked elements,
1211 we risk having an element connected by only one node! */
1212 for (int inpe = 0; inpe < node.nbCell(); inpe++) {
1213 const Cell cell = node.cell(inpe); // element linked to this node //int Element
1214
1215 /* for this new element, we insert it into the new front
1216 and look at the nodes it possesses */
1217 if (MasqueDesElements[cell.localId()] == marqueNonVu) {
1218 FrontsElements.add(cell);
1219 IndFe += 1;
1220 MasqueDesElements[cell.localId()] = marqueVu;
1221
1222 PoidsActuel += m_poids_aux_mailles[cell];
1223
1224 for (int iepn = 0; iepn < cell.nbNode(); iepn++) {
1225 const Node nodeVois = cell.node(iepn); // neighbor node // int NeighborNode
1226
1227 /* for each new node, we insert it into the new front*/
1228 if (MasqueDesNoeuds[nodeVois.localId()] == marqueNonVu) {
1229 FrontsNoeuds.add(nodeVois);
1230 IndFn += 1;
1231 MasqueDesNoeuds[nodeVois.localId()] = marqueVu;
1232 } /* end if MasqueDesNoeuds == marqueNonVu */
1233 } /* end for iepn */
1234 } /* end if MasqueDesElements == marqueNonVu */
1235 } /* end for inpe */
1236 } /* end for in */
1237
1238 /* test the case where it would get blocked */
1239 if (IndFrontsNoeuds[*pNbFronts - 1] == IndFrontsNoeuds[*pNbFronts]) {
1240 bloque = true;
1241 }
1242
1243 *pNbFronts += 1;
1244 IndFrontsNoeuds[*pNbFronts] = IndFn;
1245 IndFrontsElements[*pNbFronts] = IndFe;
1246
1247 } while (*pNbFronts < NbFrontsMax && PoidsActuel < Delta && !bloque);
1248
1249#ifdef ARCANE_DEBUG
1250 info() << " NbFronts = " << *pNbFronts;
1251 info() << " Delta = " << Delta;
1252 info() << " PoidsActuel = " << PoidsActuel;
1253 info() << " NbNoeuds = " << IndFrontsNoeuds[*pNbFronts];
1254 info() << " NbElements = " << IndFrontsElements[*pNbFronts];
1255 info() << " blocked = " << (bloque ? "TRUE" : "FALSE");
1256
1257 if (!(*pNbFronts < NbFrontsMax)) {
1258 info() << " = we stop after obtaining the maximum number of fronts " << NbFrontsMax;
1259 }
1260 else if (!(PoidsActuel < Delta)) {
1261 info() << " = we stop after obtaining the desired weight " << PoidsActuel;
1262 }
1263 else if (bloque) {
1264 info() << " = we are blocked (not connected ?) =";
1265 }
1266 else {
1267 info() << " = we stop because we have seen everything =";
1268 }
1269 info() << " = we are exiting FrontalTraversal . =";
1270#endif
1271
1272 return ((bloque) ? 1 : 0);
1273}
1274/*---------------------------------------------------------------------------*/
1275/*---------------------------------------------------------------------------*/
1276
1277void SplitSDMeshPartitioner::
1278LissageDuFront(int* MasqueDesNoeuds, int* MasqueDesElements,
1279 int marqueVu, int marqueNonVu,
1280 int NbFronts,
1281 Arcane::Array<Arcane::Node>& FrontsNoeuds, int* IndFrontsNoeuds,
1282 Arcane::Array<Arcane::Cell>& FrontsElements, int* IndFrontsElements)
1283{
1284 ARCANE_UNUSED(IndFrontsElements);
1285
1286 debug() << " we are entering LissageDuFront : NbFronts = " << NbFronts;
1287
1288 int NbElementsAjoutes = 0;
1289
1290 Arcane::UniqueArray<Arcane::Cell> ElementsALiberer;
1291
1292 /* Retrieval of elements taken in the last node front */
1293 for (int IndFn = IndFrontsNoeuds[NbFronts - 1]; IndFn < IndFrontsNoeuds[NbFronts]; IndFn++) {
1294 const Node node = FrontsNoeuds[IndFn]; // node of the previous front // int Node
1295
1296 for (int inpe = 0; inpe < node.nbCell(); inpe++) {
1297 const Cell cell = node.cell(inpe); //element linked to this node //int Element
1298
1299 /* if this element is unseen */
1300 if (MasqueDesElements[cell.localId()] == marqueNonVu) {
1301 /* we check if all nodes of this element are marked as seen */
1302 int iepn;
1303 for (iepn = 0; iepn < cell.nbNode() && MasqueDesNoeuds[cell.node(iepn).localId()] == marqueVu; iepn++) {
1304 }
1305 /* case where all nodes are marked */
1306 if (iepn == cell.nbNode()) {
1307 /* we add the element to the last front */
1308
1309 FrontsElements.add(cell);
1310 NbElementsAjoutes += 1;
1311 MasqueDesElements[cell.localId()] = marqueVu;
1312 }
1313 else {
1314 /* we mark the element */
1315 MasqueDesElements[cell.localId()] = marqueVu; // so as not to pick it up immediately
1316 ElementsALiberer.add(cell);
1317 }
1318
1319 } /* end if Element unseen */
1320 } /* end for inpe ... */
1321 } /* end for IndFn ... */
1322
1323 // we reset those we marked back to unseen just so we only see them once
1324 for (int i = 0; i < ElementsALiberer.size(); i++)
1325 MasqueDesElements[ElementsALiberer[i].localId()] = marqueNonVu;
1326
1327#ifdef ARCANE_DEBUG
1328 info() << " we exit LissageDuFront (" << NbElementsAjoutes << " elements added)";
1329#endif
1330}
1331/*---------------------------------------------------------------------------*/
1332/*---------------------------------------------------------------------------*/
1333void SplitSDMeshPartitioner::
1334ConnexifieDomaine(StrucInfoProc* InfoProc, StructureBlocEtendu* Domaine, StrucMaillage* Maillage,
1335 double tolConnexite)
1336{
1337#ifdef ARCANE_DEBUG
1338 info() << " entering ConnexifieDomaine, tolConnexite = " << tolConnexite;
1339#endif
1340
1341 int* MasqueDesNoeuds = GetMasqueDesNoeuds(InfoProc);
1342 int* MasqueDesElements = GetMasqueDesElements(InfoProc);
1343 int marqueVu = 1;
1344 int marqueNonVu = 0;
1345
1346 // Maillage->NbElements is only known on the master!
1347 // double tailleMoy = (double)Maillage->NbElements / (double)Maillage->NbDomainesMax;
1348 double tailleMoy = (double)Domaine->NbElements;
1349
1350 // we mark the phantom cells as already seen
1351 int me = InfoProc->me;
1352 IPrimaryMesh* mesh = this->mesh()->toPrimaryMesh();
1353 CellGroup all_cells = mesh->allCells(); // elements on this processor (including phantom cells)
1354
1355 ENUMERATE_CELL (i_item, all_cells) {
1356 Cell cell = *i_item;
1357 if (cell.owner() != me)
1358 MasqueDesElements[cell.localId()] = marqueVu;
1359 } // end ENUMERATE_CELL
1360
1361 int NbElementsVus = 0;
1362 int NbElementsAVoir = Domaine->NbElements;
1363#ifdef ARCANE_DEBUG
1364 info() << " NbElementsAVoir = " << NbElementsAVoir;
1365#endif
1366
1367 int NbFrontsMax;
1368 int NbFronts;
1369 int* IndFrontsNoeuds;
1370 int* IndFrontsElements;
1371
1372 NbFrontsMax = Domaine->NbElements / 2;
1373
1374 /* nodes taken into the fronts */
1376
1377 /* elements taken into the fronts */
1379
1380 IndFrontsNoeuds = (int*)malloc((size_t)(NbFrontsMax + 1) * sizeof(int));
1381 CHECK_IF_NOT_NULL(IndFrontsNoeuds);
1382
1383 IndFrontsElements = (int*)malloc((size_t)(NbFrontsMax + 1) * sizeof(int));
1384 CHECK_IF_NOT_NULL(IndFrontsElements);
1385
1386 /* we loop to see all elements of the domain */
1387 while (NbElementsVus < NbElementsAVoir) {
1388
1389 FrontsNoeuds.clear();
1390 Arcane::SharedArray<Arcane::Cell> FrontsElements;
1391
1392 /* search for an unseen element (it is put in the first front) */
1393 //TODO to optimize?
1394 bool trouve = false;
1395 ENUMERATE_CELL (i_item, all_cells) {
1396 const Cell cell = *i_item;
1397 if (!trouve && MasqueDesElements[cell.localId()] == marqueNonVu) {
1398 FrontsElements.add(cell);
1399 trouve = true;
1400 }
1401 }
1402 if (!trouve) {
1403 pfatal() << "ConnexifieDomaine is blocked while searching for a starting element";
1404 }
1405
1406 NbFronts = 1;
1407 IndFrontsNoeuds[0] = 0;
1408 IndFrontsNoeuds[1] = 0;
1409 IndFrontsElements[0] = 0;
1410 IndFrontsElements[1] = 1;
1411
1412 /* search for the associated connected set of unseen elements */
1413 ParcoursFrontalDelta(MasqueDesNoeuds, MasqueDesElements,
1414 marqueVu, marqueNonVu,
1415 Domaine->PoidsDom,
1416 &NbFronts, NbFrontsMax,
1417 FrontsNoeuds, IndFrontsNoeuds,
1418 FrontsElements, IndFrontsElements);
1419
1420 /* we set aside this set of elements */
1421 ListeFrontsElements.add(FrontsElements);
1422
1423 NbElementsVus += FrontsElements.size();
1424#ifdef ARCANE_DEBUG
1425 info() << " NbElementsVus+=" << FrontsElements.size();
1426#endif
1427
1428 } /* end while (NbElementsVus < NbElementsAVoir) */
1429
1430 // number of transferred components
1431 int nbCCTransf = 0;
1432
1433 /* if there is more than one connected component */
1434 if (ListeFrontsElements.size() > 1) {
1435
1436#ifdef ARCANE_DEBUG
1437 info() << " NbComposantesConnexes = " << ListeFrontsElements.size();
1438#endif
1439
1440 // analysis of the number of domains below the threshold
1441 int nbDomEnDessous = 0;
1442 int plusGrosseCC = 0; // largest connected component
1443
1444 int seuil = (int)(tailleMoy * tolConnexite);
1445#ifdef ARCANE_DEBUG
1446 info() << " threshold = " << seuil;
1447#endif
1448
1449 for (int i = 0; i < ListeFrontsElements.size(); i++) {
1450 Arcane::Array<Arcane::Cell>& FrontsElements = ListeFrontsElements[i];
1451 plusGrosseCC = MAX(plusGrosseCC, FrontsElements.size());
1452 if (FrontsElements.size() < seuil)
1453 nbDomEnDessous += 1;
1454 }
1455
1456#ifdef ARCANE_DEBUG
1457 info() << " nbDomEnDessous = " << nbDomEnDessous;
1458#endif
1459
1460 // to avoid taking all components
1461 if (nbDomEnDessous == ListeFrontsElements.size()) {
1462#ifdef ARCANE_DEBUG
1463 info() << " threshold lowered to " << plusGrosseCC;
1464#endif
1465 seuil = plusGrosseCC;
1466 }
1467
1468 // for each component smaller than the threshold, we transfer it to a neighbor
1469 VariableItemInt32& cells_new_owner = mesh->itemsNewOwner(IK_Cell);
1470 for (int i = 0; i < ListeFrontsElements.size(); i++) {
1471 Arcane::Array<Arcane::Cell>& FrontsElements = ListeFrontsElements[i];
1472 if (FrontsElements.size() < seuil) {
1473 nbCCTransf += 1;
1474
1475 // search for the neighboring subdomain having the maximum shared face
1476 int indDomVois = getDomVoisMaxFace(FrontsElements, me);
1477
1478 // we assign the cells to this neighbor
1479 for (int j = 0; j < FrontsElements.size(); j++) {
1480 const Cell item = FrontsElements[j];
1481 cells_new_owner[item] = indDomVois;
1482 }
1483
1484 } // if FrontsElements.size()<seuil
1485 } // end for i<ListeFrontsElements.size()
1486#ifdef ARCANE_DEBUG
1487 info() << " Number of transferred components: " << nbCCTransf;
1488#endif
1489
1490 } // end if ListeFrontsElements.size() > 1
1491
1492 /* memory deallocations */
1493 free((void*)IndFrontsNoeuds);
1494 IndFrontsNoeuds = NULL;
1495 free((void*)IndFrontsElements);
1496 IndFrontsElements = NULL;
1497
1498 free((void*)MasqueDesNoeuds);
1499 MasqueDesNoeuds = NULL;
1500 free((void*)MasqueDesElements);
1501 MasqueDesElements = NULL;
1502
1503 // we only synchronize if one of the subdomains made a modification
1504 // sum up nbCCTransf across all procs
1505
1506 int nbCCTransfMin = 0;
1507 int nbCCTransfMax = 0;
1508 int nbCCTransfSum = 0;
1509 Int32 procMin = 0;
1510 Int32 procMax = 0;
1511
1512 ISubDomain* sd = subDomain();
1513 IParallelMng* pm = sd->parallelMng();
1514
1515 pm->computeMinMaxSum(nbCCTransf, nbCCTransfMin, nbCCTransfMax, nbCCTransfSum, procMin, procMax);
1516
1517 bool synchroNecessaire = (nbCCTransfSum > 0);
1518#if defined(ARCANE_DEBUG) || defined(DEBUG_PARTITIONER)
1519 info() << " ConnexifieDomaine: nbCCTransfSum = " << nbCCTransfSum;
1520#endif
1521
1522 if (synchroNecessaire) {
1523#ifdef ARCANE_DEBUG
1524 info() << " we perform the synchronization";
1525#endif
1526 // we only synchronize for a single series of calls to Equil2Dom
1527 VariableItemInt32& cells_new_owner = mesh->itemsNewOwner(IK_Cell);
1528 cells_new_owner.synchronize();
1530 // performs the effective transfer of data from one proc to another, without data compaction
1531 bool compact = mesh->properties()->getBool("compact");
1532 mesh->properties()->setBool("compact", false);
1533 mesh->exchangeItems();
1534 mesh->properties()->setBool("compact", compact);
1535
1536 // Update Domain
1537 MAJDomaine(Domaine);
1538
1539 /* we update the Maillage->ListeDomaines structure */
1540 MAJMaillageMaitre(InfoProc, Domaine, Maillage);
1541 }
1542#ifdef ARCANE_DEBUG
1543 info() << " we exit ConnexifieDomaine";
1544#endif
1545}
1546/*---------------------------------------------------------------------------*/
1547/*---------------------------------------------------------------------------*/
1548int SplitSDMeshPartitioner::
1549getDomVoisMaxFace(Arcane::Array<Arcane::Cell>& ListeElements, int me)
1550{
1551 int indDomVois = -1;
1552
1553 // number of faces per neighboring subdomain
1554 std::map<int, int> indVois_nbFace;
1555
1556 for (int i = 0; i < ListeElements.size(); i++) {
1557 const Cell cell = ListeElements[i];
1558
1559 for (int j = 0; j < cell.nbFace(); j++) {
1560 const Face face = cell.face(j);
1561
1562 if (!face.isSubDomainBoundary()) {
1563 int id1 = face.backCell().owner();
1564 int id2 = face.frontCell().owner();
1565
1566 if (id1 == me && id2 != me)
1567 indVois_nbFace[id2] += 1;
1568 else if (id1 != me && id2 == me)
1569 indVois_nbFace[id1] += 1;
1570 }
1571 }
1572 }
1573
1574 // search for the largest number of faces
1575 int maxNbFaces = 0;
1576 std::map<int, int>::iterator iter;
1577 for (iter = indVois_nbFace.begin();
1578 iter != indVois_nbFace.end();
1579 ++iter) {
1580 int nbFaces = (*iter).second;
1581 if (nbFaces > maxNbFaces) {
1582 maxNbFaces = nbFaces;
1583 indDomVois = (*iter).first;
1584 }
1585 }
1586
1587 if (indDomVois == -1)
1588 pfatal() << "indDomVois always at -1 !!!";
1589
1590#ifdef ARCANE_DEBUG
1591 pinfo() << " getDomVoisMaxFace, me = " << me << ", ListeElements.size() = " << ListeElements.size()
1592 << ", indDomVois = " << indDomVois << ", maxNbFaces = " << maxNbFaces;
1593#endif
1594 return indDomVois;
1595}
1596/*---------------------------------------------------------------------------*/
1597/*---------------------------------------------------------------------------*/
1598int* SplitSDMeshPartitioner::
1599GetMasqueDesNoeuds(StrucInfoProc* InfoProc)
1600{
1601 int* MasqueDesNoeuds = NULL;
1602
1603 IMesh* mesh = this->mesh();
1604 // search for the largest id
1605 int maxNodeLocalId = 0;
1606
1607 NodeGroup all_nodes = mesh->allNodes();
1608 ENUMERATE_NODE (i_item, all_nodes) {
1609 const Node node = *i_item;
1610 maxNodeLocalId = MAX(maxNodeLocalId, node.localId());
1611 }
1612#ifdef ARCANE_DEBUG
1613 info() << "SplitSDMeshPartitioner::GetMasqueDesNoeuds(), maxNodeLocalId = " << maxNodeLocalId;
1614#endif
1615
1616 /* allocation and initialization to 0 of the mask */
1617 MasqueDesNoeuds = (int*)calloc((size_t)(maxNodeLocalId + 1), sizeof(int));
1618 CHECK_IF_NOT_NULL(MasqueDesNoeuds);
1619
1620 return MasqueDesNoeuds;
1621}
1622/*---------------------------------------------------------------------------*/
1623/*---------------------------------------------------------------------------*/
1624int* SplitSDMeshPartitioner::
1625GetMasqueDesElements(StrucInfoProc* InfoProc)
1626{
1627 int* MasqueDesElements = NULL;
1628
1629 IMesh* mesh = this->mesh();
1630 // search for the largest id
1631 int maxCellLocalId = 0;
1632
1633 CellGroup all_cells = mesh->allCells(); // elements on this processor (including phantom cells)
1634 ENUMERATE_CELL (i_item, all_cells) {
1635 const Cell cell = *i_item;
1636 maxCellLocalId = MAX(maxCellLocalId, cell.localId());
1637 }
1638
1639#ifdef ARCANE_DEBUG
1640 info() << "SplitSDMeshPartitioner::GetMasqueDesElements(), maxCellLocalId = " << maxCellLocalId;
1641#endif
1642
1643 /* allocation and initialization to 0 of the mask */
1644 MasqueDesElements = (int*)calloc((size_t)(maxCellLocalId + 1), sizeof(int));
1645 CHECK_IF_NOT_NULL(MasqueDesElements);
1646
1647 return MasqueDesElements;
1648}
1649/*---------------------------------------------------------------------------*/
1650/*---------------------------------------------------------------------------*/
1651
1652void SplitSDMeshPartitioner::
1653LibereInfoProc(StrucInfoProc*& InfoProc)
1654{
1655 ARCANE_UNUSED(InfoProc);
1656}
1657
1658/*---------------------------------------------------------------------------*/
1659/*---------------------------------------------------------------------------*/
1660
1661void SplitSDMeshPartitioner::
1662LibereDomaine(StructureBlocEtendu*& Domaine)
1663{
1664#ifdef ARCANE_DEBUG
1665 info() << "LibereDomaine(...)";
1666#endif
1667
1668 if (Domaine->NbIntf != 0) {
1669 if (Domaine->Intf != NULL) {
1670 for (int i = 0; i < Domaine->NbIntf; i++)
1671 Domaine->Intf[i].ListeNoeuds.clear();
1672 delete[] Domaine->Intf;
1673 Domaine->Intf = NULL;
1674 }
1675 }
1676
1677 Domaine->NbIntf = 0;
1678 Domaine->NbElements = 0;
1679 Domaine->PoidsDom = 0.0;
1680}
1681/*---------------------------------------------------------------------------*/
1682/*---------------------------------------------------------------------------*/
1683void SplitSDMeshPartitioner::
1684LibereMaillage(StrucMaillage*& Maillage)
1685{
1686#ifdef ARCANE_DEBUG
1687 info() << "LibereMaillage(...)";
1688#endif
1689
1690 if (Maillage->NbElements != 0) {
1691 if (Maillage->ListeDomaines != NULL) {
1692 for (int i = 0; i < Maillage->NbDomainesMax; i++) {
1693 if (Maillage->ListeDomaines[i].ListeVoisins != NULL) {
1694 delete[] Maillage->ListeDomaines[i].ListeVoisins;
1695 Maillage->ListeDomaines[i].ListeVoisins = NULL;
1696 }
1697 }
1698 delete[] Maillage->ListeDomaines;
1699 Maillage->ListeDomaines = NULL;
1700 }
1701 }
1702 Maillage->NbElements = 0;
1703 Maillage->Poids = 0.0;
1704 Maillage->NbDomainesPleins = 0;
1705 Maillage->NbProcsVides = 0;
1706}
1707/*---------------------------------------------------------------------------*/
1708/*---------------------------------------------------------------------------*/
1709void SplitSDMeshPartitioner::
1710AfficheDomaine(int NbDom, StructureBlocEtendu* Domaine)
1711{
1712 int i;
1713 int idom;
1714
1715 for (idom = 0; idom < NbDom; idom++) {
1716 info() << " --------------------";
1717 info() << " --- Domaine (" << idom << ") ---";
1718 info() << " --------------------";
1719
1720 if (Domaine == NULL) {
1721 info() << " Domaine vide ! (pointeur NULL)";
1722 }
1723 else if (Domaine[idom].NbElements == 0) {
1724 info() << " Domaine vide ! (pas d'éléments)";
1725 }
1726 else {
1727 info() << " NbElements = " << Domaine[idom].NbElements;
1728 info() << " PoidsDom = " << Domaine[idom].PoidsDom;
1729 info() << " Interfaces (NbIntf = " << Domaine[idom].NbIntf << ") :";
1730 for (i = 0; i < Domaine[idom].NbIntf; i++) {
1731 info() << " (" << i << ") NoDomVois = " << Domaine[idom].Intf[i].NoDomVois
1732 << ", number of nodes " << Domaine[idom].Intf[i].ListeNoeuds.size();
1733 }
1734
1735 } /* end else if 'empty domain' */
1736 } /* end for idom */
1737}
1738/*---------------------------------------------------------------------------*/
1739/*---------------------------------------------------------------------------*/
1740void SplitSDMeshPartitioner::
1741AfficheMaillage(StrucMaillage* Maillage)
1742{
1743 info() << " ----------------";
1744 info() << " ----- Mesh -----";
1745 info() << " ----------------";
1746 if (Maillage == NULL) {
1747 info() << " Mesh structure is empty!";
1748 }
1749 else {
1750 info() << " NbElements (total) = " << Maillage->NbElements;
1751 info() << " Poids (total) = " << Maillage->Poids;
1752 info() << " NbDomainesMax = " << Maillage->NbDomainesMax;
1753 info() << " NbDomainesPleins = " << Maillage->NbDomainesPleins;
1754 info() << " NbProcsVides = " << Maillage->NbProcsVides;
1755
1756 if (Maillage->ListeDomaines == NULL) {
1757 info() << " Maillage.ListeDomaines == NULL";
1758 }
1759 else {
1760 AfficheListeDomaines(Maillage->ListeDomaines, Maillage->NbDomainesMax);
1761 }
1762
1763 } /* else if Maillage==NULL */
1764}
1765/*---------------------------------------------------------------------------*/
1766/*---------------------------------------------------------------------------*/
1767void SplitSDMeshPartitioner::
1768AfficheListeDomaines(StrucListeDomMail* ListeDomaines, int NbDomaines)
1769{
1770 info() << " ListeDomaines :";
1771 for (int i = 0; i < NbDomaines; i++) {
1772 info() << " (" << i << ") NbElements = " << ListeDomaines[i].NbElements << "; Weight = " << ListeDomaines[i].Poids;
1773 info() << " (" << i << ") NbVoisins = " << ListeDomaines[i].NbVoisins << "; ListeVoisins :";
1774 for (int j = 0; j < ListeDomaines[i].NbVoisins; j++) {
1775 info() << " (" << i << ") NoDomVois = " << ListeDomaines[i].ListeVoisins[j].NoDomVois
1776 << "; NbNoeudsInterface = " << ListeDomaines[i].ListeVoisins[j].NbNoeudsInterface
1777 << "; Delta = " << ListeDomaines[i].ListeVoisins[j].Delta;
1778 }
1779 }
1780}
1781/*---------------------------------------------------------------------------*/
1782/*---------------------------------------------------------------------------*/
1783void SplitSDMeshPartitioner::
1784AfficheEquilMaillage(StrucMaillage* Maillage)
1785{
1786 info() << " AfficheEquilMaillage(...)";
1787
1788 double poidsMin = 0.0;
1789 double poidsMax = 0.0;
1790
1791 if (Maillage->ListeDomaines != NULL) {
1792
1793 poidsMin = Maillage->ListeDomaines[0].Poids;
1794
1795 for (int i = 0; i < Maillage->NbDomainesMax; i++) {
1796 double poidsDom = Maillage->ListeDomaines[i].Poids;
1797
1798 if (poidsDom > poidsMax)
1799 poidsMax = poidsDom;
1800 if (poidsDom < poidsMin)
1801 poidsMin = poidsDom;
1802 }
1803
1804 info() << " INFO balancing / nodes : max : " << poidsMax << ", min : " << poidsMin
1805 << ", max/avg = " << poidsMax / (Maillage->Poids / (double)Maillage->NbDomainesMax);
1806 }
1807 else {
1808 info() << "AfficheEquilMaillage : Maillage->ListeDomaines == NULL";
1809 }
1810}
1811/*---------------------------------------------------------------------------*/
1812/*---------------------------------------------------------------------------*/
1833void* SplitSDMeshPartitioner::RecoitMessage(StrucInfoProc* InfoProc, int FromProc, int Tag, int* pTailleTMP)
1834{
1835 void* TabTMP;
1836 int ierror; /* error return on MPI lib */
1837 MPI_Status status; /* for MPI communication */
1838
1839 if (*pTailleTMP <= 0) {
1840 /* to retrieve information about the size of the arrays that will follow,
1841 wait for a message to arrive */
1842 ierror = MPI_Probe(FromProc,
1843 Tag,
1844 InfoProc->Split_Comm,
1845 &status);
1846
1847 if (ierror != MPI_SUCCESS) {
1848 InfoProc->m_service->pfatal() << "Problem on " << InfoProc->me << " communication from "
1849 << FromProc << ", during MPI_Probe";
1850 }
1851
1852 /* retrieving the size of the message | array */
1853 ierror = MPI_Get_count(&status,
1854 MPI_PACKED,
1855 pTailleTMP);
1856
1857 if (ierror != MPI_SUCCESS) {
1858 InfoProc->m_service->pfatal() << "Problem on " << InfoProc->me << " communication from "
1859 << FromProc << ", during MPI_Get_count";
1860 }
1861 } /* end if *pTailleTMP <= 0 */
1862
1863 /* allocation for the buffer array */
1864 if (*pTailleTMP > 0) {
1865 TabTMP = malloc((size_t)*pTailleTMP);
1866 CHECK_IF_NOT_NULL(TabTMP);
1867 }
1868 else
1869 TabTMP = NULL;
1870
1871 /* receiving the message */
1872 ierror = MPI_Recv(TabTMP,
1873 *pTailleTMP,
1874 MPI_PACKED,
1875 FromProc,
1876 Tag,
1877 InfoProc->Split_Comm,
1878 &status);
1879
1880 if (ierror != MPI_SUCCESS) {
1881 InfoProc->m_service->pfatal() << "Problem on " << InfoProc->me << " communication from "
1882 << FromProc << ", during MPI_Recv";
1883 }
1884
1885 return (TabTMP);
1886}
1887
1888/*---------------------------------------------------------------------------*/
1889/*---------------------------------------------------------------------------*/
1906void SplitSDMeshPartitioner::EnvoieMessage(StrucInfoProc* InfoProc, int ToProc, int Tag, void* TabTMP, int TailleTMP)
1907{
1908 int ierror; /* error return on MPI functions */
1909
1910 ierror = MPI_Send((void*)TabTMP,
1911 TailleTMP,
1912 MPI_PACKED,
1913 ToProc,
1914 Tag,
1915 InfoProc->Split_Comm);
1916
1917 if (ierror != MPI_SUCCESS) {
1918 InfoProc->m_service->pfatal() << "Problem on " << InfoProc->me << " communication to "
1919 << ToProc << ", during MPI_Send";
1920 }
1921}
1922
1923/*---------------------------------------------------------------------------*/
1924/*---------------------------------------------------------------------------*/
1925// /**
1926// Function responsible for sending an array with non-blocking communication.
1927
1928// {\em Note:} The array size is in bytes.
1929
1930// @memo Sending a non-blocking message.
1931// @param InfoProc (I) structure describing the processor on which the application runs.
1932// @param ToProc (I) destination computing node.
1933// @param Tag (I) tag to differentiate messages.
1934// @param TabTMP (I) array that is sent.
1935// @param TailleTMP (I) size of TabTMP (in bytes).
1936// @return (MPI_Request*) prequest: pointer to an MPI-specific structure for message management.
1937// @see
1938// @author Eric Brière de l'Isle, ONERA, DRIS/SRL
1939// @version Created December 1998
1940// */
1941// MPI_Request* EnvoieIMessage(StrucInfoProc* InfoProc, int ToProc, int Tag, void* TabTMP, int TailleTMP)
1942// {
1943// int ierror;
1944// MPI_Request *prequest;
1945
1946// prequest = (MPI_Request*) malloc(sizeof(MPI_Request));
1947// CHECK_IF_NOT_NULL(prequest);
1948
1949// ierror = MPI_Isend ((void *) TabTMP,
1950// TailleTMP,
1951// MPI_PACKED,
1952// ToProc,
1953// Tag,
1954// InfoProc->Split_Comm,
1955// prequest);
1956
1957// if (ierror != MPI_SUCCESS) {
1958// InfoProc->m_service->pfatal()<<"Problem on "<<InfoProc->me<<" communication to "
1959// <<ToProc<<", during MPI_Isend";
1960// }
1961
1962// return prequest;
1963
1964// }
1965
1966/*---------------------------------------------------------------------------*/
1967/*---------------------------------------------------------------------------*/
1984void* SplitSDMeshPartitioner::DiffuseMessage(StrucInfoProc* InfoProc, int FromProc, void* TabTMP, int TailleTMP)
1985{
1986 int ierror; /* error return on MPI functions */
1987
1988 if (TailleTMP <= 0) {
1989 InfoProc->m_service->pfatal() << "DiffuseMessage from " << InfoProc->me << ", it is necessary that the array size is known !!!\n";
1990 }
1991
1992 if (InfoProc->me != FromProc) {
1993 if (TabTMP == NULL) {
1994 TabTMP = malloc((size_t)TailleTMP);
1995 CHECK_IF_NOT_NULL(TabTMP);
1996 }
1997 } /* end if me != FromProc */
1998
1999 /* broadcasting the TabTMP array */
2000 ierror = MPI_Bcast(TabTMP,
2001 TailleTMP,
2002 MPI_PACKED,
2003 FromProc,
2004 InfoProc->Split_Comm);
2005
2006 if (ierror != MPI_SUCCESS) {
2007 InfoProc->m_service->pfatal() << "Problem on " << InfoProc->me << " from "
2008 << FromProc << ", during MPI_Bcast";
2009 }
2010
2011 return (TabTMP);
2012}
2013/*---------------------------------------------------------------------------*/
2014/*---------------------------------------------------------------------------*/
2025Integer SplitSDMeshPartitioner::
2026TailleDom(StructureBlocEtendu* Domaine)
2027{
2028 size_t s = (2 + 2 * Domaine->NbIntf) * sizeof(int) + sizeof(double);
2029 return arcaneCheckArraySize(s);
2030}
2031
2032/*---------------------------------------------------------------------------*/
2033/*---------------------------------------------------------------------------*/
2046void SplitSDMeshPartitioner::
2047PackDom(StrucInfoProc* InfoProc, StructureBlocEtendu* Domaine, void* TabTMP,
2048 int TailleTMP, MPI_Comm comm)
2049{
2050 int position = 0; // initialization to put into the array at the beginning
2051 int ier;
2052
2053 ier = MPI_Pack(&Domaine->NbElements, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2054 CHECK_MPI_PACK_ERR(ier);
2055
2056 ier = MPI_Pack(&Domaine->PoidsDom, 1, MPI_DOUBLE, TabTMP, TailleTMP, &position, comm);
2057 CHECK_MPI_PACK_ERR(ier);
2058
2059 ier = MPI_Pack(&Domaine->NbIntf, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2060 CHECK_MPI_PACK_ERR(ier);
2061
2062 for (int i = 0; i < Domaine->NbIntf; i++) {
2063 ier = MPI_Pack(&Domaine->Intf[i].NoDomVois, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2064 CHECK_MPI_PACK_ERR(ier);
2065
2066 int NbNoeuds = Domaine->Intf[i].ListeNoeuds.size();
2067 ier = MPI_Pack(&NbNoeuds, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2068 CHECK_MPI_PACK_ERR(ier);
2069 }
2070}
2071/*---------------------------------------------------------------------------*/
2072/*---------------------------------------------------------------------------*/
2085void SplitSDMeshPartitioner::UnpackDom(void* TabTMP, int TailleTMP, MPI_Comm comm, StrucListeDomMail* DomMail)
2086{
2087 int position = 0; // initialization to take from the beginning of the array
2088
2089 MPI_Unpack(TabTMP, TailleTMP, &position, &DomMail->NbElements, 1, MPI_INT, comm);
2090 MPI_Unpack(TabTMP, TailleTMP, &position, &DomMail->Poids, 1, MPI_DOUBLE, comm);
2091 MPI_Unpack(TabTMP, TailleTMP, &position, &DomMail->NbVoisins, 1, MPI_INT, comm);
2092
2093 DomMail->ListeVoisins = new StrucListeVoisMail[DomMail->NbVoisins];
2094
2095 for (int i = 0; i < DomMail->NbVoisins; i++) {
2096 MPI_Unpack(TabTMP, TailleTMP, &position, &DomMail->ListeVoisins[i].NoDomVois, 1, MPI_INT, comm);
2097 MPI_Unpack(TabTMP, TailleTMP, &position, &DomMail->ListeVoisins[i].NbNoeudsInterface, 1, MPI_INT, comm);
2098 DomMail->ListeVoisins[i].Delta = 0.0;
2099 }
2100}
2101
2102/*---------------------------------------------------------------------------*/
2103/*---------------------------------------------------------------------------*/
2107
2109{
2110 return 2 * sizeof(int) + sizeof(double);
2111}
2112/*---------------------------------------------------------------------------*/
2113/*---------------------------------------------------------------------------*/
2117void SplitSDMeshPartitioner::PackEquil(StrucInfoProc* InfoProc, int indDomCharge, int indDomVois, double Delta, void* TabTMP, int TailleTMP, MPI_Comm comm)
2118{
2119 int position = 0; // initialization to put into the array at the beginning
2120 int ier;
2121 ier = MPI_Pack(&indDomCharge, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2122 CHECK_MPI_PACK_ERR(ier);
2123
2124 ier = MPI_Pack(&indDomVois, 1, MPI_INT, TabTMP, TailleTMP, &position, comm);
2125 CHECK_MPI_PACK_ERR(ier);
2126
2127 ier = MPI_Pack(&Delta, 1, MPI_DOUBLE, TabTMP, TailleTMP, &position, comm);
2128 CHECK_MPI_PACK_ERR(ier);
2129}
2130/*---------------------------------------------------------------------------*/
2131/*---------------------------------------------------------------------------*/
2135void SplitSDMeshPartitioner::UnpackEquil(void* TabTMP, int TailleTMP, MPI_Comm comm, int* indDomCharge, int* indDomVois, double* Delta)
2136{
2137 int position = 0; // initialization to take from the beginning of the array
2138 MPI_Unpack(TabTMP, TailleTMP, &position, indDomCharge, 1, MPI_INT, comm);
2139 MPI_Unpack(TabTMP, TailleTMP, &position, indDomVois, 1, MPI_INT, comm);
2140 MPI_Unpack(TabTMP, TailleTMP, &position, Delta, 1, MPI_DOUBLE, comm);
2141}
2142
2143/*---------------------------------------------------------------------------*/
2144/*---------------------------------------------------------------------------*/
2145
2147 ServiceProperty("SplitSD", ST_SubDomain),
2150
2151ARCANE_REGISTER_SERVICE_SPLITSDMESHPARTITIONER(SplitSD, SplitSDMeshPartitioner);
2152
2153/*---------------------------------------------------------------------------*/
2154/*---------------------------------------------------------------------------*/
2155
2156} // End namespace Arcane
2157
2158/*---------------------------------------------------------------------------*/
2159/*---------------------------------------------------------------------------*/
Types and macros for iterating over mesh entities.
#define ENUMERATE_FACE(name, group)
Generic enumerator for a face group.
#define ENUMERATE_CELL(name, group)
Generic enumerator for a cell group.
#define ENUMERATE_NODE(name, group)
Generic enumerator for a node group.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro to declare an interface when registering a service.
Integer size() const
Number of elements in the vector.
Generation de la classe de base du Service.
Base class for 1D data vectors.
void fill(ConstReferenceType value)
Fills the array with the value value.
void clear()
Removes the elements from the array.
iterator begin()
Iterator over the first element of the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
Cell of a mesh.
Definition Item.h:1300
Face face(Int32 i) const
i-th face of the cell
Definition Item.h:1400
Int32 nbFace() const
Number of faces of the cell.
Definition Item.h:1397
Face of a cell.
Definition Item.h:1032
Cell frontCell() const
Cell in front of the face (null cell if none).
Definition Item.h:1780
bool isSubDomainBoundary() const
Indicates if the face is on the subdomain boundary (i.e nbCell()==1).
Definition Item.h:1148
Cell backCell() const
Cell behind the face (null cell if none).
Definition Item.h:1774
Interface of a mesh partitioner.
Interface of a mesh partitioner.
virtual IPrimaryMesh * toPrimaryMesh()=0
Returns the instance in the form of an IPrimaryMesh.
Interface of the parallelism manager for a subdomain.
virtual void computeMinMaxSum(char val, char &min_val, char &max_val, char &sum_val, Int32 &min_rank, Int32 &max_rank)=0
Calculates the sum, min, and max of a value in one operation.
virtual Int32 commSize() const =0
Number of instances in the communicator.
Interface of the subdomain manager.
Definition ISubDomain.h:75
virtual Int32 subDomainId() const =0
Subdomain ID associated with this manager.
virtual IParallelMng * parallelMng()=0
Returns the parallelism manager.
Interface of a variable.
Definition IVariable.h:40
Integer size() const
Number of elements in the group.
Definition ItemGroup.h:93
Node node(Int32 i) const
i-th node of the entity
Definition Item.h:840
Int32 nbNode() const
Number of nodes of the entity.
Definition Item.h:837
constexpr Int32 localId() const
Local identifier of the entity in the processor subdomain.
Definition Item.h:233
Int32 owner() const
Owner subdomain number of the entity.
Definition Item.h:252
Real maxImbalance() const override
Maximum allowed imbalance.
virtual void changeOwnersFromCells()
Positions the new owners of nodes, edges and faces based on the cells.
Node of a mesh.
Definition Item.h:598
Cell cell(Int32 i) const
i-th cell of the node
Definition Item.h:1744
Int32 nbCell() const
Number of cells connected to the node.
Definition Item.h:701
Structure containing the information to create a service.
Service creation properties.
1D vector of data with reference semantics.
Mesh partitioner inspired by the SplitSD library, developed initially at ONERA for Dassault Aviation.
void Equil2Dom(int *MasqueDesNoeuds, int *MasqueDesElements, int marqueVu, int marqueNonVu, StrucInfoProc *InfoProc, StructureBlocEtendu *Domaine, StrucMaillage *Maillage, int indDomCharge, int indDomVois, double Delta)
transfer phase between 2 domains, MAJ of domains
void ConnexifieDomaine(StrucInfoProc *InfoProc, StructureBlocEtendu *Domaine, StrucMaillage *Maillage, double tolConnexite)
makes the domain connected when parts are too small and not connected
double CalculDeltaMin(StrucMaillage *Maillage, double deltaMin, int iterEquilibrage, int NbMaxIterEquil)
calculates a deltaMin based on local transfers
void PackEquil(StrucInfoProc *InfoProc, int indDomCharge, int indDomVois, double Delta, void *TabTMP, int TailleTMP, MPI_Comm comm)
int * GetMasqueDesElements(StrucInfoProc *InfoProc)
creation of an array that serves as a mask on the LocalId of elements
int getDomVoisMaxFace(Arcane::Array< Arcane::Cell > &ListeElements, int me)
searches for the neighboring domain having the max number of shared Faces with the set of cells
void UnpackDom(void *TabTMP, int TailleTMP, MPI_Comm comm, StrucListeDomMail *DomMail)
void MAJDelta(double don, int iDOmTmpPrec, int iDomTmp, StrucListeDomMail *ListeDomaines)
function to shift the Delta associated with a searched interface for a pair, domain,...
int ParcoursFrontalDelta(int *MasqueDesNoeuds, int *MasqueDesElements, int marqueVu, int marqueNonVu, double Delta, int *pNbFronts, int NbFrontsMax, Arcane::Array< Arcane::Node > &FrontsNoeuds, int *IndFrontsNoeuds, Arcane::Array< Arcane::Cell > &FrontsElements, int *IndFrontsElements)
limited front-tracking following the Delta (cumulative weight of elements taken in the fronts),...
void initPoids(bool initial_partition)
initialization of weights (m_cells_weight => m_poids_aux_mailles)
void * RecoitMessage(StrucInfoProc *InfoProc, int FromProc, int Tag, int *pTailleTMP)
void MAJDomaine(StructureBlocEtendu *Domaine)
update of the local structure (nodes on interfaces with neighboring subdomains)
void EnvoieMessage(StrucInfoProc *InfoProc, int ToProc, int Tag, void *TabTMP, int TailleTMP)
void PackDom(StrucInfoProc *InfoProc, StructureBlocEtendu *Domaine, void *TabTMP, int TailleTMP, MPI_Comm comm)
void SelectElements(int *MasqueDesNoeuds, int *MasqueDesElements, int marqueVu, int marqueNonVu, StrucInfoProc *InfoProc, StructureBlocEtendu *Domaine, double Delta, int indDomVois, Arcane::Array< Arcane::Cell > &ListeElements)
selection of elements in a domain for balancing between 2 domains, by performing a front-tracking fro...
void * DiffuseMessage(StrucInfoProc *InfoProc, int FromProc, void *TabTMP, int TailleTMP)
int TailleDom(StructureBlocEtendu *Domaine)
Gives the size in bytes required for the memory storage of a domain (without the list of interface no...
void verifMaillageMaitre(StrucMaillage *Maillage)
consistency check (reciprocity) of the interfaces
void UnpackEquil(void *TabTMP, int TailleTMP, MPI_Comm comm, int *indDomCharge, int *indDomVois, double *Delta)
void LissageDuFront(int *MasqueDesNoeuds, int *MasqueDesElements, int marqueVu, int marqueNonVu, int NbFronts, Arcane::Array< Arcane::Node > &FrontsNoeuds, int *IndFrontsNoeuds, Arcane::Array< Arcane::Cell > &FrontsElements, int *IndFrontsElements)
void fin(StrucInfoProc *&InfoProc, StructureBlocEtendu *&Domaine, StrucMaillage *&Maillage)
memory freeing of structures
void MAJMaillageMaitre(StrucInfoProc *InfoProc, StructureBlocEtendu *Domaine, StrucMaillage *Maillage)
update of the structure on processor 0
void MAJDeltaGlobal(StrucInfoProc *InfoProc, StrucMaillage *Maillage, double tolerance)
We use a front-tracking method to go from an overloaded node to other nodes by memorizing the path to...
int * GetMasqueDesNoeuds(StrucInfoProc *InfoProc)
creation of an array that serves as a mask on the LocalId of nodes
void Equilibrage(StrucInfoProc *InfoProc, StructureBlocEtendu *Domaine, StrucMaillage *Maillage)
iterative phase to balance the load
void init(bool initial_partition, StrucInfoProc *&InfoProc, StructureBlocEtendu *&Domaine, StrucMaillage *&Maillage)
initialization of structures
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flow for a debug message.
TraceMessage pinfo() const
Flow for a parallel information message.
TraceMessage fatal() const
Flow for a fatal error message.
TraceMessage pfatal() const
Flow for a parallel fatal error message.
TraceMessage info() const
Flow for an information message.
TraceMessage perror() const
1D data vector with value semantics (STL style).
Parameters necessary for building a variable.
Integer size() const
Number of elements in the vector.
void clear()
Removes the elements from the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
ItemGroupT< Cell > CellGroup
Group of cells.
Definition ItemTypes.h:184
ItemGroupT< Face > FaceGroup
Group of faces.
Definition ItemTypes.h:179
ItemGroupT< Node > NodeGroup
Group of nodes.
Definition ItemTypes.h:168
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro for registering a service.
ItemVariableScalarRefT< Integer > VariableItemInteger
Integer type quantity.
ItemVariableScalarRefT< Int32 > VariableItemInt32
32-bit integer type quantity
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Integer arcaneCheckArraySize(unsigned long long size)
Checks that size can be converted into an 'Integer' to serve as the size of an array....
Int32 Integer
Type representing an integer.
@ ST_SubDomain
The service is used at the subdomain level.
bool arcaneIsDebug()
True if the ARCANE_DEBUG macro is defined.
Definition Misc.cc:76
@ IK_Cell
Cell mesh entity.
std::int32_t Int32
Signed integer type of 32 bits.
Arcane::AbstractService * m_service
For trace management (messages, errors, fatal ...).
StrucListeVoisMail * ListeVoisins
StrucListeDomMail * ListeDomaines
StructureInterface * Intf
Arcane::UniqueArray< Arcane::Node > ListeNoeuds