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
588 <<
" n0,n1=" << edge.node(0).uniqueId() <<
"," << edge.node(1).uniqueId()
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()) {
627 if (edge.itemBase().backCell() == cell)
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;
659 if (edge.itemBase().backCell() == cell) {
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) {
670 edge.mutableItemBase().setUniqueId(edge_new_uid);
681 Int64 opposite_cell_uid = NULL_ITEM_UNIQUE_ID;
682 bool true_boundary =
false;
683 bool internal_other =
false;
684 if (edge.itemBase().backCell() == cell) {
686 else if (edge.nbCell() == 1) {
687 true_boundary =
true;
690 internal_other =
true;
691 opposite_cell_uid = edge.itemBase().backCell().uniqueId().asInt64();
693 ostr() <<
"NEW LOCAL ID FOR CELLEDGE " << cell_uid <<
' '
694 << index <<
' ' << edge.uniqueId() <<
" (";
695 for (
Node node : edge.nodes()) {
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) };
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 throwing a FatalErrorException.
void fill(ConstReferenceType value)
Fills the array with the value value.
void resize(Int64 s)
Changes the number of elements in the array to s.
void clear()
Removes the elements from the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
EdgeConnectedListViewType edges() const
List of edges of the cell.
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
Int32 nbCell() const
Number of cells of the face (1 or 2).
Hash table for associative arrays.
Data * lookupAdd(KeyTypeConstRef id, const ValueType &value, bool &is_add)
Searches for or adds the value corresponding to key id.
bool add(KeyTypeConstRef id, const ValueType &value)
Adds the value value corresponding to key id.
void eachValue(const Lambda &lambda)
Applies the functor f to all elements of the collection and uses x->value() (of type ValueType) as an...
Interface of an entity family.
virtual Int32 maxLocalId() const =0
virtual Integer edgeBuilderVersion() const =0
Edge numbering version.
Information exchange between processors.
virtual void addSender(Int32 rank)=0
Adds a processor to send to.
virtual Integer nbSender() const =0
Number of processors to which we send.
virtual bool initializeCommunicationsMessages()=0
Calculates communications.
virtual ISerializeMessage * messageToSend(Integer i)=0
Message intended for the i-th processor.
virtual void processExchange()=0
Performs the exchange using the default options of ParallelExchangerOptions.
Interface of the parallelism manager for a subdomain.
virtual char reduce(eReduceType rt, char v)=0
Performs a reduction of type rt on the real v and returns the value.
virtual void barrier()=0
Performs a barrier.
void reserveInt64(Int64 n)
Reserve for n Int64.
@ ModePut
The serializer expects reserve().
@ ModeGet
The serializer expects get().
virtual Int64 getInt64()=0
Retrieve a size.
virtual void allocateBuffer()=0
Allocates the serializer memory.
virtual void putSpan(Span< const Real > values)
Add the array values.
virtual void getSpan(Span< Real > values)
Retrieve the array values.
virtual void reserveSpan(eBasicDataType dt, Int64 n)=0
Reserves memory for n values of dt.
virtual void setMode(eMode new_mode)=0
Sets the current mode.
virtual void putInt64(Int64 value)=0
Add the integer value.
virtual void flush()=0
Flushes all streams.
Info on a mesh entity type.
Integer nbLocalNode() const
Number of nodes of the entity.
Mesh entity type manager.
ItemTypeInfo * typeFromId(Integer id) const
Type corresponding to the number id.
Node node(Int32 i) const
i-th node of the entity
NodeConnectedListViewType nodes() const
List of nodes of the entity.
NodeLocalIdView nodeIds() const
List of nodes of the entity.
Base class for a mesh element.
impl::MutableItemBase mutableItemBase() const
Mutable internal part of the entity.
constexpr Int32 localId() const
Local identifier of the entity in the processor subdomain.
ItemUniqueId uniqueId() const
Unique identifier across all domains.
Int16 type() const
Entity type.
Interface for a serialization message between IMessagePassingMng.
virtual MessageRank destination() const =0
Destination rank (if isSend() is true) or sender.
virtual ISerializer * serializer()=0
Serializer.
Int32 value() const
Rank value.
Output stream linked to a String.
InstanceType * get() const
Associated instance or nullptr if none.
Reference to an instance.
1D vector of data with reference semantics.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flow for a debug message.
TraceMessage info() const
Flow for an information message.
ITraceMng * traceMng() const
Trace manager.
1D data vector with value semantics (STL style).
Construction of a mesh incrementally.
Implementation of a mesh.
IParallelMng * parallelMng() override
Parallelism manager.
String name() const override
Mesh name.
ItemTypeMng * itemTypeMng() const override
Associated entity type manager.
IMeshUniqueIdMng * meshUniqueIdMng() const override
Unique ID numbering manager.
EdgeUniqueIdBuilder(DynamicMeshIncrementalBuilder *mesh_builder)
Constructs an instance for the mesh mesh.
void _computeEdgesUniqueIdsSequential()
Calculates the unique IDs for every edge sequentially.
Associative array of ItemInternal.
void notifyUniqueIdsChanged()
Notifies that the unique IDs of the entities have changed.
void eachItem(const Lambda &lambda)
Template function to iterate over the instance's entities.
void _exchangeData(IParallelExchanger *exchanger)
void compute()
Calculates the unique IDs for every edge in parallel.
T max(const T &a, const T &b, const T &c)
Returns the maximum of three elements.
@ ReduceMax
Maximum of values.
Ref< IParallelExchanger > createExchangerRef(IParallelMng *pm)
Returns an interface to transfer messages between ranks.
Array< Int64 > Int64Array
Dynamic one-dimensional array of 64-bit integers.
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
@ Int64
64-bit integer data type
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
UniqueArray< Integer > IntegerUniqueArray
Dynamic 1D array of integers.
std::int32_t Int32
Signed integer type of 32 bits.