Arcane  v3.16.2.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
ArcaneCasePartitioner.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 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/* Service de partitionnement externe du maillage. */
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
112 public:
113
114 explicit ArcaneCasePartitioner(const ServiceBuildInfo& sbi);
115 ~ArcaneCasePartitioner() override;
116
117 public:
118
119 void build() override {}
120 void execute() override;
121 void setParallelMng(IParallelMng*) override {}
122 bool isActive() const override { return true; }
123
124 private:
125
127 void _initCorrespondance(Int32 my_rank);
128
130 void _writeCorrespondance(Int32 rank, Int64Array& nodesUniqueId, Int64Array& cellsUniqueId);
131
133 void _finalizeCorrespondance(Int32 my_rank);
134
135
136 private:
137
138 std::ofstream m_sortiesCorrespondance;
139
140 ArcaneInitialPartitioner* m_init_part = nullptr;
141
142 void _partitionMesh(Int32 nb_part);
143 void _computeGroups(IItemFamily* current_family,IItemFamily* new_family);
144 void _addGhostLayers(CellGroup current_all_cells, Array<Cell>& cells_selected_for_new_mesh,
145 Integer nb_layer,Integer maxLocalIdCell, Integer maxLocalIdNode);
146 void _addGhostGroups(IMesh* new_mesh, Array<Cell>& cells_selected_for_new_mesh,
147 VariableCellInt32& true_cells_owner, VariableNodeInt32& true_nodes_owner,
148 Int32Array& new_cells_local_id, Integer id_loc);
149};
150
151/*---------------------------------------------------------------------------*/
152/*---------------------------------------------------------------------------*/
153
156{
157 Integer nb_mesh = meshes.size();
158 if (nb_mesh!=1)
159 ARCANE_FATAL("Can not partition multiple meshes");
160
161 IMesh* mesh = meshes[0];
162 ISubDomain* sd = m_sub_domain;
163 ITraceMng* tm = sd->traceMng();
164
165 tm->info()<<" _regroupeContraintes: nbMailles = "<<meshes[0]->nbCell() <<", nbMaillesLocales = "<< meshes[0]->ownCells().size();
166
167 Integer nb_contraintes = m_main->options()->constraints.size();
168 tm->info() << "Number of constraints = " << nb_contraintes;
169 if (nb_contraintes==0)
170 return;
171
172 IItemFamily* current_cell_family = mesh->cellFamily();
173 VariableItemInt32& cells_new_owner(current_cell_family->itemsNewOwner());
174 ENUMERATE_CELL(icell,current_cell_family->allItems()){
175 cells_new_owner[icell] = (*icell).owner();
176 }
177
179 IMeshPartitionConstraint* c = new ExternalPartitionConstraint(mesh, m_main->options()->constraints);
180 mesh->partitionConstraintMng()->addConstraint(c);
181 mesh->partitionConstraintMng()->computeAndApplyConstraints();
182
183 cells_new_owner.synchronize();
184 mesh->utilities()->changeOwnersFromCells();
185 mesh->modifier()->setDynamic(true);
186 bool compact = mesh->properties()->getBool("compact");
187 mesh->properties()->setBool("compact", true);
188 mesh->toPrimaryMesh()->exchangeItems();
189 mesh->properties()->setBool("compact", compact);
190#if 0
191#ifdef ARCANE_DEBUG
192 ScopedPtrT<IMeshWriter> mesh_writer;
193 FactoryT<IMeshWriter> mesh_writer_factory(sd->serviceMng());
194 mesh_writer = mesh_writer_factory.createInstance("Lima",true);
195 IParallelMng* pm = sd->parallelMng();
196 Int32 my_rank = pm->commRank();
197
198 StringBuilder filename = "cut_mesh_after_";
199 filename += my_rank;
200 filename += ".mli2";
201 mesh_writer->writeMeshToFile(mesh,filename);
202#endif
203#endif
204}
205
206/*---------------------------------------------------------------------------*/
207/*---------------------------------------------------------------------------*/
208
211{
212 String lib_name = m_main->options()->library();
213 ISubDomain* sd = m_sub_domain;
214 IParallelMng* pm = sd->parallelMng();
215 Int32 nb_rank = pm->commSize();
216 //Int32 my_rank = pm->commRank();
217 ServiceBuilder<IMeshPartitioner> service_builder(sd);
218 auto mesh_partitioner(service_builder.createReference(lib_name,SB_AllowNull));
219 ITraceMng* tm = sd->traceMng();
220 tm->info() << "DoInitialPartition. Service=" << lib_name;
221
222 if (!mesh_partitioner.get())
223 ARCANE_FATAL("can not found service named '{0}' for initial mesh partitioning", lib_name);
224
225 _mergeConstraints(meshes);
226
227 Integer nb_mesh = meshes.size();
228 if (nb_mesh!=1)
229 ARCANE_FATAL("Can not partition multiple meshes");
230
231 m_part_indexes.resize(nb_mesh);
232 Int32 nb_part = m_main->options()->nbCutPart();
233 if (nb_part==0)
234 nb_part = nb_rank;
235 tm->info() << "NbPart = " << nb_part << " nb_mesh=" << nb_mesh;
236
237 for( Integer i=0; i<nb_mesh; ++i ){
238 IMesh* mesh = meshes[i];
240 VariableCellInt32* p_true_cells_owner = new VariableCellInt32(VariableBuildInfo(mesh,"TrueCellsOwner"));
241 VariableNodeInt32* p_true_nodes_owner = new VariableNodeInt32(VariableBuildInfo(mesh,"TrueNodesOwner"));
242 m_part_indexes[i].m_true_cells_owner = p_true_cells_owner;
243 m_part_indexes[i].m_true_nodes_owner = p_true_nodes_owner;
244 VariableCellInt32& true_cells_owner = *p_true_cells_owner;
245 VariableNodeInt32& true_nodes_owner = *p_true_nodes_owner;
246 IItemFamily* current_cell_family = mesh->cellFamily();
247 IItemFamily* current_node_family = mesh->nodeFamily();
248 VariableItemInt32& cells_new_owner(current_cell_family->itemsNewOwner());
249 VariableItemInt32& nodes_new_owner(current_node_family->itemsNewOwner());
250 bool is_dynamic = mesh->isDynamic();
251 mesh->modifier()->setDynamic(true);
252 // Premier partitionnement (optionnel) pour donner un premier resultat correct
253 //mesh_partitioner->partitionMesh(mesh);
254 //mesh->exchangeItems(false);
255
256 // Partitionnement final
257 {
259 Timer t(sd,"InitPartTimer",Timer::TimerReal);
260 {
261 Timer::Sentry ts(&t);
262 mesh_partitioner->partitionMesh(mesh,nb_part);
263 }
264 tm->info() << "Partitioning time t=" << t.lastActivationTime();
266 }
267 ENUMERATE_CELL(icell,current_cell_family->allItems()){
268 Int32 new_owner = cells_new_owner[icell];
269 true_cells_owner[icell] = new_owner;
270 cells_new_owner[icell] = new_owner % nb_rank;
271 }
272 ENUMERATE_NODE(inode,current_node_family->allItems()){
273 true_nodes_owner[inode] = nodes_new_owner[inode];
274 }
275 _printStats(nb_part,mesh,true_cells_owner);
276 mesh->utilities()->changeOwnersFromCells();
277 //mesh->modifier()->setDynamic(true);
278 //PRIMARYMESH_CAST(mesh)->exchangeItems();
279 bool compact = mesh->properties()->getBool("compact");
280 mesh->properties()->setBool("compact", true);
281 mesh->toPrimaryMesh()->exchangeItems();
282 mesh->modifier()->setDynamic(is_dynamic);
283 mesh->properties()->setBool("compact", compact);
284 }
285
286 // ajout d'une 2ème couche de mailles
287 // il ne faut plus faire exchangeItems avec les 2 couches de mailles
288 IMesh* mesh = meshes[0];
289 if (m_main->options()->nbGhostLayer()==2)
290 mesh->updateGhostLayers(false);
291}
292
293/*---------------------------------------------------------------------------*/
294/*---------------------------------------------------------------------------*/
295
297_printStats(Integer nb_part,IMesh* mesh,VariableCellInt32& new_owners)
298{
299 Int64UniqueArray nb_cells(nb_part,0);
300 ENUMERATE_CELL(icell,mesh->ownCells()){
301 Int32 new_owner = new_owners[icell];
302 ++nb_cells[new_owner];
303 }
304 IParallelMng* pm = mesh->parallelMng();
305 pm->reduce(Parallel::ReduceSum,nb_cells);
306 ITraceMng* tm = m_sub_domain->traceMng();
307 tm->info() << " -- Partitioning statistics --";
308 tm->info() << " Part NbCell";
309 for( Integer i=0; i<nb_part; ++i ){
310 tm->info() << Trace::Width(6) << i << Trace::Width(18) << nb_cells[i];
311 }
312}
313
314/*---------------------------------------------------------------------------*/
315/*---------------------------------------------------------------------------*/
316
317ArcaneCasePartitioner::
318ArcaneCasePartitioner(const ServiceBuildInfo& sb)
320{
321 m_init_part = new ArcaneInitialPartitioner(this,sb.subDomain());
322 info() << "** ** SET INITIAL PARTITIONER 2";
323 sb.subDomain()->setInitialPartitioner(m_init_part);
324}
325
326/*---------------------------------------------------------------------------*/
327/*---------------------------------------------------------------------------*/
328
329ArcaneCasePartitioner::
330~ArcaneCasePartitioner()
331{
332}
333
334/*---------------------------------------------------------------------------*/
335/*---------------------------------------------------------------------------*/
336
338execute()
339{
340 Int32 nb_part = options()->nbCutPart();
341 info() << "ArcaneCasePartitioner::execute() nb_part=" << nb_part;
342 if (nb_part!=0){
343 subDomain()->timeStats()->dumpTimeAndMemoryUsage(subDomain()->parallelMng());
344 _partitionMesh(nb_part);
345 }
346}
347
348/*---------------------------------------------------------------------------*/
349/*---------------------------------------------------------------------------*/
350
351/*---------------------------------------------------------------------------*/
352/*---------------------------------------------------------------------------*/
353
354void ArcaneCasePartitioner::
355_partitionMesh(Int32 nb_part)
356{
357 //String lib_name = m_main->options()->library(); //"Metis";
358 ISubDomain* sd = subDomain();
359 IMesh* current_mesh = mesh();
360 IParallelMng* pm = sd->parallelMng();
361 Int32 nb_rank = pm->commSize();
362 Int32 my_rank = pm->commRank();
363
364 //FactoryT<IMeshWriter> mesh_writer_factory(sd->serviceMng());
365 String mesh_writer_name = options()->writerServiceName();
366 if (mesh_writer_name.empty())
367 pfatal() << "No service selected to write the mesh";
369 auto mesh_writer = sb.createReference(mesh_writer_name,SB_Collective);
370
371 String pattern = options()->meshFileNamePattern();
372 info() << "Mesh file pattern=" << pattern;
373
374 // Partitionne le maillage.
375 // En retour, \a cells_new_owner contient le numéro de la partie à laquelle
376 // chaque maille appartiendra. Pour sauver le fichier, il faut que toutes
377 // les mailles d'une partie soient sur le même sous-domaine. Pour cela,
378 // on stocke le numéro de la partie dans \a true_cells_owner, puis
379 // on échange le maillage.
380 VariableCellInt32 true_cells_owner(*m_init_part->m_part_indexes[0].m_true_cells_owner);
381 VariableNodeInt32 true_nodes_owner(*m_init_part->m_part_indexes[0].m_true_nodes_owner);
382 IItemFamily* current_cell_family = mesh()->cellFamily();
383 //VariableItemInt32& cells_new_owner(current_cell_family->itemsNewOwner());
384 CellGroup current_all_cells = current_cell_family->allItems();
385 Integer total_current_nb_cell = pm->reduce(Parallel::ReduceSum,current_all_cells.own().size());
386 info() << "TOTAL_NB_CELL=" << total_current_nb_cell;
387
388 IPrimaryMesh* new_mesh = nullptr;
389 {
390 IMeshFactoryMng* mfm = sd->meshMng()->meshFactoryMng();
391 MeshBuildInfo build_info("SubMesh");
392 build_info.addMeshKind(current_mesh->meshKind());
393 build_info.addParallelMng(makeRef(pm->sequentialParallelMng()));
394 new_mesh = mfm->createMesh(build_info);
395 }
396
397 new_mesh->setDimension(mesh()->dimension());
398 // Pour optimiser, il n'y a pas besoin de trier ni de compacter les entités.
399 new_mesh->properties()->setBool("compact",false);
400 new_mesh->properties()->setBool("sort",false);
401 new_mesh->modifier()->setDynamic(true);
402 new_mesh->allocateCells(0,Int64ConstArrayView(),true);
403
404 // Si le maillage d'origine a des informations de génération de MSH,
405 // on les copie sur le nouveau maillage.
406 // TODO: regarder comment faire cela automatiquement, par exemple en ajoutant
407 // une méthode pour cloner le maillage.
408 impl::MshMeshGenerationInfo* new_msh_mesh_info = nullptr;
409 auto* msh_mesh_info = impl::MshMeshGenerationInfo::getReference(mesh(), false);
410 if (msh_mesh_info){
411 new_msh_mesh_info = impl::MshMeshGenerationInfo::getReference(new_mesh, true);
412 *new_msh_mesh_info = *msh_mesh_info;
413 }
414
415 Int32 saved_nb_cell = 0;
416 Int32 min_nb_cell = total_current_nb_cell;
417 Int32 max_nb_cell = 0;
418
419 if (options()->createCorrespondances())
420 _initCorrespondance(my_rank);
421
422 // recherche une fois pour toute les id max
423 Integer maxLocalIdCell = mesh()->cellFamily()->maxLocalId();
424 Integer maxLocalIdNode = mesh()->nodeFamily()->maxLocalId();
425
426 // Force le propriétaire des entités au sous-domaine 0 car
427 // new_mesh utilise un parallelMng() séquentiel.
428 for( IItemFamily* family : mesh()->itemFamilies() ){
429 ENUMERATE_ITEM(iitem,family->allItems()){
430 iitem->mutableItemBase().setOwner(0,0);
431 }
432 }
433
434 // Pour chaque partie à traiter, créé un maillage
435 // contenant les entités de cette partie
436 // et le sauvegarde
437 info() << "NbPart=" << nb_part << " my_rank=" << my_rank;
438 for( Integer i=0; i<nb_part; ++i ){
439 if ((i % nb_rank)!=my_rank){
440 if (my_rank==0 && options()->createCorrespondances()){
441
442 info()<<"Receive on master to build correspondence file on sub-domain "<<i
443 <<" sent from processor "<<i % nb_rank;
444 Int32UniqueArray taillesTab(2);
445 Int64UniqueArray nodesUniqueId;
446 Int64UniqueArray cellsUniqueId;
447
448 pm->recv(taillesTab, i % nb_rank);
449 nodesUniqueId.resize(taillesTab[0]);
450 cellsUniqueId.resize(taillesTab[1]);
451 pm->recv(nodesUniqueId, i % nb_rank);
452 pm->recv(cellsUniqueId, i % nb_rank);
453 _writeCorrespondance(i, nodesUniqueId, cellsUniqueId);
454 }
455 continue;
456 }
457
458 new_mesh->destroyGroups();
459 new_mesh->modifier()->clearItems();
460 new_mesh->modifier()->endUpdate();
461 UniqueArray<Cell> cells_selected_for_new_mesh;
462 ENUMERATE_CELL(icell,current_all_cells.own()){
463 if (true_cells_owner[icell]==i){
464 Cell cell = *icell;
465 cells_selected_for_new_mesh.add(cell);
466 //info() << "ADD CELL " << ItemPrinter(cell);
467 }
468 }
469
470 // sélectionne les mailles fantômes en plus si nécessaire
471 _addGhostLayers(current_all_cells, cells_selected_for_new_mesh, options()->nbGhostLayer(), maxLocalIdCell, maxLocalIdNode);
472
473 Int32UniqueArray cells_local_id;
474 Int64UniqueArray cells_unique_id;
475 for( Integer j=0, js=cells_selected_for_new_mesh.size(); j<js; ++j ){
476 Cell cell = cells_selected_for_new_mesh[j];
477 cells_local_id.add(cell.localId());
478 cells_unique_id.add(static_cast<Int64>(cell.uniqueId()));
479 }
480
481 Integer nb_cell_to_copy = cells_local_id.size();
482 SerializeBuffer buffer;
483 current_mesh->serializeCells(&buffer,cells_local_id);
484 info() << "NB_CELL_TO_SERIALIZE=" << nb_cell_to_copy;
485 new_mesh->modifier()->addCells(&buffer);
486 new_mesh->modifier()->endUpdate();
487 // Pour mettre a jour les coordonnees
488 //new_mesh->nodeFamily()->endUpdate();
489 ItemInternalList new_cells = new_mesh->itemsInternal(IK_Cell);
490 ItemInternalList current_cells = current_mesh->itemsInternal(IK_Cell);
491 VariableNodeReal3& new_coordinates(new_mesh->nodesCoordinates());
492 VariableNodeReal3& current_coordinates(current_mesh->toPrimaryMesh()->nodesCoordinates());
493 Int32UniqueArray new_cells_local_id(nb_cell_to_copy);
494 new_mesh->cellFamily()->itemsUniqueIdToLocalId(new_cells_local_id,cells_unique_id);
495 for( Integer zid=0; zid<nb_cell_to_copy; ++zid ){
496 Cell current_cell = current_cells[cells_local_id[zid]];
497 Cell new_cell = new_cells[new_cells_local_id[zid]];
498 if (current_cell.uniqueId()!=new_cell.uniqueId())
499 fatal() << "Inconsistent unique ids";
500 Integer nb_node = current_cell.nbNode();
501 //info() << "Current=" << ItemPrinter(current_cell)
502 // << " new=" << ItemPrinter(new_cell)
503 // << " nb_node=" << nb_node;
504 for( Integer z2=0; z2<nb_node; ++z2 ){
505 Real3 coord = current_coordinates[current_cell.node(z2)];
506 // info() << "Node=" << ItemPrinter(new_cell.node(z2)) << " coord=" << coord
507 // << " orig_node=" << ItemPrinter(current_cell.node(z2));
508 new_coordinates[new_cell.node(z2)] = coord;
509 // Positionne le propriétaire final du noeud
510 new_cell.node(z2).mutableItemBase().setOwner(true_nodes_owner[current_cell.node(z2)],0);
511 }
512 }
513 // Maintenant, il faut recopier les groupes
514 {
515 _computeGroups(current_mesh->nodeFamily(),new_mesh->nodeFamily());
516 _computeGroups(current_mesh->edgeFamily(),new_mesh->edgeFamily());
517 _computeGroups(current_mesh->faceFamily(),new_mesh->faceFamily());
518 _computeGroups(current_mesh->cellFamily(),new_mesh->cellFamily());
519
520 if (options()->nbGhostLayer()>0)
521 _addGhostGroups(new_mesh, cells_selected_for_new_mesh, true_cells_owner, true_nodes_owner, new_cells_local_id, i);
522 }
523 Integer new_nb_cell = new_mesh->nbCell();
524 info() << "NB_NEW_CELL=" << new_nb_cell;
525 min_nb_cell = math::min(min_nb_cell,new_nb_cell);
526 max_nb_cell = math::max(max_nb_cell,new_nb_cell);
527 saved_nb_cell += new_nb_cell;
528 String filename;
529 if (pattern.empty()){
530 StringBuilder sfilename = "cut_mesh_";
531 sfilename += i;
532 sfilename += ".mli2";
533 filename = sfilename;
534 }
535 else{
536 //ATTENTION potentiel debordement si pattern est trop long.
537 //Verifier aussi qu'il y a un %d. A terme, utiliser String::format()
538 char buf[4096];
539 if (pattern.length()>128){
540 pfatal() << "Pattern too long (max=128)";
541 }
542 sprintf(buf,pattern.localstr(),i);
543 filename = String(StringView(buf));
544 }
545 {
546 info() << "Writing mesh file filename='" << filename << "'";
547 bool is_bad = mesh_writer->writeMeshToFile(new_mesh, filename);
548 if (is_bad)
549 ARCANE_FATAL("Can not write mesh file '{0}'", filename);
550 }
551
552 // Fichier Correspondance
553 if (options()->createCorrespondances()){
554 info()<<"Participation to build correspondence file on sub-domain "<<i;
555
556 Int32UniqueArray taillesTab;
557 taillesTab.add(new_mesh->nodeFamily()->nbItem());
558 taillesTab.add(new_mesh->cellFamily()->nbItem());
559 Int64UniqueArray nodesUniqueId(taillesTab[0]);
560 Int64UniqueArray cellsUniqueId(taillesTab[1]);
561
562 NodeInfoListView nodes(new_mesh->nodeFamily());
563 for( int j=0; j<taillesTab[0]; ++j ){
564 Node node = nodes[j];
565 nodesUniqueId[j] = node.uniqueId();
566 }
567
568 CellInfoListView cells(new_mesh->cellFamily());
569 for( int j=0; j<taillesTab[1]; ++j ){
570 Cell cell = cells[j];
571 cellsUniqueId[j] = cell.uniqueId();
572 }
573
574 if (my_rank!=0){
575 pm->send(taillesTab, 0);
576 pm->send(nodesUniqueId, 0);
577 pm->send(cellsUniqueId, 0);
578 }
579 else {
580 _writeCorrespondance(i, nodesUniqueId, cellsUniqueId);
581 }
582 }
583 } // end i<nb_part
584
585 Integer total_new_nb_cell = pm->reduce(Parallel::ReduceSum,saved_nb_cell);
586 Integer total_min_nb_cell = pm->reduce(Parallel::ReduceMin,min_nb_cell);
587 Integer total_max_nb_cell = pm->reduce(Parallel::ReduceMax,max_nb_cell);
588 info() << "TOTAL_NEW_NB_CELL=" << total_new_nb_cell
589 << " min=" << total_min_nb_cell
590 << " max=" << total_max_nb_cell
591 << " computed_average=" << (total_current_nb_cell/nb_part);
592
593 subDomain()->timeStats()->dumpTimeAndMemoryUsage(pm);
594
595 if (options()->createCorrespondances())
597
598 if (options()->nbGhostLayer()==0)
599 if (total_new_nb_cell!=total_current_nb_cell)
600 pfatal() << "Bad number of saved cells current=" << total_current_nb_cell
601 << " saved=" << total_new_nb_cell;
602
603 pinfo()<<"Total Memory Used : "<<platform::getMemoryUsed();
604}
605
606/*---------------------------------------------------------------------------*/
607/*---------------------------------------------------------------------------*/
608
611{
612 info()<<" _initCorrespondance("<<my_rank<<")";
613
614 if (my_rank)
615 return;
616
617 m_sortiesCorrespondance.open("Correspondances");
618
619 if (m_sortiesCorrespondance.fail ()){
620 pfatal() << "Unable to write to file 'Correspondances' ";
621 }
622
623 m_sortiesCorrespondance << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
624 m_sortiesCorrespondance << "<!-- Correspondance file generated by Arcane/Decoupe3D V2 -->\n";
625 m_sortiesCorrespondance << "\n<cpus>\n";
626}
627
628/*---------------------------------------------------------------------------*/
629/*---------------------------------------------------------------------------*/
630
632_writeCorrespondance(Int32 rank, Int64Array& nodesUniqueId, Int64Array& cellsUniqueId)
633{
634 info()<<" _writeCorrespondance("<<rank<<", nodesUniqueId.size() = "
635 <<nodesUniqueId.size()<<", cellsUniqueId.size() = "<<cellsUniqueId.size()<<")";
636
637 m_sortiesCorrespondance << " <cpu id=\"" << rank << "\">" << "\n"
638 << " <noeuds>" << "\n" << " ";
639 for( Integer i=0; i<nodesUniqueId.size(); ++i )
640 m_sortiesCorrespondance <<nodesUniqueId[i]<< " ";
641
642 m_sortiesCorrespondance << "\n" << " </noeuds>"
643 << "\n"
644 << " <mailles>" << "\n"
645 << " ";
646 for( Integer i=0; i<cellsUniqueId.size(); ++i )
647 m_sortiesCorrespondance <<cellsUniqueId[i]<< " ";
648 m_sortiesCorrespondance << "\n" << " </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 // Détermine le localId() dans le maillage d'origine des entités
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/* \brief Ajoute au tableau de mailles le nombre de couches de mailles désiré
727 */
728void ArcaneCasePartitioner::
729_addGhostLayers(CellGroup current_all_cells, Array<Cell>& cells_selected_for_new_mesh,
730 Integer nbCouches,Integer maxLocalIdCell, Integer maxLocalIdNode)
731{
732 if (nbCouches==0)
733 return;
734
735 Int32UniqueArray filtre_lid_cell(maxLocalIdCell);
736 filtre_lid_cell.fill(0);
737 Int32UniqueArray filtre_lid_node(maxLocalIdNode);
738 filtre_lid_node.fill(0);
739
740 // on marque les mailles déjà sélectionnées
741 for( Integer j=0, js=cells_selected_for_new_mesh.size(); j<js; ++j ){
742 Cell cell = cells_selected_for_new_mesh[j];
743 filtre_lid_cell[cell.localId()] = 1;
744 }
745
746 // recherhe pour tous les noeuds associés aux mailles sélectionnées une mailles reliée
747 // à ce même noeud qui ne soit pas sélectionnée
748 for( Integer j=0, js=cells_selected_for_new_mesh.size(); j<js; ++j ){
749 Cell cell = cells_selected_for_new_mesh[j];
750
751 NodeVectorView nodes = cell.nodes();
752 for( Integer k=0, ks=nodes.size(); k<ks; ++k){
753 Node node = nodes[k];
754 if (filtre_lid_node[node.localId()]==0){
755 // les mailles reliées par un noeud
756 CellVectorView cells_vois = node.cells();
757
758 for( Integer i=0, is=cells_vois.size(); i<is; ++i ){
759 Cell cell_vois = cells_vois[i];
760 if (filtre_lid_cell[cell_vois.localId()]==0){
761
762 // ajoute la maille qui n'a pas encore été vue
763 cells_selected_for_new_mesh.add(cell_vois);
764
765 filtre_lid_cell[cell_vois.localId()] = 1;
766 }
767 }
768 filtre_lid_node[node.localId()] = 1;
769 }
770 }
771 }
772
773 // pour la deuxième couche (si besoin) il est plus simple de le faire récurcivement
774 _addGhostLayers(current_all_cells, cells_selected_for_new_mesh, nbCouches-1, maxLocalIdCell, maxLocalIdNode);
775
776}
777/*---------------------------------------------------------------------------*/
778/*---------------------------------------------------------------------------*/
779/* \brief Ajoute les groupes de mailles TOUT, LOCAL et MF_* en fonctions des groupes voisins
780 * Ajoute aussi le groupe de noeuds LOCALN (mais pas les NF_*)
781 */
782void ArcaneCasePartitioner::
783_addGhostGroups(IMesh* new_mesh, Array<Cell>& cells_selected_for_new_mesh, VariableCellInt32& true_cells_owner,
784 VariableNodeInt32& true_nodes_owner,
785 Int32Array& new_cells_local_id, Integer id_loc)
786{
787 info()<<"ArcaneCasePartitioner::_addGhostGroups (id_loc = "<<id_loc<<")";
788 // il faut déterminer les groupes voisins existant
789 // on utilise un "map" pour stocker les différents sous-domaines qui apparaissent et le nombre de mailles dedans
790 std::map<Integer, Integer> dom_vois;
791 for( Integer j=0, js=cells_selected_for_new_mesh.size(); j<js; ++j ){
792 Cell cell = cells_selected_for_new_mesh[j];
793 dom_vois[true_cells_owner[cell]] += 1;
794 }
795
796 // on utilise une seconde map pour lister les mailles suivant le domaine de destination
797 std::map<Integer,SharedArray<Int32> > map_groupes;
798 for (std::map<Integer, Integer>::const_iterator iter=dom_vois.begin(); iter!=dom_vois.end(); ++iter){
799 Integer no_sous_dom = iter->first;
800 Integer nb_mailles_sous_dom = iter->second;
801
802 // réservation de la mémoire pour les différentes listes
803 Int32Array& tab = map_groupes[no_sous_dom];
804 tab.reserve(nb_mailles_sous_dom);
805 }
806
807 for( Integer j=0, js=cells_selected_for_new_mesh.size(); j<js; ++j ){
808 Cell cell = cells_selected_for_new_mesh[j];
809 Integer no_sous_dom = true_cells_owner[cell];
810
811 // remplissage des listes par sous-domaine
812 Int32Array & liste_lid = map_groupes[no_sous_dom];
813 liste_lid.add(new_cells_local_id[j]);
814 }
815
816 // création (si nécessaire) des différents groupes et on y met les mailles
817 for (std::map<Integer,SharedArray<Int32> >::iterator iter=map_groupes.begin(); iter!=map_groupes.end(); ++iter){
818 Integer no_sous_dom = iter->first;
819 Int32Array & liste_lid = iter->second;
820
821 ItemGroup groupe_loc;
822 if (no_sous_dom==id_loc)
823 groupe_loc = new_mesh->cellFamily()->findGroup("LOCAL", true);
824 else {
825 String nom_mf("MF_");
826 nom_mf = nom_mf+no_sous_dom;
827 groupe_loc = new_mesh->cellFamily()->findGroup(nom_mf, true);
828 }
829
830 groupe_loc.addItems(liste_lid, false);
831 }
832
833 // Faire le groupe LOCALN : noeuds locaux
834 {
835 // TODO: Optimiser la maniere de construire ce groupe
836 Int32UniqueArray liste_lid;
837 Integer nbnodes = new_mesh->nodeFamily()->nbItem();
838 liste_lid.reserve(nbnodes);
839 NodeInfoListView nodes(new_mesh->nodeFamily());
840 for (int j= 0 ; j < nbnodes ; ++j) {
841 Node node= nodes[j];
842 if (true_nodes_owner[node] == id_loc)
843 liste_lid.add(node.localId());
844 }
845
846 ItemGroup groupe_loc = new_mesh->nodeFamily()->findGroup("LOCALN", true);
847 groupe_loc.addItems(liste_lid, false);
848 }
849
850
851 // le groupe avec toute les mailles
852 ItemGroup groupe_glob = new_mesh->cellFamily()->findGroup("TOUT", true);
853
854 groupe_glob.addItems(new_cells_local_id, false);
855}
856/*---------------------------------------------------------------------------*/
857/*---------------------------------------------------------------------------*/
858
859ARCANE_REGISTER_SERVICE_ARCANECASEPARTITIONER(ArcaneCasePartitioner,ArcaneCasePartitioner);
860
861/*---------------------------------------------------------------------------*/
862/*---------------------------------------------------------------------------*/
863
864}
865
866/*---------------------------------------------------------------------------*/
867/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_CELL(name, group)
Enumérateur générique d'un groupe de mailles.
#define ENUMERATE_ITEM(name, group)
Enumérateur générique d'un groupe de noeuds.
#define ENUMERATE_NODE(name, group)
Enumérateur générique d'un groupe de noeuds.
Integer size() const
Nombre d'éléments du vecteur.
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.
Service de partitionnement externe du maillage.
bool isActive() const override
Vrai si le service est actif.
void execute() override
Exécute l'opération du service.
void _initCorrespondance(Int32 my_rank)
Ouverture du fichier Correspondance (seulement sur le proc 0)
void _computeGroups(IItemFamily *current_family, IItemFamily *new_family)
Recopie les groupes de la famille courante dans la nouvelle.
void build() override
Construction de niveau build du service.
void _finalizeCorrespondance(Int32 my_rank)
Fermeture du fichier Correspondance (seulement sur le proc 0)
void setParallelMng(IParallelMng *) override
Positionne le gestionnaire de parallèlisme associé. Cette méthode doit être appelée avant execute()
void _writeCorrespondance(Int32 rank, Int64Array &nodesUniqueId, Int64Array &cellsUniqueId)
Ecriture du fichier Correspondance.
void partitionAndDistributeMeshes(ConstArrayView< IMesh * > meshes) override
Partitionne les maillages.
void _printStats(Integer nb_part, IMesh *mesh, VariableCellInt32 &new_owners)
Affiche des statistiques sur le partitionnement.
void _mergeConstraints(ConstArrayView< IMesh * > meshes)
Regroupe les mailles associées aux contraintes sur un même proc.
UniqueArray< TrueOwnerInfo > m_part_indexes
Stocke pour chaque maillage une variable indiquant pour chaque maille quelle partie la possède.
Tableau d'items de types quelconques.
void fill(const DataType &data)
Remplissage du tableau.
void clear()
Supprime les éléments du tableau.
void reserve(Int64 new_capacity)
Réserve le mémoire pour new_capacity éléments.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Maille d'un maillage.
Definition Item.h:1199
EnumeratorT< ItemGroup > Enumerator
Definition Collection.h:129
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
virtual IServiceMng * serviceMng() const =0
Gestionnaire de services.
Interface d'un partitionneur initial.
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual ItemGroupCollection groups() const =0
Liste des groupes de cette famille.
virtual ItemGroup allItems() const =0
Groupe de toutes les entités.
virtual ItemGroup createGroup(const String &name, Int32ConstArrayView local_ids, bool do_override=false)=0
Créé un groupe d'entités de nom name contenant les entités local_ids.
virtual Int32 maxLocalId() const =0
virtual String name() const =0
Nom de la famille.
virtual void itemsUniqueIdToLocalId(Int32ArrayView local_ids, Int64ConstArrayView unique_ids, bool do_fatal=true) const =0
Converti un tableau de numéros uniques en numéros locaux.
virtual Integer nbItem() const =0
Nombre d'entités.
virtual VariableItemInt32 & itemsNewOwner()=0
Variable contenant le numéro du nouveau sous-domaine propriétaire de l'entité.
virtual IItemFamily * nodeFamily()=0
Retourne la famille des noeuds.
virtual Integer nbCell()=0
Nombre de mailles du maillage.
virtual IItemFamily * edgeFamily()=0
Retourne la famille des arêtes.
virtual IItemFamily * faceFamily()=0
Retourne la famille des faces.
virtual IItemFamily * cellFamily()=0
Retourne la famille des mailles.
Interface du gestionnaire de fabriques de maillages.
virtual IPrimaryMesh * createMesh(const MeshBuildInfo &build_info)=0
Créé un maillage ou un sous-maillage.
virtual IMeshFactoryMng * meshFactoryMng() const =0
Fabrique de maillages associée à ce gestionnaire.
virtual void setDynamic(bool v)=0
Positionne la propriété indiquant si le maillage peut évoluer.
virtual void addCells(Integer nb_cell, Int64ConstArrayView cell_infos, Int32ArrayView cells_lid=Int32ArrayView())=0
Ajoute des mailles.
virtual void endUpdate()=0
Notifie l'instance de la fin de la modification du maillage.
virtual void clearItems()=0
Supprime toutes les entitées de toutes les familles de ce maillage.
Interface d'une contrainte de partitionnement d'un maillage.
virtual ItemInternalList itemsInternal(eItemKind)=0
Tableau interne des éléments du maillage de type type.
virtual IMeshModifier * modifier()=0
Interface de modification associée.
virtual ARCANE_DEPRECATED_240 void serializeCells(ISerializer *buffer, Int32ConstArrayView cells_local_id)=0
virtual void destroyGroups()=0
Détruit tous les groupes de toutes les familles.
virtual const MeshKind meshKind() const =0
Caractéristiques du maillage.
virtual IPrimaryMesh * toPrimaryMesh()=0
Retourne l'instance sous la forme d'un IPrimaryMesh.
virtual Properties * properties()=0
Propriétés associées à ce maillage.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual IParallelMng * sequentialParallelMng()=0
Retourne un gestionnaire de parallélisme séquentiel.
virtual void recv(ArrayView< char > values, Int32 rank)=0
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
virtual VariableNodeReal3 & nodesCoordinates()=0
Coordonnées des noeuds.
virtual void allocateCells(Integer nb_cell, Int64ConstArrayView cells_infos, bool one_alloc=true)=0
Allocation d'un maillage.
virtual void setDimension(Integer dim)=0
Positionne la dimension du maillage (1D, 2D ou 3D).
Interface du gestionnaire d'un sous-domaine.
Definition ISubDomain.h:74
virtual ITimeStats * timeStats() const =0
Statistiques des temps d'exécution.
virtual IParallelMng * parallelMng()=0
Retourne le gestionnaire de parallélisme.
virtual IMeshMng * meshMng() const =0
Retourne le gestionnaire de maillage.
virtual void setInitialPartitioner(IInitialPartitioner *partitioner)=0
Positionne le partitionneur initial.
virtual void dumpTimeAndMemoryUsage(IParallelMng *pm)=0
Affiche la date actuelle et la mémoire consommée.
Interface du gestionnaire de traces.
virtual TraceMessage info()=0
Flot pour un message d'information.
Groupe d'entités de maillage.
Definition ItemGroup.h:49
const String & name() const
Nom du groupe.
Definition ItemGroup.h:76
bool isOwn() const
Retourne si le groupe contient uniquement des éléments propres au sous-domaine.
Definition ItemGroup.cc:158
Integer size() const
Nombre d'éléments du groupe.
Definition ItemGroup.h:88
bool isAllItems() const
Indique si le groupe est celui de toutes les entités.
Definition ItemGroup.cc:610
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:219
Paramètres nécessaires à la construction d'un maillage.
void setBool(const String &name, bool value)
Positionne une propriété de type bool de nom name et de valeur value.
Encapsulation d'un pointeur qui se détruit automatiquement.
Definition ScopedPtr.h:44
ISubDomain * subDomain() const
Accès au ISubDomain associé.
Structure contenant les informations pour créer un service.
Classe utilitaire pour instantier un service d'une interface donnée.
Ref< InterfaceType > createReference(const String &name, eServiceBuilderProperties properties=SB_None)
Créé une instance implémentant l'interface InterfaceType.
Constructeur de chaîne de caractère unicode.
Chaîne de caractères unicode.
Int64 length() const
Retourne la longueur de la chaîne.
Definition String.cc:338
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:227
bool empty() const
Vrai si la chaîne est vide (nulle ou "")
Definition String.cc:315
Sentinelle pour le timer. La sentinelle associée à un timer permet de déclancher celui-ci au moment d...
Definition Timer.h:89
Gestion d'un timer.
Definition Timer.h:62
@ TimerReal
Timer utilisant le temps réel.
Definition Timer.h:76
Real lastActivationTime() const
Retourne le temps (en secondes) passé lors de la dernière activation du timer.
Definition Timer.h:219
TraceMessage pinfo() const
Flot pour un message d'information en parallèle.
TraceMessage fatal() const
Flot pour un message d'erreur fatale.
TraceMessage pfatal() const
Flot pour un message d'erreur fatale en parallèle.
TraceMessage info() const
Flot pour un message d'information.
Formattage du flot en longueur.
Vecteur 1D de données avec sémantique par valeur (style STL).
Paramètres nécessaires à la construction d'une variable.
__host__ __device__ Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
Definition MathUtils.h:336
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
ItemVectorViewT< Node > NodeVectorView
Vue sur un vecteur de noeuds.
Definition ItemTypes.h:289
ItemGroupT< Cell > CellGroup
Groupe de mailles.
Definition ItemTypes.h:183
ItemVectorViewT< Cell > CellVectorView
Vue sur un vecteur de mailles.
Definition ItemTypes.h:304
MeshVariableScalarRefT< Node, Int32 > VariableNodeInt32
Grandeur au noeud de type entier 32 bits.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
MeshVariableScalarRefT< Cell, Int32 > VariableCellInt32
Grandeur au centre des mailles de type entier 32 bits.
ItemVariableScalarRefT< Int32 > VariableItemInt32
Grandeur de type entier 32 bits.
@ ReduceSum
Somme des valeurs.
@ ReduceMin
Minimum des valeurs.
@ ReduceMax
Maximum des valeurs.
ARCCORE_BASE_EXPORT double getMemoryUsed()
Mémoire utilisée em octets.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Array< Int64 > Int64Array
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:212
@ SB_Collective
Indique que tous les processus font la même opération.
@ SB_AllowNull
Autorise l'absence du service.
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:426
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
ConstArrayView< ItemInternal * > ItemInternalList
Type de la liste interne des entités.
Definition ItemTypes.h:466
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:567
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:428
@ IK_Cell
Entité de maillage de genre maille.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
Array< Int32 > Int32Array
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:214
@ Cell
Le maillage est AMR par maille.
Definition MeshKind.h:52
std::int32_t Int32
Type entier signé sur 32 bits.