14#include "arcane/utils/HashTableMap.h"
15#include "arcane/utils/ITraceMng.h"
16#include "arcane/utils/CheckedConvert.h"
17#include "arcane/utils/ValueConvert.h"
19#include "arcane/core/parallel/BitonicSortT.H"
21#include "arcane/core/IParallelExchanger.h"
22#include "arcane/core/ISerializeMessage.h"
23#include "arcane/core/SerializeBuffer.h"
24#include "arcane/core/ISerializer.h"
25#include "arcane/core/ItemPrinter.h"
26#include "arcane/core/Timer.h"
27#include "arcane/core/IGhostLayerMng.h"
28#include "arcane/core/IItemFamilyPolicyMng.h"
29#include "arcane/core/IItemFamilySerializer.h"
30#include "arcane/core/ParallelMngUtils.h"
32#include "arcane/mesh/DynamicMesh.h"
33#include "arcane/mesh/DynamicMeshIncrementalBuilder.h"
75 bool m_is_verbose =
false;
76 bool m_is_allocate =
false;
78 bool m_use_optimized_node_layer =
true;
79 bool m_use_only_minimal_cell_uid =
true;
99, m_parallel_mng(m_mesh->parallelMng())
104 Int32
vv = v.value();
105 m_use_optimized_node_layer = (
vv == 1 ||
vv == 3);
106 m_use_only_minimal_cell_uid = (v == 2 ||
vv == 3);
109 m_is_verbose = (v.value()!=0);
116void GhostLayerBuilder2::
139 using BasicType = Int64;
140 static constexpr Int64 nbBasicTypeSize() {
return 3; }
148 auto*
ptr =
reinterpret_cast<const Int64*
>(
fsi_base);
162 static_assert((
sizeof(Int64) * nbBasicTypeSize()) ==
sizeof(
BoundaryNodeInfo));
182 size_t h1 = std::hash<Int64>{}(a.node_uid);
183 size_t h2 = std::hash<Int64>{}(a.cell_uid);
184 size_t h3 = std::hash<Int32>{}(a.cell_owner);
190 return (a.node_uid ==
b.node_uid && a.cell_uid ==
b.cell_uid && a.cell_owner ==
b.cell_owner);
195 Int64 node_uid = NULL_ITEM_UNIQUE_ID;
196 Int64 cell_uid = NULL_ITEM_UNIQUE_ID;
197 Int32 cell_owner = -1;
225 return (
k1.cell_owner<
k2.cell_owner);
230 auto buf_view = BoundaryNodeInfo::asBasicBuffer(values);
231 return pm->send(
buf_view, rank,
false);
236 auto buf_view = BoundaryNodeInfo::asBasicBuffer(values);
242 return BoundaryNodeInfo::messageSize(values);
248 bni.node_uid = INT64_MAX;
249 bni.cell_uid = INT64_MAX;
256 return bni.node_uid!=INT64_MAX;
301 info() <<
"** GHOST LAYER BUILDER V" << m_version <<
" with sort (nb_ghost_layer=" <<
nb_ghost_layer <<
")";
323 warning() <<
"Invalid call to addGhostLayers() with version 3 because mesh "
324 <<
" already has '" <<
nb_ghost <<
"' ghost cells. The computed ghost cells"
325 <<
" may be wrong. Use version 4 of ghost layer builder if you want to handle this case";
395 if (m_use_optimized_node_layer) {
437 for( Integer i=0, n=face.
nbCell(); i<n; ++i )
456void GhostLayerBuilder2::
468 bool is_verbose = m_is_verbose;
490 for(
Node node : cell.nodes() ){
504 Int32 node_lid = node.localId();
505 if (do_only_minimal_uid) {
506 Int64 current_uid = node_cell_uids[node_lid];
507 if ((current_uid == NULL_ITEM_UNIQUE_ID) || cell_uid < current_uid) {
508 node_cell_uids[node_lid] = cell_uid;
510 info() <<
"AddNode node_uid=" << node.uniqueId() <<
" cell=" << cell_uid;
514 info() <<
"AddNode node_uid=" << node.uniqueId() <<
" cell=" << cell_uid <<
" not done current=" << current_uid;
517 Int64 node_uid = node.uniqueId();
518 BoundaryNodeInfo nci;
519 nci.node_uid = node_uid;
520 nci.cell_uid = cell_uid;
521 nci.cell_owner = my_rank;
522 boundary_node_list.add(nci);
524 info() <<
"AddNode node_uid=" << node.uniqueId() <<
" cell=" << cell_uid;
530 if (do_only_minimal_uid) {
532 Int32 lid = node.localId();
533 Int64 cell_uid = node_cell_uids[lid];
534 if (cell_uid != NULL_ITEM_UNIQUE_ID) {
535 Int64 node_uid = node.uniqueId();
536 BoundaryNodeInfo nci;
537 nci.node_uid = node_uid;
538 nci.cell_uid = cell_uid;
539 nci.cell_owner = my_rank;
540 boundary_node_list.add(nci);
545 info() <<
"NB BOUNDARY NODE LIST=" << boundary_node_list.size()
546 <<
" nb_added_for_different_rank=" << nb_added_for_different_rank
547 <<
" nb_added_for_in_layer=" << nb_added_for_in_layer
548 <<
" do_only_minimal=" << do_only_minimal_uid;
551 SharedArray<BoundaryNodeInfo> all_boundary_node_info = boundary_node_list;
553 UniqueArray<BoundaryNodeToSendInfo> node_list_to_send;
555 ConstArrayView<BoundaryNodeInfo> all_bni = all_boundary_node_info;
557 for( Integer i=0; i<bi_n; ++i ){
558 const BoundaryNodeInfo& bni = all_bni[i];
561 Int64 node_uid = bni.node_uid;
563 for( ; last_i<bi_n; ++last_i )
564 if (all_bni[last_i].node_uid!=node_uid)
566 Integer nb_same_node = (last_i - i);
568 info() <<
"NB_SAME_NODE uid=" << node_uid <<
" n=" << nb_same_node <<
" last_i=" << last_i;
572 Int32 owner = bni.cell_owner;
573 bool has_ghost =
false;
574 for( Integer z=0; z<nb_same_node; ++z )
575 if (all_bni[i+z].cell_owner!=owner){
580 BoundaryNodeToSendInfo si;
582 si.m_nb_cell = nb_same_node;
583 node_list_to_send.add(si);
585 info() <<
"Add ghost uid=" << node_uid <<
" index=" << i <<
" nb_same_node=" << nb_same_node;
593 ConstArrayView<BoundaryNodeInfo> all_bni = all_boundary_node_info;
594 Integer nb_node_to_send = node_list_to_send.size();
595 std::set<Int32> ranks_done;
596 for( Integer i=0; i<nb_node_to_send; ++i ){
597 Integer index = node_list_to_send[i].m_index;
598 Integer nb_cell = node_list_to_send[i].m_nb_cell;
602 for( Integer kz=0; kz<nb_cell; ++kz ){
603 Int32 krank = all_bni[index+kz].cell_owner;
604 if (ranks_done.find(krank)==ranks_done.end()){
605 ranks_done.insert(krank);
611 nb_info_to_send[krank] += (nb_cell*2) + 2;
618 for( Integer i=0; i<nb_rank; ++i ){
619 Integer nb_to_send = nb_info_to_send[i];
621 info() <<
"NB_TO_SEND rank=" << i <<
" n=" << nb_to_send;
627 for( Integer i=0; i<nb_rank; ++i ){
628 nb_info_to_send_indexes[i] = total_nb_to_send;
629 total_nb_to_send += nb_info_to_send[i];
631 info() <<
"TOTAL_NB_TO_SEND=" << total_nb_to_send;
633 UniqueArray<Int64> resend_infos(total_nb_to_send);
635 ConstArrayView<BoundaryNodeInfo> all_bni = all_boundary_node_info;
636 Integer nb_node_to_send = node_list_to_send.size();
637 std::set<Int32> ranks_done;
638 for( Integer i=0; i<nb_node_to_send; ++i ){
639 Integer node_index = node_list_to_send[i].m_index;
640 Integer nb_cell = node_list_to_send[i].m_nb_cell;
641 Int64 node_uid = all_bni[node_index].node_uid;
645 for( Integer kz=0; kz<nb_cell; ++kz ){
646 Int32 krank = all_bni[node_index+kz].cell_owner;
647 if (ranks_done.find(krank)==ranks_done.end()){
648 ranks_done.insert(krank);
649 Integer send_index = nb_info_to_send_indexes[krank];
650 resend_infos[send_index] = node_uid;
652 resend_infos[send_index] = nb_cell;
654 for( Integer zz=0; zz<nb_cell; ++zz ){
655 resend_infos[send_index] = all_bni[node_index+zz].cell_uid;
657 resend_infos[send_index] = all_bni[node_index+zz].cell_owner;
660 nb_info_to_send_indexes[krank] = send_index;
668 Timer::SimplePrinter sp(
traceMng(),
"Sending size with AllToAll");
669 pm->allToAll(nb_info_to_send,nb_info_to_recv,1);
673 for( Integer i=0; i<nb_rank; ++i )
674 info() <<
"NB_TO_RECV: I=" << i <<
" n=" << nb_info_to_recv[i];
677 for( Integer i=0; i<nb_rank; ++i )
678 total_nb_to_recv += nb_info_to_recv[i];
685 UniqueArray<Int64> recv_infos;
692 Int32 total_send = 0;
693 Int32 total_recv = 0;
694 for( Integer i=0; i<nb_rank; ++i ){
695 send_counts[i] = (
Int32)(nb_info_to_send[i] * vsize);
696 recv_counts[i] = (
Int32)(nb_info_to_recv[i] * vsize);
697 send_indexes[i] = total_send;
698 recv_indexes[i] = total_recv;
699 total_send += send_counts[i];
700 total_recv += recv_counts[i];
702 recv_infos.resize(total_nb_to_recv);
707 info() <<
"BUF_SIZES: send=" << send_buf.size() <<
" recv=" << recv_buf.size();
709 Timer::SimplePrinter sp(
traceMng(),
"Send values with AllToAll");
710 pm->allToAllVariable(send_buf,send_counts,send_indexes,recv_buf,recv_counts,recv_indexes);
714 SubDomainItemMap cells_to_send(50,
true);
723 UniqueArray<Int32> my_cells;
724 SharedArray<Int32> ranks_to_send;
725 std::set<Int32> ranks_done;
726 while (index<total_nb_to_recv){
727 Int64 node_uid = recv_infos[index];
729 Int64 nb_cell = recv_infos[index];
731 Node current_node(nodes_map.
findItem(node_uid));
733 info() <<
"NODE uid=" << node_uid <<
" nb_cell=" << nb_cell <<
" idx=" << (index-2);
735 ranks_to_send.clear();
737 for( Integer kk=0; kk<nb_cell; ++kk ){
738 Int64 cell_uid = recv_infos[index];
742 if (kk==0 && current_layer==1 && m_is_allocate)
748 info() <<
" CELL=" << cell_uid <<
" owner=" << cell_owner;
749 if (cell_owner==my_rank){
750 impl::ItemBase dcell = cells_map.
tryFind(cell_uid);
752 ARCANE_FATAL(
"Internal error: cell uid={0} is not in our mesh", cell_uid);
753 if (do_only_minimal_uid){
755 for( CellLocalId c : current_node.cellIds() )
759 my_cells.add(dcell.localId());
762 if (ranks_done.find(cell_owner)==ranks_done.end()){
763 ranks_to_send.add(cell_owner);
764 ranks_done.insert(cell_owner);
770 info() <<
"CELLS TO SEND: node_uid=" << node_uid
771 <<
" nb_rank=" << ranks_to_send.size()
772 <<
" nb_cell=" << my_cells.size();
773 info(4) <<
"CELLS TO SEND: node_uid=" << node_uid
774 <<
" rank=" << ranks_to_send
775 <<
" cell=" << my_cells;
778 for( Integer zrank=0, zn=ranks_to_send.size(); zrank<zn; ++zrank ){
779 Int32 send_rank = ranks_to_send[zrank];
780 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(send_rank);
782 for( Integer zid=0, zid_size=my_cells.size(); zid<zid_size; ++zid ){
784 c.
add(my_cells[zid]);
790 info() <<
"GHOST V3 SERIALIZE CELLS";
791 _sendAndReceiveCells(cells_to_send);
809 bool is_verbose = m_is_verbose;
822 for( Integer i=0; i<n; ++i ){
824 info() <<
"NODES_KEY i=" << i
825 <<
" node=" <<
bni.node_uid
826 <<
" cell=" <<
bni.cell_uid
827 <<
" rank=" <<
bni.cell_owner;
848 if (BoundaryNodeBitonicSortTraits::isValid(
all_bni[0])){
849 Int64 node_uid =
all_bni[0].node_uid;
850 for( Integer i=0; i<n; ++i ){
851 if (
all_bni[i].node_uid!=node_uid){
903void GhostLayerBuilder2::
908 const bool is_verbose = m_is_verbose;
912 Int32
sd =
i_map.data()->key();
918 std::sort(std::begin(items),std::end(items));
919 auto new_end = std::unique(std::begin(items),std::end(items));
922 info(4) <<
"CELLS TO SEND SD=" <<
sd <<
" Items=" << items;
924 info(4) <<
"CELLS TO SEND SD=" <<
sd <<
" nb=" << items.size();
925 exchanger->addSender(
sd);
927 exchanger->initializeCommunicationsMessages();
928 for( Integer i=0, ns=exchanger->nbSender(); i<ns; ++i ){
929 ISerializeMessage* sm = exchanger->messageToSend(i);
930 Int32 rank = sm->destination().value();
931 ISerializer* s = sm->serializer();
935 exchanger->processExchange();
936 info(4) <<
"END EXCHANGE CELLS";
937 for( Integer i=0, ns=exchanger->nbReceiver(); i<ns; ++i ){
938 ISerializeMessage* sm = exchanger->messageToReceive(i);
939 ISerializer* s = sm->serializer();
942 m_mesh_builder->printStats();
967 is_sub_domain_boundary_face = true;
970 if (face.nbCell()==2 && (face.cell(0).owner()!=my_rank || face.cell(1).owner()!=my_rank))
971 is_sub_domain_boundary_face = true;
990 glb.addGhostLayers();
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Tableau d'items de types quelconques.
Cell cell(Int32 i) const
i-ème maille de la face
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2)
EdgeConnectedListViewType edges() const
Liste des arêtes de la face.
Table de hachage pour tableaux associatifs.
virtual Integer nbGhostLayer() const =0
Nombre de couches fantômes.
virtual Int32 maxLocalId() const =0
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual void recv(ArrayView< char > values, Int32 rank)=0
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual void waitAllRequests(ArrayView< Request > rvalues)=0
Bloque en attendant que les requêtes rvalues soient terminées.
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
MutableItemBase toMutable()
Interface modifiable de cette entité
Int32 flags() const
Flags 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_Boundary
L'entité est sur la frontière.
Structure interne d'une entité de maillage.
Classe utilitaire pour imprimer les infos sur une entité.
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
NodeLocalIdView nodeIds() const
Liste des noeuds de l'entité
Classe de base d'un élément de maillage.
impl::MutableItemBase mutableItemBase() const
Partie interne modifiable de l'entité.
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
bool isOwn() const
true si l'entité est appartient au sous-domaine
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
impl::ItemBase itemBase() const
Partie interne de l'entité.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
void setOwner(Integer suid, Int32 current_sub_domain)
Positionne le numéro du sous-domaine propriétaire de l'entité.
void addFlags(Int32 added_flags)
Ajoute les flags \added_flags à ceux de l'entité
Affiche le temps passé entre l'appel au constructeur et le destructeur.
Construction d'un maillage de manière incrémentale.
Implémentation d'un maillage.
IItemFamily * nodeFamily() override
Retourne la famille des noeuds.
IItemFamily * cellFamily() override
Retourne la famille des mailles.
IParallelMng * parallelMng() override
Gestionnaire de parallèlisme.
void serializeCells(ISerializer *buffer, Int32ConstArrayView cells_local_id) override
void addCells(Integer nb_cell, Int64ConstArrayView cell_infos, Int32ArrayView cells) override
Ajoute des mailles.
IGhostLayerMng * ghostLayerMng() const override
Gestionnare de couche fantômes associé
Fonctor pour trier les BoundaryNodeInfo via le tri bitonic.
Structure contenant les informations des noeuds frontières.
Construction des couches fantômes.
void _sortBoundaryNodeList(Array< BoundaryNodeInfo > &boundary_node_list)
Trie parallèle de la liste des infos sur les noeuds frontières.
void _markBoundaryItems()
Marque les entitées au bord du sous-domaine.
GhostLayerBuilder2(DynamicMeshIncrementalBuilder *mesh_builder, bool is_allocate, Int32 version)
Construit une instance pour le maillage mesh.
void addGhostLayers()
Ajoute les couches de mailles fantomes.
void _markBoundaryNodes(ArrayView< Int32 > node_layer)
Détermine les noeuds frontières.
Tableau associatif de ItemInternal.
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.
impl::ItemBase tryFind(Int64 key) const
Retourne l'entité associée à key si trouvé ou l'entité nulle sinon.
Vue modifiable d'un tableau d'un type T.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Vue constante d'un tableau de type T.
Classe d'accès aux traces.
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage warning() const
Flot pour un message d'avertissement.
TraceMessage info() const
Flot pour un message d'information.
Integer toInteger(Real r)
Converti un Int64 en un Integer.
Int32 toInt32(Int64 v)
Converti un Int64 en un Int32.
Ref< IParallelExchanger > createExchangerRef(IParallelMng *pm)
Retourne une interface pour transférer des messages entre rangs.
void add(ArrayView< T > lhs, ConstArrayView< T > copy_array)
Ajoute le tableau copy_array dans l'instance.
ConstArrayView< Int32 > Int32ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
ArrayView< Int64 > Int64ArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
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.
UniqueArray< Integer > IntegerUniqueArray
Tableau dynamique à une dimension d'entiers.
Int32 Integer
Type représentant un entier.