Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
ArcaneCasePartitioner.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/* ArcaneCasePartitioner.cc (C) 2000-2025 */
9/* */
10/* External mesh partitioning service. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ScopedPtr.h"
15#include "arcane/utils/StringBuilder.h"
16#include "arcane/utils/PlatformUtils.h"
17#include "arcane/utils/ITraceMng.h"
18
19#include "arcane/core/BasicService.h"
20#include "arcane/core/ISubDomain.h"
21#include "arcane/core/ServiceFinder2.h"
22#include "arcane/core/FactoryService.h"
23#include "arcane/core/SerializeBuffer.h"
24#include "arcane/core/IMeshPartitioner.h"
25#include "arcane/core/IMainFactory.h"
26#include "arcane/core/IMeshModifier.h"
27#include "arcane/core/Properties.h"
28#include "arcane/core/IMeshMng.h"
29#include "arcane/core/IMeshFactoryMng.h"
30#include "arcane/core/MeshBuildInfo.h"
31#include "arcane/core/MeshKind.h"
32#include "arcane/core/IInitialPartitioner.h"
33#include "arcane/core/Timer.h"
34#include "arcane/core/IMesh.h"
35#include "arcane/core/IMeshSubMeshTransition.h"
36#include "arcane/core/IItemFamily.h"
37#include "arcane/core/IDirectExecution.h"
38#include "arcane/core/IParallelMng.h"
39#include "arcane/core/IMeshUtilities.h"
40#include "arcane/core/IMeshWriter.h"
41#include "arcane/core/ITimeStats.h"
42#include "arcane/core/ServiceBuilder.h"
43#include "arcane/core/IMeshPartitionConstraintMng.h"
44#include "arcane/core/ExternalPartitionConstraint.h"
45#include "arcane/core/internal/MshMeshGenerationInfo.h"
46
47#include "arcane/std/ArcaneCasePartitioner_axl.h"
48
49#include <map>
50
51/*---------------------------------------------------------------------------*/
52/*---------------------------------------------------------------------------*/
53
54namespace Arcane
55{
56
57/*---------------------------------------------------------------------------*/
58/*---------------------------------------------------------------------------*/
59
61
62/*---------------------------------------------------------------------------*/
63/*---------------------------------------------------------------------------*/
64
65class ArcaneInitialPartitioner
67{
68 public:
69
71 {
72 VariableCellInt32* m_true_cells_owner = nullptr;
73 VariableNodeInt32* m_true_nodes_owner = nullptr;
74 };
75
76 public:
77
78 ArcaneInitialPartitioner(ArcaneCasePartitioner* mt, ISubDomain* sd)
79 : m_sub_domain(sd)
80 , m_main(mt)
81 {
82 }
83 void build() override {}
84 void partitionAndDistributeMeshes(ConstArrayView<IMesh*> meshes) override;
85
86 private:
87
89 void _mergeConstraints(ConstArrayView<IMesh*> meshes);
90
92 void _printStats(Integer nb_part, IMesh* mesh, VariableCellInt32& new_owners);
93
94 public:
95
96 ISubDomain* m_sub_domain = nullptr;
97 ArcaneCasePartitioner* m_main = nullptr;
100};
101
102/*---------------------------------------------------------------------------*/
103/*---------------------------------------------------------------------------*/
107class ArcaneCasePartitioner
109{
110 public:
111 public:
112
113 explicit ArcaneCasePartitioner(const ServiceBuildInfo& sbi);
114 ~ArcaneCasePartitioner() override;
115
116 public:
117
118 void build() override {}
119 void execute() override;
120 void setParallelMng(IParallelMng*) override {}
121 bool isActive() const override { return true; }
122
123 private:
124
126 void _initCorrespondance(Int32 my_rank);
127
129 void _writeCorrespondance(Int32 rank, Int64Array& nodesUniqueId, Int64Array& cellsUniqueId);
130
132 void _finalizeCorrespondance(Int32 my_rank);
133
134 private:
135
136 std::ofstream m_sortiesCorrespondance;
137
138 ArcaneInitialPartitioner* m_init_part = nullptr;
139
140 void _partitionMesh(Int32 nb_part);
141 void _computeGroups(IItemFamily* current_family, IItemFamily* new_family);
142 void _addGhostLayers(CellGroup current_all_cells, Array<Cell>& cells_selected_for_new_mesh,
143 Integer nb_layer, Integer maxLocalIdCell, Integer maxLocalIdNode);
144 void _addGhostGroups(IMesh* new_mesh, Array<Cell>& cells_selected_for_new_mesh,
145 VariableCellInt32& true_cells_owner, VariableNodeInt32& true_nodes_owner,
146 Int32Array& new_cells_local_id, Integer id_loc);
147};
148
149/*---------------------------------------------------------------------------*/
150/*---------------------------------------------------------------------------*/
151
154{
155 Integer nb_mesh = meshes.size();
156 if (nb_mesh != 1)
157 ARCANE_FATAL("Can not partition multiple meshes");
158
159 IMesh* mesh = meshes[0];
160 ISubDomain* sd = m_sub_domain;
161 ITraceMng* tm = sd->traceMng();
162
163 tm->info() << " _regroupeContraintes: nbMailles = " << meshes[0]->nbCell() << ", nbMaillesLocales = " << meshes[0]->ownCells().size();
164
165 Integer nb_contraintes = m_main->options()->constraints.size();
166 tm->info() << "Number of constraints = " << nb_contraintes;
167 if (nb_contraintes == 0)
168 return;
169
170 IItemFamily* current_cell_family = mesh->cellFamily();
171 VariableItemInt32& cells_new_owner(current_cell_family->itemsNewOwner());
172 ENUMERATE_CELL (icell, current_cell_family->allItems()) {
173 cells_new_owner[icell] = (*icell).owner();
174 }
175
177 IMeshPartitionConstraint* c = new ExternalPartitionConstraint(mesh, m_main->options()->constraints);
178 mesh->partitionConstraintMng()->addConstraint(c);
179 mesh->partitionConstraintMng()->computeAndApplyConstraints();
180
181 cells_new_owner.synchronize();
182 mesh->utilities()->changeOwnersFromCells();
183 mesh->modifier()->setDynamic(true);
184 bool compact = mesh->properties()->getBool("compact");
185 mesh->properties()->setBool("compact", true);
186 mesh->toPrimaryMesh()->exchangeItems();
187 mesh->properties()->setBool("compact", compact);
188#if 0
189#ifdef ARCANE_DEBUG
190 ScopedPtrT<IMeshWriter> mesh_writer;
191 FactoryT<IMeshWriter> mesh_writer_factory(sd->serviceMng());
192 mesh_writer = mesh_writer_factory.createInstance("Lima",true);
193 IParallelMng* pm = sd->parallelMng();
194 Int32 my_rank = pm->commRank();
195
196 StringBuilder filename = "cut_mesh_after_";
197 filename += my_rank;
198 filename += ".mli2";
199 mesh_writer->writeMeshToFile(mesh,filename);
200#endif
201#endif
202}
203
204/*---------------------------------------------------------------------------*/
205/*---------------------------------------------------------------------------*/
206
209{
210 String lib_name = m_main->options()->library();
211 ISubDomain* sd = m_sub_domain;
212 IParallelMng* pm = sd->parallelMng();
213 Int32 nb_rank = pm->commSize();
214 //Int32 my_rank = pm->commRank();
215 ServiceBuilder<IMeshPartitioner> service_builder(sd);
216 auto mesh_partitioner(service_builder.createReference(lib_name, SB_AllowNull));
217 ITraceMng* tm = sd->traceMng();
218 tm->info() << "DoInitialPartition. Service=" << lib_name;
219
220 if (!mesh_partitioner.get())
221 ARCANE_FATAL("can not found service named '{0}' for initial mesh partitioning", lib_name);
222
223 _mergeConstraints(meshes);
224
225 Integer nb_mesh = meshes.size();
226 if (nb_mesh != 1)
227 ARCANE_FATAL("Can not partition multiple meshes");
228
229 m_part_indexes.resize(nb_mesh);
230 Int32 nb_part = m_main->options()->nbCutPart();
231 if (nb_part == 0)
232 nb_part = nb_rank;
233 tm->info() << "NbPart = " << nb_part << " nb_mesh=" << nb_mesh;
234
235 for (Integer i = 0; i < nb_mesh; ++i) {
236 IMesh* mesh = meshes[i];
238 VariableCellInt32* p_true_cells_owner = new VariableCellInt32(VariableBuildInfo(mesh, "TrueCellsOwner"));
239 VariableNodeInt32* p_true_nodes_owner = new VariableNodeInt32(VariableBuildInfo(mesh, "TrueNodesOwner"));
240 m_part_indexes[i].m_true_cells_owner = p_true_cells_owner;
241 m_part_indexes[i].m_true_nodes_owner = p_true_nodes_owner;
242 VariableCellInt32& true_cells_owner = *p_true_cells_owner;
243 VariableNodeInt32& true_nodes_owner = *p_true_nodes_owner;
244 IItemFamily* current_cell_family = mesh->cellFamily();
245 IItemFamily* current_node_family = mesh->nodeFamily();
246 VariableItemInt32& cells_new_owner(current_cell_family->itemsNewOwner());
247 VariableItemInt32& nodes_new_owner(current_node_family->itemsNewOwner());
248 bool is_dynamic = mesh->isDynamic();
249 mesh->modifier()->setDynamic(true);
250 // First partitioning (optional) to provide an initial correct result
251 //mesh_partitioner->partitionMesh(mesh);
252 //mesh->exchangeItems(false);
253
254 // Final partitioning
255 {
257 Timer t(sd, "InitPartTimer", Timer::TimerReal);
258 {
259 Timer::Sentry ts(&t);
260 mesh_partitioner->partitionMesh(mesh, nb_part);
261 }
262 tm->info() << "Partitioning time t=" << t.lastActivationTime();
264 }
265 ENUMERATE_CELL (icell, current_cell_family->allItems()) {
266 Int32 new_owner = cells_new_owner[icell];
267 true_cells_owner[icell] = new_owner;
268 cells_new_owner[icell] = new_owner % nb_rank;
269 }
270 ENUMERATE_NODE (inode, current_node_family->allItems()) {
271 true_nodes_owner[inode] = nodes_new_owner[inode];
272 }
273 _printStats(nb_part, mesh, true_cells_owner);
274 mesh->utilities()->changeOwnersFromCells();
275 //mesh->modifier()->setDynamic(true);
276 //PRIMARYMESH_CAST(mesh)->exchangeItems();
277 bool compact = mesh->properties()->getBool("compact");
278 mesh->properties()->setBool("compact", true);
279 mesh->toPrimaryMesh()->exchangeItems();
280 mesh->modifier()->setDynamic(is_dynamic);
281 mesh->properties()->setBool("compact", compact);
282 }
283
284 // Adding a second layer of cells
285 // We should no longer call exchangeItems with the two cell layers
286 IMesh* mesh = meshes[0];
287 if (m_main->options()->nbGhostLayer() == 2)
288 mesh->updateGhostLayers(false);
289}
290
291/*---------------------------------------------------------------------------*/
292/*---------------------------------------------------------------------------*/
293
295_printStats(Integer nb_part, IMesh* mesh, VariableCellInt32& new_owners)
296{
297 Int64UniqueArray nb_cells(nb_part, 0);
298 ENUMERATE_CELL (icell, mesh->ownCells()) {
299 Int32 new_owner = new_owners[icell];
300 ++nb_cells[new_owner];
301 }
302 IParallelMng* pm = mesh->parallelMng();
303 pm->reduce(Parallel::ReduceSum, nb_cells);
304 ITraceMng* tm = m_sub_domain->traceMng();
305 tm->info() << " -- Partitioning statistics --";
306 tm->info() << " Part NbCell";
307 for (Integer i = 0; i < nb_part; ++i) {
308 tm->info() << Trace::Width(6) << i << Trace::Width(18) << nb_cells[i];
309 }
310}
311
312/*---------------------------------------------------------------------------*/
313/*---------------------------------------------------------------------------*/
314
315ArcaneCasePartitioner::
316ArcaneCasePartitioner(const ServiceBuildInfo& sb)
318{
319 m_init_part = new ArcaneInitialPartitioner(this, sb.subDomain());
320 info() << "** ** SET INITIAL PARTITIONER 2";
321 sb.subDomain()->setInitialPartitioner(m_init_part);
322}
323
324/*---------------------------------------------------------------------------*/
325/*---------------------------------------------------------------------------*/
326
327ArcaneCasePartitioner::
328~ArcaneCasePartitioner()
329{
330}
331
332/*---------------------------------------------------------------------------*/
333/*---------------------------------------------------------------------------*/
334
336execute()
337{
338 Int32 nb_part = options()->nbCutPart();
339 info() << "ArcaneCasePartitioner::execute() nb_part=" << nb_part;
340 if (nb_part != 0) {
341 subDomain()->timeStats()->dumpTimeAndMemoryUsage(subDomain()->parallelMng());
342 _partitionMesh(nb_part);
343 }
344}
345
346/*---------------------------------------------------------------------------*/
347/*---------------------------------------------------------------------------*/
348
349/*---------------------------------------------------------------------------*/
350/*---------------------------------------------------------------------------*/
351
352void ArcaneCasePartitioner::
353_partitionMesh(Int32 nb_part)
354{
355 //String lib_name = m_main->options()->library(); //"Metis";
356 ISubDomain* sd = subDomain();
357 IMesh* current_mesh = mesh();
358 IParallelMng* pm = sd->parallelMng();
359 Int32 nb_rank = pm->commSize();
360 Int32 my_rank = pm->commRank();
361
362 //FactoryT<IMeshWriter> mesh_writer_factory(sd->serviceMng());
363 String mesh_writer_name = options()->writerServiceName();
364 if (mesh_writer_name.empty())
365 pfatal() << "No service selected to write the mesh";
367 auto mesh_writer = sb.createReference(mesh_writer_name, SB_Collective);
368
369 String pattern = options()->meshFileNamePattern();
370 info() << "Mesh file pattern=" << pattern;
371
372 // Partitions the mesh.
373 // In return, \a cells_new_owner contains the number of the partition to which
374 // each cell will belong. To save the file, all
375 // cells of a partition must be on the same subdomain. For this,
376 // we store the partition number in \a true_cells_owner, then
377 // we exchange the mesh.
378 VariableCellInt32 true_cells_owner(*m_init_part->m_part_indexes[0].m_true_cells_owner);
379 VariableNodeInt32 true_nodes_owner(*m_init_part->m_part_indexes[0].m_true_nodes_owner);
380 IItemFamily* current_cell_family = mesh()->cellFamily();
381 //VariableItemInt32& cells_new_owner(current_cell_family->itemsNewOwner());
382 CellGroup current_all_cells = current_cell_family->allItems();
383 Integer total_current_nb_cell = pm->reduce(Parallel::ReduceSum, current_all_cells.own().size());
384 info() << "TOTAL_NB_CELL=" << total_current_nb_cell;
385
386 IPrimaryMesh* new_mesh = nullptr;
387 {
388 IMeshFactoryMng* mfm = sd->meshMng()->meshFactoryMng();
389 MeshBuildInfo build_info("SubMesh");
390 build_info.addMeshKind(current_mesh->meshKind());
391 build_info.addParallelMng(makeRef(pm->sequentialParallelMng()));
392 new_mesh = mfm->createMesh(build_info);
393 }
394
395 new_mesh->setDimension(mesh()->dimension());
396 // To optimize, there is no need to sort or compact the entities.
397 new_mesh->properties()->setBool("compact", false);
398 new_mesh->properties()->setBool("sort", false);
399 new_mesh->modifier()->setDynamic(true);
400 new_mesh->allocateCells(0, Int64ConstArrayView(), true);
401
402 // If the original mesh has MSH generation information,
403 // we copy it to the new mesh.
404 // TODO: look into how to do this automatically, for example by adding
405 // a method to clone the mesh.
406 impl::MshMeshGenerationInfo* new_msh_mesh_info = nullptr;
407 auto* msh_mesh_info = impl::MshMeshGenerationInfo::getReference(mesh(), false);
408 if (msh_mesh_info) {
409 new_msh_mesh_info = impl::MshMeshGenerationInfo::getReference(new_mesh, true);
410 *new_msh_mesh_info = *msh_mesh_info;
411 }
412
413 Int32 saved_nb_cell = 0;
414 Int32 min_nb_cell = total_current_nb_cell;
415 Int32 max_nb_cell = 0;
416
417 if (options()->createCorrespondances())
418 _initCorrespondance(my_rank);
419
420 // Searches for the maximum IDs once.
421 Integer maxLocalIdCell = mesh()->cellFamily()->maxLocalId();
422 Integer maxLocalIdNode = mesh()->nodeFamily()->maxLocalId();
423
424 // Forces the owner of the entities to subdomain 0 because
425 // new_mesh uses a sequential parallelMng().
426 for (IItemFamily* family : mesh()->itemFamilies()) {
427 ENUMERATE_ITEM (iitem, family->allItems()) {
428 iitem->mutableItemBase().setOwner(0, 0);
429 }
430 }
431 // For each part to process, create a mesh
432 // containing the entities of that part
433 // and save it
434 info() << "NbPart=" << nb_part << " my_rank=" << my_rank;
435 for (Integer i = 0; i < nb_part; ++i) {
436 if ((i % nb_rank) != my_rank) {
437 if (my_rank == 0 && options()->createCorrespondances()) {
438
439 info() << "Receive on master to build correspondence file on sub-domain " << i
440 << " sent from processor " << i % nb_rank;
441 Int32UniqueArray taillesTab(2);
442 Int64UniqueArray nodesUniqueId;
443 Int64UniqueArray cellsUniqueId;
444
445 pm->recv(taillesTab, i % nb_rank);
446 nodesUniqueId.resize(taillesTab[0]);
447 cellsUniqueId.resize(taillesTab[1]);
448 pm->recv(nodesUniqueId, i % nb_rank);
449 pm->recv(cellsUniqueId, i % nb_rank);
450 _writeCorrespondance(i, nodesUniqueId, cellsUniqueId);
451 }
452 continue;
453 }
454
455 new_mesh->destroyGroups();
456 new_mesh->modifier()->clearItems();
457 new_mesh->modifier()->endUpdate();
458 UniqueArray<Cell> cells_selected_for_new_mesh;
459 ENUMERATE_CELL (icell, current_all_cells.own()) {
460 if (true_cells_owner[icell] == i) {
461 Cell cell = *icell;
462 cells_selected_for_new_mesh.add(cell);
463 //info() << "ADD CELL " << ItemPrinter(cell);
464 }
465 }
466
467 // select ghost layers additionally if necessary
468 _addGhostLayers(current_all_cells, cells_selected_for_new_mesh, options()->nbGhostLayer(), maxLocalIdCell, maxLocalIdNode);
469
470 Int32UniqueArray cells_local_id;
471 Int64UniqueArray cells_unique_id;
472 for (Integer j = 0, js = cells_selected_for_new_mesh.size(); j < js; ++j) {
473 Cell cell = cells_selected_for_new_mesh[j];
474 cells_local_id.add(cell.localId());
475 cells_unique_id.add(static_cast<Int64>(cell.uniqueId()));
476 }
477
478 Integer nb_cell_to_copy = cells_local_id.size();
479 SerializeBuffer buffer;
480 current_mesh->serializeCells(&buffer, cells_local_id);
481 info() << "NB_CELL_TO_SERIALIZE=" << nb_cell_to_copy;
482 new_mesh->modifier()->addCells(&buffer);
483 new_mesh->modifier()->endUpdate();
484 // To update coordinates
485 //new_mesh->nodeFamily()->endUpdate();
486 ItemInternalList new_cells = new_mesh->itemsInternal(IK_Cell);
487 ItemInternalList current_cells = current_mesh->itemsInternal(IK_Cell);
488 VariableNodeReal3& new_coordinates(new_mesh->nodesCoordinates());
489 VariableNodeReal3& current_coordinates(current_mesh->toPrimaryMesh()->nodesCoordinates());
490 Int32UniqueArray new_cells_local_id(nb_cell_to_copy);
491 new_mesh->cellFamily()->itemsUniqueIdToLocalId(new_cells_local_id, cells_unique_id);
492 for (Integer zid = 0; zid < nb_cell_to_copy; ++zid) {
493 Cell current_cell = current_cells[cells_local_id[zid]];
494 Cell new_cell = new_cells[new_cells_local_id[zid]];
495 if (current_cell.uniqueId() != new_cell.uniqueId())
496 fatal() << "Inconsistent unique ids";
497 Integer nb_node = current_cell.nbNode();
498 //info() << "Current=" << ItemPrinter(current_cell)
499 // << " new=" << ItemPrinter(new_cell)
500 // << " nb_node=" << nb_node;
501 for (Integer z2 = 0; z2 < nb_node; ++z2) {
502 Real3 coord = current_coordinates[current_cell.node(z2)];
503 // info() << "Node=" << ItemPrinter(new_cell.node(z2)) << " coord=" << coord
504 // << " orig_node=" << ItemPrinter(current_cell.node(z2));
505 new_coordinates[new_cell.node(z2)] = coord;
506 // Position the final owner of the node
507 new_cell.node(z2).mutableItemBase().setOwner(true_nodes_owner[current_cell.node(z2)], 0);
508 }
509 }
510 // Now, we must copy the groups
511 {
512 _computeGroups(current_mesh->nodeFamily(), new_mesh->nodeFamily());
513 _computeGroups(current_mesh->edgeFamily(), new_mesh->edgeFamily());
514 _computeGroups(current_mesh->faceFamily(), new_mesh->faceFamily());
515 _computeGroups(current_mesh->cellFamily(), new_mesh->cellFamily());
516
517 if (options()->nbGhostLayer() > 0)
518 _addGhostGroups(new_mesh, cells_selected_for_new_mesh, true_cells_owner, true_nodes_owner, new_cells_local_id, i);
519 }
520 Integer new_nb_cell = new_mesh->nbCell();
521 info() << "NB_NEW_CELL=" << new_nb_cell;
522 min_nb_cell = math::min(min_nb_cell, new_nb_cell);
523 max_nb_cell = math::max(max_nb_cell, new_nb_cell);
524 saved_nb_cell += new_nb_cell;
525 String filename;
526 if (pattern.empty()) {
527 StringBuilder sfilename = "cut_mesh_";
528 sfilename += i;
529 sfilename += ".mli2";
530 filename = sfilename;
531 }
532 else {
533 // ATTENTION potential overflow if pattern is too long.
534 // Also check if there is a %d. Eventually, use String::format()
535 char buf[4096];
536 if (pattern.length() > 128) {
537 pfatal() << "Pattern too long (max=128)";
538 }
539 sprintf(buf, pattern.localstr(), i);
540 filename = String(StringView(buf));
541 }
542 {
543 info() << "Writing mesh file filename='" << filename << "'";
544 bool is_bad = mesh_writer->writeMeshToFile(new_mesh, filename);
545 if (is_bad)
546 ARCANE_FATAL("Can not write mesh file '{0}'", filename);
547 }
548
549 // Correspondence File
550 if (options()->createCorrespondances()) {
551 info() << "Participation to build correspondence file on sub-domain " << i;
552
553 Int32UniqueArray taillesTab;
554 taillesTab.add(new_mesh->nodeFamily()->nbItem());
555 taillesTab.add(new_mesh->cellFamily()->nbItem());
556 Int64UniqueArray nodesUniqueId(taillesTab[0]);
557 Int64UniqueArray cellsUniqueId(taillesTab[1]);
558
559 NodeInfoListView nodes(new_mesh->nodeFamily());
560 for (int j = 0; j < taillesTab[0]; ++j) {
561 Node node = nodes[j];
562 nodesUniqueId[j] = node.uniqueId();
563 }
564
565 CellInfoListView cells(new_mesh->cellFamily());
566 for (int j = 0; j < taillesTab[1]; ++j) {
567 Cell cell = cells[j];
568 cellsUniqueId[j] = cell.uniqueId();
569 }
570
571 if (my_rank != 0) {
572 pm->send(taillesTab, 0);
573 pm->send(nodesUniqueId, 0);
574 pm->send(cellsUniqueId, 0);
575 }
576 else {
577 _writeCorrespondance(i, nodesUniqueId, cellsUniqueId);
578 }
579 }
580 } // end i<nb_part
581
582 Integer total_new_nb_cell = pm->reduce(Parallel::ReduceSum, saved_nb_cell);
583 Integer total_min_nb_cell = pm->reduce(Parallel::ReduceMin, min_nb_cell);
584 Integer total_max_nb_cell = pm->reduce(Parallel::ReduceMax, max_nb_cell);
585 info() << "TOTAL_NEW_NB_CELL=" << total_new_nb_cell
586 << " min=" << total_min_nb_cell
587 << " max=" << total_max_nb_cell
588 << " computed_average=" << (total_current_nb_cell / nb_part);
589
590 subDomain()->timeStats()->dumpTimeAndMemoryUsage(pm);
591
592 if (options()->createCorrespondances())
594
595 if (options()->nbGhostLayer() == 0)
596 if (total_new_nb_cell != total_current_nb_cell)
597 pfatal() << "Bad number of saved cells current=" << total_current_nb_cell
598 << " saved=" << total_new_nb_cell;
599
600 pinfo() << "Total Memory Used : " << platform::getMemoryUsed();
601}
602
603/*---------------------------------------------------------------------------*/
604/*---------------------------------------------------------------------------*/
605
608{
609 info() << " _initCorrespondance(" << my_rank << ")";
610
611 if (my_rank)
612 return;
613
614 m_sortiesCorrespondance.open("Correspondances");
615
616 if (m_sortiesCorrespondance.fail()) {
617 pfatal() << "Unable to write to file 'Correspondances' ";
618 }
619
620 m_sortiesCorrespondance << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
621 m_sortiesCorrespondance << "<!-- Correspondence file generated by Arcane/Decoupe3D V2 -->\n";
622 m_sortiesCorrespondance << "\n<cpus>\n";
623}
624
625/*---------------------------------------------------------------------------*/
626/*---------------------------------------------------------------------------*/
627
629_writeCorrespondance(Int32 rank, Int64Array& nodesUniqueId, Int64Array& cellsUniqueId)
630{
631 info() << " _writeCorrespondance(" << rank << ", nodesUniqueId.size() = "
632 << nodesUniqueId.size() << ", cellsUniqueId.size() = " << cellsUniqueId.size() << ")";
633
634 m_sortiesCorrespondance << " <cpu id=\"" << rank << "\">" << "\n"
635 << " <noeuds>" << "\n"
636 << " ";
637 for (Integer i = 0; i < nodesUniqueId.size(); ++i)
638 m_sortiesCorrespondance << nodesUniqueId[i] << " ";
639
640 m_sortiesCorrespondance << "\n"
641 << " </noeuds>"
642 << "\n"
643 << " <mailles>" << "\n"
644 << " ";
645 for (Integer i = 0; i < cellsUniqueId.size(); ++i)
646 m_sortiesCorrespondance << cellsUniqueId[i] << " ";
647 m_sortiesCorrespondance << "\n"
648 << " </mailles>" << "\n"
649 << " </cpu>" << "\n";
650}
651
652/*---------------------------------------------------------------------------*/
653/*---------------------------------------------------------------------------*/
654
657{
658 if (my_rank)
659 return;
660
661 m_sortiesCorrespondance << "</cpus>\n";
662 m_sortiesCorrespondance.close();
663}
664
665/*---------------------------------------------------------------------------*/
666/*---------------------------------------------------------------------------*/
680_computeGroups(IItemFamily* current_family, IItemFamily* new_family)
681{
682 info() << "Compute groups family=" << current_family->name();
683
684 ItemGroup new_all_items = new_family->allItems();
685 Integer nb_new_item = new_all_items.size();
686
687 Int64UniqueArray new_items_uid(nb_new_item);
688 Int32UniqueArray new_items_lid(nb_new_item);
689 {
690 Integer index = 0;
691 ENUMERATE_ITEM (iitem, new_all_items) {
692 new_items_uid[index] = (*iitem).uniqueId();
693 new_items_lid[index] = iitem.itemLocalId();
694 ++index;
695 }
696 }
697 Int32UniqueArray items_lid(nb_new_item);
698 // Determine the localId() in the original mesh of the entities
699 current_family->itemsUniqueIdToLocalId(items_lid, new_items_uid);
700
701 Int32UniqueArray items_current_to_new_local_id(current_family->maxLocalId());
702 items_current_to_new_local_id.fill(NULL_ITEM_LOCAL_ID);
703 for (Integer i = 0; i < nb_new_item; ++i)
704 items_current_to_new_local_id[items_lid[i]] = new_items_lid[i];
705
706 Int32UniqueArray create_local_ids;
707 for (ItemGroupCollection::Enumerator igroup(current_family->groups()); ++igroup;) {
708 ItemGroup group = *igroup;
709 if (group.isOwn())
710 continue;
711 if (group.isAllItems())
712 continue;
713 create_local_ids.clear();
714 ENUMERATE_ITEM (iitem, group) {
715 Int32 current_uid = iitem.itemLocalId();
716 Int32 new_lid = items_current_to_new_local_id[current_uid];
717 if (new_lid != NULL_ITEM_LOCAL_ID)
718 create_local_ids.add(new_lid);
719 }
720 new_family->createGroup(group.name(), create_local_ids, true);
721 }
722}
723
724/*---------------------------------------------------------------------------*/
725/*---------------------------------------------------------------------------*/
726
731_addGhostLayers(CellGroup current_all_cells, Array<Cell>& cells_selected_for_new_mesh,
732 Integer nbCouches, Integer maxLocalIdCell, Integer maxLocalIdNode)
733{
734 if (nbCouches == 0)
735 return;
736
737 Int32UniqueArray filtre_lid_cell(maxLocalIdCell);
738 filtre_lid_cell.fill(0);
739 Int32UniqueArray filtre_lid_node(maxLocalIdNode);
740 filtre_lid_node.fill(0);
741
742 // mark the already selected cells
743 for (Integer j = 0, js = cells_selected_for_new_mesh.size(); j < js; ++j) {
744 Cell cell = cells_selected_for_new_mesh[j];
745 filtre_lid_cell[cell.localId()] = 1;
746 }
747
748 // search for all nodes associated with selected cells a connected cell
749 // to this same node that is not selected
750 for (Integer j = 0, js = cells_selected_for_new_mesh.size(); j < js; ++j) {
751 Cell cell = cells_selected_for_new_mesh[j];
752
753 NodeVectorView nodes = cell.nodes();
754 for (Integer k = 0, ks = nodes.size(); k < ks; ++k) {
755 Node node = nodes[k];
756 if (filtre_lid_node[node.localId()] == 0) {
757 // cells connected by a node
758 CellVectorView cells_vois = node.cells();
759
760 for (Integer i = 0, is = cells_vois.size(); i < is; ++i) {
761 Cell cell_vois = cells_vois[i];
762 if (filtre_lid_cell[cell_vois.localId()] == 0) {
763 // add the cell that has not yet been seen
764 cells_selected_for_new_mesh.add(cell_vois);
765
766 filtre_lid_cell[cell_vois.localId()] = 1;
767 }
768 }
769 filtre_lid_node[node.localId()] = 1;
770 }
771 }
772 }
773
774 // for the second layer (if needed) it is simpler to do it recursively
775 _addGhostLayers(current_all_cells, cells_selected_for_new_mesh, nbCouches - 1, maxLocalIdCell, maxLocalIdNode);
776}
777/*---------------------------------------------------------------------------*/
778/*---------------------------------------------------------------------------*/
779
785_addGhostGroups(IMesh* new_mesh, Array<Cell>& cells_selected_for_new_mesh, VariableCellInt32& true_cells_owner,
786 VariableNodeInt32& true_nodes_owner,
787 Int32Array& new_cells_local_id, Integer id_loc)
788{
789 info() << "ArcaneCasePartitioner::_addGhostGroups (id_loc = " << id_loc << ")";
790 // we must determine the existing neighbor groups
791 // we use a "map" to store the different sub-domains that appear and the number of cells in them
792 std::map<Integer, Integer> dom_vois;
793 for (Integer j = 0, js = cells_selected_for_new_mesh.size(); j < js; ++j) {
794 Cell cell = cells_selected_for_new_mesh[j];
795 dom_vois[true_cells_owner[cell]] += 1;
796 }
797
798 // we use a second map to list the cells according to the destination domain
799 std::map<Integer, SharedArray<Int32>> map_groupes;
800 for (std::map<Integer, Integer>::const_iterator iter = dom_vois.begin(); iter != dom_vois.end(); ++iter) {
801 Integer no_sous_dom = iter->first;
802 Integer nb_mailles_sous_dom = iter->second;
803
804 // memory reservation for the different lists
805 Int32Array& tab = map_groupes[no_sous_dom];
806 tab.reserve(nb_mailles_sous_dom);
807 }
808
809 for (Integer j = 0, js = cells_selected_for_new_mesh.size(); j < js; ++j) {
810 Cell cell = cells_selected_for_new_mesh[j];
811 Integer no_sous_dom = true_cells_owner[cell];
812
813 // filling the lists by sub-domain
814 Int32Array& liste_lid = map_groupes[no_sous_dom];
815 liste_lid.add(new_cells_local_id[j]);
816 }
817
818 // creation (if necessary) of the different groups and adding the cells to them
819 for (std::map<Integer, SharedArray<Int32>>::iterator iter = map_groupes.begin(); iter != map_groupes.end(); ++iter) {
820 Integer no_sous_dom = iter->first;
821 Int32Array& liste_lid = iter->second;
822
823 ItemGroup groupe_loc;
824 if (no_sous_dom == id_loc)
825 groupe_loc = new_mesh->cellFamily()->findGroup("LOCAL", true);
826 else {
827 String nom_mf("MF_");
828 nom_mf = nom_mf + no_sous_dom;
829 groupe_loc = new_mesh->cellFamily()->findGroup(nom_mf, true);
830 }
831
832 groupe_loc.addItems(liste_lid, false);
833 }
834
835 // Create the LOCALN group: local nodes
836 {
837 // TODO: Optimize the way this group is built
838 Int32UniqueArray liste_lid;
839 Integer nbnodes = new_mesh->nodeFamily()->nbItem();
840 liste_lid.reserve(nbnodes);
841 NodeInfoListView nodes(new_mesh->nodeFamily());
842 for (int j = 0; j < nbnodes; ++j) {
843 Node node = nodes[j];
844 if (true_nodes_owner[node] == id_loc)
845 liste_lid.add(node.localId());
846 }
847
848 ItemGroup groupe_loc = new_mesh->nodeFamily()->findGroup("LOCALN", true);
849 groupe_loc.addItems(liste_lid, false);
850 }
851
852 // the group with all cells
853 ItemGroup groupe_glob = new_mesh->cellFamily()->findGroup("TOUT", true);
854
855 groupe_glob.addItems(new_cells_local_id, false);
856}
857/*---------------------------------------------------------------------------*/
858/*---------------------------------------------------------------------------*/
859
860ARCANE_REGISTER_SERVICE_ARCANECASEPARTITIONER(ArcaneCasePartitioner, ArcaneCasePartitioner);
861
862/*---------------------------------------------------------------------------*/
863/*---------------------------------------------------------------------------*/
864
865} // namespace Arcane
866
867/*---------------------------------------------------------------------------*/
868/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ENUMERATE_CELL(name, group)
Generic enumerator for a cell group.
#define ENUMERATE_ITEM(name, group)
Generic enumerator for a node group.
#define ENUMERATE_NODE(name, group)
Generic enumerator for a node group.
Integer size() const
Number of elements in the vector.
Generation de la classe de base du Service.
ArcaneArcaneCasePartitionerObject(const Arcane::ServiceBuildInfo &sbi)
Constructeur.
CaseOptionsArcaneCasePartitioner * options() const
Options du jeu de données du service.
External mesh partitioning service.
void _addGhostLayers(CellGroup current_all_cells, Array< Cell > &cells_selected_for_new_mesh, Integer nb_layer, Integer maxLocalIdCell, Integer maxLocalIdNode)
Adds to the cell array the desired number of cell layers.
bool isActive() const override
True if the service is active.
void execute() override
Executes the service operation.
void _initCorrespondance(Int32 my_rank)
Opens the Correspondence file (only on proc 0).
void _computeGroups(IItemFamily *current_family, IItemFamily *new_family)
Recopy the groups of the current family into the new one.
void build() override
Build-level construction of the service.
void _finalizeCorrespondance(Int32 my_rank)
Closes the Correspondence file (only on proc 0).
void setParallelMng(IParallelMng *) override
Positions the associated parallelism manager. This method must be called before execute().
void _writeCorrespondance(Int32 rank, Int64Array &nodesUniqueId, Int64Array &cellsUniqueId)
Writes the Correspondence file.
void _addGhostGroups(IMesh *new_mesh, Array< Cell > &cells_selected_for_new_mesh, VariableCellInt32 &true_cells_owner, VariableNodeInt32 &true_nodes_owner, Int32Array &new_cells_local_id, Integer id_loc)
Adds the TOUT, LOCAL, and MF_* cell groups based on neighbor groups Also adds the LOCALN node group (...
void partitionAndDistributeMeshes(ConstArrayView< IMesh * > meshes) override
Partitions the meshes.
void _printStats(Integer nb_part, IMesh *mesh, VariableCellInt32 &new_owners)
Prints statistics on the partitioning.
void _mergeConstraints(ConstArrayView< IMesh * > meshes)
Groups cells associated with constraints on the same process.
UniqueArray< TrueOwnerInfo > m_part_indexes
Stores for each mesh a variable indicating which partition each cell belongs to.
Base class for 1D data vectors.
void fill(ConstReferenceType value)
Fills the array with the value value.
void clear()
Removes the elements from the array.
iterator begin()
Iterator over the first element of the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
Cell of a mesh.
Definition Item.h:1300
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
virtual ITraceMng * traceMng() const =0
Trace manager.
virtual IServiceMng * serviceMng() const =0
Service manager.
Interface of an initial partitioner.
Interface of an entity family.
Definition IItemFamily.h:83
virtual ItemGroup findGroup(const String &name) const =0
Searches for a group.
virtual ItemGroupCollection groups() const =0
Collection of groups in this family.
virtual ItemGroup allItems() const =0
Group of all entities.
virtual ItemGroup createGroup(const String &name, Int32ConstArrayView local_ids, bool do_override=false)=0
Creates an entity group named name containing the entities local_ids.
virtual Int32 maxLocalId() const =0
virtual String name() const =0
Family name.
virtual void itemsUniqueIdToLocalId(Int32ArrayView local_ids, Int64ConstArrayView unique_ids, bool do_fatal=true) const =0
Converts an array of unique numbers to local numbers.
virtual Integer nbItem() const =0
Number of entities.
virtual VariableItemInt32 & itemsNewOwner()=0
Variable containing the number of the new subdomain owning the entity.
virtual IItemFamily * nodeFamily()=0
Returns the node family.
virtual Integer nbCell()=0
Number of mesh cells.
virtual IItemFamily * edgeFamily()=0
Returns the edge family.
virtual IItemFamily * faceFamily()=0
Returns the face family.
virtual IItemFamily * cellFamily()=0
Returns the cell family.
Interface of the mesh factory manager.
virtual IPrimaryMesh * createMesh(const MeshBuildInfo &build_info)=0
Creates a mesh or a sub-mesh.
virtual IMeshFactoryMng * meshFactoryMng() const =0
Mesh factory associated with this manager.
virtual void setDynamic(bool v)=0
Sets the property indicating whether the mesh can evolve.
virtual void addCells(Integer nb_cell, Int64ConstArrayView cell_infos, Int32ArrayView cells_lid=Int32ArrayView())=0
Adds cells.
virtual void endUpdate()=0
Notifies the instance that mesh modification is finished.
virtual void clearItems()=0
Deletes all entities of all families in this mesh.
Interface of a mesh partitioning constraint.
virtual ItemInternalList itemsInternal(eItemKind)=0
Internal array of mesh elements of type type.
virtual IMeshModifier * modifier()=0
Associated modifier interface.
virtual ARCANE_DEPRECATED_240 void serializeCells(ISerializer *buffer, Int32ConstArrayView cells_local_id)=0
virtual void destroyGroups()=0
Destroys all groups of all families.
virtual const MeshKind meshKind() const =0
Mesh characteristics.
virtual IPrimaryMesh * toPrimaryMesh()=0
Returns the instance in the form of an IPrimaryMesh.
virtual Properties * properties()=0
Properties associated with this mesh.
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual IParallelMng * sequentialParallelMng()=0
Returns a sequential parallelism manager.
virtual void recv(ArrayView< char > values, Int32 rank)=0
virtual Int32 commSize() const =0
Number of instances in the communicator.
virtual char reduce(eReduceType rt, char v)=0
Performs a reduction of type rt on the real v and returns the value.
virtual VariableNodeReal3 & nodesCoordinates()=0
Node coordinates.
virtual void allocateCells(Integer nb_cell, Int64ConstArrayView cells_infos, bool one_alloc=true)=0
Allocation of a mesh.
virtual void setDimension(Integer dim)=0
Positions the mesh dimension (1D, 2D, or 3D).
Interface of the subdomain manager.
Definition ISubDomain.h:75
virtual ITimeStats * timeStats() const =0
Execution time statistics.
virtual IParallelMng * parallelMng()=0
Returns the parallelism manager.
virtual IMeshMng * meshMng() const =0
Returns the mesh manager.
virtual void setInitialPartitioner(IInitialPartitioner *partitioner)=0
Sets the initial partitioner.
virtual void dumpTimeAndMemoryUsage(IParallelMng *pm)=0
Displays the current date and memory consumption.
virtual TraceMessage info()=0
Stream for an information message.
Mesh entity group.
Definition ItemGroup.h:51
const String & name() const
Group name.
Definition ItemGroup.h:81
bool isOwn() const
Returns whether the group contains only elements belonging to the subdomain.
Definition ItemGroup.cc:149
Integer size() const
Number of elements in the group.
Definition ItemGroup.h:93
void addItems(Int32ConstArrayView items_local_id, bool check_if_present=true)
Adds entities.
Definition ItemGroup.cc:439
bool isAllItems() const
Indicates if the group is that of all entities.
Definition ItemGroup.cc:607
Int32 size() const
Number of elements in the vector.
NodeConnectedListViewType nodes() const
List of nodes of the entity.
Definition Item.h:843
constexpr Int32 localId() const
Local identifier of the entity in the processor subdomain.
Definition Item.h:233
Parameters necessary for building a mesh.
View of node information.
Node of a mesh.
Definition Item.h:598
CellConnectedListViewType cells() const
List of cells of the node.
Definition Item.h:728
void setBool(const String &name, bool value)
Sets a boolean property of name name and value value.
Encapsulation of an automatically destructing pointer.
Definition ScopedPtr.h:44
ISubDomain * subDomain() const
Access to the associated ISubDomain.
Structure containing the information to create a service.
Utility class for instantiating a service of a given interface.
Ref< InterfaceType > createReference(const String &name, eServiceBuilderProperties properties=SB_None)
Creates an instance implementing the InterfaceType interface.
1D vector of data with reference semantics.
Unicode character string constructor.
Int64 length() const
Returns the length of the string.
Definition String.cc:340
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:229
bool empty() const
True if the string is empty (null or "").
Definition String.cc:317
Sentinel for the timer. The sentinel associated with a timer allows it to be triggered upon its const...
Definition Timer.h:90
Management of a timer.
Definition Timer.h:63
@ TimerReal
Timer using real time.
Definition Timer.h:77
Real lastActivationTime() const
Returns the time (in seconds) spent during the last activation of the timer.
Definition Timer.h:243
TraceMessage pinfo() const
Flow for a parallel information message.
TraceMessage fatal() const
Flow for a fatal error message.
TraceMessage pfatal() const
Flow for a parallel fatal error message.
TraceMessage info() const
Flow for an information message.
Formatting the stream by length.
1D data vector with value semantics (STL style).
Parameters necessary for building a variable.
__host__ __device__ Real2 min(Real2 a, Real2 b)
Returns the minimum of two Real2.
Definition MathUtils.h:346
T max(const T &a, const T &b, const T &c)
Returns the maximum of three elements.
Definition MathUtils.h:407
ItemVectorViewT< Node > NodeVectorView
View over a vector of nodes.
Definition ItemTypes.h:290
ItemGroupT< Cell > CellGroup
Group of cells.
Definition ItemTypes.h:184
ItemVectorViewT< Cell > CellVectorView
View over a vector of cells.
Definition ItemTypes.h:305
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
MeshVariableScalarRefT< Node, Int32 > VariableNodeInt32
Quantity at the node of 32-bit integer type.
ItemVariableScalarRefT< Int32 > VariableItemInt32
32-bit integer type quantity
MeshVariableScalarRefT< Cell, Int32 > VariableCellInt32
Quantity at the cell center of 32-bit integer type.
@ ReduceMin
Minimum of values.
@ ReduceMax
Maximum of values.
double getMemoryUsed()
Memory used in bytes.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Array< Int64 > Int64Array
Dynamic one-dimensional array of 64-bit integers.
Definition UtilsTypes.h:125
@ SB_Collective
Indicates that all processes perform the same operation.
@ SB_AllowNull
Allows the service to be absent.
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
Definition UtilsTypes.h:339
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
ConstArrayView< ItemInternal * > ItemInternalList
Type of the internal list of entities.
Definition ItemTypes.h:466
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
@ IK_Cell
Cell mesh entity.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Creates a reference on a pointer.
Array< Int32 > Int32Array
Dynamic one-dimensional array of 32-bit integers.
Definition UtilsTypes.h:127
@ Cell
The mesh is AMR by cell.
Definition MeshKind.h:53
std::int32_t Int32
Signed integer type of 32 bits.