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)
96 else if (version == 2) {
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;
122 : m_cell_last_index(5000,
true)
129 Int32 current_index = m_cell_indexes.size();
130 m_cell_indexes.add(cell_uid);
131 m_cell_indexes.add(cell_owner);
134 m_cell_indexes.add(d->value());
135 d->value() = current_index;
147void GhostLayerBuilder::
150 for (BoundaryInfosMapEnumerator i_map(boundary_infos_to_send); ++i_map;) {
151 Int32 sd = i_map.data()->key();
162 s->
setMode(ISerializer::ModeReserve);
172 debug() <<
"END EXCHANGE";
178void GhostLayerBuilder::
181 info() <<
"** NEW GHOST LAYER BUILDER V2";
182 if (m_mesh->ghostLayerMng()->nbGhostLayer() != 1)
183 ARCANE_THROW(NotImplementedException,
"Only one layer of ghost cells is supported");
185 IParallelMng* pm = m_mesh->parallelMng();
186 Int32 my_rank = pm->commRank();
187 Int32 nb_rank = pm->commSize();
188 debug() <<
" RANK=" << pm->commRank() <<
" size=" << pm->commSize();
189 if (!pm->isParallel()) {
190 debug() <<
"NOT PARALLEL";
193#ifdef ARCANE_DEBUG_DYNAMIC_MESH
194 const bool is_verbose =
true;
196 const bool is_verbose =
false;
201 ostr() <<
"** FACES LIST\n";
203 Integer nb_sub_domain_boundary_face = 0;
205 ItemInternalMap& cells_map = m_mesh_internal->cellsMap();
206 ItemInternalMap& faces_map = m_mesh_internal->facesMap();
208 ItemInternalMap& nodes_map = m_mesh_internal->nodesMap();
212 faces_map.eachItem([&](Face face) {
213 impl::ItemBase face_base = face.itemBase();
215 ostr() << ItemPrinter(face);
218 bool is_sub_domain_boundary_face =
false;
220 is_sub_domain_boundary_face =
true;
223 if (face.nbCell() == 2 && (face.cell(0).owner() != my_rank || face.cell(1).owner() != my_rank))
224 is_sub_domain_boundary_face =
true;
226 if (is_sub_domain_boundary_face) {
227 face_base.toMutable().addFlags(shared_and_boundary_flags);
228 ++nb_sub_domain_boundary_face;
229 for (Item inode : face.nodes())
230 inode.mutableItemBase().addFlags(shared_and_boundary_flags);
231 for (Item iedge : face.edges())
232 iedge.mutableItemBase().addFlags(shared_and_boundary_flags);
236 Integer boundary_nodes_uid_count = 0;
239 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
240 nodes_map.eachItem([&](Node node) {
241 Int32 f = node.itemBase().flags();
243 Int64 node_uid = node.uniqueId();
244 if (node_uid > my_max_node_uid)
245 my_max_node_uid = node_uid;
246 ++boundary_nodes_uid_count;
251 debug() <<
"NB BOUNDARY NODE=" << boundary_nodes_uid_count
252 <<
" MY_MAX_UID=" << my_max_node_uid
253 <<
" GLOBAL=" << global_max_node_uid;
257 ostr() <<
"List of shared cells:\n";
261 BoundaryInfosMap boundary_infos_to_send(200,
true);
262 NodeUidToSubDomain uid_to_subdomain_converter(global_max_node_uid, nb_rank);
264 cells_map.eachItem([&](
Cell cell) {
266 ostr() <<
"Send cell " << ItemPrinter(cell) <<
'\n';
270 for (Node node : cell.nodes()) {
273 Int64 node_uid = node.uniqueId();
275 Int32 dest_rank = uid_to_subdomain_converter.uidToRank(node_uid);
276 SharedArray<Int64> v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
279 v.add(cell.uniqueId());
288 info() << ostr.str();
290 info() <<
"Number of shared faces: " << nb_sub_domain_boundary_face;
297 _exchangeData(exchanger.get(), boundary_infos_to_send);
301 NodeCellList node_cell_list;
304 debug() <<
"NB RECEIVER=" << nb_receiver;
306 for (
Integer i = 0; i < nb_receiver; ++i) {
309 ISerializer* s = sm->serializer();
311 s->getArray(received_infos);
312 Int64 nb_info = received_infos.largeSize();
314 if ((nb_info % 3) != 0)
315 ARCANE_FATAL(
"Inconsistent received data v={0}", nb_info);
316 Int64 nb_info_true = nb_info / 3;
317 for (
Int64 z = 0; z < nb_info_true; ++z) {
318 Int64 node_uid = received_infos[(z * 3) + 0];
319 Int64 cell_owner = received_infos[(z * 3) + 1];
320 Int64 cell_uid = received_infos[(z * 3) + 2];
321 node_cell_list.add(node_uid, cell_uid, cell_owner);
326 boundary_infos_to_send = BoundaryInfosMap(1000,
true);
330 debug() <<
"NB_CELL_INDEXES = " << cell_indexes.size();
335 for (HashTableMapEnumeratorT<Int64, Int32> i_map(node_cell_list.m_cell_last_index); ++i_map;) {
336 HashTableMapT<Int64, Int32>::Data* d = i_map.data();
337 Int32 index = d->value();
338 Int64 node_uid = d->key();
346 Int32 node_new_owner = NULL_SUB_DOMAIN_ID;
347 Int64 smallest_cell_uid = NULL_ITEM_UNIQUE_ID;
349 while (index != (-1)) {
350 Int64 cell_uid = cell_indexes[index];
351 Int32 cell_owner = CheckedConvert::toInt32(cell_indexes[index + 1]);
352 index = CheckedConvert::toInteger(cell_indexes[index + 2]);
354 ranks.add((
Int32)cell_owner);
356 if (cell_uid < smallest_cell_uid || node_new_owner == NULL_SUB_DOMAIN_ID) {
357 smallest_cell_uid = cell_uid;
358 node_new_owner = cell_owner;
362 std::sort(std::begin(ranks), std::end(ranks));
363 Integer new_size = CheckedConvert::toInteger(std::unique(std::begin(ranks), std::end(ranks)) - std::begin(ranks));
364 ranks.resize(new_size);
373 Integer nb_cell = cells.size();
374 for (
Integer z = 0; z < new_size; ++z) {
375 Int32 dest_rank = ranks[z];
377 Int64Array& v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
379 v.add(node_new_owner);
382 for (
Integer z2 = 0; z2 < new_size; ++z2)
384 for (
Integer z2 = 0; z2 < nb_cell; ++z2)
391 _exchangeData(exchanger.get(), boundary_infos_to_send);
392 debug() <<
"END OF EXCHANGE";
394 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
395 SubDomainItemMap cells_to_send(50,
true);
398 debug() <<
"NB RECEIVER 2 =" << nb_receiver;
401 for (
Integer i = 0; i < nb_receiver; ++i) {
407 s->getArray(received_infos);
408 Int64 nb_info = received_infos.largeSize();
412 while (z < nb_info) {
413 Int64 node_uid = received_infos[z];
414 Int32 node_new_owner = CheckedConvert::toInt32(received_infos[z + 1]);
415 Int32 nb_rank = CheckedConvert::toInt32(received_infos[z + 2]);
416 Int32 nb_cell = CheckedConvert::toInt32(received_infos[z + 3]);
418 nodes_map.findItem(node_uid).toMutable().setOwner(node_new_owner, my_rank);
422 for (
Integer z2 = 0; z2 < nb_rank; ++z2) {
424 if (nrank != my_rank)
428 for (
Integer z2 = 0; z2 < nb_cell; ++z2) {
429 Int64 cell_uid = received_infos[z + z2];
430 impl::ItemBase dcell = cells_map.tryFind(cell_uid);
432 cells.add(dcell.localId());
434 for (
Integer z2 = 0, zs = ranks.size(); z2 < zs; ++z2) {
435 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(ranks[z2]);
436 SharedArray<Int32> dv = d->value();
437 for (
Integer z3 = 0, zs3 = cells.size(); z3 < zs3; ++z3)
446 _exchangeCells(cells_to_send,
false);
447 m_mesh_internal->printStats(TraceMessage::DEFAULT_LEVEL);
453void GhostLayerBuilder::
454_exchangeCells(HashTableMapT<
Int32, SharedArray<Int32>>& cells_to_send,
bool with_flags)
457 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
458 IParallelMng* pm = m_mesh->parallelMng();
460 for (SubDomainItemMap::Enumerator i_map(cells_to_send); ++i_map;) {
461 Int32 sd = i_map.data()->key();
465 info(4) <<
"CELLS TO SEND SD=" << sd <<
" NB=" << items.size();
472 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";
487 ScopedPtrT<IItemFamilySerializer> cell_serializer(m_mesh->cellFamily()->policyMng()->createSerializer(with_flags));
488 cell_serializer->deserializeItems(s,
nullptr);
498 info() <<
"** AMR GHOST CHILD FROM PARENT BUILDER V1";
503 debug() <<
"NOT PARALLEL";
509 ItemInternalMap& cells_map = m_mesh_internal->cellsMap();
511 FaceFamily& true_face_family = m_mesh_internal->trueFaceFamily();
514 BoundaryInfosMap boundary_infos_to_send(200,
true);
517 ARCANE_ASSERT((cell.
owner() != -1), (
""));
519 ARCANE_ASSERT((cell.
owner() != -1), (
""));
528 _exchangeData(exchanger.get(), boundary_infos_to_send);
534 SubDomainItemMap cells_to_send(50,
true);
537 debug() <<
"NB RECEIVER=" << nb_receiver;
539 for (
Integer i = 0; i < nb_receiver; ++i) {
547 if ((nb_info % 2) != 0)
548 ARCANE_FATAL(
"info size can not be divided by 2 v={0}", nb_info);
549 Int64 nb_info_true = nb_info / 2;
551 for (
Int64 z = 0; z < nb_info_true; ++z) {
552 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z * 2) + 0]);
553 Int64 cell_uid = received_infos[(z * 2) + 1];
555 impl::ItemBase cell = cells_map.
findItem(cell_uid);
556 ARCANE_ASSERT((cell.uniqueId() == cell_uid), (
""));
557 if (!cell.hasHChildren())
560 ARCANE_ASSERT((cell.level() == 0), (
""));
561 ARCANE_ASSERT((cell.owner() != -1), (
"CELL"));
562 ARCANE_ASSERT((cell_owner != -1), (
"CELL"));
563 true_face_family.familyTree(cell_family, cell);
564 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
568 for (
Integer c = 1; c < cs; c++) {
570 ARCANE_ASSERT((child->
owner() != -1), (
"CHILD"));
577 debug() <<
"nb_recv_child= " << nb_recv_child;
581 _exchangeCells(cells_to_send,
true);
582 m_mesh_internal->printStats(TraceMessage::DEFAULT_LEVEL);
590void GhostLayerBuilder::
591addGhostChildFromParent2(
Array<Int64>& ghost_cell_to_refine)
593 info() <<
"** AMR GHOST CHILD FROM PARENT BUILDER V2";
598 debug() <<
"NOT PARALLEL";
604 ItemInternalMap& cells_map = m_mesh_internal->cellsMap();
607 BoundaryInfosMap boundary_infos_to_send(200,
true);
611 cells_map.eachItem([&](
Item cell) {
612 ARCANE_ASSERT((cell.
owner() != -1), (
""));
613 if (cell.
owner() == sid)
619 Int64Array& v = boundary_infos_to_send.lookupAdd(cell.
owner())->value();
627 _exchangeData(exchanger.get(), boundary_infos_to_send);
632 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
633 SubDomainItemMap cells_to_send(50,
true);
636 debug() <<
"NB RECEIVER=" << nb_receiver;
638 for (
Integer i = 0; i < nb_receiver; ++i) {
644 s->getArray(received_infos);
645 Int64 nb_info = received_infos.size();
646 if ((nb_info % 2) != 0)
647 ARCANE_FATAL(
"info size can not be divided by 2 v={0}", nb_info);
648 Int64 nb_info_true = nb_info / 2;
650 for (
Int64 z = 0; z < nb_info_true; ++z) {
651 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z * 2) + 0]);
652 Int64 cell_uid = received_infos[(z * 2) + 1];
654 Cell cell = cells_map.findItem(cell_uid);
655 ARCANE_ASSERT((cell.uniqueId() == cell_uid), (
""));
656 ARCANE_ASSERT((cell.owner() != -1), (
"CELL"));
657 ARCANE_ASSERT((cell_owner != -1), (
"CELL"));
659 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
662 nb_recv_child += cell.nbHChildren();
663 for (
Integer c = 0, cs = cell.nbHChildren(); c < cs; c++) {
664 Cell child = cell.hChild(c);
665 ARCANE_ASSERT((child.owner() != -1), (
"CHILD"));
668 dv.add(child.localId());
671 debug() <<
"nb_recv_child= " << nb_recv_child;
676 _exchangeCells(cells_to_send,
true);
677 m_mesh_internal->printStats(TraceMessage::DEFAULT_LEVEL);
685NodeUidToSubDomain(
Int64 max_uid,
Int32 nb_rank)
688, m_nb_by_rank(max_uid)
690 m_nb_by_rank = max_uid / nb_rank;
691 if (m_nb_by_rank == 0)
692 m_nb_by_rank = max_uid;
699 bool is_ok = builtInGetValue(div_value, s);
703 if (div_value > m_nb_rank)
704 div_value = m_nb_rank;
707 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.
virtual IParallelMng * parallelMng()=0
Parallelism manager.
virtual IGhostLayerMng * ghostLayerMng() const =0
Associated ghost layer manager.
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).
void addGhostChildFromParent()
AMR.
GhostLayerBuilder(IMesh *mesh)
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.