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"
37#include "arcane/mesh/DynamicMesh.h"
38#include "arcane/mesh/GhostLayerBuilder.h"
39#include "arcane/mesh/OneMeshItemAdder.h"
51_buildGhostLayerNewVersion(
DynamicMesh* mesh,
bool is_allocate,
Int32 version);
68, m_mesh(mesh_builder->
mesh())
69, m_mesh_builder(mesh_builder)
87void GhostLayerBuilder::
88addGhostLayers(
bool is_allocate)
95 else if (version == 2) {
96 info() <<
"Use ghost layer builder version 2";
97 _addOneGhostLayerV2();
99 else if (version == 3 || version == 4) {
100 info() <<
"Use GhostLayerBuilder with sort (version " << version <<
")";
101 _buildGhostLayerNewVersion(m_mesh, is_allocate, version);
104 throw NotSupportedException(A_FUNCINFO,
"Bad version number for addGhostLayer");
107 Real diff = (
Real)(end_time - begin_time);
108 info() <<
"TIME to compute ghost layer=" << diff;
121 : m_cell_last_index(5000,
true)
128 Int32 current_index = m_cell_indexes.size();
129 m_cell_indexes.add(cell_uid);
130 m_cell_indexes.add(cell_owner);
133 m_cell_indexes.add(d->value());
134 d->value() = current_index;
146void GhostLayerBuilder::
149 for (BoundaryInfosMapEnumerator i_map(boundary_infos_to_send); ++i_map;) {
150 Int32 sd = i_map.data()->key();
161 s->
setMode(ISerializer::ModeReserve);
171 debug() <<
"END EXCHANGE";
177void GhostLayerBuilder::
180 info() <<
"** NEW GHOST LAYER BUILDER V2";
181 if (m_mesh->ghostLayerMng()->nbGhostLayer() != 1)
182 ARCANE_THROW(NotImplementedException,
"Only one layer of ghost cells is supported");
184 IParallelMng* pm = m_mesh->parallelMng();
185 Int32 my_rank = pm->commRank();
186 Int32 nb_rank = pm->commSize();
187 debug() <<
" RANK=" << pm->commRank() <<
" size=" << pm->commSize();
188 if (!pm->isParallel()) {
189 debug() <<
"NOT PARALLEL";
192#ifdef ARCANE_DEBUG_DYNAMIC_MESH
193 const bool is_verbose =
true;
195 const bool is_verbose =
false;
200 ostr() <<
"** FACES LIST\n";
202 Integer nb_sub_domain_boundary_face = 0;
204 ItemInternalMap& cells_map = m_mesh->cellsMap();
205 ItemInternalMap& faces_map = m_mesh->facesMap();
207 ItemInternalMap& nodes_map = m_mesh->nodesMap();
211 faces_map.eachItem([&](Face face) {
212 impl::ItemBase face_base = face.itemBase();
214 ostr() << ItemPrinter(face);
217 bool is_sub_domain_boundary_face =
false;
219 is_sub_domain_boundary_face =
true;
222 if (face.nbCell() == 2 && (face.cell(0).owner() != my_rank || face.cell(1).owner() != my_rank))
223 is_sub_domain_boundary_face =
true;
225 if (is_sub_domain_boundary_face) {
226 face_base.toMutable().addFlags(shared_and_boundary_flags);
227 ++nb_sub_domain_boundary_face;
228 for (Item inode : face.nodes())
229 inode.mutableItemBase().addFlags(shared_and_boundary_flags);
230 for (Item iedge : face.edges())
231 iedge.mutableItemBase().addFlags(shared_and_boundary_flags);
235 Integer boundary_nodes_uid_count = 0;
238 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
239 nodes_map.eachItem([&](Node node) {
240 Int32 f = node.itemBase().flags();
242 Int64 node_uid = node.uniqueId();
243 if (node_uid > my_max_node_uid)
244 my_max_node_uid = node_uid;
245 ++boundary_nodes_uid_count;
250 debug() <<
"NB BOUNDARY NODE=" << boundary_nodes_uid_count
251 <<
" MY_MAX_UID=" << my_max_node_uid
252 <<
" GLOBAL=" << global_max_node_uid;
256 ostr() <<
"List of shared cells:\n";
260 BoundaryInfosMap boundary_infos_to_send(200,
true);
261 NodeUidToSubDomain uid_to_subdomain_converter(global_max_node_uid, nb_rank);
263 cells_map.eachItem([&](
Cell cell) {
265 ostr() <<
"Send cell " << ItemPrinter(cell) <<
'\n';
269 for (Node node : cell.nodes()) {
272 Int64 node_uid = node.uniqueId();
274 Int32 dest_rank = uid_to_subdomain_converter.uidToRank(node_uid);
275 SharedArray<Int64> v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
278 v.add(cell.uniqueId());
287 info() << ostr.str();
289 info() <<
"Number of shared faces: " << nb_sub_domain_boundary_face;
296 _exchangeData(exchanger.get(), boundary_infos_to_send);
300 NodeCellList node_cell_list;
303 debug() <<
"NB RECEIVER=" << nb_receiver;
305 for (
Integer i = 0; i < nb_receiver; ++i) {
308 ISerializer* s = sm->serializer();
310 s->getArray(received_infos);
311 Int64 nb_info = received_infos.largeSize();
313 if ((nb_info % 3) != 0)
314 ARCANE_FATAL(
"Inconsistent received data v={0}", nb_info);
315 Int64 nb_info_true = nb_info / 3;
316 for (
Int64 z = 0; z < nb_info_true; ++z) {
317 Int64 node_uid = received_infos[(z * 3) + 0];
318 Int64 cell_owner = received_infos[(z * 3) + 1];
319 Int64 cell_uid = received_infos[(z * 3) + 2];
320 node_cell_list.add(node_uid, cell_uid, cell_owner);
325 boundary_infos_to_send = BoundaryInfosMap(1000,
true);
329 debug() <<
"NB_CELL_INDEXES = " << cell_indexes.size();
334 for (HashTableMapEnumeratorT<Int64, Int32> i_map(node_cell_list.m_cell_last_index); ++i_map;) {
335 HashTableMapT<Int64, Int32>::Data* d = i_map.data();
336 Int32 index = d->value();
337 Int64 node_uid = d->key();
345 Int32 node_new_owner = NULL_SUB_DOMAIN_ID;
346 Int64 smallest_cell_uid = NULL_ITEM_UNIQUE_ID;
348 while (index != (-1)) {
349 Int64 cell_uid = cell_indexes[index];
350 Int32 cell_owner = CheckedConvert::toInt32(cell_indexes[index + 1]);
351 index = CheckedConvert::toInteger(cell_indexes[index + 2]);
353 ranks.add((
Int32)cell_owner);
355 if (cell_uid < smallest_cell_uid || node_new_owner == NULL_SUB_DOMAIN_ID) {
356 smallest_cell_uid = cell_uid;
357 node_new_owner = cell_owner;
361 std::sort(std::begin(ranks), std::end(ranks));
362 Integer new_size = CheckedConvert::toInteger(std::unique(std::begin(ranks), std::end(ranks)) - std::begin(ranks));
363 ranks.resize(new_size);
372 Integer nb_cell = cells.size();
373 for (
Integer z = 0; z < new_size; ++z) {
374 Int32 dest_rank = ranks[z];
376 Int64Array& v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
378 v.add(node_new_owner);
381 for (
Integer z2 = 0; z2 < new_size; ++z2)
383 for (
Integer z2 = 0; z2 < nb_cell; ++z2)
390 _exchangeData(exchanger.get(), boundary_infos_to_send);
391 debug() <<
"END OF EXCHANGE";
393 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
394 SubDomainItemMap cells_to_send(50,
true);
397 debug() <<
"NB RECEIVER 2 =" << nb_receiver;
400 for (
Integer i = 0; i < nb_receiver; ++i) {
406 s->getArray(received_infos);
407 Int64 nb_info = received_infos.largeSize();
411 while (z < nb_info) {
412 Int64 node_uid = received_infos[z];
413 Int32 node_new_owner = CheckedConvert::toInt32(received_infos[z + 1]);
414 Int32 nb_rank = CheckedConvert::toInt32(received_infos[z + 2]);
415 Int32 nb_cell = CheckedConvert::toInt32(received_infos[z + 3]);
417 nodes_map.findItem(node_uid).toMutable().setOwner(node_new_owner, my_rank);
421 for (
Integer z2 = 0; z2 < nb_rank; ++z2) {
423 if (nrank != my_rank)
427 for (
Integer z2 = 0; z2 < nb_cell; ++z2) {
428 Int64 cell_uid = received_infos[z + z2];
429 impl::ItemBase dcell = cells_map.tryFind(cell_uid);
431 cells.add(dcell.localId());
433 for (
Integer z2 = 0, zs = ranks.size(); z2 < zs; ++z2) {
434 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(ranks[z2]);
435 SharedArray<Int32> dv = d->value();
436 for (
Integer z3 = 0, zs3 = cells.size(); z3 < zs3; ++z3)
445 _exchangeCells(cells_to_send,
false);
446 m_mesh_builder->printStats();
452void GhostLayerBuilder::
453_exchangeCells(HashTableMapT<
Int32, SharedArray<Int32>>& cells_to_send,
bool with_flags)
456 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
457 IParallelMng* pm = m_mesh->parallelMng();
459 for (SubDomainItemMap::Enumerator i_map(cells_to_send); ++i_map;) {
460 Int32 sd = i_map.data()->key();
464 info(4) <<
"CELLS TO SEND SD=" << sd <<
" NB=" << items.size();
471 ISerializer* s = sm->serializer();
474 ScopedPtrT<IItemFamilySerializer> cell_serializer(m_mesh->cellFamily()->policyMng()->createSerializer(with_flags));
475 s->setMode(ISerializer::ModeReserve);
476 cell_serializer->serializeItems(s, items_to_send);
479 cell_serializer->serializeItems(s, items_to_send);
482 info(4) <<
"END EXCHANGE CELLS";
488 ScopedPtrT<IItemFamilySerializer> cell_serializer(m_mesh->cellFamily()->policyMng()->createSerializer(with_flags));
489 cell_serializer->deserializeItems(s,
nullptr);
499 info() <<
"** AMR GHOST CHILD FROM PARENT BUILDER V1";
504 debug() <<
"NOT PARALLEL";
510 ItemInternalMap& cells_map = m_mesh->cellsMap();
512 FaceFamily& true_face_family = m_mesh->trueFaceFamily();
515 BoundaryInfosMap boundary_infos_to_send(200,
true);
518 ARCANE_ASSERT((cell.
owner() != -1), (
""));
520 ARCANE_ASSERT((cell.
owner() != -1), (
""));
529 _exchangeData(exchanger.get(), boundary_infos_to_send);
535 SubDomainItemMap cells_to_send(50,
true);
538 debug() <<
"NB RECEIVER=" << nb_receiver;
540 for (
Integer i = 0; i < nb_receiver; ++i) {
548 if ((nb_info % 2) != 0)
549 ARCANE_FATAL(
"info size can not be divided by 2 v={0}", nb_info);
550 Int64 nb_info_true = nb_info / 2;
552 for (
Int64 z = 0; z < nb_info_true; ++z) {
553 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z * 2) + 0]);
554 Int64 cell_uid = received_infos[(z * 2) + 1];
556 impl::ItemBase cell = cells_map.
findItem(cell_uid);
557 ARCANE_ASSERT((cell.uniqueId() == cell_uid), (
""));
558 if (!cell.hasHChildren())
561 ARCANE_ASSERT((cell.level() == 0), (
""));
562 ARCANE_ASSERT((cell.owner() != -1), (
"CELL"));
563 ARCANE_ASSERT((cell_owner != -1), (
"CELL"));
564 true_face_family.familyTree(cell_family, cell);
565 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
569 for (
Integer c = 1; c < cs; c++) {
571 ARCANE_ASSERT((child->
owner() != -1), (
"CHILD"));
578 debug() <<
"nb_recv_child= " << nb_recv_child;
582 _exchangeCells(cells_to_send,
true);
583 m_mesh_builder->printStats();
591void GhostLayerBuilder::
592addGhostChildFromParent2(
Array<Int64>& ghost_cell_to_refine)
594 info() <<
"** AMR GHOST CHILD FROM PARENT BUILDER V2";
599 debug() <<
"NOT PARALLEL";
605 ItemInternalMap& cells_map = m_mesh->cellsMap();
608 BoundaryInfosMap boundary_infos_to_send(200,
true);
612 cells_map.eachItem([&](
Item cell) {
613 ARCANE_ASSERT((cell.
owner() != -1), (
""));
614 if (cell.
owner() == sid)
620 Int64Array& v = boundary_infos_to_send.lookupAdd(cell.
owner())->value();
628 _exchangeData(exchanger.get(), boundary_infos_to_send);
633 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
634 SubDomainItemMap cells_to_send(50,
true);
637 debug() <<
"NB RECEIVER=" << nb_receiver;
639 for (
Integer i = 0; i < nb_receiver; ++i) {
645 s->getArray(received_infos);
646 Int64 nb_info = received_infos.size();
647 if ((nb_info % 2) != 0)
648 ARCANE_FATAL(
"info size can not be divided by 2 v={0}", nb_info);
649 Int64 nb_info_true = nb_info / 2;
651 for (
Int64 z = 0; z < nb_info_true; ++z) {
652 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z * 2) + 0]);
653 Int64 cell_uid = received_infos[(z * 2) + 1];
655 Cell cell = cells_map.findItem(cell_uid);
656 ARCANE_ASSERT((cell.uniqueId() == cell_uid), (
""));
657 ARCANE_ASSERT((cell.owner() != -1), (
"CELL"));
658 ARCANE_ASSERT((cell_owner != -1), (
"CELL"));
660 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
663 nb_recv_child += cell.nbHChildren();
664 for (
Integer c = 0, cs = cell.nbHChildren(); c < cs; c++) {
665 Cell child = cell.hChild(c);
666 ARCANE_ASSERT((child.owner() != -1), (
"CHILD"));
669 dv.add(child.localId());
672 debug() <<
"nb_recv_child= " << nb_recv_child;
677 _exchangeCells(cells_to_send,
true);
678 m_mesh_builder->printStats();
686NodeUidToSubDomain(
Int64 max_uid,
Int32 nb_rank)
689, m_nb_by_rank(max_uid)
691 m_nb_by_rank = max_uid / nb_rank;
692 if (m_nb_by_rank == 0)
693 m_nb_by_rank = max_uid;
700 bool is_ok = builtInGetValue(div_value, s);
704 if (div_value > m_nb_rank)
705 div_value = m_nb_rank;
708 m_modulo = m_nb_rank / div_value;
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Utility functions for the mesh.
Integer size() const
Number of elements in the vector.
Base class for 1D data vectors.
void clear()
Removes the elements from the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
constexpr const_pointer data() const noexcept
Pointer to the allocated memory.
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.
virtual Integer builderVersion() const =0
Ghost cell builder version.
Information exchange between processors.
virtual void addSender(Int32 rank)=0
Adds a processor to send to.
@ EM_Collective
Uses collective operations (allToAll).
virtual Integer nbSender() const =0
Number of processors to which we send.
virtual void setExchangeMode(eExchangeMode mode)=0
Sets the exchange mode.
virtual Integer nbReceiver() const =0
Number of processors from which we will receive messages.
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.
virtual ISerializeMessage * messageToReceive(Integer i)=0
Message received from the i-th processor.
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual Int32 commSize() const =0
Number of instances in the communicator.
virtual bool isParallel() const =0
Returns true if the execution is parallel.
virtual void barrier()=0
Performs a barrier.
virtual void putArray(Span< const Real > values)=0
Save the number of elements and the values elements.
virtual void reserveArray(Span< const Real > values)=0
Reserve to save the number of elements and the values elements.
virtual void getArray(Array< Real > &values)=0
Resize and fill values.
@ ModePut
The serializer expects reserve().
@ ModeGet
The serializer expects get().
virtual void allocateBuffer()=0
Allocates the serializer memory.
virtual void setMode(eMode new_mode)=0
Sets the current mode.
virtual void flush()=0
Flushes all streams.
Int32 owner() const
Number of the owning subdomain of the entity.
Int32 localId() const
Local number (in the subdomain) of the entity.
@ II_Shared
The entity is shared by another subdomain.
@ II_SubDomainBoundary
The entity is at the boundary of two subdomains.
@ II_JustRefined
The entity has just been refined.
@ II_Boundary
The entity is on the boundary.
Internal structure of a mesh entity.
Base class for a mesh element.
Int32 owner() const
Owner subdomain number of the entity.
constexpr bool hasFlags(Int32 flags) const
Returns if the flags are set for the entity.
ItemUniqueId uniqueId() const
Unique identifier across all domains.
impl::ItemBase itemBase() const
Internal part of the entity.
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.
Exception when an operation is not supported.
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.
IGhostLayerMng * ghostLayerMng() const override
Associated ghost layer manager.
void addGhostChildFromParent()
AMR.
GhostLayerBuilder(DynamicMeshIncrementalBuilder *mesh_builder)
Constructs an instance for the mesh.
impl::ItemBase findItem(Int64 uid) const
Returns the unique ID entity uid.
void eachItem(const Lambda &lambda)
Template function to iterate over the instance's entities.
@ 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.
ConstArrayView< Int32 > Int32ConstArrayView
C equivalent of a 1D array of 32-bit integers.
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
double Real
Type representing a real number.
Array< Int32 > Int32Array
Dynamic one-dimensional array of 32-bit integers.
@ Cell
The mesh is AMR by cell.
std::int32_t Int32
Signed integer type of 32 bits.