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);
391 const Int32 verbose_level = m_verbose_level;
394 std::unordered_set<Int32> done_nodes;
396 FaceInfoListView faces(m_mesh->faceFamily());
397 UniqueArray<Int32> nodes_to_add;
398 faces_map.eachItem([&](Face face) {
399 Int32 face_nb_cell = face.nbCell();
400 if (face_nb_cell == 2)
402 for (Node node : face.nodes()) {
403 Int32 node_id = node.localId();
404 if (done_nodes.find(node_id) == done_nodes.end()) {
405 nodes_to_add.add(node_id);
406 done_nodes.insert(node_id);
407 node.mutableItemBase().setOwner(A_NULL_RANK, my_rank);
412 info() <<
"ItemsOwnerBuilder: NB_NODE_TO_ADD=" << nodes_to_add.size();
413 NodeInfoListView nodes(&node_family);
414 for (
Int32 lid : nodes_to_add) {
415 Node node(nodes[lid]);
416 Int64 node_uid = node.uniqueId();
417 for (
Cell cell : node.cells()) {
418 if (verbose_level >= 2)
419 info() <<
"ADD lid=" << lid <<
" uid=" << node_uid <<
" cell_uid=" << cell.uniqueId() <<
" owner=" << cell.owner();
420 m_items_owner_info.add(
ItemOwnerInfo(node_uid, node_uid, cell.uniqueId(), my_rank, cell.owner()));
427 _processSortedInfos(nodes_map);
429 node_family.notifyItemsOwnerChanged();
442 const Int32 verbose_level = m_verbose_level;
445 items_sorter.setNeedIndexAndRank(
false);
447 items_sorter.
sort(m_items_owner_info);
449 m_items_owner_info = items_sorter.
keys();
450 info() <<
"END_ALL_ITEM_OWNER_SORTER time=" << (
Real)(sort_end_time - sort_begin_time);
451 if (verbose_level >= 2)
453 info() <<
"Sorted first_node_uid=" << x.m_first_node_uid <<
" item_uid="
454 << x.m_item_uid <<
" cell_uid=" << x.m_cell_uid <<
" owner=" << x.m_cell_owner;
461void ItemsOwnerBuilderImpl::
468 Int32 nb_sorted = items_owner_info.
size();
469 info() <<
"NbSorted=" << nb_sorted;
470 const bool is_last_rank = ((my_rank + 1) == nb_rank);
471 const bool is_first_rank = (my_rank == 0);
472 const Int32 verbose_level = m_verbose_level;
482 if (nb_sorted > 0 && !is_last_rank) {
483 Int32 send_index = nb_sorted;
484 Int64 last_uid = items_owner_info[nb_sorted - 1].m_item_uid;
485 for (
Int32 i = (nb_sorted - 1); i >= 0; --i) {
486 const ItemOwnerInfo& x = items_owner_info[i];
487 if (x.m_item_uid != last_uid) {
492 info() <<
"SendIndext=" << send_index <<
" nb_sorted=" << nb_sorted;
493 for (Int32 i = send_index; i < nb_sorted; ++i) {
494 const ItemOwnerInfo& x = items_owner_info[i];
495 items_owner_info_send_to_next.
add(x);
496 if (verbose_level >= 2)
497 info() <<
"AddSendToNext item_uid=" << x.m_item_uid <<
" owner=" << x.m_cell_owner
498 <<
" from_rank=" << x.m_item_sender_rank <<
" index=" << i;
501 Int32 nb_send_to_next = items_owner_info_send_to_next.
size();
502 info() <<
"NbSendToNext=" << nb_send_to_next;
504 Int32 nb_to_receive_from_previous = 0;
505 SmallArray<Parallel::Request> requests;
508 requests.add(pm->send(ConstArrayView<Int32>(1, &nb_send_to_next), my_rank + 1,
false));
510 requests.add(pm->
recv(ArrayView<Int32>(1, &nb_to_receive_from_previous), my_rank - 1,
false));
516 UniqueArray<ItemOwnerInfo> items_owner_info_received_from_previous(nb_to_receive_from_previous);
518 requests.add(ItemOwnerInfoSortTraits::send(pm, my_rank + 1, items_owner_info_send_to_next));
520 requests.add(ItemOwnerInfoSortTraits::recv(pm, my_rank - 1, items_owner_info_received_from_previous));
524 m_items_owner_info.resize(nb_sorted - nb_send_to_next);
525 items_owner_info = m_items_owner_info.view();
526 nb_sorted = items_owner_info.
size();
527 info() <<
"NbRemaining=" << nb_sorted;
529 Int64 current_item_uid = NULL_ITEM_UNIQUE_ID;
530 Int32 current_item_owner = A_NULL_RANK;
540 impl::HashTableMap2<Int32, UniqueArray<Int64>> resend_items_owner_info_map;
541 for (
Int32 index = 0; index < (nb_sorted + nb_to_receive_from_previous); ++index) {
545 if (index < nb_to_receive_from_previous)
546 first_ioi = &items_owner_info_received_from_previous[index];
548 first_ioi = &items_owner_info[index - nb_to_receive_from_previous];
549 Int64 item_uid = first_ioi->m_item_uid;
552 if (item_uid != current_item_uid) {
553 current_item_uid = item_uid;
555 current_item_owner = first_ioi->m_cell_owner;
557 current_item_owner = first_ioi->m_item_sender_rank;
558 if (verbose_level >= 2)
559 info() <<
"SetOwner from sorted index=" << index <<
" item_uid=" << current_item_uid <<
" new_owner=" << current_item_owner;
561 Int32 orig_sender = first_ioi->m_item_sender_rank;
562 UniqueArray<Int64>& send_array = resend_items_owner_info_map[orig_sender];
563 send_array.add(current_item_uid);
564 send_array.add(current_item_owner);
565 if (verbose_level >= 2)
566 info() <<
"SEND i=" << index <<
" rank=" << orig_sender <<
" item_uid=" << current_item_uid <<
" new_owner=" << current_item_owner;
570 info() <<
"NbResendRanks=" << resend_items_owner_info_map.size();
571 for (
const auto& [key, value] : resend_items_owner_info_map) {
572 if (verbose_level >= 1)
573 info() <<
"RESEND_INFO to_rank=" << key <<
" nb=" << value.size();
574 exchanger->addSender(key);
576 exchanger->initializeCommunicationsMessages();
579 for (
const auto& [key, value] : resend_items_owner_info_map) {
580 ISerializeMessage* sm = exchanger->messageToSend(index);
582 ISerializer* s = sm->serializer();
583 s->setMode(ISerializer::ModeReserve);
584 s->reserveArray(value);
590 exchanger->processExchange();
591 UniqueArray<Int64> receive_info;
593 for (
Integer i = 0, ns = exchanger->nbReceiver(); i < ns; ++i) {
594 ISerializeMessage* sm = exchanger->messageToReceive(i);
595 ISerializer* s = sm->serializer();
597 s->getArray(receive_info);
598 Int32 receive_size = receive_info.size();
599 if (verbose_level >= 1)
600 info() <<
"RECEIVE_INFO size=" << receive_size <<
" rank2=" << sm->destination();
602 if ((receive_size % 2) != 0)
603 ARCANE_FATAL(
"Size '{0}' is not a multiple of 2", receive_size);
604 Int32 buf_size = receive_size / 2;
605 for (
Int32 z = 0; z < buf_size; ++z) {
606 Int64 item_uid = receive_info[z * 2];
608 impl::ItemBase x = items_map.
findItem(item_uid);
609 if (verbose_level >= 2)
610 info() <<
"SetOwner uid=" << item_uid <<
" new_owner=" << item_owner;
611 x.toMutable().setOwner(item_owner, my_rank);
623ItemsOwnerBuilder(IMesh* mesh)
624: m_p(std::make_unique<ItemsOwnerBuilderImpl>(mesh))
637void ItemsOwnerBuilder::
640 m_p->computeFacesOwner();
646void ItemsOwnerBuilder::
649 m_p->computeEdgesOwner();
655void ItemsOwnerBuilder::
658 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.