14#include "arcane/mesh/ItemsOwnerBuilder.h"
16#include "arcane/utils/PlatformUtils.h"
17#include "arcane/utils/SmallArray.h"
18#include "arcane/utils/HashTableMap2.h"
20#include "arcane/core/IParallelMng.h"
21#include "arcane/core/ParallelMngUtils.h"
22#include "arcane/core/IParallelExchanger.h"
23#include "arcane/core/ISerializeMessage.h"
24#include "arcane/core/ISerializer.h"
26#include "arcane/parallel/BitonicSortT.H"
28#include "arcane/mesh/ItemInternalMap.h"
29#include "arcane/mesh/NodeFamily.h"
30#include "arcane/mesh/EdgeFamily.h"
31#include "arcane/mesh/DynamicMesh.h"
33#include <unordered_set>
68class ItemsOwnerBuilderImpl
88 ItemOwnerInfo() =
default;
114 explicit ItemsOwnerBuilderImpl(
IMesh*
mesh);
118 void computeFacesOwner();
119 void computeEdgesOwner();
120 void computeNodesOwner();
125 Int32 m_verbose_level = 0;
152 explicit ItemOwnerInfoSortTraits(
bool use_cell_uid_to_sort)
153 : m_use_cell_uid_to_sort(use_cell_uid_to_sort)
170 if (m_use_cell_uid_to_sort) {
199 return pm->send(
ByteConstArrayView(messageSize(values),
reinterpret_cast<const Byte*
>(fsi_base)), rank,
false);
212 return ItemOwnerInfo(INT64_MAX, INT64_MAX, INT64_MAX, INT32_MAX, INT32_MAX);
221 bool m_use_cell_uid_to_sort =
true;
230ItemsOwnerBuilderImpl::
236 ARCANE_FATAL(
"Mesh is not an instance of 'DynamicMesh'");
239 m_verbose_level = v.value();
249void ItemsOwnerBuilderImpl::
252 m_items_owner_info.clear();
257 FaceFamily& face_family = m_mesh->trueFaceFamily();
259 info() <<
"** BEGIN ComputeFacesOwner nb_face=" << faces_map.
count();
276 info() <<
"ItemsOwnerBuilder: NB_FACE_TO_TRANSFER=" << faces_to_add.
size();
277 const Int32 verbose_level = m_verbose_level;
279 FaceInfoListView faces(&face_family);
280 for (Int32 lid : faces_to_add) {
281 Face face(faces[lid]);
284 if (verbose_level >= 2)
285 info() <<
"ADD lid=" << lid <<
" uid=" << face_uid <<
" cell_uid=" << cell.uniqueId() <<
" owner=" << cell.owner();
286 m_items_owner_info.add(ItemOwnerInfo(face_uid, face.
node(0).
uniqueId(), cell.uniqueId(), my_rank, cell.owner()));
293 _processSortedInfos(faces_map);
301void ItemsOwnerBuilderImpl::
304 m_items_owner_info.clear();
306 IParallelMng* pm = m_mesh->parallelMng();
308 ItemInternalMap& edges_map = m_mesh->edgesMap();
309 EdgeFamily& edge_family = m_mesh->trueEdgeFamily();
311 info() <<
"** BEGIN ComputeEdgesOwner nb_edge=" << edges_map.count();
316 UniqueArray<Int32> edges_to_add;
317 UniqueArray<Int64> edges_to_add_uid;
323 bool do_brute_force =
true;
324 edges_map.eachItem([&](Edge edge) {
325 Int32 nb_cell = edge.nbCell();
326 Int32 nb_cell_with_my_rank = 0;
327 for (
Cell cell : edge.cells())
328 if (cell.owner() == my_rank)
329 ++nb_cell_with_my_rank;
330 bool do_add = (nb_cell == 1 || (nb_cell != nb_cell_with_my_rank));
331 if (do_add || do_brute_force) {
332 edges_to_add.add(edge.localId());
333 edges_to_add_uid.add(edge.uniqueId());
336 edge.mutableItemBase().setOwner(my_rank, my_rank);
338 info() <<
"ItemsOwnerBuilder: NB_FACE_TO_TRANSFER=" << edges_to_add.size();
339 const Int32 verbose_level = m_verbose_level;
341 EdgeInfoListView edges(&edge_family);
342 for (
Int32 lid : edges_to_add) {
343 Edge edge(edges[lid]);
344 Int64 edge_uid = edge.uniqueId();
345 for (
Cell cell : edge.cells()) {
346 if (verbose_level >= 2)
347 info() <<
"ADD lid=" << lid <<
" uid=" << edge_uid <<
" cell_uid=" << cell.uniqueId() <<
" owner=" << cell.owner();
348 m_items_owner_info.add(
ItemOwnerInfo(edge_uid, edge.node(0).uniqueId(), cell.uniqueId(), my_rank, cell.owner()));
355 _processSortedInfos(edges_map);
357 edge_family.notifyItemsOwnerChanged();
363void ItemsOwnerBuilderImpl::
366 m_items_owner_info.clear();
368 IParallelMng* pm = m_mesh->parallelMng();
369 const Int32 my_rank = pm->commRank();
370 ItemInternalMap& faces_map = m_mesh->facesMap();
371 ItemInternalMap& nodes_map = m_mesh->nodesMap();
372 NodeFamily& node_family = m_mesh->trueNodeFamily();
374 info() <<
"** BEGIN ComputeNodesOwner nb_node=" << nodes_map.count();
377 nodes_map.eachItem([&](Node node) {
378 node.mutableItemBase().setOwner(my_rank, my_rank);
385 const Int32 verbose_level = m_verbose_level;
388 UniqueArray<Int32> nodes_to_add;
391 std::unordered_set<Int32> done_nodes;
393 const bool is_mono_dimension = m_mesh->meshKind().isMonoDimension();
395 FaceInfoListView faces(m_mesh->faceFamily());
396 if (is_mono_dimension) {
397 faces_map.eachItem([&](Face face) {
398 Int32 face_nb_cell = face.nbCell();
399 if (face_nb_cell == 2)
401 for (Node node : face.nodes()) {
402 Int32 node_id = node.localId();
403 if (done_nodes.find(node_id) == done_nodes.end()) {
404 nodes_to_add.add(node_id);
405 done_nodes.insert(node_id);
406 node.mutableItemBase().setOwner(A_NULL_RANK, my_rank);
418 ENUMERATE_ (Node, inode, m_mesh->allNodes()) {
419 nodes_to_add.add(inode.itemLocalId());
423 info() <<
"ItemsOwnerBuilder: NB_NODE_TO_ADD=" << nodes_to_add.size() <<
" is_mono_dim=" << is_mono_dimension;
424 NodeInfoListView nodes(&node_family);
425 for (
Int32 lid : nodes_to_add) {
426 Node node(nodes[lid]);
427 Int64 node_uid = node.uniqueId();
428 for (
Cell cell : node.cells()) {
429 if (verbose_level >= 2)
430 info() <<
"ADD lid=" << lid <<
" uid=" << node_uid <<
" cell_uid=" << cell.uniqueId() <<
" owner=" << cell.owner();
431 m_items_owner_info.add(
ItemOwnerInfo(node_uid, node_uid, cell.uniqueId(), my_rank, cell.owner()));
438 _processSortedInfos(nodes_map);
440 node_family.notifyItemsOwnerChanged();
453 const Int32 verbose_level = m_verbose_level;
456 items_sorter.setNeedIndexAndRank(
false);
458 items_sorter.
sort(m_items_owner_info);
460 m_items_owner_info = items_sorter.
keys();
461 info() <<
"END_ALL_ITEM_OWNER_SORTER time=" << (
Real)(sort_end_time - sort_begin_time);
462 if (verbose_level >= 2)
464 info() <<
"Sorted first_node_uid=" << x.m_first_node_uid <<
" item_uid="
465 << x.m_item_uid <<
" cell_uid=" << x.m_cell_uid <<
" owner=" << x.m_cell_owner;
472void ItemsOwnerBuilderImpl::
479 Int32 nb_sorted = items_owner_info.
size();
480 info() <<
"NbSorted=" << nb_sorted;
481 const bool is_last_rank = ((my_rank + 1) == nb_rank);
482 const bool is_first_rank = (my_rank == 0);
483 const Int32 verbose_level = m_verbose_level;
493 if (nb_sorted > 0 && !is_last_rank) {
494 Int32 send_index = nb_sorted;
495 Int64 last_uid = items_owner_info[nb_sorted - 1].m_item_uid;
496 for (
Int32 i = (nb_sorted - 1); i >= 0; --i) {
497 const ItemOwnerInfo& x = items_owner_info[i];
498 if (x.m_item_uid != last_uid) {
503 info() <<
"SendIndext=" << send_index <<
" nb_sorted=" << nb_sorted;
504 for (Int32 i = send_index; i < nb_sorted; ++i) {
505 const ItemOwnerInfo& x = items_owner_info[i];
506 items_owner_info_send_to_next.
add(x);
507 if (verbose_level >= 2)
508 info() <<
"AddSendToNext item_uid=" << x.m_item_uid <<
" owner=" << x.m_cell_owner
509 <<
" from_rank=" << x.m_item_sender_rank <<
" index=" << i;
512 Int32 nb_send_to_next = items_owner_info_send_to_next.
size();
513 info() <<
"NbSendToNext=" << nb_send_to_next;
515 Int32 nb_to_receive_from_previous = 0;
516 SmallArray<Parallel::Request> requests;
519 requests.add(pm->send(ConstArrayView<Int32>(1, &nb_send_to_next), my_rank + 1,
false));
521 requests.add(pm->
recv(ArrayView<Int32>(1, &nb_to_receive_from_previous), my_rank - 1,
false));
527 UniqueArray<ItemOwnerInfo> items_owner_info_received_from_previous(nb_to_receive_from_previous);
529 requests.add(ItemOwnerInfoSortTraits::send(pm, my_rank + 1, items_owner_info_send_to_next));
531 requests.add(ItemOwnerInfoSortTraits::recv(pm, my_rank - 1, items_owner_info_received_from_previous));
535 m_items_owner_info.resize(nb_sorted - nb_send_to_next);
536 items_owner_info = m_items_owner_info.view();
537 nb_sorted = items_owner_info.
size();
538 info() <<
"NbRemaining=" << nb_sorted;
540 Int64 current_item_uid = NULL_ITEM_UNIQUE_ID;
541 Int32 current_item_owner = A_NULL_RANK;
551 impl::HashTableMap2<Int32, UniqueArray<Int64>> resend_items_owner_info_map;
552 for (
Int32 index = 0; index < (nb_sorted + nb_to_receive_from_previous); ++index) {
556 if (index < nb_to_receive_from_previous)
557 first_ioi = &items_owner_info_received_from_previous[index];
559 first_ioi = &items_owner_info[index - nb_to_receive_from_previous];
560 Int64 item_uid = first_ioi->m_item_uid;
563 if (item_uid != current_item_uid) {
564 current_item_uid = item_uid;
566 current_item_owner = first_ioi->m_cell_owner;
568 current_item_owner = first_ioi->m_item_sender_rank;
569 if (verbose_level >= 2)
570 info() <<
"SetOwner from sorted index=" << index <<
" item_uid=" << current_item_uid <<
" new_owner=" << current_item_owner;
572 Int32 orig_sender = first_ioi->m_item_sender_rank;
573 UniqueArray<Int64>& send_array = resend_items_owner_info_map[orig_sender];
574 send_array.add(current_item_uid);
575 send_array.add(current_item_owner);
576 if (verbose_level >= 2)
577 info() <<
"SEND i=" << index <<
" rank=" << orig_sender <<
" item_uid=" << current_item_uid <<
" new_owner=" << current_item_owner;
581 info() <<
"NbResendRanks=" << resend_items_owner_info_map.size();
582 for (
const auto& [key, value] : resend_items_owner_info_map) {
583 if (verbose_level >= 1)
584 info() <<
"RESEND_INFO to_rank=" << key <<
" nb=" << value.size();
585 exchanger->addSender(key);
587 exchanger->initializeCommunicationsMessages();
590 for (
const auto& [key, value] : resend_items_owner_info_map) {
591 ISerializeMessage* sm = exchanger->messageToSend(index);
593 ISerializer* s = sm->serializer();
594 s->setMode(ISerializer::ModeReserve);
595 s->reserveArray(value);
601 exchanger->processExchange();
602 UniqueArray<Int64> receive_info;
604 for (
Integer i = 0, ns = exchanger->nbReceiver(); i < ns; ++i) {
605 ISerializeMessage* sm = exchanger->messageToReceive(i);
606 ISerializer* s = sm->serializer();
608 s->getArray(receive_info);
609 Int32 receive_size = receive_info.size();
610 if (verbose_level >= 1)
611 info() <<
"RECEIVE_INFO size=" << receive_size <<
" rank2=" << sm->destination();
613 if ((receive_size % 2) != 0)
614 ARCANE_FATAL(
"Size '{0}' is not a multiple of 2", receive_size);
615 Int32 buf_size = receive_size / 2;
616 for (
Int32 z = 0; z < buf_size; ++z) {
617 Int64 item_uid = receive_info[z * 2];
619 impl::ItemBase x = items_map.
findItem(item_uid);
620 if (verbose_level >= 2)
621 info() <<
"SetOwner uid=" << item_uid <<
" new_owner=" << item_owner;
622 x.toMutable().setOwner(item_owner, my_rank);
634ItemsOwnerBuilder(IMesh* mesh)
635: m_p(std::make_unique<ItemsOwnerBuilderImpl>(mesh))
648void ItemsOwnerBuilder::
651 m_p->computeFacesOwner();
657void ItemsOwnerBuilder::
660 m_p->computeEdgesOwner();
666void ItemsOwnerBuilder::
669 m_p->computeNodesOwner();
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Integer size() const
Nombre d'éléments du vecteur.
Vue modifiable d'un tableau d'un type T.
constexpr const_pointer data() const noexcept
Pointeur sur le début de la vue.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Vue constante d'un tableau de type T.
constexpr const_pointer data() const noexcept
Pointeur sur la mémoire allouée.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Cell cell(Int32 i) const
i-ème maille de la face
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2)
CellConnectedListViewType cells() const
Liste des mailles de la face.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual void recv(ArrayView< char > values, Int32 rank)=0
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual void waitAllRequests(ArrayView< Request > rvalues)=0
Bloque en attendant que les requêtes rvalues soient terminées.
@ ModePut
Le sérialiseur attend des reserve()
@ ModeGet
Le sérialiseur attend des get()
Node node(Int32 i) const
i-ème noeud de l'entité
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.
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
void setOwner(Integer suid, Int32 current_sub_domain)
Positionne le numéro du sous-domaine propriétaire de l'entité.
Algorithme de tri bi-tonique parallèle.
ConstArrayView< KeyType > keys() const override
Après un tri, retourne la liste des éléments de ce rang.
void sort(ConstArrayView< KeyType > keys) override
Trie en parallèle les éléments de keys sur tous les rangs.
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
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).
Implémentation d'un maillage.
IParallelMng * parallelMng() override
Gestionnaire de parallèlisme.
void notifyItemsOwnerChanged() override
Notifie que les entités propres au sous-domaine de la famille ont été modifiées.
Tableau associatif de ItemInternal.
impl::ItemBase findItem(Int64 uid) const
Retourne l'entité de numéro unique uid.
void eachItem(const Lambda &lambda)
Fonction template pour itérer sur les entités de l'instance.
Int32 count() const
Nombre d'éléments de la table.
Informations sur une entité partagée.
Int32 m_item_sender_rank
rang de celui qui a créé cette instance
Int64 m_first_node_uid
uniqueId() du premier noeud de l'entité
Int32 m_cell_owner
Propriétaire de la maille connectée à cette entité
Int64 m_item_uid
uniqueId() de l'entité
Int64 m_cell_uid
uniqueId() de la maille à laquelle l'entité appartient
bool m_use_cell_uid_to_sort
Indique comment effectuer le tri.
void _sortInfos()
Tri les instances contenues dans m_items_owner_info replace les valeurs triées dans ce même tableau.
Integer toInteger(Real r)
Converti un Int64 en un Integer.
Int32 toInt32(Int64 v)
Converti un Int64 en un Int32.
Ref< IParallelExchanger > createExchangerRef(IParallelMng *pm)
Retourne une interface pour transférer des messages entre rangs.
ArrayView< Byte > ByteArrayView
Equivalent C d'un tableau à une dimension de caractères.
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
double Real
Type représentant un réel.
ConstArrayView< Byte > ByteConstArrayView
Equivalent C d'un tableau à une dimension de caractères.
unsigned char Byte
Type d'un octet.
@ Cell
Le maillage est AMR par maille.
std::int32_t Int32
Type entier signé sur 32 bits.