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