14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/ScopedPtr.h"
16#include "arcane/utils/ITraceMng.h"
17#include "arcane/utils/OStringStream.h"
19#include "arcane/mesh/DynamicMesh.h"
20#include "arcane/mesh/EdgeUniqueIdBuilder.h"
21#include "arcane/mesh/GhostLayerBuilder.h"
22#include "arcane/mesh/OneMeshItemAdder.h"
23#include "arcane/mesh/ItemsOwnerBuilder.h"
25#include "arcane/core/IParallelExchanger.h"
26#include "arcane/core/IParallelMng.h"
27#include "arcane/core/ISerializeMessage.h"
28#include "arcane/core/ISerializer.h"
29#include "arcane/core/ParallelMngUtils.h"
30#include "arcane/core/IMeshUniqueIdMng.h"
46, m_mesh(mesh_builder->
mesh())
47, m_mesh_builder(mesh_builder)
57void EdgeUniqueIdBuilder::
58computeEdgesUniqueIds()
64 info() <<
"Using version=" << edge_version <<
" to compute edges unique ids"
65 <<
" mesh=" << m_mesh->
name();
66 bool need_compute_owner =
false;
67 bool has_renumbering =
true;
68 if (edge_version == 1)
69 _computeEdgesUniqueIdsParallel3();
70 else if (edge_version == 2)
71 _computeEdgesUniqueIdsParallelV2();
72 else if (edge_version == 3) {
73 need_compute_owner =
true;
74 _computeEdgesUniqueIdsParallel64bit();
76 else if (edge_version == 0) {
77 need_compute_owner =
true;
78 has_renumbering =
false;
79 info() <<
"No renumbering for edges";
82 ARCANE_FATAL(
"Invalid valid version '{0}'. Valid values are 0, 1, 2 or 3");
85 Real diff =
static_cast<Real
>(end_time - begin_time);
86 info() <<
"TIME to compute edge unique ids=" << diff;
88 ItemInternalMap& edges_map = m_mesh->edgesMap();
95 if (m_mesh_builder->isVerbose()) {
96 info() <<
"NEW EDGES_MAP after re-indexing";
97 edges_map.eachItem([&](Item edge) {
98 info() <<
"Edge uid=" << edge.uniqueId() <<
" lid=" << edge.localId();
105 if (need_compute_owner && m_mesh->parallelMng()->isParallel()) {
106 ItemsOwnerBuilder owner_builder(m_mesh);
107 owner_builder.computeEdgesOwner();
127 , m_nb_back_edge(nb_back_edge)
128 , m_nb_true_boundary_edge(nb_true_boundary_edge)
133 : m_unique_id(NULL_ITEM_ID)
135 , m_nb_true_boundary_edge(0)
141 bool operator<(
const T_CellEdgeInfo& ci)
const
143 return m_unique_id < ci.m_unique_id;
149 Int64 m_nb_back_edge;
150 Int64 m_nb_true_boundary_edge;
153template <
typename DataType>
154class ItemInfoMultiList
163 MyInfo(
const DataType& d,
Integer n)
177 : m_last_index(5000, true)
182 void add(
Int64 node_uid,
const DataType& data)
184 Integer current_index = m_values.size();
189 m_values.add(MyInfo(data, d->value()));
190 d->value() = current_index;
202class Parallel3EdgeUniqueIdBuilder
205 using BoundaryInfosMap = std::unordered_map<Int32, SharedArray<Int64>>;
221 const Int32 m_my_rank = A_NULL_RANK;
222 const Int32 m_nb_rank = A_NULL_RANK;
223 BoundaryInfosMap m_boundary_infos_to_send;
225 std::unordered_map<Int64, SharedArray<Int64>> m_nodes_info;
227 bool m_is_verbose =
false;
232 void _addEdgeBoundaryInfo(
Edge edge);
233 void _computeEdgesUniqueId();
234 void _sendInfosToOtherRanks();
240Parallel3EdgeUniqueIdBuilder::
243, m_mesh(mesh_builder->
mesh())
244, m_mesh_builder(mesh_builder)
245, m_parallel_mng(m_mesh->parallelMng())
246, m_my_rank(m_parallel_mng->commRank())
247, m_nb_rank(m_parallel_mng->commSize())
248, m_uid_to_subdomain_converter(max_node_uid, m_nb_rank)
249, m_is_verbose(m_mesh_builder->isVerbose())
262 for (
const auto& [key, value] : m_boundary_infos_to_send) {
273 s->
setMode(ISerializer::ModeReserve);
284 debug() <<
"END EXCHANGE";
290void Parallel3EdgeUniqueIdBuilder::
291_addEdgeBoundaryInfo(
Edge edge)
296 Int32 dest_rank = -1;
297 if (!m_is_boundary_nodes[first_node.
localId()]) {
298 v = m_nodes_info[first_node_uid];
301 dest_rank = m_uid_to_subdomain_converter.uidToRank(first_node_uid);
302 v = m_boundary_infos_to_send[dest_rank];
304 v.
add(first_node_uid);
308 v.
add(NULL_ITEM_UNIQUE_ID);
309 v.
add(NULL_ITEM_UNIQUE_ID);
312 <<
" n0=" << ItemPrinter(edge.
node(0)) <<
" n1=" << ItemPrinter(edge.
node(1)) <<
" dest_rank=" << dest_rank;
313 for (Node edge_node : edge.
nodes())
314 v.
add(edge_node.uniqueId());
338 Integer nb_local_edge = m_mesh_builder->oneMeshItemAdder()->nbEdge();
339 info() <<
"ComputeEdgesUniqueIdsParallel3 nb_edge=" << nb_local_edge;
342 edges_opposite_cell_uid.
fill(NULL_ITEM_ID);
350 edges_new_uid.
fill(NULL_ITEM_UNIQUE_ID);
375 m_is_boundary_nodes.resize(node_family->
maxLocalId(),
false);
382 if (face_nb_cell == 1) {
384 m_is_boundary_nodes[ilid] =
true;
397 const bool is_new_item_map_impl = ItemInternalMap::UseNewImpl;
398 if (is_new_item_map_impl) {
399 info() <<
"Edge: ItemInternalMap is using new implementation";
405 _addEdgeBoundaryInfo(edge);
410 _addEdgeBoundaryInfo(edge);
414 _computeEdgesUniqueId();
415 _sendInfosToOtherRanks();
419 info() <<
"END OF TEST NEW EDGE COMPUTE";
425void Parallel3EdgeUniqueIdBuilder::
426_computeEdgesUniqueId()
433 Integer nb_receiver = exchanger->nbReceiver();
434 debug() <<
"NB RECEIVER=" << nb_receiver;
436 for (
Integer i = 0; i < nb_receiver; ++i) {
443 received_infos.
resize(nb_info);
448 while (z < nb_info) {
449 Int64 node_uid = received_infos[z + 0];
452 Int32 edge_type = (
Int32)received_infos[z + 3];
470 for (
const auto& [key, value] : m_nodes_info) {
477 while (z < nb_info) {
485 ItemTypeInfo* itt = itm->
typeFromId(edge_type);
494 my_max_edge_node =
math::max(node_nb_edge, my_max_edge_node);
497 debug() <<
"GLOBAL MAX EDGE NODE=" << global_max_edge_node;
500 m_boundary_infos_to_send.
clear();
502 for (
const auto& [key, value] : m_nodes_info) {
508 while (z < nb_info) {
509 Int64 node_uid = a[z + 0];
511 Int64 edge_uid = a[z + 2];
515 ItemTypeInfo* itt = itm->
typeFromId(edge_type);
519 Integer edge_index = node_nb_edge;
520 Int32 edge_new_owner = sender_rank;
521 for (
Integer y = 0; y < node_nb_edge; ++y) {
522 if (memcmp(&a[indexes[y] + 6], &a[z + 6],
sizeof(
Int64) * edge_nb_node) == 0) {
524 edge_new_owner = (
Int32)a[indexes[y] + 1];
527 Int64 edge_new_uid = (node_uid * global_max_edge_node) + edge_index;
528 Int64Array& v = m_boundary_infos_to_send[sender_rank];
532 v.add(edge_new_owner);
542 my_max_edge_node =
math::max(node_nb_edge, my_max_edge_node);
549void Parallel3EdgeUniqueIdBuilder::
550_sendInfosToOtherRanks()
552 const bool is_verbose = m_mesh_builder->isVerbose();
553 IParallelMng* pm = m_parallel_mng;
558 ItemInternalMap& edges_map = m_mesh->edgesMap();
559 Integer nb_receiver = exchanger->nbReceiver();
560 debug() <<
"NB RECEIVER=" << nb_receiver;
562 for (
Integer i = 0; i < nb_receiver; ++i) {
563 ISerializeMessage* sm = exchanger->messageToReceive(i);
565 ISerializer* s = sm->serializer();
567 Int64 nb_info = s->getInt64();
569 info() <<
"RECEIVE NB_INFO=" << nb_info <<
" from=" << orig_rank;
570 received_infos.resize(nb_info);
571 s->getSpan(received_infos);
572 if ((nb_info % 3) != 0)
573 ARCANE_FATAL(
"info size can not be divided by 3 x={0}", nb_info);
574 Int64 nb_item = nb_info / 3;
575 for (
Int64 z = 0; z < nb_item; ++z) {
576 Int64 old_uid = received_infos[(z * 3)];
577 Int64 new_uid = received_infos[(z * 3) + 1];
578 Int32 new_owner =
static_cast<Int32>(received_infos[(z * 3) + 2]);
580 impl::MutableItemBase iedge(edges_map.tryFind(old_uid));
583 iedge.setUniqueId(new_uid);
584 iedge.setOwner(new_owner, m_my_rank);
587 info() <<
"SetEdgeOwner uid=" << new_uid <<
" owner=" << new_owner
589 <<
" n0=" << ItemPrinter(edge.
node(0)) <<
" n1=" << ItemPrinter(edge.
node(1));
604 bool is_verbose = m_mesh_builder->isVerbose();
605 Integer nb_cell = m_mesh_builder->oneMeshItemAdder()->nbCell();
614 if (cell_uid>max_uid)
617 info() <<
"Max uid=" << max_uid;
625 Integer nb_true_boundary_edge = 0;
626 for(
Edge edge : cell.edges()){
629 else if (edge.
nbCell()==1){
630 ++nb_true_boundary_edge;
633 cell_nb_num_back_edge[cell_uid] = nb_num_back_edge;
634 cell_true_boundary_edge[cell_uid] = nb_true_boundary_edge;
638 for(
Integer i=0; i<nb_cell; ++i ){
639 cell_first_edge_uid[i] = current_edge_uid;
640 current_edge_uid += cell_nb_num_back_edge[i] + cell_true_boundary_edge[i];
644 for(
Integer i=0; i<nb_cell; ++i ){
645 info() <<
"Recv: Cell EdgeInfo celluid=" << i
646 <<
" firstedgeuid=" << cell_first_edge_uid[i]
647 <<
" nbback=" << cell_nb_num_back_edge[i]
648 <<
" nbbound=" << cell_true_boundary_edge[i];
655 Integer nb_true_boundary_edge = 0;
656 for(
Edge edge : cell.edges() ){
657 Int64 edge_new_uid = NULL_ITEM_UNIQUE_ID;
660 edge_new_uid = cell_first_edge_uid[cell_uid] + nb_num_back_edge;
663 else if (edge.
nbCell()==1){
664 edge_new_uid = cell_first_edge_uid[cell_uid] + cell_nb_num_back_edge[cell_uid] + nb_true_boundary_edge;
665 ++nb_true_boundary_edge;
667 if (edge_new_uid!=NULL_ITEM_UNIQUE_ID){
681 Int64 opposite_cell_uid = NULL_ITEM_UNIQUE_ID;
682 bool true_boundary =
false;
683 bool internal_other =
false;
686 else if (edge.
nbCell()==1){
687 true_boundary =
true;
690 internal_other =
true;
693 ostr() <<
"NEW LOCAL ID FOR CELLEDGE " << cell_uid <<
' '
694 << index <<
' ' << edge.
uniqueId() <<
" (";
696 ostr() <<
' ' << node.uniqueId();
700 ostr() <<
" internal-other";
702 ostr() <<
" true-boundary";
703 if (opposite_cell_uid!=NULL_ITEM_ID)
704 ostr() <<
" opposite " << opposite_cell_uid;
709 info() << ostr.str();
716void EdgeUniqueIdBuilder::
717_computeEdgesUniqueIdsParallelV2()
738 if (total_max_uid>INT32_MAX)
739 ARCANE_FATAL(
"Max uniqueId() for node is too big v={0} max_allowed={1}",total_max_uid,INT32_MAX);
743 Node node1{edge.
node(1)};
744 Int64 new_uid = (node0.uniqueId().asInt64() * total_max_uid) + node1.
uniqueId().asInt64();
752void EdgeUniqueIdBuilder::
753_computeEdgesUniqueIdsParallel3()
755 IParallelMng* pm = m_mesh->parallelMng();
756 ItemInternalMap& nodes_map = m_mesh->nodesMap();
759 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
761 Int64 node_uid = item.uniqueId();
762 if (node_uid > my_max_node_uid)
763 my_max_node_uid = node_uid;
766 debug() <<
"NODE_UID_INFO: MY_MAX_UID=" << my_max_node_uid
767 <<
" GLOBAL=" << global_max_node_uid;
769 Parallel3EdgeUniqueIdBuilder builder(
traceMng(), m_mesh_builder, global_max_node_uid);
776void EdgeUniqueIdBuilder::
777_computeEdgesUniqueIdsParallel64bit()
781 ItemInternalMap& edges_map = m_mesh->edgesMap();
783 std::hash<Int64> hasher;
786 Node node0{edge.node(0)};
787 Node node1{edge.node(1)};
788 size_t hash0 = hasher(node0.uniqueId().asInt64());
789 size_t hash1 = hasher(node1.uniqueId().asInt64());
790 hash0 ^= hash1 + 0x9e3779b9 + (hash0 << 6) + (hash0 >> 2);
791 Int64 new_uid = hash0 & 0x7fffffff;
792 edge.mutableItemBase().setUniqueId(new_uid);
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
void fill(const DataType &data)
Remplissage du tableau.
void clear()
Supprime les éléments du tableau.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
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.
EdgeConnectedListViewType edges() const
Liste des arêtes de la maille.
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Int32 nbCell() const
Nombre de mailles connectées à l'arête.
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2)
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.
bool add(KeyTypeConstRef id, const ValueType &value)
Ajoute la valeur value correspondant à la clé id.
void eachValue(const Lambda &lambda)
Applique le fonctor f à tous les éléments de la collection et utilise x->value() (de type ValueType) ...
Interface d'une famille d'entités.
virtual Int32 maxLocalId() const =0
virtual Integer edgeBuilderVersion() const =0
Version de la numérotation des arêtes.
Échange d'informations entre processeurs.
virtual void addSender(Int32 rank)=0
Ajoute un processeur à envoyer.
virtual Integer nbSender() const =0
Nombre de processeurs auquel on envoie.
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.
Interface du gestionnaire de parallélisme pour un sous-domaine.
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 void barrier()=0
Effectue une barière.
Interface d'un sérialiseur.
void reserveInt64(Int64 n)
Réserve pour n Int64.
@ ModePut
Le sérialiseur attend des reserve()
@ ModeGet
Le sérialiseur attend des get()
virtual Int64 getInt64()=0
Récupère une taille.
virtual void allocateBuffer()=0
Alloue la mémoire du sérialiseur.
virtual void putSpan(Span< const Real > values)
Ajoute le tableau values.
virtual void getSpan(Span< Real > values)
Récupère le tableau values.
virtual void reserveSpan(eBasicDataType dt, Int64 n)=0
Réserve de la mémoire pour n valeurs de dt.
virtual void setMode(eMode new_mode)=0
Positionne le fonctionnement actuel.
virtual void putInt64(Int64 value)=0
Ajoute l'entier value.
Interface du gestionnaire de traces.
virtual void flush()=0
Flush tous les flots.
ItemUniqueId uniqueId() const
Numéro unique de l'entité
ItemBase backCell() const
Maille derrière l'entité (nullItem() si aucune)
Infos sur un type d'entité du maillage.
Integer nbLocalNode() const
Nombre de noeuds de l'entité
Gestionnaire des types d'entités d'un maillage.
ItemTypeInfo * typeFromId(Integer id) const
Type correspondant au numéro id.
Node node(Int32 i) const
i-ème noeud de l'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.
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
impl::ItemBase itemBase() const
Partie interne de l'entité.
Int16 type() const
Type 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.
Flot de sortie lié à une String.
Référence à une instance.
Vecteur 1D de données avec sémantique par référence.
Classe d'accès aux traces.
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).
Construction d'un maillage de manière incrémentale.
Implémentation d'un maillage.
IParallelMng * parallelMng() override
Gestionnaire de parallèlisme.
String name() const override
Nom du maillage.
ItemTypeMng * itemTypeMng() const override
Gestionnaire de types d'entités associé
IMeshUniqueIdMng * meshUniqueIdMng() const override
Gestionnare de la numérotation des identifiants uniques.
EdgeUniqueIdBuilder(DynamicMeshIncrementalBuilder *mesh_builder)
Construit une instance pour le maillage mesh.
void _computeEdgesUniqueIdsSequential()
Calcul les numéros uniques de chaque edge en séquentiel.
Tableau associatif de ItemInternal.
void notifyUniqueIdsChanged()
Notifie que les numéros uniques des entités ont changés.
void eachItem(const Lambda &lambda)
Fonction template pour itérer sur les entités de l'instance.
void _exchangeData(IParallelExchanger *exchanger)
void compute()
Calcule les numéros uniques de chaque edge en parallèle.
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
@ 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.
@ Int64
Donnée de type entier 64 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.
UniqueArray< Integer > IntegerUniqueArray
Tableau dynamique à une dimension d'entiers.
std::int32_t Int32
Type entier signé sur 32 bits.