14#include "arcane/utils/ArgumentException.h"
15#include "arcane/utils/NotImplementedException.h"
16#include "arcane/utils/NotSupportedException.h"
17#include "arcane/utils/HashTableMap.h"
18#include "arcane/utils/PlatformUtils.h"
19#include "arcane/utils/ScopedPtr.h"
20#include "arcane/utils/ITraceMng.h"
21#include "arcane/utils/ValueConvert.h"
22#include "arcane/utils/OStringStream.h"
23#include "arcane/utils/CheckedConvert.h"
25#include "arcane/core/ItemTypeMng.h"
27#include "arcane/core/IParallelMng.h"
28#include "arcane/core/SerializeBuffer.h"
29#include "arcane/core/ItemPrinter.h"
30#include "arcane/core/IParallelExchanger.h"
31#include "arcane/core/ISerializeMessage.h"
32#include "arcane/core/IItemFamilyPolicyMng.h"
33#include "arcane/core/IItemFamilySerializer.h"
34#include "arcane/core/ParallelMngUtils.h"
35#include "arcane/core/IGhostLayerMng.h"
36#include "arcane/core/internal/IMeshInternal.h"
38#include "arcane/mesh/DynamicMesh.h"
39#include "arcane/mesh/GhostLayerBuilder.h"
40#include "arcane/mesh/OneMeshItemAdder.h"
52_buildGhostLayerNewVersion(IMesh* mesh,
bool is_allocate,
Int32 version);
70, m_mesh_internal(
mesh->_internalApi())
88void GhostLayerBuilder::
89addGhostLayers(
bool is_allocate)
97 info() <<
"Use ghost layer builder version 2";
98 _addOneGhostLayerV2();
100 else if (version==3 || version==4){
101 info() <<
"Use GhostLayerBuilder with sort (version " << version <<
")";
102 _buildGhostLayerNewVersion(m_mesh,is_allocate,version);
105 throw NotSupportedException(A_FUNCINFO,
"Bad version number for addGhostLayer");
108 Real diff = (
Real)(end_time - begin_time);
109 info() <<
"TIME to compute ghost layer=" << diff;
121 NodeCellList() : m_cell_last_index(5000,
true) {}
127 Int32 current_index = m_cell_indexes.size();
128 m_cell_indexes.add(cell_uid);
129 m_cell_indexes.add(cell_owner);
132 m_cell_indexes.add(d->value());
133 d->value() = current_index;
144void GhostLayerBuilder::
147 for( BoundaryInfosMapEnumerator i_map(boundary_infos_to_send); ++i_map; ){
148 Int32 sd = i_map.data()->key();
159 s->
setMode(ISerializer::ModeReserve);
169 debug() <<
"END EXCHANGE";
175void GhostLayerBuilder::
178 info() <<
"** NEW GHOST LAYER BUILDER V2";
179 if (m_mesh->ghostLayerMng()->nbGhostLayer()!=1)
180 ARCANE_THROW(NotImplementedException,
"Only one layer of ghost cells is supported");
182 IParallelMng* pm = m_mesh->parallelMng();
183 Int32 my_rank = pm->commRank();
184 Int32 nb_rank = pm->commSize();
185 debug() <<
" RANK="<< pm->commRank() <<
" size=" << pm->commSize();
186 if (!pm->isParallel()){
187 debug() <<
"NOT PARALLEL";
190#ifdef ARCANE_DEBUG_DYNAMIC_MESH
191 const bool is_verbose =
true;
193 const bool is_verbose =
false;
198 ostr() <<
"** FACES LIST\n";
200 Integer nb_sub_domain_boundary_face = 0;
202 ItemInternalMap& cells_map = m_mesh_internal->cellsMap();
203 ItemInternalMap& faces_map = m_mesh_internal->facesMap();
205 ItemInternalMap& nodes_map = m_mesh_internal->nodesMap();
209 faces_map.eachItem([&](Face face) {
210 impl::ItemBase face_base = face.itemBase();
212 ostr() << ItemPrinter(face);
215 bool is_sub_domain_boundary_face =
false;
217 is_sub_domain_boundary_face =
true;
220 if (face.nbCell()==2 && (face.cell(0).owner()!=my_rank || face.cell(1).owner()!=my_rank))
221 is_sub_domain_boundary_face =
true;
223 if (is_sub_domain_boundary_face){
224 face_base.toMutable().addFlags(shared_and_boundary_flags);
225 ++nb_sub_domain_boundary_face;
226 for( Item inode : face.nodes() )
227 inode.mutableItemBase().addFlags(shared_and_boundary_flags);
228 for( Item iedge : face.edges() )
229 iedge.mutableItemBase().addFlags(shared_and_boundary_flags);
233 Integer boundary_nodes_uid_count = 0;
236 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
237 nodes_map.eachItem([&](Node node) {
238 Int32 f = node.itemBase().flags();
240 Int64 node_uid = node.uniqueId();
241 if (node_uid > my_max_node_uid)
242 my_max_node_uid = node_uid;
243 ++boundary_nodes_uid_count;
248 debug() <<
"NB BOUNDARY NODE=" << boundary_nodes_uid_count
249 <<
" MY_MAX_UID=" << my_max_node_uid
250 <<
" GLOBAL=" << global_max_node_uid;
254 ostr() <<
"List of shared cells:\n";
259 BoundaryInfosMap boundary_infos_to_send(200,
true);
260 NodeUidToSubDomain uid_to_subdomain_converter(global_max_node_uid,nb_rank);
262 cells_map.eachItem([&](
Cell cell) {
264 ostr() <<
"Send cell " << ItemPrinter(cell) <<
'\n';
268 for( Node node : cell.nodes() ){
271 Int64 node_uid = node.uniqueId();
273 Int32 dest_rank = uid_to_subdomain_converter.uidToRank(node_uid);
274 SharedArray<Int64> v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
277 v.add(cell.uniqueId());
286 info() << ostr.str();
288 info() <<
"Number of shared faces: " << nb_sub_domain_boundary_face;
295 _exchangeData(exchanger.get(),boundary_infos_to_send);
299 NodeCellList node_cell_list;
302 debug() <<
"NB RECEIVER=" << nb_receiver;
304 for(
Integer i=0; i<nb_receiver; ++i ){
307 ISerializer* s = sm->serializer();
309 s->getArray(received_infos);
310 Int64 nb_info = received_infos.largeSize();
312 if ((nb_info % 3)!=0)
313 ARCANE_FATAL(
"Inconsistent received data v={0}",nb_info);
314 Int64 nb_info_true = nb_info / 3;
315 for(
Int64 z=0; z<nb_info_true; ++z ){
316 Int64 node_uid = received_infos[(z*3)+0];
317 Int64 cell_owner = received_infos[(z*3)+1];
318 Int64 cell_uid = received_infos[(z*3)+2];
319 node_cell_list.add(node_uid,cell_uid,cell_owner);
324 boundary_infos_to_send = BoundaryInfosMap(1000,
true);
328 debug() <<
"NB_CELL_INDEXES = " << cell_indexes.size();
333 for( HashTableMapEnumeratorT<Int64,Int32> i_map(node_cell_list.m_cell_last_index); ++i_map; ){
334 HashTableMapT<Int64,Int32>::Data* d = i_map.data();
335 Int32 index = d->value();
336 Int64 node_uid = d->key();
344 Int32 node_new_owner = NULL_SUB_DOMAIN_ID;
345 Int64 smallest_cell_uid = NULL_ITEM_UNIQUE_ID;
348 Int64 cell_uid = cell_indexes[index];
349 Int32 cell_owner = CheckedConvert::toInt32(cell_indexes[index+1]);
350 index = CheckedConvert::toInteger(cell_indexes[index+2]);
352 ranks.add((
Int32)cell_owner);
354 if (cell_uid<smallest_cell_uid || node_new_owner==NULL_SUB_DOMAIN_ID){
355 smallest_cell_uid = cell_uid;
356 node_new_owner = cell_owner;
360 std::sort(std::begin(ranks),std::end(ranks));
361 Integer new_size = CheckedConvert::toInteger(std::unique(std::begin(ranks),std::end(ranks)) - std::begin(ranks));
362 ranks.resize(new_size);
371 Integer nb_cell = cells.size();
372 for(
Integer z=0; z<new_size; ++z ){
373 Int32 dest_rank = ranks[z];
375 Int64Array& v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
377 v.add(node_new_owner);
380 for(
Integer z2=0; z2<new_size; ++z2 )
382 for(
Integer z2=0; z2<nb_cell; ++z2 )
389 _exchangeData(exchanger.get(),boundary_infos_to_send);
390 debug() <<
"END OF EXCHANGE";
392 typedef HashTableMapT<Int32,SharedArray<Int32> > SubDomainItemMap;
393 SubDomainItemMap cells_to_send(50,
true);
396 debug() <<
"NB RECEIVER 2 =" << nb_receiver;
399 for(
Integer i=0; i<nb_receiver; ++i ){
405 s->getArray(received_infos);
406 Int64 nb_info = received_infos.largeSize();
411 Int64 node_uid = received_infos[z];
412 Int32 node_new_owner = CheckedConvert::toInt32(received_infos[z+1]);
413 Int32 nb_rank = CheckedConvert::toInt32(received_infos[z+2]);
414 Int32 nb_cell = CheckedConvert::toInt32(received_infos[z+3]);
416 nodes_map.findItem(node_uid).toMutable().setOwner(node_new_owner, my_rank);
420 for(
Integer z2=0; z2<nb_rank; ++z2 ){
426 for(
Integer z2=0; z2<nb_cell; ++z2 ){
427 Int64 cell_uid = received_infos[z+z2];
428 impl::ItemBase dcell = cells_map.tryFind(cell_uid);
430 cells.add(dcell.localId());
432 for(
Integer z2=0,zs=ranks.size(); z2<zs; ++z2 ){
433 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(ranks[z2]);
434 SharedArray<Int32> dv = d->value();
435 for(
Integer z3=0, zs3=cells.size(); z3<zs3; ++z3 )
444 _exchangeCells(cells_to_send,
false);
445 m_mesh_internal->printStats(TraceMessage::DEFAULT_LEVEL);
451void GhostLayerBuilder::
452_exchangeCells(HashTableMapT<
Int32,SharedArray<Int32>>& cells_to_send,
bool with_flags)
455 typedef HashTableMapT<Int32,SharedArray<Int32>> SubDomainItemMap;
456 IParallelMng* pm = m_mesh->parallelMng();
458 for( SubDomainItemMap::Enumerator i_map(cells_to_send); ++i_map; ){
459 Int32 sd = i_map.data()->key();
463 info(4) <<
"CELLS TO SEND SD=" << sd <<
" NB=" << items.size();
470 ISerializer* s = sm->serializer();
472 ScopedPtrT<IItemFamilySerializer> cell_serializer(m_mesh->cellFamily()->policyMng()->createSerializer(with_flags));
473 s->setMode(ISerializer::ModeReserve);
474 cell_serializer->serializeItems(s,items_to_send);
477 cell_serializer->serializeItems(s,items_to_send);
480 info(4) <<
"END EXCHANGE CELLS";
485 ScopedPtrT<IItemFamilySerializer> cell_serializer(m_mesh->cellFamily()->policyMng()->createSerializer(with_flags));
486 cell_serializer->deserializeItems(s,
nullptr);
496 info() <<
"** AMR GHOST CHILD FROM PARENT BUILDER V1";
501 debug() <<
"NOT PARALLEL";
507 ItemInternalMap& cells_map = m_mesh_internal->cellsMap();
509 FaceFamily& true_face_family = m_mesh_internal->trueFaceFamily();
512 BoundaryInfosMap boundary_infos_to_send(200,
true);
515 ARCANE_ASSERT((cell.
owner() != -1), (
""));
517 ARCANE_ASSERT((cell.
owner() != -1), (
""));
526 _exchangeData(exchanger.get(),boundary_infos_to_send);
532 SubDomainItemMap cells_to_send(50,
true);
535 debug() <<
"NB RECEIVER=" << nb_receiver;
537 for(
Integer i=0; i<nb_receiver; ++i ){
545 if ((nb_info % 2)!=0)
546 ARCANE_FATAL(
"info size can not be divided by 2 v={0}",nb_info);
547 Int64 nb_info_true = nb_info / 2;
549 for(
Int64 z=0; z<nb_info_true; ++z ){
550 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z*2)+0]);
551 Int64 cell_uid = received_infos[(z*2)+1];
553 impl::ItemBase cell = cells_map.
findItem(cell_uid);
554 ARCANE_ASSERT((cell.uniqueId() == cell_uid), (
""));
555 if (!cell.hasHChildren())
558 ARCANE_ASSERT((cell.level() == 0), (
""));
559 ARCANE_ASSERT((cell.owner() != -1), (
"CELL"));
560 ARCANE_ASSERT((cell_owner != -1),(
"CELL"));
561 true_face_family.familyTree(cell_family,cell);
562 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
568 ARCANE_ASSERT((child->
owner() != -1),(
"CHILD"));
575 debug() <<
"nb_recv_child= " << nb_recv_child;
579 _exchangeCells(cells_to_send,
true);
580 m_mesh_internal->printStats(TraceMessage::DEFAULT_LEVEL);
587void GhostLayerBuilder::
588addGhostChildFromParent2(
Array<Int64>& ghost_cell_to_refine)
590 info() <<
"** AMR GHOST CHILD FROM PARENT BUILDER V2";
595 debug() <<
"NOT PARALLEL";
601 ItemInternalMap& cells_map = m_mesh_internal->cellsMap();
604 BoundaryInfosMap boundary_infos_to_send(200,
true);
608 cells_map.eachItem([&](
Item cell) {
609 ARCANE_ASSERT((cell.
owner() != -1), (
""));
610 if (cell.
owner() == sid)
616 Int64Array& v = boundary_infos_to_send.lookupAdd(cell.
owner())->value();
624 _exchangeData(exchanger.get(), boundary_infos_to_send);
629 typedef HashTableMapT<Int32,SharedArray<Int32> > SubDomainItemMap;
630 SubDomainItemMap cells_to_send(50,
true);
633 debug() <<
"NB RECEIVER=" << nb_receiver;
635 for(
Integer i=0; i<nb_receiver; ++i ){
641 s->getArray(received_infos);
642 Int64 nb_info = received_infos.size();
643 if ((nb_info % 2)!=0)
644 ARCANE_FATAL(
"info size can not be divided by 2 v={0}",nb_info);
645 Int64 nb_info_true = nb_info / 2;
647 for(
Int64 z=0; z<nb_info_true; ++z ){
648 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z*2)+0]);
649 Int64 cell_uid = received_infos[(z*2)+1];
651 Cell cell = cells_map.findItem(cell_uid);
652 ARCANE_ASSERT((cell.uniqueId() == cell_uid),(
""));
653 ARCANE_ASSERT((cell.owner() != -1),(
"CELL"));
654 ARCANE_ASSERT((cell_owner != -1),(
"CELL"));
656 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
659 nb_recv_child +=cell.nbHChildren();
660 for(
Integer c=0,cs=cell.nbHChildren();c<cs;c++){
661 Cell child= cell.hChild(c);
662 ARCANE_ASSERT((child.owner() != -1),(
"CHILD"));
665 dv.add(child.localId());
668 debug() <<
"nb_recv_child= " << nb_recv_child;
673 _exchangeCells(cells_to_send,
true);
674 m_mesh_internal->printStats(TraceMessage::DEFAULT_LEVEL);
682NodeUidToSubDomain(
Int64 max_uid,
Int32 nb_rank)
685, m_nb_by_rank(max_uid)
687 m_nb_by_rank = max_uid / nb_rank;
689 m_nb_by_rank = max_uid;
696 bool is_ok = builtInGetValue(div_value,s);
700 if (div_value>m_nb_rank)
701 div_value = m_nb_rank;
704 m_modulo = m_nb_rank / div_value;
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Fonctions utilitaires sur le maillage.
Integer size() const
Nombre d'éléments du vecteur.
Tableau d'items de types quelconques.
void clear()
Supprime les éléments du tableau.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
constexpr const_pointer data() const noexcept
Pointeur sur la mémoire allouée.
Table de hachage pour tableaux associatifs.
Data * lookupAdd(KeyTypeConstRef id, const ValueType &value, bool &is_add)
Recherche ou ajoute la valeur correspondant à la clé id.
virtual Integer builderVersion() const =0
Version du constructeur de mailles fantômes.
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual IGhostLayerMng * ghostLayerMng() const =0
Gestionnare de couche fantômes associé
Échange d'informations entre processeurs.
virtual void addSender(Int32 rank)=0
Ajoute un processeur à envoyer.
@ EM_Collective
Utilise les opération collectives (allToAll).
virtual Integer nbSender() const =0
Nombre de processeurs auquel on envoie.
virtual void setExchangeMode(eExchangeMode mode)=0
Positionne le mode d'échange.
virtual Integer nbReceiver() const =0
Nombre de processeurs dont on va réceptionner les messages.
virtual bool initializeCommunicationsMessages()=0
Calcule les communications.
virtual ISerializeMessage * messageToSend(Integer i)=0
Message destiné au ième processeur.
virtual void processExchange()=0
Effectue l'échange avec les options par défaut de ParallelExchangerOptions.
virtual ISerializeMessage * messageToReceive(Integer i)=0
Message reçu du ième processeur.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
virtual void barrier()=0
Effectue une barière.
Interface d'un sérialiseur.
virtual void putArray(Span< const Real > values)=0
Sauve le nombre d'éléments et les values éléments.
virtual void reserveArray(Span< const Real > values)=0
Réserve pour sauver le nombre d'éléments et les values éléments.
virtual void getArray(Array< Real > &values)=0
Redimensionne et remplit values.
@ ModePut
Le sérialiseur attend des reserve().
@ ModeGet
Le sérialiseur attend des get().
virtual void allocateBuffer()=0
Alloue la mémoire du sérialiseur.
virtual void setMode(eMode new_mode)=0
Positionne le fonctionnement actuel.
virtual void flush()=0
Flush tous les flots.
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
Int32 localId() const
Numéro local (au sous-domaine) de l'entité
@ II_Shared
L'entité est partagée par un autre sous-domaine.
@ II_SubDomainBoundary
L'entité est à la frontière de deux sous-domaines.
@ II_JustRefined
L'entité vient d'être raffinée.
@ II_Boundary
L'entité est sur la frontière.
Structure interne d'une entité de maillage.
Classe de base d'un élément de maillage.
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
constexpr bool hasFlags(Int32 flags) const
Retourne si les flags flags sont positionnées pour l'entité
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
impl::ItemBase itemBase() const
Partie interne de l'entité.
Interface d'un message de sérialisation entre IMessagePassingMng.
virtual MessageRank destination() const =0
Rang du destinataire (si isSend() est vrai) ou de l'envoyeur.
virtual ISerializer * serializer()=0
Sérialiseur.
Int32 value() const
Valeur du rang.
Exception lorsqu'une opération n'est pas supportée.
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flot pour un message de debug.
TraceMessage info() const
Flot pour un message d'information.
ITraceMng * traceMng() const
Gestionnaire de trace.
Vecteur 1D de données avec sémantique par valeur (style STL).
void addGhostChildFromParent()
AMR.
GhostLayerBuilder(IMesh *mesh)
Construit une instance pour le maillage mesh.
impl::ItemBase findItem(Int64 uid) const
Retourne l'entité de numéro unique uid.
void eachItem(const Lambda &lambda)
Fonction template pour itérer sur les entités de l'instance.
@ ReduceMax
Maximum des valeurs.
Ref< IParallelExchanger > createExchangerRef(IParallelMng *pm)
Retourne une interface pour transférer des messages entre rangs.
Array< Int64 > Int64Array
Tableau dynamique à une dimension d'entiers 64 bits.
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
ConstArrayView< Int32 > Int32ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
double Real
Type représentant un réel.
Array< Int32 > Int32Array
Tableau dynamique à une dimension d'entiers 32 bits.
@ Cell
Le maillage est AMR par maille.
std::int32_t Int32
Type entier signé sur 32 bits.