Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
ZoltanMeshPartitioner.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2023 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/* ZoltanMeshPartitioner.cc (C) 2000-2023 */
9/* */
10/* Partitioneur de maillage utilisant la bibliotheque Zoltan. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/ArcanePrecomp.h"
16#include "arcane/utils/Convert.h"
17#include "arcane/utils/CheckedConvert.h"
18#include "arcane/utils/Array.h"
19#include "arcane/utils/StringBuilder.h"
20#include "arcane/utils/Iostream.h"
21#include "arcane/utils/ScopedPtr.h"
22#include "arcane/utils/NotImplementedException.h"
23#include "arcane/utils/ArgumentException.h"
24
25#include "arcane/ISubDomain.h"
26#include "arcane/IParallelMng.h"
27#include "arcane/ItemEnumerator.h"
28#include "arcane/IMeshSubMeshTransition.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/CommonVariables.h"
38#include "arcane/utils/HashTableMap.h"
39
40// Au cas ou on utilise mpich2 ou openmpi
41#define MPICH_SKIP_MPICXX
42#define OMPI_SKIP_MPICXX
43#include <zoltan.h>
44
45#include "arcane/std/MeshPartitionerBase.h"
46#include "arcane/std/ZoltanMeshPartitioner_axl.h"
47
48#include <set>
49
50#ifdef WIN32
51#include <Windows.h>
52#define sleep Sleep
53#endif
54
55#define ARCANE_DEBUG_ZOLTAN
56
57// GG: NOTE: L'implémentation actuelle ne supporte que les uniqueId() sur 32 bits.
58
59/*---------------------------------------------------------------------------*/
60/*---------------------------------------------------------------------------*/
61
62namespace Arcane
63{
64
65/*---------------------------------------------------------------------------*/
66/*---------------------------------------------------------------------------*/
67
68
69enum ZoltanModel
70{
71 ZOLTAN_HG = (1<<0),
72 ZOLTAN_GRAPH = (1<<1),
73 ZOLTAN_GEOM = (1<<2)
74};
75
76/*---------------------------------------------------------------------------*/
82 : public TraceAccessor
83{
84public:
85 ZoltanInfo(MeshPartitionerBase* basePartitionner,ostream* ofile, int model=1, const Real edgeWeightMultiplier = 1.)
87 , m_mesh_partitionner_base(basePartitionner)
88 , m_nbEdges(0)
89 , m_nbPins(0)
90 , m_ofile(ofile)
91 , m_model(model)
92 , m_edgeGIDStart(0)
93 , m_edge_weight_multiplier(edgeWeightMultiplier)
94 {
95 m_own_cells = m_mesh_partitionner_base->mesh()->ownCells();
96 build();
97 }
98 MeshPartitionerBase* m_mesh_partitionner_base;
99private:
100 CellGroup m_own_cells;
101 int m_nbEdges;
102 int m_nbPins;
103 ostream* m_ofile;
104 int m_model;
105 int m_edgeGIDStart;
106 Real m_edge_weight_multiplier;
107 std::set<std::pair<Int64, Int64> > m_weight_set;
108public:
109 void build()
110 {
111 info() << "ZoltanInfo::build()";
112 if (m_model & ZOLTAN_GEOM) // No topological informations to build
113 return;
114
115 Integer nbOwnCells = m_own_cells.size();
116 Integer nbOwnEdges = 0;
117
118 if (m_model & ZOLTAN_HG) {
120 }
121 if (m_model & ZOLTAN_GRAPH) {
122 // Neighboors, each and then neighboorhood HE
123 nbOwnEdges += nbOwnCells * 6;
124 }
125
126 // Compute m_edgeGIDStart = Sum_k<i nbOwnEdges
127 IParallelMng* pm = m_mesh_partitionner_base->mesh()->parallelMng();
129 scanouille.fill(0);
131 pm->scan(Parallel::ReduceSum,scanouille);
132 m_edgeGIDStart = 0;
133 for (int i = 0 ; i < pm->commRank() ; ++i) {
134 m_edgeGIDStart += scanouille[i];
135 }
136
137 m_nbEdges = 0;
138 m_nbPins = 0;
139 ENUMERATE_CELL(iCell,m_own_cells)
140 {
141 if (!m_mesh_partitionner_base->cellUsedWithConstraints(*iCell))
142 continue;
143
144 int nbNgb = m_mesh_partitionner_base->nbNeighbourCellsWithConstraints(*iCell);
145 if (m_model & ZOLTAN_HG) {
146 m_nbEdges ++;
147 m_nbPins += nbNgb + 1;
148 }
149 if (m_model & ZOLTAN_GRAPH) {
150 m_nbEdges += nbNgb;
151 m_nbPins += (nbNgb*2);
152 }
153 }
154
155 info() << "nbEdges=" << m_nbEdges << " ; nbPins=" << m_nbPins;
156
157 if(m_mesh_partitionner_base->haveWeakConstraints())
158 {
159 MeshVariableScalarRefT<Face, Integer> weak_constraint(VariableBuildInfo(m_mesh_partitionner_base->mesh(), "EdgeWeight"));
160 ENUMERATE_FACE(iface,m_mesh_partitionner_base->mesh()->ownFaces())
161 {
162 const Face& face = *iface;
163 const Cell& bCell = iface->backCell();
164 const Cell& fCell = iface->frontCell();
165 if(bCell.null() || fCell.null())
166 continue;
167 if(weak_constraint[face]==2)
168 {
169 m_weight_set.insert(std::pair<Int64,Int64>(face.backCell().uniqueId(), face.frontCell().uniqueId()));
170 m_weight_set.insert(std::pair<Int64,Int64>(face.frontCell().uniqueId(), face.backCell().uniqueId()));
171 }
172 }
173 }
174 } // end build()
175
176
177public:
178 static int getHgNumVertices(void *data, int *ierr)
179 {
180 ARCANE_UNUSED(ierr);
181
182 ZoltanInfo* zi = (ZoltanInfo*)data;
183
184 /*
185 * Supply this query function to Zoltan with Zoltan_Set_Num_Obj_Fn().
186 * It returns the number of vertices that this process owns.
187 *
188 * The parallel hypergraph method requires that vertex global IDs and
189 * weights are returned by the application with query functions. The
190 * global IDs should be unique, and no two processes should
191 * return the same vertex.
192 */
193 return zi->m_mesh_partitionner_base->nbOwnCellsWithConstraints();
194 }
195
196 static void getHgVerticesAndWeights(void *data, int num_gid_entries,
198 int wgt_dim, float *obj_weights, int *ierr)
199 {
200 ARCANE_UNUSED(num_gid_entries);
201 ARCANE_UNUSED(num_lid_entries);
202
203 ZoltanInfo* zi = (ZoltanInfo*)data;
204 /*
205 * Supply this query function to Zoltan with Zoltan_Set_Obj_List_Fn().
206 *
207 * It supplies vertex global IDs, local IDs,
208 * and weights to the Zoltan library. The application has previously
209 * indicated the number of weights per vertex by setting the
210 * OBJ_WEIGHT_DIM parameter.
211 */
212 //int nb_cell = zi->m_own_cells.size();
213
215 if (wgt_dim != 0) { // No weight, does not mean no limitation like for Arcane
216 if (zi->m_mesh_partitionner_base->nbCellWeight() <= wgt_dim) { // We can use all criteria, so we do
217 cells_weights = zi->m_mesh_partitionner_base->cellsWeightsWithConstraints(wgt_dim);
218 }
219 else { // We need more criteria than available
220 // So we try to balance memory !
221 cells_weights = zi->m_mesh_partitionner_base->cellsSizeWithConstraints();
222 }
225 }
226
227 int index = 0;
228 ENUMERATE_CELL(icell,zi->m_own_cells)
229 {
230 if (!zi->m_mesh_partitionner_base->cellUsedWithConstraints(*icell))
231 continue;
232
233 gids[index] = (*icell).uniqueId().asInt32();
234 lids[index] = zi->m_mesh_partitionner_base->localIdWithConstraints(*icell);
235
236 if (zi->m_ofile) {
237 for( int j=0; j< wgt_dim; ++j ){
238 float weight = cells_weights[lids[index]*wgt_dim+j];
239 *obj_weights++ = weight;
240 // zi->info() << " Weight uid=" << gids[index] << " w=" << weight;
241 (*zi->m_ofile) << " Weight uid=" << gids[index] << " w=" << weight << '\n';
242 }
243 }
244 index ++;
245 }
246 *ierr = ZOLTAN_OK;
247 }
248
249 static void getHgSizeAndFormat(void *data, int *num_lists, int *num_pins, int *format, int *ierr)
250 {
251 ZoltanInfo* zi = (ZoltanInfo*)data;
252
253 zi->info() << " ZoltanInfo::getHgSizeAndFormat() ";
254
255 /*
256 * Supply this query function to Zoltan with Zoltan_Set_HG_Size_CS_Fn().
257 * It tells Zoltan the number of rows or columns to be supplied by
258 * the process, the number of pins (non-zeroes) in the rows or columns,
259 * and whether the pins are provided in compressed row format or
260 * compressed column format.
261 */
262 *format = ZOLTAN_COMPRESSED_EDGE;
263 *num_pins = zi->m_nbPins;
264 *num_lists = zi->m_nbEdges;
265
266 // if (zi->m_model == ZOLTAN_MY_HG) {
267 // *format = ZOLTAN_COMPRESSED_VERTEX;
268 // }
269 zi->info() << " ZoltanInfo::getHgSizeAndFormat() " << " num_list= " << *num_lists << " num_pins= " << *num_pins;
270 *ierr =ZOLTAN_OK;
271 }
272
273 static void getHg(void *data, int num_gid_entries,
274 int nrowcol, int npins, int format,
276 {
277 ZoltanInfo* zi = (ZoltanInfo*)data;
278
279 zi->info() << " ZoltanInfo::getHg() "
280 << " num_gid_entries= " << num_gid_entries
281 << " nrowcol= " << nrowcol
282 << " npins= " << npins
283 << " format= " << format;
284
285 // 6 neighbors max ? >> Not true for groups !
287 neighbour_cells.reserve(6);
288 int indexPin = 0;
289 int indexEdge = 0;
290 int gid = zi->m_edgeGIDStart;
291 z_vtxedge_ptr[0] = 0;
292 ENUMERATE_CELL(i_item, zi->m_own_cells) {
293 const Cell& item = *i_item;
294
295 if (!zi->m_mesh_partitionner_base->cellUsedWithConstraints(item))
296 continue;
297
298 neighbour_cells.resize(0);
299 zi->m_mesh_partitionner_base->getNeighbourCellsUidWithConstraints(item,
301
302 if (zi->m_model & ZOLTAN_HG)
303 {
304 for( Integer z=0; z<neighbour_cells.size(); ++z )
306 z_pin_GID[indexPin++] = item.uniqueId().asInt32(); // Don't forget current cell
308 // +1 because current cell is it's own neighbor !
310 indexEdge ++;
311 }
312
313 if (zi->m_model & ZOLTAN_GRAPH)
314 {
315 // size 2 edges are face communications
316 // other are neighborhood description
317 for( Integer z=0; z<neighbour_cells.size(); ++z ) {
319 z_pin_GID[indexPin++] = (item.uniqueId().asInt32());
322 indexEdge++;
323 }
324 }
325 }
326 if (zi->m_ofile) {
327 for (int i = 0 ; i < nrowcol ; ++i) {
328 (*zi->m_ofile) << "*topo GID " << z_vtxedge_GID[i]
329 << " : " << z_vtxedge_ptr[i+1] - z_vtxedge_ptr[i];
330 for (int j = z_vtxedge_ptr[i] ; j < z_vtxedge_ptr[i+1] ; ++j) {
331 (*zi->m_ofile) << '\t' << z_pin_GID[j];
332 }
333 (*zi->m_ofile) << '\n';
334 }
335 }
336 *ierr = ZOLTAN_OK;
337 }
338
339
340 /*
341 For a list of objects, it returns the per-objects sizes (in bytes)
342 of the data buffers needed to pack object data.
343 void (*)(void*, int, int, int, ZOLTAN_ID_TYPE*, ZOLTAN_ID_TYPE*, int*, int*)
344 */
345
346 static void getHgVertexSizes (void *data, int num_gid_entries, int num_lid_entries,
348 int *sizes, int *ierr)
349 {
350 ARCANE_UNUSED(num_gid_entries);
351 ARCANE_UNUSED(num_lid_entries);
352 ARCANE_UNUSED(global_ids);
353
354 ZoltanInfo* zi = (ZoltanInfo*)data;
355
356 SharedArray<float> cellSizes = zi->m_mesh_partitionner_base->cellsSizeWithConstraints();
357
358 for (int i = 0 ; i < num_ids ; ++i)
359 {
360 sizes[i] = Convert::toInteger(cellSizes[local_ids[i]]);
361 }
362
363 *ierr = ZOLTAN_OK;
364 }
365
366 static void getHgEdgeWeightSize(void *data, int *num_edges, int *ierr)
367 {
368 ZoltanInfo* zi = (ZoltanInfo*)data;
369
370 /*
371 * Supply this query function to Zoltan with Zoltan_Set_HG_Size_Edge_Weights_Fn().
372 * It tells Zoltan the number edges for which this process will supply
373 * edge weights. The number of weights per edge was specified with the
374 * parameter EDGE_WEIGHT_DIM. If more than one process provides a weight
375 * for the same edge, the multiple weights are resolved according the
376 * value for the PHG_EDGE_WEIGHT_OPERATION parameter.
377 */
378
379 *num_edges = zi->m_nbEdges;
380 *ierr = ZOLTAN_OK;
381 }
382
383 static void getHgEdgeWeights(void *data, int num_gid_entries,
386 {
387 ARCANE_UNUSED(num_lid_entries);
388
389 ZoltanInfo* zi = (ZoltanInfo*)data;
390 /*
391 * Supply this query function to Zoltan with Zoltan_Set_HG_Edge_Weights_Fn().
392 * It tells Zoltan the weights for some subset of edges.
393 */
394
395 zi->info() << " ZoltanInfo::getHgEdgeWeights() "
396 << " num_gid_entries= " << num_gid_entries
397 << " nedges= " << nedges
398 << " edge_weight_dim= " << edge_weight_dim;
399
402 neighbour_cells.reserve(6);
403 connectivityWeights.reserve(6);
404 int indexEdge = 0;
405
406 ENUMERATE_CELL(i_item, zi->m_own_cells) {
407 Cell item = *i_item;
408
409 if (!zi->m_mesh_partitionner_base->cellUsedWithConstraints(item))
410 continue;
411
412 connectivityWeights.resize(0);
413 neighbour_cells.resize(0);
414 bool hg_model=(zi->m_model & ZOLTAN_HG);
415 Real he_weight= 0;
416 he_weight =
417 zi->m_mesh_partitionner_base->getNeighbourCellsUidWithConstraints(item,
419
420 if (zi->m_model & ZOLTAN_HG) {
421 if (!(zi->m_model & ZOLTAN_GRAPH)) {
422 // We have to sum-up de Weight of pins to define HyperEdge's one.
423 for( Integer z=0; z<neighbour_cells.size(); ++z ) {
425 }
426 }
427 edge_GID[indexEdge] = indexEdge + zi->m_edgeGIDStart;
430 }
431
432 if (zi->m_model & ZOLTAN_GRAPH) {
433 // size 2 edges are face communications
434 // other are neighborhood description
435 for( Integer z=0; z<neighbour_cells.size(); ++z ){
436 edge_GID[indexEdge] = indexEdge + zi->m_edgeGIDStart;
438 Real w = connectivityWeights[z];
440 if (zi->m_mesh_partitionner_base->haveWeakConstraints()){
441 std::pair<Int64,Int64> items(item.uniqueId(), neighbour_cells[z]);
442 if(zi->m_mesh_partitionner_base->cellUsedWithWeakConstraints(items)){
443 edge_weight[indexEdge] *= (float)zi->m_edge_weight_multiplier;
444 }
445 }
446 ++indexEdge;
447 }
448 }
449 }
450 *ierr = ZOLTAN_OK;
451 }
452
453 // Return the dimension of a vertex, for geometric methods
454 static int get_num_geometry(void *data, int *ierr)
455 {
456 ARCANE_UNUSED(data);
457 *ierr = ZOLTAN_OK;
458 return 3;
459 }
460
461 // Return the coordinates of my objects (vertices), for geometric methods.
462 static void get_geometry_list(void *data, int sizeGID, int sizeLID,
463 int num_obj,
465 int num_dim, double *geom_vec, int *ierr)
466 {
467 ARCANE_UNUSED(global_ids);
468 ARCANE_UNUSED(local_ids);
469
470 ZoltanInfo* zi = (ZoltanInfo*)data;
471
472 if ( (sizeGID != 1) || (sizeLID != 1) || (num_dim > 3)){
474 return;
475 }
476
477 VariableNodeReal3& coords(zi->m_mesh_partitionner_base->mesh()->nodesCoordinates());
478
479
480 int i=0;
481 ENUMERATE_CELL(icell,zi->m_own_cells){
482 if (!zi->m_mesh_partitionner_base->cellUsedWithConstraints(*icell))
483 continue;
484
485 // on calcul un barycentre
486
487 Real3 bar;
488
489 for( Integer z=0, zs = (*icell).nbNode(); z<zs; ++z ){
490 const Node& node = (*icell).node(z);
491 bar += coords[node];
492 }
493 bar /= Convert::toDouble((*icell).nbNode());
494
495 geom_vec[num_dim*i ] = bar.x;
496 geom_vec[num_dim*i+1] = bar.y;
497 geom_vec[num_dim*i+2] = bar.z;
498 i += 1;
499 }
500
501 String s = platform::getEnvironmentVariable("ZOLTAN_MODEL");
502 if (!s.null() && (s == "MYGEOM")) {
503 for (int i = 0 ; i < num_obj ; ++i) {
504 geom_vec[num_dim*i+num_dim-1] = 0.0;
505 }
506 }
507
508 *ierr = ZOLTAN_OK;
509 return;
510 }
511};
512
513/*---------------------------------------------------------------------------*/
514/*---------------------------------------------------------------------------*/
520{
521 public:
522
524
525 public:
526
527 virtual void build() {}
528
529 public:
530
531 virtual void partitionMesh(bool initial_partition);
532 virtual void partitionMesh(bool initial_partition,Int32 nb_part);
533
534 virtual void notifyEndPartition();
535
536 private:
537};
538
539/*---------------------------------------------------------------------------*/
540/*---------------------------------------------------------------------------*/
541
542ZoltanMeshPartitioner::
543ZoltanMeshPartitioner(const ServiceBuildInfo& sbi)
544 : ArcaneZoltanMeshPartitionerObject(sbi)
545{
546}
547
548/*---------------------------------------------------------------------------*/
549/*---------------------------------------------------------------------------*/
550
557
558/*---------------------------------------------------------------------------*/
559/*---------------------------------------------------------------------------*/
560
563{
564 info() << "Load balancing with Zoltan\n";
565
566 float ver;
567
568 int rc = ::Zoltan_Initialize(0,0,&ver);
570 if (rc != ZOLTAN_OK)
571 fatal() << "Can not initialize zoltan (r=" << rc << ")";
572 IMesh* mesh = this->mesh();
573 IParallelMng* pm = mesh->parallelMng();
574 Integer nb_rank = pm->commSize();
575
576 if (nb_part<nb_rank)
577 throw ArgumentException(A_FUNCINFO,"partition with nb_part<nb_rank");
578
579 if (nb_rank==1){
580 warning() << "Unable to test load balancing on a single sub-domain";
581 return;
582 }
583
584 Integer nb_weight = nbCellWeight();
585
586 struct Zoltan_Struct *zz;
587 int changes;
588 int numGidEntries;
589 int numLidEntries;
590 int numImport;
591 ZOLTAN_ID_PTR importGlobalIds;
592 ZOLTAN_ID_PTR importLocalIds;
593 int *importProcs;
594 int *importToPart;
595 int numExport;
596 ZOLTAN_ID_PTR exportGlobalIds;
597 int *exportProcs;
598
599 /******************************************************************
600 ** Prepare to partition the example hypergraph using the Zoltan
601 ** parallel hypergraph package.
602 **
603 ** Set parameter values, and supply to Zoltan the query functions
604 ** defined in the example library which will provide to the Zoltan
605 ** library the hypergraph data.
606 ******************************************************************/
607 zz = Zoltan_Create(*(MPI_Comm*)getCommunicator());
608
609 Zoltan_Set_Param(zz, "RCB_REUSE", "1"); // Try to do "repartitioning"
610 // option entre PHG et RCB (hypergraphe et coordonnee bissection)
611
612 // Anciennes valeurs par defaut si pas de variable d'environnement (cf OLD_HG)
613 bool usePHG = true;
614
615 String s = platform::getEnvironmentVariable("ZOLTAN_MODEL");
616
617 if (options()) {
618 if (!s.null() && options()->model.isPresent())
619 fatal() << "Conflicting configuration between ZOLTAN_MODEL environment variable and user data set";
620 usePHG = options()->useHypergraphe();
621 if (!usePHG)
622 s = "RCB";
623 else if (s.null())
624 s = options()->model();
625 } else if (s.null()) {
626 s = "OLDHG";
627 }
628 // => s != null
629
630 if (s == "HYBRID") {
631 if (subDomain()->commonVariables().globalIteration() <= 2)
632 s = "RCB";
633 else
634 s = "DUALHG";
635 }
636
637 String algo = "HYPERGRAPH";
638 if (s == "MYHG" || s == "OLDHG" /* nuance avec OLD_HG ? */ || s == "DUALHG" || s == "GRAPH") {
639 algo = "HYPERGRAPH";
640 usePHG = true;
641 } else if (s == "RIB" || s== "HSFC") {
642 algo = s;
643 usePHG = false;
644 } else if (s == "RCB" || s == "MYGEOM") {
645 algo = "RCB";
646 usePHG = false;
647 } else {
648 fatal() << "Undefined zoltan model '" << s << "'";
649 }
650
651 int model = ZOLTAN_HG;
652 if (usePHG == false) {
653 model = ZOLTAN_GEOM;
654 }
655
656 if (s == "DUALHG") {
657 model |= ZOLTAN_GRAPH;
658 } else if (s == "GRAPH") {
659 model = ZOLTAN_GRAPH;
660 }
661
662 if (usePHG) {
663 nb_weight = 1; // up to 2 weights for RCB
664 }
665
666 Real edgeWeightMultiplier = 1;
667 Integer repartitionFrequency = 10;
668 Real imbalanceTol = 1.05;
669 Real phgRepartMultiplier = 10;
670 Integer phgOutputLevel = 0;
671 Integer debugLevel = 0;
672
673 if(options())
674 {
675 edgeWeightMultiplier = options()->edgeWeightMultiplier();
676 repartitionFrequency = options()->repartFrequency();
677 imbalanceTol = options()->imbalanceTol();
678 phgRepartMultiplier = options()->phgRepartMultiplier();
679 phgOutputLevel = options()->phgOutputLevel();
680 debugLevel = options()->debugLevel();
681 }
682
683 /* General parameters */
684 info() << "Zoltan: utilise un repartitionnement " << algo <<" (" << s << ").";
685 Zoltan_Set_Param(zz, "LB_METHOD", algo.localstr()); /* partitioning method */
686 Zoltan_Set_Param(zz, "HYPERGRAPH_PACKAGE", "PHG"); /* version of method */
687 //if(!initial_partition)
688 if(mesh->subDomain()->commonVariables().globalIteration()==1)
689 {
690 Zoltan_Set_Param(zz, "LB_APPROACH", "PARTITION"); /* version of method */
691 info() << "Zoltan: Partition";
692 }
693 else if(mesh->subDomain()->commonVariables().globalIteration()%repartitionFrequency==0 && repartitionFrequency!=-1)
694 {
695 Zoltan_Set_Param(zz, "LB_APPROACH", "REPARTITION"); /* version of method */
696 info() << "Zoltan: Repartition";
697 }
698 else
699 {
700 Zoltan_Set_Param(zz, "LB_APPROACH", "REFINE"); /* version of method */
701 info() << "Zoltan: Refine";
702 }
703
704 String s_imbalaceTol(String::fromNumber(imbalanceTol));
705 Zoltan_Set_Param(zz, "IMBALANCE_TOL", s_imbalaceTol.localstr()); /* version of method */
706
707 String s_nb_part(String::fromNumber(nb_part));
708 Zoltan_Set_Param(zz, "NUM_GLOBAL_PARTS", s_nb_part.localstr());
709
710 Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");/* global IDs are integers */
711 Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");/* local IDs are integers */
712 Zoltan_Set_Param(zz, "RETURN_LISTS", "EXPORT"); /* only export lists */
713 String s_nb_weight(String::fromNumber(nb_weight));
714
715 Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", s_nb_weight.localstr()); /* 2 vtx weight */
716
717 /* Graph parameters */
718 Zoltan_Set_Param(zz, "ADD_OBJ_WEIGHT", "NONE"); /* Don't calculate extra weights */
719
720 if (usePHG) {
721 /* Parallel hypergraph parameters */
722 Zoltan_Set_Param(zz, "FINAL_OUTPUT", "0"); /* provide stats at the end */
723 Zoltan_Set_Param(zz, "PHG_USE_TIMERS", "1");
724
725 String s_phgOutputLevel(String::fromNumber(phgOutputLevel));
726 Zoltan_Set_Param(zz, "PHG_OUTPUT_LEVEL", s_phgOutputLevel.localstr());
727
728 // Utilisation en debug
729 Zoltan_Set_Param(zz, "CHECK_HYPERGRAPH", "0"); /* see User's Guide */
730 String s_debugLevel(String::fromNumber(debugLevel));
731 Zoltan_Set_Param(zz, "DEBUG_LEVEL", s_debugLevel.localstr());
732
733 // La methode par defaut (ipm) donne en theorie de meilleurs resultats
734 // mais elle semble des fois bloquer avec la version 2.0 de zoltan
735
736 Zoltan_Set_Param(zz, "PHG_COARSENING_METHOD", "IPM");
737 //Zoltan_Set_Param(zz, "PHG_COARSEPARTITION_METHOD", "GREEDY");
738 //Zoltan_Set_Param(zz, "PHG_CUT_OBJECTIVE", "HYPEREDGES");
739
740 Zoltan_Set_Param(zz, "EDGE_WEIGHT_DIM", "1");
741 Zoltan_Set_Param(zz, "PHG_EDGE_WEIGHT_OPERATION", "add");
742
743 if(!initial_partition)
744 {
745 // Number of iterations between 2 load balances. Used to scale the cost
746 // of data migration.
747 String s_phgRepartMultiplier(String::fromNumber(phgRepartMultiplier));
748 Zoltan_Set_Param(zz, "PHG_REPART_MULTIPLIER", s_phgRepartMultiplier.localstr());
749 }
750
751 }
752 else {
753 Zoltan_Set_Param(zz, "KEEP_CUTS", "0");
754 Zoltan_Set_Param(zz, "RCB_OUTPUT_LEVEL", "0");
755 Zoltan_Set_Param(zz, "RCB_RECTILINEAR_BLOCKS", "0");
756 // The 2 following options are for multi-weights partitioning
757 // Object weights are not comparable
758 Zoltan_Set_Param(zz, "OBJ_WEIGHTS_COMPARABLE", "0");
759 // 1 : minimize total (ie Sum over all phases)
760 // 2 : between
761 // 3 : Minimize worst case for each phase
762 Zoltan_Set_Param(zz, "RCB_MULTICRITERIA_NORM", "3");
763 Zoltan_Set_Param(zz, "RCB_MAX_ASPECT_RATIO", "10");
764 }
765
766 bool dump_infos = false;
767 if (platform::getEnvironmentVariable("ARCANE_DEBUG_PARTITION")=="TRUE")
768 dump_infos = true;
769 ofstream ofile;
770 if (dump_infos){
771 StringBuilder fname;
772 Integer iteration = mesh->subDomain()->commonVariables().globalIteration();
773 fname = "weigth-";
774 fname += pm->commRank();
775 fname += "-";
776 fname += iteration;
777 String f(fname);
778 ofile.open(f.localstr());
779 }
780
781 /* Application defined query functions (defined in exphg.c) */
782
783 // initialisation pour la gestion des contraintes
784 initConstraints();
785
786 ostream* zofile = 0;
787 if (dump_infos)
788 zofile = &ofile;
789
790 ScopedPtrT<ZoltanInfo> zoltan_info(new ZoltanInfo(this,zofile, model, edgeWeightMultiplier));
791 Zoltan_Set_Num_Obj_Fn(zz,&ZoltanInfo::getHgNumVertices, zoltan_info.get());
792 Zoltan_Set_Obj_List_Fn(zz, &ZoltanInfo::getHgVerticesAndWeights, zoltan_info.get());
793 if (!initial_partition) {
794 Zoltan_Set_Obj_Size_Multi_Fn(zz, &ZoltanInfo::getHgVertexSizes,
795 zoltan_info.get());
796 }
797 if (usePHG){
798 info() <<"Setting up HG Callbacks";
799 Zoltan_Set_HG_Size_CS_Fn(zz, &ZoltanInfo::getHgSizeAndFormat, zoltan_info.get());
800 Zoltan_Set_HG_CS_Fn(zz, &ZoltanInfo::getHg, zoltan_info.get());
801 Zoltan_Set_HG_Size_Edge_Weights_Fn(zz, &ZoltanInfo::getHgEdgeWeightSize, zoltan_info.get());
802 Zoltan_Set_HG_Edge_Weights_Fn(zz, &ZoltanInfo::getHgEdgeWeights, zoltan_info.get());
803 }
804 else
805 {
806 info() <<"Setting up Geom Callbacks";
807 Zoltan_Set_Num_Geom_Fn(zz, ZoltanInfo::get_num_geometry, zoltan_info.get());
808 Zoltan_Set_Geom_Multi_Fn(zz, ZoltanInfo::get_geometry_list, zoltan_info.get());
809 }
810
811 /* Parallel partitioning occurs now */
812
813 int* export_partitions = 0;
814 ZOLTAN_ID_PTR export_local_ids = 0;
815
816 info() << "Doing partition";
817 rc = Zoltan_LB_Partition(zz, &changes, &numGidEntries, &numLidEntries,
818 &numImport, &importGlobalIds, &importLocalIds,
819 &importProcs, &importToPart,
820 &numExport, &exportGlobalIds, &export_local_ids,
821 &exportProcs, &export_partitions);
822 pm->barrier();
823
824 VariableItemInt32& cells_new_owner = mesh->toPrimaryMesh()->itemsNewOwner(IK_Cell);
825 ENUMERATE_ITEM(icell,mesh->ownCells()){
826 cells_new_owner[icell] = (*icell).owner();
827 }
828
829 invertArrayLid2LidCompacted();
830
831 {
832 CellInfoListView items_internal(m_cell_family);
833 Integer nb_export = numExport;
834 info() <<"numExport = "<<numExport;
835 for( Integer i=0; i<nb_export; ++i ){
836 Item item = items_internal[ localIdWithConstraints(export_local_ids[i]) ];
837 // changement pour la maille ou tout le groupe s'il y a lieu
838 changeCellOwner(item, cells_new_owner, export_partitions[i]);
839 if (dump_infos) // ces infos ne tiennent pas compte des groupes/contraintes
840 ofile << "EXPORT: uid=" << ItemPrinter(item) << " OLD=" << item.owner()
841 << " NEW=" << cells_new_owner[item] << " PROC=" << exportProcs[i] << '\n';
842 }
843 // pinfo() << "Proc " << my_rank << " nombre de mailles changeant de domaine: "
844 // << nb_export << " changes=" << changes
845 // << " ZoltanMem=" << Zoltan_Memory_Usage(ZOLTAN_MEM_STAT_MAXIMUM);
846 }
847
848 // Libere la memoire de zoltan_info
849 zoltan_info = 0;
850 if (dump_infos)
851 ofile.close();
852
853 if (numExport < 0) {
854 sleep(3);
855 MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
856 }
857
858 Zoltan_LB_Free_Part(&exportGlobalIds, &export_local_ids,
859 &exportProcs, &export_partitions);
860
861 // Zoltan_Destroy(&zz);
862
863 // liberation des tableau temporaires
864 freeConstraints();
865
866 cells_new_owner.synchronize();
868}
869
870/*---------------------------------------------------------------------------*/
871/*---------------------------------------------------------------------------*/
872
877
878/*---------------------------------------------------------------------------*/
879/*---------------------------------------------------------------------------*/
880
885ARCANE_REGISTER_SERVICE_ZOLTANMESHPARTITIONER(Zoltan,ZoltanMeshPartitioner);
886
887#if ARCANE_DEFAULT_PARTITIONER == ZOLTAN_DEFAULT_PARTITIONER
889 ServiceProperty("DefaultPartitioner",ST_SubDomain),
892ARCANE_REGISTER_SERVICE_ZOLTANMESHPARTITIONER(DefaultPartitioner,ZoltanMeshPartitioner);
893#endif
894
895/*---------------------------------------------------------------------------*/
896/*---------------------------------------------------------------------------*/
897
898} // End namespace Arcane
899
900/*---------------------------------------------------------------------------*/
901/*---------------------------------------------------------------------------*/
#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_ITEM(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.
Generation de la classe de base du Service.
CaseOptionsZoltanMeshPartitioner * options() const
Options du jeu de données du service.
Maille d'un maillage.
Definition Item.h:1178
Face d'une maille.
Definition Item.h:932
Cell frontCell() const
Maille devant la face (maille nulle si aucune)
Definition Item.h:1604
Cell backCell() const
Maille derrière la face (maille nulle si aucune)
Definition Item.h:1598
virtual CellGroup ownCells()=0
Groupe de toutes les mailles propres au domaine.
virtual FaceGroup ownFaces()=0
Groupe de toutes les faces propres au domaine.
Interface d'un partitionneur de maillage.
Interface d'un partitionneur de maillage.
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual ISubDomain * subDomain()=0
Sous-domaine associé
virtual IPrimaryMesh * toPrimaryMesh()=0
Retourne l'instance sous la forme d'un IPrimaryMesh.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual void scan(eReduceType rt, ArrayView< char > v)=0
Applique un algorithme de prefix-um sur les valeurs de v via l'opération rt.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual void barrier()=0
Effectue une barière.
Integer size() const
Nombre d'éléments du groupe.
Definition ItemGroup.h:88
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:216
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Classe de base d'un service d'équilibrage de charge.
IMesh * mesh() const
Maillage associé au partitionneur.
virtual void changeOwnersFromCells()
Positionne les nouveaux propriétaires des noeuds, arêtes et faces à partir des mailles.
Noeud d'un maillage.
Definition Dom.h:204
Classe gérant un vecteur de réel de dimension 3.
Definition Real3.h:132
Structure contenant les informations pour créer un service.
Propriétés de création d'un service.
Paramètres nécessaires à la construction d'une variable.
Informations pour le partitionnement avec Zoltan.
Partitioneur de maillage utilisant la bibliotheque Zoltan.
virtual void notifyEndPartition()
Notification lors de la fin d'un repartionnement (après échange des entités)
virtual void build()
Construction de niveau build du service.
virtual void partitionMesh(bool initial_partition)
Exception lorsqu'un argument est invalide.
Chaîne de caractères unicode.
bool null() const
Retourne true si la chaîne est nulle.
Definition String.cc:304
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage warning() const
Flot pour un message d'avertissement.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage fatal() const
Flot pour un message d'erreur fatale.
Vecteur 1D de données avec sémantique par valeur (style STL).
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
ItemVariableScalarRefT< Int32 > VariableItemInt32
Grandeur de type entier 32 bits.
Integer toInteger(Real r)
Converti un Int64 en un Integer.
Integer toInteger(Real r)
Converti un Real en Integer.
Definition Convert.h:53
double toDouble(Real r)
Converti un Real en double.
Definition Convert.h:40
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
@ ST_SubDomain
Le service s'utilise au niveau du sous-domaine.
@ IK_Cell
Entité de maillage de genre maille.
ARCCORE_BASE_EXPORT void sleep(Integer nb_second)
Met le process en sommeil pendant nb_second secondes.
Int32 Integer
Type représentant un entier.