14#include "arcane/utils/ScopedPtr.h"
15#include "arcane/utils/StringBuilder.h"
16#include "arcane/utils/PlatformUtils.h"
17#include "arcane/utils/ITraceMng.h"
19#include "arcane/core/BasicService.h"
21#include "arcane/core/ISubDomain.h"
22#include "arcane/core/ServiceFinder2.h"
23#include "arcane/core/FactoryService.h"
24#include "arcane/core/SerializeBuffer.h"
25#include "arcane/core/IMeshPartitioner.h"
26#include "arcane/core/IMainFactory.h"
27#include "arcane/core/IMeshModifier.h"
28#include "arcane/core/Properties.h"
29#include "arcane/core/IInitialPartitioner.h"
30#include "arcane/core/Timer.h"
31#include "arcane/core/IMesh.h"
32#include "arcane/core/IMeshSubMeshTransition.h"
33#include "arcane/core/IItemFamily.h"
34#include "arcane/core/IDirectExecution.h"
35#include "arcane/core/IParallelMng.h"
36#include "arcane/core/IMeshUtilities.h"
37#include "arcane/core/IMeshWriter.h"
38#include "arcane/core/ITimeStats.h"
39#include "arcane/core/ServiceBuilder.h"
41#include "arcane/std/ArcaneCasePartitioner_axl.h"
43#include "arcane/core/IMeshPartitionConstraintMng.h"
44#include "arcane/mesh/ExternalPartitionConstraint.h"
57class ArcaneCasePartitioner;
80 void build()
override {}
93 ISubDomain* m_sub_domain =
nullptr;
94 ArcaneCasePartitioner* m_main =
nullptr;
135 std::ofstream m_sortiesCorrespondance;
139 void _partitionMesh(Int32
nb_part);
154 Integer
nb_mesh = meshes.size();
158 IMesh* mesh = meshes[0];
162 tm->
info()<<
" _regroupeContraintes: nbMailles = "<<meshes[0]->nbCell() <<
", nbMaillesLocales = "<< meshes[0]->ownCells().size();
175 sd->timeStats()->dumpTimeAndMemoryUsage(
sd->parallelMng());
181 mesh->
utilities()->changeOwnersFromCells();
183 bool compact = mesh->
properties()->getBool(
"compact");
186 mesh->
properties()->setBool(
"compact", compact);
219 if (!mesh_partitioner.get())
224 Integer
nb_mesh = meshes.size();
234 for( Integer i=0; i<
nb_mesh; ++i ){
235 IMesh* mesh = meshes[i];
255 sd->timeStats()->dumpTimeAndMemoryUsage(pm);
259 mesh_partitioner->partitionMesh(mesh,
nb_part);
261 tm->
info() <<
"Partitioning time t=" <<
t.lastActivationTime();
262 sd->timeStats()->dumpTimeAndMemoryUsage(pm);
273 mesh->
utilities()->changeOwnersFromCells();
276 bool compact = mesh->
properties()->getBool(
"compact");
280 mesh->
properties()->setBool(
"compact", compact);
285 IMesh* mesh = meshes[0];
286 if (m_main->
options()->nbGhostLayer()==2)
287 mesh->updateGhostLayers(
false);
304 tm->
info() <<
" -- Partitioning statistics --";
305 tm->
info() <<
" Part NbCell";
306 for( Integer i=0; i<
nb_part; ++i ){
314ArcaneCasePartitioner::
319 info() <<
"** ** SET INITIAL PARTITIONER 2";
326ArcaneCasePartitioner::
327~ArcaneCasePartitioner()
338 info() <<
"ArcaneCasePartitioner::execute() nb_part=" <<
nb_part;
340 subDomain()->timeStats()->dumpTimeAndMemoryUsage(subDomain()->parallelMng());
351void ArcaneCasePartitioner::
364 pfatal() <<
"No service selected to write the mesh";
369 info() <<
"Mesh file pattern=" << pattern;
388 new_mesh->setDimension(mesh()->dimension());
390 new_mesh->properties()->setBool(
"compact",
false);
391 new_mesh->properties()->setBool(
"sort",
false);
392 new_mesh->modifier()->setDynamic(
true);
399 if (
options()->createCorrespondances())
408 for(
IItemFamily* family : mesh()->itemFamilies() ){
410 iitem->mutableItemBase().setOwner(0,0);
417 info() <<
"NbPart=" << nb_part <<
" my_rank=" << my_rank;
418 for( Integer i=0; i<nb_part; ++i ){
419 if ((i % nb_rank)!=my_rank){
420 if (my_rank==0 &&
options()->createCorrespondances()){
422 info()<<
"Receive on master to build correspondence file on sub-domain "<<i
423 <<
" sent from processor "<<i % nb_rank;
428 pm->
recv(taillesTab, i % nb_rank);
429 nodesUniqueId.resize(taillesTab[0]);
430 cellsUniqueId.resize(taillesTab[1]);
431 pm->
recv(nodesUniqueId, i % nb_rank);
432 pm->
recv(cellsUniqueId, i % nb_rank);
441 UniqueArray<Cell> cells_selected_for_new_mesh;
443 if (true_cells_owner[icell]==i){
445 cells_selected_for_new_mesh.add(cell);
451 _addGhostLayers(current_all_cells, cells_selected_for_new_mesh,
options()->nbGhostLayer(), maxLocalIdCell, maxLocalIdNode);
455 for( Integer j=0, js=cells_selected_for_new_mesh.size(); j<js; ++j ){
456 Cell cell = cells_selected_for_new_mesh[j];
457 cells_local_id.add(cell.localId());
458 cells_unique_id.add(
static_cast<Int64>(cell.uniqueId()));
461 Integer nb_cell_to_copy = cells_local_id.size();
462 SerializeBuffer buffer;
464 info() <<
"NB_CELL_TO_SERIALIZE=" << nb_cell_to_copy;
465 new_mesh->
modifier()->addCells(&buffer);
474 new_mesh->
cellFamily()->itemsUniqueIdToLocalId(new_cells_local_id,cells_unique_id);
475 for( Integer zid=0; zid<nb_cell_to_copy; ++zid ){
476 Cell current_cell = current_cells[cells_local_id[zid]];
477 Cell new_cell = new_cells[new_cells_local_id[zid]];
478 if (current_cell.uniqueId()!=new_cell.uniqueId())
479 fatal() <<
"Inconsistent unique ids";
480 Integer nb_node = current_cell.nbNode();
484 for( Integer z2=0; z2<nb_node; ++z2 ){
485 Real3 coord = current_coordinates[current_cell.node(z2)];
488 new_coordinates[new_cell.node(z2)] = coord;
490 new_cell.node(z2).mutableItemBase().setOwner(true_nodes_owner[current_cell.node(z2)],0);
500 if (
options()->nbGhostLayer()>0)
501 _addGhostGroups(new_mesh, cells_selected_for_new_mesh, true_cells_owner, true_nodes_owner, new_cells_local_id, i);
504 info() <<
"NB_NEW_CELL=" << new_nb_cell;
505 min_nb_cell =
math::min(min_nb_cell,new_nb_cell);
506 max_nb_cell =
math::max(max_nb_cell,new_nb_cell);
507 saved_nb_cell += new_nb_cell;
509 if (pattern.
empty()){
510 StringBuilder sfilename =
"cut_mesh_";
513 filename = sfilename;
519 if (pattern.
length()>128){
520 pfatal() <<
"Pattern too long (max=128)";
523 filename = String(StringView(buf));
526 info() <<
"Writing mesh file filename='" << filename <<
"'";
527 bool is_bad = mesh_writer->writeMeshToFile(new_mesh, filename);
529 ARCANE_FATAL(
"Can not write mesh file '{0}'", filename);
533 if (
options()->createCorrespondances()){
534 info()<<
"Participation to build correspondence file on sub-domain "<<i;
538 taillesTab.add(new_mesh->
cellFamily()->nbItem());
542 NodeInfoListView nodes(new_mesh->
nodeFamily());
543 for(
int j=0; j<taillesTab[0]; ++j ){
544 Node node = nodes[j];
545 nodesUniqueId[j] = node.uniqueId();
548 CellInfoListView cells(new_mesh->
cellFamily());
549 for(
int j=0; j<taillesTab[1]; ++j ){
550 Cell cell = cells[j];
551 cellsUniqueId[j] = cell.uniqueId();
555 pm->send(taillesTab, 0);
556 pm->send(nodesUniqueId, 0);
557 pm->send(cellsUniqueId, 0);
565 Integer total_new_nb_cell = pm->
reduce(Parallel::ReduceSum,saved_nb_cell);
566 Integer total_min_nb_cell = pm->
reduce(Parallel::ReduceMin,min_nb_cell);
567 Integer total_max_nb_cell = pm->
reduce(Parallel::ReduceMax,max_nb_cell);
568 info() <<
"TOTAL_NEW_NB_CELL=" << total_new_nb_cell
569 <<
" min=" << total_min_nb_cell
570 <<
" max=" << total_max_nb_cell
571 <<
" computed_average=" << (total_current_nb_cell/nb_part);
573 subDomain()->timeStats()->dumpTimeAndMemoryUsage(pm);
575 if (
options()->createCorrespondances())
578 if (
options()->nbGhostLayer()==0)
579 if (total_new_nb_cell!=total_current_nb_cell)
580 pfatal() <<
"Bad number of saved cells current=" << total_current_nb_cell
581 <<
" saved=" << total_new_nb_cell;
583 pinfo()<<
"Total Memory Used : "<<platform::getMemoryUsed();
597 m_sortiesCorrespondance.open(
"Correspondances");
599 if (m_sortiesCorrespondance.fail ()){
600 pfatal() <<
"Unable to write to file 'Correspondances' ";
603 m_sortiesCorrespondance <<
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
604 m_sortiesCorrespondance <<
"<!-- Correspondance file generated by Arcane/Decoupe3D V2 -->\n";
605 m_sortiesCorrespondance <<
"\n<cpus>\n";
614 info()<<
" _writeCorrespondance("<<rank<<
", nodesUniqueId.size() = "
617 m_sortiesCorrespondance <<
" <cpu id=\"" << rank <<
"\">" <<
"\n"
618 <<
" <noeuds>" <<
"\n" <<
" ";
622 m_sortiesCorrespondance <<
"\n" <<
" </noeuds>"
624 <<
" <mailles>" <<
"\n"
628 m_sortiesCorrespondance <<
"\n" <<
" </mailles>" <<
"\n"
629 <<
" </cpu>" <<
"\n";
641 m_sortiesCorrespondance <<
"</cpus>\n";
642 m_sortiesCorrespondance.close ();
697 if (
new_lid!=NULL_ITEM_LOCAL_ID)
708void ArcaneCasePartitioner::
728 for( Integer j=0, js=cells_selected_for_new_mesh.size(); j<js; ++j ){
729 Cell cell = cells_selected_for_new_mesh[j];
732 for( Integer k=0, ks=nodes.size(); k<ks; ++k){
733 Node node = nodes[k];
734 if (filtre_lid_node[node.localId()]==0){
738 for( Integer i=0, is=cells_vois.size(); i<is; ++i ){
739 Cell cell_vois = cells_vois[i];
740 if (filtre_lid_cell[cell_vois.localId()]==0){
743 cells_selected_for_new_mesh.add(cell_vois);
745 filtre_lid_cell[cell_vois.localId()] = 1;
748 filtre_lid_node[node.localId()] = 1;
754 _addGhostLayers(current_all_cells, cells_selected_for_new_mesh, nbCouches-1, maxLocalIdCell, maxLocalIdNode);
762void ArcaneCasePartitioner::
763_addGhostGroups(IMesh* new_mesh, Array<Cell>& cells_selected_for_new_mesh,
VariableCellInt32& true_cells_owner,
765 Int32Array& new_cells_local_id, Integer id_loc)
767 info()<<
"ArcaneCasePartitioner::_addGhostGroups (id_loc = "<<id_loc<<
")";
770 std::map<Integer, Integer> dom_vois;
771 for( Integer j=0, js=cells_selected_for_new_mesh.size(); j<js; ++j ){
772 Cell cell = cells_selected_for_new_mesh[j];
773 dom_vois[true_cells_owner[cell]] += 1;
777 std::map<Integer,SharedArray<Int32> > map_groupes;
778 for (std::map<Integer, Integer>::const_iterator iter=dom_vois.begin(); iter!=dom_vois.end(); ++iter){
779 Integer no_sous_dom = iter->first;
780 Integer nb_mailles_sous_dom = iter->second;
784 tab.
reserve(nb_mailles_sous_dom);
787 for( Integer j=0, js=cells_selected_for_new_mesh.size(); j<js; ++j ){
788 Cell cell = cells_selected_for_new_mesh[j];
789 Integer no_sous_dom = true_cells_owner[cell];
792 Int32Array & liste_lid = map_groupes[no_sous_dom];
793 liste_lid.
add(new_cells_local_id[j]);
797 for (std::map<Integer,SharedArray<Int32> >::iterator iter=map_groupes.begin(); iter!=map_groupes.end(); ++iter){
798 Integer no_sous_dom = iter->first;
801 ItemGroup groupe_loc;
802 if (no_sous_dom==id_loc)
803 groupe_loc = new_mesh->cellFamily()->findGroup(
"LOCAL",
true);
805 String nom_mf(
"MF_");
806 nom_mf = nom_mf+no_sous_dom;
807 groupe_loc = new_mesh->cellFamily()->findGroup(nom_mf,
true);
810 groupe_loc.addItems(liste_lid,
false);
817 Integer nbnodes = new_mesh->nodeFamily()->nbItem();
818 liste_lid.reserve(nbnodes);
819 NodeInfoListView nodes(new_mesh->nodeFamily());
820 for (
int j= 0 ; j < nbnodes ; ++j) {
822 if (true_nodes_owner[node] == id_loc)
823 liste_lid.add(node.localId());
826 ItemGroup groupe_loc = new_mesh->nodeFamily()->findGroup(
"LOCALN",
true);
827 groupe_loc.addItems(liste_lid,
false);
832 ItemGroup groupe_glob = new_mesh->cellFamily()->findGroup(
"TOUT",
true);
834 groupe_glob.addItems(new_cells_local_id,
false);
839ARCANE_REGISTER_SERVICE_ARCANECASEPARTITIONER(ArcaneCasePartitioner,ArcaneCasePartitioner);
#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.
Generation de la classe de base du Service.
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.
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
Interface d'un partitionneur initial.
Interface d'une famille d'entités.
Manufacture des classes d'Arcane.
virtual IItemFamily * nodeFamily()=0
Retourne la famille des noeuds.
virtual Integer nbCell()=0
Nombre de mailles du maillage.
virtual CellGroup ownCells()=0
Groupe de toutes les mailles propres au domaine.
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 d'une contrainte de partitionnement d'un maillage.
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
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 IMeshUtilities * utilities()=0
Interface des fonctions utilitaires associée.
virtual IMeshPartitionConstraintMng * partitionConstraintMng()=0
Gestionnaire des contraintes de partitionnement associées à ce maillage.
virtual IPrimaryMesh * toPrimaryMesh()=0
Retourne l'instance sous la forme d'un IPrimaryMesh.
virtual bool isDynamic() const =0
Indique si le maillage est dynamique (peut évoluer)
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.
Interface du gestionnaire d'un sous-domaine.
virtual void setInitialPartitioner(IInitialPartitioner *partitioner)=0
Positionne le partitionneur initial.
Groupe d'entités de maillage.
const String & name() const
Nom du groupe.
bool isOwn() const
Retourne si le groupe contient uniquement des éléments propres au sous-domaine.
bool isAllItems() const
Indique si le groupe est celui de toutes les entités.
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Structure contenant les informations pour créer un service.
Sentinelle pour le timer. La sentinelle associée à un timer permet de déclancher celui-ci au moment d...
@ TimerReal
Timer utilisant le temps réel.
Paramètres nécessaires à la construction d'une variable.
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.
Interface du gestionnaire de traces.
Constructeur de chaîne de caractère unicode.
Chaîne de caractères unicode.
bool empty() const
Vrai si la chaîne est vide (nulle ou "")
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Int64 length() const
Retourne la longueur de la chaîne.
TraceMessage pinfo() const
Flot pour un message d'information en parallèle.
TraceMessage pfatal() const
Flot pour un message d'erreur fatale en parallèle.
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage fatal() const
Flot pour un message d'erreur fatale.
Formattage du flot en longueur.
Vecteur 1D de données avec sémantique par valeur (style STL).
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
ARCCORE_HOST_DEVICE Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
ItemVectorViewT< Node > NodeVectorView
Vue sur un vecteur de noeuds.
ItemVectorViewT< Cell > CellVectorView
Vue sur un vecteur de mailles.
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.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
@ 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.
ConstArrayView< ItemInternal * > ItemInternalList
Type de la liste interne des entités.
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
@ IK_Cell
Entité de maillage de genre maille.
Array< Int32 > Int32Array
Tableau dynamique à une dimension d'entiers 32 bits.
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Int32 Integer
Type représentant un entier.