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();
475 ScopedPtrT<IItemFamilySerializer> cell_serializer(m_mesh->cellFamily()->policyMng()->createSerializer(with_flags));
476 s->setMode(ISerializer::ModeReserve);
477 cell_serializer->serializeItems(s, items_to_send);
480 cell_serializer->serializeItems(s, items_to_send);
483 info(4) <<
"END EXCHANGE CELLS";
489 ScopedPtrT<IItemFamilySerializer> cell_serializer(m_mesh->cellFamily()->policyMng()->createSerializer(with_flags));
490 cell_serializer->deserializeItems(s,
nullptr);
500 info() <<
"** AMR GHOST CHILD FROM PARENT BUILDER V1";
505 debug() <<
"NOT PARALLEL";
511 ItemInternalMap& cells_map = m_mesh_internal->cellsMap();
513 FaceFamily& true_face_family = m_mesh_internal->trueFaceFamily();
516 BoundaryInfosMap boundary_infos_to_send(200,
true);
519 ARCANE_ASSERT((cell.
owner() != -1), (
""));
521 ARCANE_ASSERT((cell.
owner() != -1), (
""));
530 _exchangeData(exchanger.get(), boundary_infos_to_send);
536 SubDomainItemMap cells_to_send(50,
true);
539 debug() <<
"NB RECEIVER=" << nb_receiver;
541 for (
Integer i = 0; i < nb_receiver; ++i) {
549 if ((nb_info % 2) != 0)
550 ARCANE_FATAL(
"info size can not be divided by 2 v={0}", nb_info);
551 Int64 nb_info_true = nb_info / 2;
553 for (
Int64 z = 0; z < nb_info_true; ++z) {
554 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z * 2) + 0]);
555 Int64 cell_uid = received_infos[(z * 2) + 1];
557 impl::ItemBase cell = cells_map.
findItem(cell_uid);
558 ARCANE_ASSERT((cell.uniqueId() == cell_uid), (
""));
559 if (!cell.hasHChildren())
562 ARCANE_ASSERT((cell.level() == 0), (
""));
563 ARCANE_ASSERT((cell.owner() != -1), (
"CELL"));
564 ARCANE_ASSERT((cell_owner != -1), (
"CELL"));
565 true_face_family.familyTree(cell_family, cell);
566 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
570 for (
Integer c = 1; c < cs; c++) {
572 ARCANE_ASSERT((child->
owner() != -1), (
"CHILD"));
579 debug() <<
"nb_recv_child= " << nb_recv_child;
583 _exchangeCells(cells_to_send,
true);
584 m_mesh_internal->printStats(TraceMessage::DEFAULT_LEVEL);
592void GhostLayerBuilder::
593addGhostChildFromParent2(
Array<Int64>& ghost_cell_to_refine)
595 info() <<
"** AMR GHOST CHILD FROM PARENT BUILDER V2";
600 debug() <<
"NOT PARALLEL";
606 ItemInternalMap& cells_map = m_mesh_internal->cellsMap();
609 BoundaryInfosMap boundary_infos_to_send(200,
true);
613 cells_map.eachItem([&](
Item cell) {
614 ARCANE_ASSERT((cell.
owner() != -1), (
""));
615 if (cell.
owner() == sid)
621 Int64Array& v = boundary_infos_to_send.lookupAdd(cell.
owner())->value();
629 _exchangeData(exchanger.get(), boundary_infos_to_send);
634 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
635 SubDomainItemMap cells_to_send(50,
true);
638 debug() <<
"NB RECEIVER=" << nb_receiver;
640 for (
Integer i = 0; i < nb_receiver; ++i) {
646 s->getArray(received_infos);
647 Int64 nb_info = received_infos.size();
648 if ((nb_info % 2) != 0)
649 ARCANE_FATAL(
"info size can not be divided by 2 v={0}", nb_info);
650 Int64 nb_info_true = nb_info / 2;
652 for (
Int64 z = 0; z < nb_info_true; ++z) {
653 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z * 2) + 0]);
654 Int64 cell_uid = received_infos[(z * 2) + 1];
656 Cell cell = cells_map.findItem(cell_uid);
657 ARCANE_ASSERT((cell.uniqueId() == cell_uid), (
""));
658 ARCANE_ASSERT((cell.owner() != -1), (
"CELL"));
659 ARCANE_ASSERT((cell_owner != -1), (
"CELL"));
661 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
664 nb_recv_child += cell.nbHChildren();
665 for (
Integer c = 0, cs = cell.nbHChildren(); c < cs; c++) {
666 Cell child = cell.hChild(c);
667 ARCANE_ASSERT((child.owner() != -1), (
"CHILD"));
670 dv.add(child.localId());
673 debug() <<
"nb_recv_child= " << nb_recv_child;
678 _exchangeCells(cells_to_send,
true);
679 m_mesh_internal->printStats(TraceMessage::DEFAULT_LEVEL);
687NodeUidToSubDomain(
Int64 max_uid,
Int32 nb_rank)
690, m_nb_by_rank(max_uid)
692 m_nb_by_rank = max_uid / nb_rank;
693 if (m_nb_by_rank == 0)
694 m_nb_by_rank = max_uid;
701 bool is_ok = builtInGetValue(div_value, s);
705 if (div_value > m_nb_rank)
706 div_value = m_nb_rank;
709 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.