Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
MeshPartitionerBase.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/* MeshPartitionerBase.cc (C) 2000-2025 */
9/* */
10/* Base class for a mesh partitioner */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ArcanePrecomp.h"
15#include "arcane/utils/HashTableMap.h"
16#include "arcane/utils/ArgumentException.h"
17#include "arcane/utils/FatalErrorException.h"
18#include "arcane/utils/PlatformUtils.h"
19#include "arcane/utils/StringBuilder.h"
20#include "arcane/utils/MultiArray2.h"
21
22#define INSURE_CONSTRAINTS
23
24#include "arcane/core/ServiceBuildInfo.h"
25#include "arcane/core/IMesh.h"
26#include "arcane/core/IMeshModifier.h"
27#include "arcane/core/IMeshSubMeshTransition.h"
28#include "arcane/core/IMeshUtilities.h"
29#include "arcane/core/IItemFamily.h"
30#include "arcane/core/ItemGroup.h"
31#include "arcane/core/ItemPrinter.h"
32#include "arcane/core/ISubDomain.h"
33#include "arcane/core/IParallelMng.h"
35#include "arcane/core/IVariableMng.h"
36#include "arcane/core/VariableTypes.h"
37#include "arcane/core/CommonVariables.h"
38#include "arcane/core/IMeshPartitionConstraintMng.h"
39#include "arcane/core/ILoadBalanceMng.h"
40#include "arcane/core/MeshKind.h"
41#include "arcane/core/internal/ILoadBalanceMngInternal.h"
42
43#include "arcane/std/MeshPartitionerBase.h"
44
45/*---------------------------------------------------------------------------*/
46/*---------------------------------------------------------------------------*/
47
48namespace Arcane
49{
50
51/*---------------------------------------------------------------------------*/
52/*---------------------------------------------------------------------------*/
53
54MeshPartitionerBase::
55MeshPartitionerBase(const ServiceBuildInfo& sbi)
56: AbstractService(sbi)
57, m_sub_domain(sbi.subDomain())
58, m_mesh(sbi.mesh())
59, m_cell_family(sbi.mesh()->cellFamily())
60, m_lbMng(sbi.subDomain()->loadBalanceMng())
61, m_lb_mng_internal(sbi.subDomain()->loadBalanceMng()->_internalApi())
62{
63 IParallelMng* pm = m_mesh->parallelMng();
64 m_pm_sub = pm;
65 m_is_non_manifold_mesh = m_mesh->meshKind().isNonManifold();
66}
67
68/*---------------------------------------------------------------------------*/
69/*---------------------------------------------------------------------------*/
70
71MeshPartitionerBase::
72~MeshPartitionerBase()
73{
74 freeConstraints();
75 delete m_unique_id_reference;
76}
77
78/*---------------------------------------------------------------------------*/
79/*---------------------------------------------------------------------------*/
80
81void* MeshPartitionerBase::
82getCommunicator() const
83{
84 return m_pm_sub->getMPICommunicator();
85}
86
87/*---------------------------------------------------------------------------*/
88/*---------------------------------------------------------------------------*/
89
90Parallel::Communicator MeshPartitionerBase::
91communicator() const
92{
93 return m_pm_sub->communicator();
94}
95
96/*---------------------------------------------------------------------------*/
97/*---------------------------------------------------------------------------*/
98
99void MeshPartitionerBase::
100changeOwnersFromCells()
101{
102 m_mesh->utilities()->changeOwnersFromCells();
103}
104
105/*---------------------------------------------------------------------------*/
106/*---------------------------------------------------------------------------*/
107
108void MeshPartitionerBase::
109initConstraints(bool uidref)
110{
111 m_mesh_dimension = m_mesh->dimension();
112
113 _initArrayCellsWithConstraints();
114
115 _initFilterLidCells();
116
117 if (uidref)
118 _initUidRef();
119
120 _initLid2LidCompacted();
121
122 _initNbCellsWithConstraints();
123
124 m_lb_mng_internal->initAccess(m_mesh);
125
126 info() << "Weight (" << subDomain()->commonVariables().globalIteration()
127 << "): " << m_lb_mng_internal->nbCriteria(m_mesh);
128}
129
130/*---------------------------------------------------------------------------*/
131/*---------------------------------------------------------------------------*/
132
133void MeshPartitionerBase::
134freeConstraints()
135{
136 m_lb_mng_internal->endAccess();
137 _clearCellWgt();
138 m_cells_with_constraints.clear();
139 m_cells_with_weak_constraints.clear();
140 m_nb_cells_with_constraints = 0;
141 m_filter_lid_cells.clear();
142 m_local_id_2_local_id_compacted.clear();
143 delete m_unique_id_reference;
144 m_unique_id_reference = nullptr;
145 m_check.clear();
146}
147
148/*---------------------------------------------------------------------------*/
149/*---------------------------------------------------------------------------*/
150
151bool MeshPartitionerBase::
152_createConstraintsLists(Int64MultiArray2& tied_uids)
153{
154 int allLocal = 0;
155
156 // It is important to define constraints only once !
157 m_cells_with_constraints.clear();
158
159 IItemFamily* cellFamily = m_mesh->itemFamily(IK_Cell);
160
161 // info()<<"tied_uids.dim1Size() = "<<tied_uids.dim1Size();
162 for (Integer i = 0, n = tied_uids.dim1Size(); i < n; ++i) {
163 // the list of uniqueIds for one constraint
164 Int64ConstArrayView uids(tied_uids[i]);
165
166 // this same list in localId, knowing that some cells are not local
167 Int32UniqueArray lids(uids.size());
168 cellFamily->itemsUniqueIdToLocalId(lids, uids, false);
169
170 // the local list in localId (without the ids of cells on other procs)
171 Int32UniqueArray lids_loc;
172 lids_loc.reserve(lids.size());
173 for (Integer j = 0, js = lids.size(); j < js; ++j) {
174 Int32 lid = lids[j];
175 if (lid != NULL_ITEM_LOCAL_ID)
176 lids_loc.add(lid);
177 }
178
179 // the array with the cells of this constraint
180 ItemVectorView items_view = cellFamily->view(lids_loc);
181 SharedArray<Cell> cells;
182 for (Integer j = 0, js = items_view.size(); j < js; j++)
183 if (items_view[j].isOwn())
184 cells.add(items_view[j].toCell());
185
186 // The elements are not crossing this processor
187 allLocal += (((cells.size() == 0) ||
188 (cells.size() == uids.size()))
189 ? 0
190 : 1);
191
192 // we add this array to the list
193 if (!cells.empty())
194 m_cells_with_constraints.add(cells);
195 }
196 IParallelMng* pm = m_mesh->parallelMng();
197
198 // Return reduction because we need all subdomains to be correct
199 int sum = pm->reduce(Parallel::ReduceSum, allLocal);
200 return (sum == 0);
201}
202
203/*---------------------------------------------------------------------------*/
204/*---------------------------------------------------------------------------*/
205
206void MeshPartitionerBase::
207_initArrayCellsWithConstraints()
208{
209 // It is important to define constraints only once !
210 m_cells_with_constraints.clear();
211 m_cells_with_weak_constraints.clear();
212
213 if (!m_mesh->partitionConstraintMng())
214 return;
215
216 // here we must retrieve the lists of lists of cells
217 // with the constraint of not being separated during repartitioning
218
219 // a 2D array with the uniqueIds of the cells
220 Int64MultiArray2 tied_uids;
221
222 // Compute tied_uids first because we cannot use this after redistribution
223 // Note: It is correct to do so because ConstraintList is global, so not changed
224 // by the redistribution.
225 m_mesh->partitionConstraintMng()->computeConstraintList(tied_uids);
226 // Be sure that constraints are local !
227#ifdef INSURE_CONSTRAINTS
228 if (!_createConstraintsLists(tied_uids)) {
229 if (m_is_non_manifold_mesh)
230 ARCANE_FATAL("Constraints are not supported for non manifold mesh");
231 // Only appends for the first iteration because constraints are not set before !
232 VariableItemInt32& cells_new_owner(m_mesh->cellFamily()->itemsNewOwner());
233 ENUMERATE_CELL (icell, m_mesh->cellFamily()->allItems()) {
234 cells_new_owner[icell] = (*icell).owner();
235 }
236 m_mesh->modifier()->setDynamic(true);
237 m_mesh->partitionConstraintMng()->computeAndApplyConstraints();
238 m_mesh->utilities()->changeOwnersFromCells();
239 m_mesh->toPrimaryMesh()->exchangeItems();
240#endif // INSURE_CONSTRAINTS
241 if (!_createConstraintsLists(tied_uids))
242 throw FatalErrorException(A_FUNCINFO, "Issue with constraints !");
243#ifdef INSURE_CONSTRAINTS
244 }
245 m_mesh->partitionConstraintMng()->computeWeakConstraintList(tied_uids);
246
247 for (Integer i = 0; i < tied_uids.dim1Size(); ++i) {
248 std::pair<Int64, Int64> ids(tied_uids[i][0], tied_uids[i][1]);
249 m_cells_with_weak_constraints.insert(ids);
250 }
251#endif //INSURE_CONSTRAINTS
252}
253/*---------------------------------------------------------------------------*/
254/*---------------------------------------------------------------------------*/
255
256void MeshPartitionerBase::
257_initFilterLidCells()
258{
259 CellGroup all_cells = m_mesh->allCells();
260
261 // Setting up a filter on the localId marked with eMarkCellWithConstraint
262 m_filter_lid_cells.resize(m_mesh->cellFamily()->maxLocalId());
263 m_filter_lid_cells.fill(eCellGhost);
264
265 ENUMERATE_CELL (icell, m_mesh->ownCells()) {
266 m_filter_lid_cells[icell->localId()] = eCellClassical;
267 }
268
269 for (Integer i = 0; i < m_cells_with_constraints.size(); ++i) {
270 Array<Cell>& listCell = m_cells_with_constraints[i];
271 m_filter_lid_cells[listCell[0].localId()] = eCellReference;
272 for (Integer j = 1; j < listCell.size(); ++j) {
273#if 0
274 if (m_filter_lid_cells[listCell[j].localId()] != eCellClassical)
275 info() << "Pb in constraint " << i << " with cell[" << j
276 <<"] = " << listCell[j].uniqueId();
277#endif
278 m_filter_lid_cells[listCell[j].localId()] = eCellGrouped;
279 }
280 }
281}
282
283/*---------------------------------------------------------------------------*/
284/*---------------------------------------------------------------------------*/
285
286void MeshPartitionerBase::
287_checkCreateVar()
288{
289 if (!m_unique_id_reference)
290 m_unique_id_reference = new VariableCellInt64(VariableBuildInfo(m_mesh, "CellUniqueIdRef", IVariable::PNoDump));
291}
292
293/*---------------------------------------------------------------------------*/
294/*---------------------------------------------------------------------------*/
295
296void MeshPartitionerBase::
297_initUidRef()
298{
299 _checkCreateVar();
300 VariableCellInt64 uids_ref(*m_unique_id_reference);
301 // Setting up an indirection array between cells and a reference uniqueId
302 // allows knowing the uid of the first cell of each constraint
303 // including for ghost cells
304 ENUMERATE_CELL (icell, m_mesh->allCells()) {
305 uids_ref[icell] = icell->uniqueId();
306 }
307 for (Integer i = 0; i < m_cells_with_constraints.size(); ++i) {
308 Array<Cell>& listCell = m_cells_with_constraints[i];
309 Int64 id_ref = listCell[0].uniqueId();
310 for (Integer j = 1; j < listCell.size(); ++j)
311 uids_ref[listCell[j]] = id_ref;
312 }
313 uids_ref.synchronize();
314}
315
316/*---------------------------------------------------------------------------*/
317/*---------------------------------------------------------------------------*/
318
319void MeshPartitionerBase::
320_initUidRef(VariableCellInteger& cell_renum_uid)
321{
322 _checkCreateVar();
323 VariableCellInt64 uids_ref(*m_unique_id_reference);
324
325 // Setting up an indirection array between cells and a reference uniqueId
326 // allows knowing the uid of the first cell of each constraint
327 // including for ghost cells
328 ENUMERATE_CELL (icell, m_mesh->allCells()) {
329 uids_ref[icell] = cell_renum_uid[icell];
330 }
331 for (Integer i = 0; i < m_cells_with_constraints.size(); ++i) {
332 Array<Cell>& listCell = m_cells_with_constraints[i];
333 Int64 id_ref = cell_renum_uid[listCell[0]];
334 for (Integer j = 1; j < listCell.size(); ++j)
335 uids_ref[listCell[j]] = id_ref;
336 }
337 uids_ref.synchronize();
338}
339
340/*---------------------------------------------------------------------------*/
341/*---------------------------------------------------------------------------*/
342
343void MeshPartitionerBase::
344_initLid2LidCompacted()
345{
346 // Construction of the indirection array between the local numbering for all cells
347 // and a numbering without ghost cells or grouped cells
348 Integer index = 0;
349 m_local_id_2_local_id_compacted.resize(m_mesh->cellFamily()->maxLocalId());
350 m_check.resize(m_mesh->cellFamily()->maxLocalId());
351 m_check.fill(-1);
352
353 ENUMERATE_CELL (icell, m_mesh->allCells()) {
354 switch (m_filter_lid_cells[icell.itemLocalId()]) {
355 case eCellClassical:
356 case eCellReference:
357 m_local_id_2_local_id_compacted[icell->localId()] = index++;
359 break;
360 case eCellGrouped:
361 case eCellGhost:
362 m_local_id_2_local_id_compacted[icell->localId()] = -1;
363 break;
364 default:
365 throw FatalErrorException(A_FUNCINFO, "Invalid filter value");
366 }
367 }
368 // info()<<"m_local_id_2_local_id_compacted from 0 to "<<index-1;
369}
370
371/*---------------------------------------------------------------------------*/
372/*---------------------------------------------------------------------------*/
373
374void MeshPartitionerBase::
375_initNbCellsWithConstraints()
376{
377 // Calculate the number of internal cells taking into account the grouping according to constraints
378 m_nb_cells_with_constraints = m_mesh->ownCells().size();
379 for (Integer i = 0; i < m_cells_with_constraints.size(); ++i) {
380 m_nb_cells_with_constraints -= (m_cells_with_constraints[i].size() - 1);
381 }
382
383#if 0
384 for (Integer i=0; i<m_cells_with_constraints.size(); ++i){
385 Array<Cell> & listCell = m_cells_with_constraints[i];
386 for (Integer j = 1 ; j < listCell.size() ; ++j) {
387 if (m_filter_lid_cells[listCell[j].localId()] != eCellGrouped) {
388 info() << "Pb in group " << i << " " << listCell[j].localId() << "is not grouped";
389 }
390 }
391 info() << "Group of size " << i << " : " << listCell.size();
392 }
393#endif
394
395 info() << "allCells().size() = " << m_mesh->allCells().size();
396 info() << "ownCells().size() = " << m_mesh->ownCells().size();
397 info() << "m_nb_cells_with_constraints = " << m_nb_cells_with_constraints;
398}
399
400/*---------------------------------------------------------------------------*/
401Int32 MeshPartitionerBase::
402nbOwnCellsWithConstraints() const
403{
404 return m_nb_cells_with_constraints;
405}
406/*---------------------------------------------------------------------------*/
407
408/*---------------------------------------------------------------------------*/
409Integer MeshPartitionerBase::
410nbNeighbourCellsWithConstraints(Cell cell)
411{
412 Integer nbNeighbors = 0;
413
414 if (m_filter_lid_cells[cell.localId()] == eCellClassical || m_filter_lid_cells[cell.localId()] == eCellReference) {
415 Int64UniqueArray neighbors;
416 neighbors.resize(0);
417 getNeighbourCellsUidWithConstraints(cell, neighbors);
418 nbNeighbors = neighbors.size();
419 }
420 else
421 nbNeighbors = -1;
422 return (nbNeighbors);
423}
424/*---------------------------------------------------------------------------*/
425/*---------------------------------------------------------------------------*/
426//< Add a ngb cell if not already present.
427Real MeshPartitionerBase::
428_addNgb(const Cell& cell, const Face& face,
429 Int64Array& neighbourcells, Array<bool>& contrib,
430 HashTableMapT<Int64, Int32>& map,
431 Array<float>* ptrcommWeights, Int32 offset,
432 HashTableMapT<Int32, Int32>& lids, bool special)
433{
434 ARCANE_UNUSED(contrib);
435 ARCANE_UNUSED(lids);
436
437 Int64 uid = (*m_unique_id_reference)[cell];
438 bool toAdd = false;
439 Int32 myoffset = neighbourcells.size();
440 Real hg_contrib = 0;
441 const VariableItemReal& commCost = m_lb_mng_internal->commCost(m_mesh);
442 const float face_comm_cost = static_cast<float>(commCost[face]);
443 // Traditional cell, we can add
444 if ((!special) && (m_filter_lid_cells[cell.localId()] == eCellClassical))
445 toAdd = true;
446 else {
447 HashTableMapT<Int64, Int32>::Data* ptr;
448 ptr = map.lookupAdd(uid, myoffset, toAdd);
449 if (!toAdd && ptrcommWeights) {
450 myoffset = ptr->value();
451 (*ptrcommWeights)[offset + myoffset] += face_comm_cost;
452 }
453 }
454 if (toAdd) {
455 neighbourcells.add(uid);
456 if (ptrcommWeights) {
457 (*ptrcommWeights).add(face_comm_cost);
458 }
459 }
460
461 // TODO make hg_contrib work again.
462 //contrib[myoffset] = true;
463
464 // Count cell contrib only once, even if it appears several times
465 // if (ptrcommWeights) {
466 // lids.lookupAdd(cell.localId(), myoffset, toAdd);
467 // if (toAdd) {
468 // hg_contrib = m_criteria.getResidentMemory(cell);
469 // (*ptrcommWeights)[offset + myoffset] += hg_contrib;
470 // }
471 // }
472
473 return (hg_contrib);
474}
475
476/*---------------------------------------------------------------------------*/
477Real MeshPartitionerBase::
478getNeighbourCellsUidWithConstraints(Cell cell, Int64Array& neighbourcells,
479 Array<float>* ptrcommWeights,
480 bool no_cell_contrib)
481{
482 ARCANE_UNUSED(no_cell_contrib);
483
484 Int32 offset = 0;
485 Real hg_contrib = 0;
486
487 if ((m_filter_lid_cells[cell.localId()] != eCellClassical) && (m_filter_lid_cells[cell.localId()] != eCellReference))
488 return 0.0;
489
490 if (ptrcommWeights)
491 offset = (*ptrcommWeights).size();
492
493 neighbourcells.resize(0);
494
495#ifdef MY_DEBUG
496 VariableCellInt64 uids_ref(*m_unique_id_reference);
497 Int64 uid = uids_ref[cell];
498#endif /* MY_DEBUG */
499
500 Integer index = -1;
501 Integer nbFaces = cell.nbFace();
502
503 // First compute max degree
504 if (m_filter_lid_cells[cell.localId()] == eCellReference) {
505 for (index = 0; index < m_cells_with_constraints.size() && m_cells_with_constraints[index][0] != cell; ++index) {
506 }
507 if (index == m_cells_with_constraints.size())
508 throw FatalErrorException(A_FUNCINFO, "Unable to find cell");
509
510 Array<Cell>& listCell = m_cells_with_constraints[index];
511 nbFaces = 0;
512 // Activate constraint, but not the reference !
513 for (Integer j = 1; j < listCell.size(); ++j) {
514 m_filter_lid_cells[listCell[j].localId()] = eCellInAConstraint;
515 nbFaces += listCell[j].nbFace();
516 }
517 }
518
519 HashTableMapT<Int64, Int32> difficultNgb(nbFaces, true);
520 HashTableMapT<Int32, Int32> lids(nbFaces, true);
521 UniqueArray<bool> contrib(nbFaces);
522 // Array<Real>memUsed(nbFaces); // (HP): bug sur cette structure dans la suite du code
523 contrib.fill(false);
524
525 if (m_filter_lid_cells[cell.localId()] == eCellClassical) {
526 if (m_is_non_manifold_mesh && cell.hasFlags(ItemFlags::II_HasEdgeFor1DItems)) {
527 // In the case of a non-manifold mesh, the cell may contain
528 // edges instead of faces. If so, we use the edges
529 // to determine neighbors.
530 // In this case, we only consider neighbors that also have
531 // 'ItemFlags::II_HasEdgeFro1DItems' positioned.
532 for (Edge sub_edge : cell.edges()) {
533 // only consider edges that have a neighboring cell
534 if (sub_edge.nbCell() >= 2) {
535 for (Cell sub_cell : sub_edge.cells()) {
536 if (sub_cell != cell && sub_cell.hasFlags(ItemFlags::II_HasEdgeFor1DItems)) {
537 hg_contrib += 1.0;
538 neighbourcells.add((*m_unique_id_reference)[sub_cell]);
539 // TODO: look at the value that needs to be added for communications
540 if (ptrcommWeights)
541 (*ptrcommWeights).add(1.0f);
542 }
543 }
544 }
545 }
546 }
547 else {
548 for (Integer z = 0; z < cell.nbFace(); ++z) {
549 Face face = cell.face(z);
550 // only consider faces that have a neighboring cell
551 if (face.nbCell() == 2) {
552 // search for the external cell
553 Cell opposite_cell = (face.cell(0) != cell ? face.cell(0) : face.cell(1));
554 hg_contrib += _addNgb(opposite_cell, face, neighbourcells, contrib, difficultNgb,
555 ptrcommWeights, offset, lids);
556 }
557 }
558 }
559 // //Now add cell contribution to edge weight
560 // if ((ptrcommWeights) &&(!noCellContrib)) {
561 // float mymem = m_criteria.getOverallMemory(cell);
562 // for (Integer j = 0 ; j < neighbourcells.size() ;++j) {
563 // (*ptrcommWeights)[offset+j] += mymem;
564 // }
565 // }
566 }
567 else { //if (m_filter_lid_cells[cell.localId()] == eCellReference){
568 Array<Cell>& listCell = m_cells_with_constraints[index];
569 m_filter_lid_cells[listCell[0].localId()] = eCellInAConstraint;
570 // memUsed.fill(0);
571 for (Integer j = 0; j < listCell.size(); ++j) {
572 contrib.fill(false);
573 // hg_contrib += m_criteria.getOverallMemory(listCell[j]);
574 // memUsed[j] = hg_contrib;
575 for (Integer z = 0; z < listCell[j].nbFace(); ++z) {
576 const Face& face = listCell[j].face(z);
577 // only consider faces that have a cell not marked as eCellInAConstraint and with a neighboring cell
578 if ((face.nbCell() == 2) && (m_filter_lid_cells[face.cell(0).localId()] != eCellInAConstraint || m_filter_lid_cells[face.cell(1).localId()] != eCellInAConstraint)) {
579 // search for the external cell
580 const Cell& opposite_cell = (m_filter_lid_cells[face.cell(0).localId()] != eCellInAConstraint ? face.cell(0) : face.cell(1));
581 hg_contrib += _addNgb(opposite_cell, face, neighbourcells, contrib, difficultNgb,
582 ptrcommWeights, offset, lids, true);
583 }
584 }
585 // //Now add cell contribution to edge weight
586 // if (ptrcommWeights && !noCellContrib) {
587 // for (Integer c = 0 ; c < neighbourcells.size() ;++c) {
588 // if (contrib[c])
589 // (*ptrcommWeights)[offset+c] += memUsed[j];
590 // }
591 // }
592 }
593 m_filter_lid_cells[listCell[0].localId()] = eCellReference;
594 for (Integer j = 1; j < listCell.size(); ++j)
595 m_filter_lid_cells[listCell[j].localId()] = eCellGrouped;
596
597 } // end if eCellReference
598
599 return (hg_contrib);
600}
601/*---------------------------------------------------------------------------*/
602/*---------------------------------------------------------------------------*/
603void MeshPartitionerBase::
604getNeighbourNodesUidWithConstraints(Cell cell, Int64UniqueArray neighbournodes)
605{
606 neighbournodes.resize(cell.nbNode());
607
608 for (Integer z = 0; z < cell.nbNode(); ++z) {
609 neighbournodes[z] = cell.node(z).uniqueId();
610 }
611}
612/*---------------------------------------------------------------------------*/
613/*---------------------------------------------------------------------------*/
614Int32 MeshPartitionerBase::
615localIdWithConstraints(Cell cell)
616{
617 return m_local_id_2_local_id_compacted[cell.localId()];
618}
619/*---------------------------------------------------------------------------*/
620Int32 MeshPartitionerBase::
621localIdWithConstraints(Int32 cell_lid)
622{
623 //info()<<"localIdWithConstraints("<<cell_lid<<") => "<<m_local_id_2_local_id_compacted[cell_lid];
624 return m_local_id_2_local_id_compacted[cell_lid];
625}
626/*---------------------------------------------------------------------------*/
627/*---------------------------------------------------------------------------*/
628void MeshPartitionerBase::
629invertArrayLid2LidCompacted()
630{
631 //info()<<"MeshPartitionerBase::invertArrayLid2LidCompacted()";
632 Integer index = 0;
633 for (Integer i = 0; i < m_mesh->allCells().size(); i++) {
634 if (m_local_id_2_local_id_compacted[i] != -1)
635 m_local_id_2_local_id_compacted[index++] = i;
636 }
637 for (; index < m_mesh->allCells().size(); index++)
638 m_local_id_2_local_id_compacted[index] = -2;
639}
640/*---------------------------------------------------------------------------*/
641
642SharedArray<float> MeshPartitionerBase::
643cellsSizeWithConstraints()
644{
645 VariableCellReal mWgt = m_lb_mng_internal->massResWeight(m_mesh);
646 return _cellsProjectWeights(mWgt);
647}
648
649SharedArray<float> MeshPartitionerBase::
650cellsWeightsWithConstraints(Int32 max_nb_weight, bool ask_lb_cells)
651{
652 ARCANE_UNUSED(ask_lb_cells);
653
654 Int32 nb_weight = max_nb_weight;
655
656 Int32 nb_criteria = m_lb_mng_internal->nbCriteria(m_mesh);
657
658 if (max_nb_weight <= 0 || max_nb_weight > nb_criteria)
659 nb_weight = nb_criteria;
660
661 info() << "Number of weights " << nb_weight << " / " << nb_criteria;
662
663 VariableCellArrayReal mWgt = m_lb_mng_internal->mCriteriaWeight(m_mesh);
664 return _cellsProjectWeights(mWgt, nb_weight);
665}
666
667/*---------------------------------------------------------------------------*/
668/*---------------------------------------------------------------------------*/
669
670SharedArray<float> MeshPartitionerBase::
671_cellsProjectWeights(VariableCellArrayReal& cellWgtIn, Int32 nbWgt) const
672{
673 SharedArray<float> cellWgtOut(nbOwnCellsWithConstraints() * nbWgt);
674 if (nbWgt > cellWgtIn.arraySize()) {
675 ARCANE_FATAL("Asked for too many weights n={0} array_size={1}", nbWgt, cellWgtIn.arraySize());
676 }
677
678 ENUMERATE_CELL (icell, m_mesh->ownCells()) {
679 if (m_filter_lid_cells[icell->localId()] == eCellClassical)
680 for (int i = 0; i < nbWgt; ++i) {
681 float v = static_cast<float>(cellWgtIn[icell][i]);
682 cellWgtOut[m_local_id_2_local_id_compacted[icell->localId()] * nbWgt + i] = v;
683 }
684 }
685 RealUniqueArray w(nbWgt);
686 for (auto& ptr : m_cells_with_constraints) {
687 w.fill(0);
688 for (const auto& cell : ptr) {
689 for (int i = 0; i < nbWgt; ++i)
690 w[i] += cellWgtIn[cell][i];
691 }
692 for (int i = 0; i < nbWgt; ++i)
693 cellWgtOut[m_local_id_2_local_id_compacted[ptr[0].localId()] * nbWgt + i] = (float)(w[i]);
694 }
695
696 return cellWgtOut;
697}
698
699/*---------------------------------------------------------------------------*/
700/*---------------------------------------------------------------------------*/
701SharedArray<float> MeshPartitionerBase::
702_cellsProjectWeights(VariableCellReal& cellWgtIn) const
703{
704 SharedArray<float> cellWgtOut(nbOwnCellsWithConstraints());
705
706 ENUMERATE_CELL (icell, m_mesh->ownCells()) {
707 if (m_filter_lid_cells[icell->localId()] == eCellClassical)
708 cellWgtOut[m_local_id_2_local_id_compacted[icell->localId()]] = (float)cellWgtIn[icell];
709 }
710 for (auto& ptr : m_cells_with_constraints) {
711 Real w = 0;
712 for (Cell cell : ptr) {
713 w += cellWgtIn[cell];
714 }
715 cellWgtOut[m_local_id_2_local_id_compacted[ptr[0].localId()]] = (float)w;
716 }
717
718 return cellWgtOut;
719}
720
721/*---------------------------------------------------------------------------*/
722bool MeshPartitionerBase::
723cellUsedWithConstraints(Cell cell)
724{
725 eMarkCellWithConstraint marque = m_filter_lid_cells[cell.localId()];
726 // info()<<"cellUsedWithConstraints("<<cell<<") => "<<(marque == eCellClassical || marque == eCellReference);
727 return (marque == eCellClassical || marque == eCellReference);
728}
729
730bool MeshPartitionerBase::
731cellUsedWithWeakConstraints(std::pair<Int64, Int64>& paired_item)
732{
733 std::pair<Int64, Int64> other_pair(paired_item.second, paired_item.first);
734 return ((m_cells_with_weak_constraints.find(paired_item) != m_cells_with_weak_constraints.end()) || m_cells_with_weak_constraints.find(other_pair) != m_cells_with_weak_constraints.end());
735}
736/*---------------------------------------------------------------------------*/
737/*---------------------------------------------------------------------------*/
738void MeshPartitionerBase::
739changeCellOwner(Item cell, VariableItemInt32& cells_new_owner, Int32 new_owner)
740{
741 // TODO to optimize for the case where there are many small constraints
742
743 //info()<<"changeCellOwner "<<cell<<", new_owner = "<<new_owner;
744 cells_new_owner[cell] = new_owner;
745
746 if (m_filter_lid_cells[cell.localId()] == eCellReference) {
747 Integer index = -1;
748 for (index = 0; index < m_cells_with_constraints.size() && m_cells_with_constraints[index][0] != cell; ++index) {
749 }
750 if (index == m_cells_with_constraints.size())
751 throw FatalErrorException("MeshPartitionerBase::changeCellOwner(): unable to find cell");
752
753 Array<Cell>& listCell = m_cells_with_constraints[index];
754 //info()<<" changement en plus pour listCell: "<<listCell;
755 for (Integer i = 1; i < listCell.size(); i++)
756 cells_new_owner[listCell[i]] = new_owner;
757 }
758}
759
760/*---------------------------------------------------------------------------*/
761/*---------------------------------------------------------------------------*/
762// Utility functions for the old partitioning interface.
763
765{
766 m_lb_mng_internal->reset(m_mesh);
767 _clearCellWgt();
768
769 for (int i = 0; i < nb_weight; ++i) {
770 StringBuilder varName("LB_wgt_");
771 varName += (i + 1);
772
773 VariableCellReal myvar(VariableBuildInfo(m_mesh, varName.toString(),
775 ENUMERATE_CELL (icell, m_mesh->ownCells()) {
776 (myvar)[icell] = weights[icell->localId() * nb_weight + i];
777 }
778 m_lb_mng_internal->addCriterion(myvar, m_mesh);
779 }
780
781 m_lb_mng_internal->initAccess(m_mesh);
782 m_lb_mng_internal->setMassAsCriterion(m_mesh, false);
783 m_lb_mng_internal->setNbCellsAsCriterion(m_mesh, false);
784}
785
786/*---------------------------------------------------------------------------*/
787/*---------------------------------------------------------------------------*/
788
789Integer MeshPartitionerBase::
790nbCellWeight() const
791{
792 return math::max(m_lb_mng_internal->nbCriteria(m_mesh), 1);
793}
794
795ArrayView<float> MeshPartitionerBase::
796cellsWeight() const
797{
798 ARCANE_FATAL("NotImplemented");
799}
800
801void MeshPartitionerBase::
802_clearCellWgt()
803{
804 //m_cell_wgt.clear();
805}
806
807/*---------------------------------------------------------------------------*/
808/*---------------------------------------------------------------------------*/
809
811template <class ArrayType> Parallel::Request
813 UniqueArray<ArrayType> data, String header, int step = 1)
814{
816 UniqueArray<Integer> sizes(pm->commSize());
817 UniqueArray<Integer> mysize(1);
818 mysize[0] = data.size();
819
820 pm->gather(mysize, sizes, pm->masterIORank());
821
822 req = pm->send(data, pm->masterIORank(), false);
823
824 if (pm->isMasterIO()) {
825 ofstream ofile;
826
827 ofile.open(filename.localstr());
828 if (!header.null()) {
829 ofile << header;
830 Int64 sum = 0;
831 for (ConstIterT<UniqueArray<Integer>> iter(sizes); iter(); ++iter)
832 sum += *iter;
833 ofile << sum << std::endl;
834 }
835
836 for (int rank = 0; rank < pm->commSize(); ++rank) {
837 UniqueArray<ArrayType> otherdata(sizes[rank]);
838 pm->recv(otherdata, rank, true);
839 for (ConstIterT<ArrayView<ArrayType>> myiter(otherdata); myiter();) {
840 for (int j = 0; (j < step) && myiter(); ++j, ++myiter)
841 ofile << *myiter << " ";
842 ofile << std::endl;
843 }
844 }
845 ofile.close();
846 }
847
848 return req;
849}
850
851/*---------------------------------------------------------------------------*/
852/*---------------------------------------------------------------------------*/
853
855{
856 int i = 0;
857 IParallelMng* pm = m_mesh->parallelMng();
858 String header;
859
860 // ---
861 // Send vertex uid first
862 Int64UniqueArray uid(m_nb_cells_with_constraints);
863 uid.fill(-1);
864 VariableCellInt64 uids_ref(*m_unique_id_reference);
865 i = 0;
866 ENUMERATE_CELL (icell, m_mesh->ownCells()) {
867 if ((m_filter_lid_cells[icell->localId()] != eCellClassical) && (m_filter_lid_cells[icell->localId()] != eCellReference))
868 continue;
869
870 uid[i++] = uids_ref[icell];
871 }
872
875 req = centralizePartInfo<Int64>(filebase + ".uid", pm, uid, header);
876 reqs.add(req);
877
878 UniqueArray<float> vwgt = cellsWeightsWithConstraints(0);
879 // Hack: use Real to avoid bugs in pm->recv ...
880 // TODO: Fix this.
881 UniqueArray<Real> rvwgt(vwgt.size());
882 IterT<UniqueArray<Real>> myiterr(rvwgt);
883 for (ConstIterT<UniqueArray<float>> myiterf(vwgt);
884 myiterf(); ++myiterf, ++myiterr)
885 (*myiterr) = (Real)(*myiterf);
886
887 req = centralizePartInfo<Real>(filebase + ".vwgt", pm, rvwgt, header, nbCellWeight());
888 reqs.add(req);
889
890 // Send vertex coords
891 VariableNodeReal3& coords(mesh()->nodesCoordinates());
892 UniqueArray<Real3> my_coords(m_nb_cells_with_constraints);
893 i = 0;
894 ENUMERATE_CELL (icell, m_mesh->ownCells()) {
895 if ((m_filter_lid_cells[icell->localId()] != eCellClassical) && (m_filter_lid_cells[icell->localId()] != eCellReference))
896 continue;
897
898 // calculate a barycenter
899 for (Integer z = 0, zs = (*icell).nbNode(); z < zs; ++z) {
900 const Node& node = (*icell).node(z);
901 my_coords[i] += coords[node];
902 }
903 my_coords[i] /= Convert::toDouble((*icell).nbNode());
904 i++;
905 }
906 req = centralizePartInfo<Real3>(filebase + ".xyz", pm, my_coords, header);
907 reqs.add(req);
908
909 // Send relationships to master
911 ENUMERATE_CELL (icell, m_mesh->ownCells()) {
912 Int64UniqueArray neighbourcells;
913 UniqueArray<float> commWeights;
914
915 if ((m_filter_lid_cells[icell->localId()] != eCellClassical) && (m_filter_lid_cells[icell->localId()] != eCellReference))
916 continue;
917 getNeighbourCellsUidWithConstraints(*icell, neighbourcells, &commWeights);
918 Int64 my_uid = uids_ref[icell];
919 for (Integer j = 0; j < neighbourcells.size(); ++j) {
920 if (neighbourcells[j] > my_uid)
921 continue;
922 Real3 tmp(static_cast<Real>(my_uid + 1), static_cast<Real>(neighbourcells[j] + 1), commWeights[j]);
923 nnz.add(tmp);
924 }
925 }
926 Integer nbvertices;
927 nbvertices = pm->reduce(Parallel::ReduceSum, m_nb_cells_with_constraints);
928 StringBuilder myheader = "%%MatrixMarket matrix coordinate real symmetric\n";
929 myheader += nbvertices;
930 myheader += " ";
931 myheader += nbvertices;
932 myheader += " ";
933 req = centralizePartInfo<Real3>(filebase + ".mtx", pm, nnz, myheader.toString());
934 reqs.add(req);
935
936 pm->waitAllRequests(reqs);
937}
938
939/*---------------------------------------------------------------------------*/
940/*---------------------------------------------------------------------------*/
941
942} // End namespace Arcane
943
944/*---------------------------------------------------------------------------*/
945/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Types and macros for iterating over mesh entities.
#define ENUMERATE_CELL(name, group)
Generic enumerator for a cell group.
Integer size() const
Number of elements in the vector.
Base class of a service.
Modifiable view of an array of type T.
void fill(ConstReferenceType value)
Fills the array with the value value.
void resize(Int64 s)
Changes the number of elements in the array to s.
void add(ConstReferenceType val)
Adds element val to the end of the array.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
Interface of the parallelism manager for a subdomain.
virtual void recv(ArrayView< char > values, Int32 rank)=0
virtual bool isMasterIO() const =0
true if the instance is a master I/O manager.
virtual Int32 commSize() const =0
Number of instances in the communicator.
virtual void waitAllRequests(ArrayView< Request > rvalues)=0
Blocks while waiting for the rvalues requests to complete.
virtual void gather(ConstArrayView< char > send_buf, ArrayView< char > recv_buf, Int32 rank)=0
Performs a gather operation onto a processor. This is a collective operation. The array send_buf must...
virtual Integer masterIORank() const =0
Rank of the instance managing I/O (for which isMasterIO() is true).
virtual char reduce(eReduceType rt, char v)=0
Performs a reduction of type rt on the real v and returns the value.
@ PTemporary
Indicates that the variable is temporary.
Definition IVariable.h:114
@ PExecutionDepend
Indicates that the variable value is dependent on the execution.
Definition IVariable.h:96
@ PNoDump
Indicates that the variable should not be saved.
Definition IVariable.h:62
Iterator intervalThis class manages an iterator pair allowing modification of the elements of the con...
void setCellsWeight(ArrayView< float > weights, Integer nb_weight) override
Allows defining the weights of objects to be partitioned: ILoadBalanceMng must now be used.
IMesh * mesh() const override
Mesh associated with the partitioner.
virtual void dumpObject(String filename="toto")
Dumps the partitioning information to disk.
Node of a mesh.
Definition Item.h:598
Class managing a 3-dimensional real vector.
Definition Real3.h:132
Structure containing the information to create a service.
Unicode character string constructor.
String toString() const
Returns the constructed character string.
bool null() const
Returns true if the string is null.
Definition String.cc:306
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:229
1D data vector with value semantics (STL style).
Parameters necessary for building a variable.
T max(const T &a, const T &b, const T &c)
Returns the maximum of three elements.
Definition MathUtils.h:407
ItemGroupT< Cell > CellGroup
Group of cells.
Definition ItemTypes.h:184
MeshVariableScalarRefT< Cell, Real > VariableCellReal
Real type quantity at cell center.
MeshVariableScalarRefT< Cell, Int64 > VariableCellInt64
Quantity at the cell center of 64-bit integer type.
ItemVariableScalarRefT< Real > VariableItemReal
Real type quantity.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
MeshVariableArrayRefT< Cell, Real > VariableCellArrayReal
Quantity at the cell center of real array type.
ItemVariableScalarRefT< Int32 > VariableItemInt32
32-bit integer type quantity
double toDouble(Real r)
Converts a Real to double.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
Definition UtilsTypes.h:339
Parallel::Request centralizePartInfo(String filename, IParallelMng *pm, UniqueArray< ArrayType > data, String header, int step=1)
Auxiliary function to dump the graph.
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
MultiArray2< Int64 > Int64MultiArray2
2D variable size array of 64-bit integers
Definition UtilsTypes.h:419
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:480
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
Definition UtilsTypes.h:341
UniqueArray< Real > RealUniqueArray
Dynamic 1D array of reals.
Definition UtilsTypes.h:349
double Real
Type representing a real number.
@ Cell
The mesh is AMR by cell.
Definition MeshKind.h:53