Arcane  v3.15.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
ItemsOwnerBuilder.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* ItemsOwnerBuilder.cc (C) 2000-2024 */
9/* */
10/* Classe pour calculer les propriétaires des entités. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/mesh/ItemsOwnerBuilder.h"
15
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/PlatformUtils.h"
18#include "arcane/utils/SmallArray.h"
19#include "arcane/utils/TraceAccessor.h"
20#include "arcane/utils/HashTableMap2.h"
21#include "arcane/utils/ValueConvert.h"
22
23#include "arcane/core/IParallelMng.h"
24#include "arcane/core/ParallelMngUtils.h"
25#include "arcane/core/IParallelExchanger.h"
26#include "arcane/core/ISerializeMessage.h"
27#include "arcane/core/ISerializer.h"
28
29#include "arcane/parallel/BitonicSortT.H"
30
31#include "arcane/mesh/ItemInternalMap.h"
32#include "arcane/mesh/DynamicMesh.h"
33
34/*---------------------------------------------------------------------------*/
35/*---------------------------------------------------------------------------*/
36
37namespace Arcane::mesh
38{
39
40/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------*/
42/*
43 * Ce fichier contient un algorithme pour calculer les propriétaires des
44 * entités autres que les mailles à partir des propriétaires des mailles.
45 *
46 * L'algorithme suppose que les propriétaires des mailles sont à jours et
47 * synchronisés. Le propriétaire d'une entité sera alors le propriétaire de
48 * la maille de plus petit uniqueId() connectée à cette entité.
49 *
50 * En parallèle, si une entité est à la frontière d'un sous-domaine, il n'est
51 * pas possible de connaitre toutes les mailles qui y sont connectées.
52 * Pour résoudre ce problème, on crée une liste des entités de la frontière
53 * contenant pour chaque maille connectée un triplet (uniqueId() de l'entité,
54 * uniqueId() de la maille connectée, owner() de la maille connectées).
55 * Cette liste est ensuite triée en parallèle (via BitonicSort) par uniqueId()
56 * de l'entité, puis par uniqueId() de la maille.
57 * Pour déterminer le propriétaire d'une entité, il suffit ensuite de prendre
58 * le propriétaire de la maille associée à la première occurrence de l'entité
59 * dans cette liste triée. Une fois ceci fait, on renvoie aux rangs qui possèdent
60 * cette entité cette information.
61 */
62/*---------------------------------------------------------------------------*/
63/*---------------------------------------------------------------------------*/
68: public TraceAccessor
69{
72 {
73 public:
74
75 ItemOwnerInfo() = default;
76 ItemOwnerInfo(Int64 item_uid, Int64 cell_uid, Int32 sender_rank, Int32 cell_owner)
77 : m_item_uid(item_uid)
78 , m_cell_uid(cell_uid)
79 , m_item_sender_rank(sender_rank)
80 , m_cell_owner(cell_owner)
81 {
82 }
83
84 public:
85
86 Int64 m_item_uid = NULL_ITEM_UNIQUE_ID;
87 Int64 m_cell_uid = NULL_ITEM_UNIQUE_ID;
88 Int32 m_item_sender_rank = A_NULL_RANK;
89 Int32 m_cell_owner = A_NULL_RANK;
90 };
91
92 public:
93
94 explicit ItemsOwnerBuilderImpl(DynamicMesh* mesh);
95
96 public:
97
98 void computeFacesOwner();
99
100 private:
101
102 DynamicMesh* m_mesh = nullptr;
103 Int32 m_verbose_level = 0;
104 UniqueArray<ItemOwnerInfo> m_items_owner_info;
105
106 private:
107
108 void _sortInfos();
109 void _processSortedInfos(ItemInternalMap& items_map);
110};
111
112/*---------------------------------------------------------------------------*/
113/*---------------------------------------------------------------------------*/
114
115/*---------------------------------------------------------------------------*/
116/*---------------------------------------------------------------------------*/
117
119{
120 public:
121
122 static bool compareLess(const ItemOwnerInfo& k1, const ItemOwnerInfo& k2)
123 {
124 if (k1.m_item_uid < k2.m_item_uid)
125 return true;
126 if (k1.m_item_uid > k2.m_item_uid)
127 return false;
128
129 if (k1.m_cell_uid < k2.m_cell_uid)
130 return true;
131 if (k1.m_cell_uid > k2.m_cell_uid)
132 return false;
133
134 if (k1.m_item_sender_rank < k2.m_item_sender_rank)
135 return true;
136 if (k1.m_item_sender_rank > k2.m_item_sender_rank)
137 return false;
138
139 // ke.node2_uid == k2.node2_uid
140 return (k1.m_cell_owner < k2.m_cell_owner);
141 }
142
143 static Parallel::Request send(IParallelMng* pm, Int32 rank, ConstArrayView<ItemOwnerInfo> values)
144 {
145 const ItemOwnerInfo* fsi_base = values.data();
146 return pm->send(ByteConstArrayView(messageSize(values), reinterpret_cast<const Byte*>(fsi_base)), rank, false);
147 }
148 static Parallel::Request recv(IParallelMng* pm, Int32 rank, ArrayView<ItemOwnerInfo> values)
149 {
150 ItemOwnerInfo* fsi_base = values.data();
151 return pm->recv(ByteArrayView(messageSize(values), reinterpret_cast<Byte*>(fsi_base)), rank, false);
152 }
153 static Integer messageSize(ConstArrayView<ItemOwnerInfo> values)
154 {
155 return CheckedConvert::toInteger(values.size() * sizeof(ItemOwnerInfo));
156 }
157 static ItemOwnerInfo maxValue()
158 {
159 return ItemOwnerInfo(INT64_MAX, INT64_MAX, INT32_MAX, INT32_MAX);
160 }
161 static bool isValid(const ItemOwnerInfo& fsi)
162 {
163 return fsi.m_item_uid != INT64_MAX;
164 }
165};
166
167/*---------------------------------------------------------------------------*/
168/*---------------------------------------------------------------------------*/
169
170/*---------------------------------------------------------------------------*/
171/*---------------------------------------------------------------------------*/
172
173ItemsOwnerBuilderImpl::
174ItemsOwnerBuilderImpl(DynamicMesh* mesh)
175: TraceAccessor(mesh->traceMng())
176, m_mesh(mesh)
177{
178 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_ITEMS_OWNER_BUILDER_IMPL_DEBUG_LEVEL", true))
179 m_verbose_level = v.value();
180}
181
182/*---------------------------------------------------------------------------*/
183/*---------------------------------------------------------------------------*/
184
185void ItemsOwnerBuilderImpl::
186computeFacesOwner()
187{
188 IParallelMng* pm = m_mesh->parallelMng();
189 const Int32 my_rank = pm->commRank();
190 ItemInternalMap& faces_map = m_mesh->facesMap();
191 FaceFamily& face_family = m_mesh->trueFaceFamily();
192
193 info() << "** BEGIN ComputeFacesOwner nb_face=" << faces_map.count();
194
195 // Parcours toutes les faces.
196 // Ne garde que celles qui sont frontières ou dont les propriétaires des
197 // deux mailles de part et d'autre sont différents de notre sous-domaine.
200 faces_map.eachItem([&](Face face) {
201 Int32 nb_cell = face.nbCell();
202 if (nb_cell == 2)
203 if (face.cell(0).owner() == my_rank && face.cell(1).owner() == my_rank) {
204 face.mutableItemBase().setOwner(my_rank, my_rank);
205 return;
206 }
207 faces_to_add.add(face.localId());
208 faces_to_add_uid.add(face.uniqueId());
209 });
210 info() << "ItemsOwnerBuilder: NB_FACE_TO_TRANSFER=" << faces_to_add.size();
211 const Int32 verbose_level = m_verbose_level;
212
214 for (Int32 lid : faces_to_add) {
215 Face face(faces[lid]);
216 Int64 face_uid = face.uniqueId();
217 for (Cell cell : face.cells()) {
218 if (verbose_level >= 2)
219 info() << "ADD lid=" << lid << " uid=" << face_uid << " cell_uid=" << cell.uniqueId() << " owner=" << cell.owner();
220 m_items_owner_info.add(ItemOwnerInfo(face_uid, cell.uniqueId(), my_rank, cell.owner()));
221 }
222 }
223
224 // Tri les instances de ItemOwnerInfo et les place les valeurs triées
225 // dans items_owner_info.
226 _sortInfos();
227 _processSortedInfos(faces_map);
228
229 face_family.notifyItemsOwnerChanged();
230}
231
232/*---------------------------------------------------------------------------*/
233/*---------------------------------------------------------------------------*/
240{
241 IParallelMng* pm = m_mesh->parallelMng();
242 const Int32 verbose_level = m_verbose_level;
244 items_sorter.setNeedIndexAndRank(false);
245 Real sort_begin_time = platform::getRealTime();
246 items_sorter.sort(m_items_owner_info);
247 Real sort_end_time = platform::getRealTime();
248 m_items_owner_info = items_sorter.keys();
249 info() << "END_ALL_ITEM_OWNER_SORTER time=" << (Real)(sort_end_time - sort_begin_time);
250 if (verbose_level >= 2)
251 for (const ItemOwnerInfo& x : m_items_owner_info) {
252 info() << "Sorted item_uid=" << x.m_item_uid << " cell_uid=" << x.m_cell_uid << " owner=" << x.m_cell_owner;
253 }
254}
255
256/*---------------------------------------------------------------------------*/
257/*---------------------------------------------------------------------------*/
258
259void ItemsOwnerBuilderImpl::
260_processSortedInfos(ItemInternalMap& items_map)
261{
262 IParallelMng* pm = m_mesh->parallelMng();
263 const Int32 my_rank = pm->commRank();
264 const Int32 nb_rank = pm->commSize();
266 const Int32 nb_sorted = items_owner_info.size();
267 info() << "NbSorted=" << nb_sorted;
268
269 // Comme les informations d'une entité peuvent être réparties sur plusieurs rangs
270 // après le tri, chaque rang envoie au rang suivant les informations
271 // de la dernière entité de sa liste.
272
274 for (Int32 i = (nb_sorted - 1); i >= 0; --i) {
275 const ItemOwnerInfo& x = items_owner_info[i];
276 if (x.m_item_uid != items_owner_info[nb_sorted - 1].m_item_uid)
277 break;
279 }
281 info() << "NbSendToNext=" << nb_send_to_next;
282
285 // Envoie et recoit les tailles des tableaux
286 if (my_rank != (nb_rank - 1))
287 requests.add(pm->send(ConstArrayView<Int32>(1, &nb_send_to_next), my_rank + 1, false));
288 if (my_rank > 0)
289 requests.add(pm->recv(ArrayView<Int32>(1, &nb_to_receive_from_previous), my_rank - 1, false));
290
291 pm->waitAllRequests(requests);
292 requests.clear();
293
294 // Envoie le tableau au suivant et récupère celui du précédent.
296 if (my_rank != (nb_rank - 1))
297 requests.add(ItemOwnerInfoSortTraits::send(pm, my_rank + 1, items_owner_info_send_to_next));
298 if (my_rank > 0)
299 requests.add(ItemOwnerInfoSortTraits::recv(pm, my_rank - 1, items_owner_info_received_from_previous));
300 pm->waitAllRequests(requests);
301
302 const Int32 verbose_level = m_verbose_level;
303
304 Int64 current_item_uid = NULL_ITEM_UNIQUE_ID;
305 Int32 current_item_owner = A_NULL_RANK;
306
307 // Parcours la liste des entités qu'on a recu.
308 // Chaque entité est présente plusieurs fois dans la liste : au moins
309 // une fois par maille connectée à cette entité. Comme cette liste est triée
310 // par uniqueId() croissant de ces mailles, et que c'est la maille de plus
311 // petit uniqueId() qui donne le propriétaire de l'entité, alors le propriétaire
312 // est celui du premier élément de cette liste.
313 // On envoie ensuite à tous les rangs qui possèdent cette entité ce nouveau propriétaire.
314 // Le tableau envoyé contient une liste de couples (item_uid, item_new_owner).
316 for (Int32 i = 0; i < nb_sorted; ++i) {
317 const ItemOwnerInfo* first_ioi = &items_owner_info[i];
318 Int64 item_uid = first_ioi->m_item_uid;
319 // Si on est au début de la liste, prend l'entité envoyée par le rang précédent
320 // si c'est la même que la nôtre.
321 if (i == 0 && nb_to_receive_from_previous > 0) {
323 if (item_uid == first_previous->m_item_uid) {
325 }
326 }
327 // Si l'id courant est différent du précédent, on commence une nouvelle liste.
328 if (item_uid != current_item_uid) {
329 current_item_uid = item_uid;
330 current_item_owner = first_ioi->m_cell_owner;
331 }
332 Int32 orig_sender = items_owner_info[i].m_item_sender_rank;
333 UniqueArray<Int64>& send_array = resend_items_owner_info_map[orig_sender];
334 send_array.add(current_item_uid);
335 send_array.add(current_item_owner);
336 if (verbose_level >= 2)
337 info() << "SEND i=" << i << " rank=" << orig_sender << " item_uid=" << current_item_uid << " new_owner=" << current_item_owner;
338 }
339
340 auto exchanger{ ParallelMngUtils::createExchangerRef(pm) };
341
342 for (const auto& [key, value] : resend_items_owner_info_map) {
343 if (verbose_level >= 1)
344 info() << "RESEND_INFO to_rank=" << key << " nb=" << value.size();
345 exchanger->addSender(key);
346 }
347 exchanger->initializeCommunicationsMessages();
348 {
349 Int32 index = 0;
350 for (const auto& [key, value] : resend_items_owner_info_map) {
351 ISerializeMessage* sm = exchanger->messageToSend(index);
352 ++index;
353 ISerializer* s = sm->serializer();
354 s->setMode(ISerializer::ModeReserve);
355 s->reserveArray(value);
356 s->allocateBuffer();
357 s->setMode(ISerializer::ModePut);
358 s->putArray(value);
359 }
360 }
361 exchanger->processExchange();
362 UniqueArray<Int64> receive_info;
363
364 for (Integer i = 0, ns = exchanger->nbReceiver(); i < ns; ++i) {
365 ISerializeMessage* sm = exchanger->messageToReceive(i);
366 ISerializer* s = sm->serializer();
367 s->setMode(ISerializer::ModeGet);
368 s->getArray(receive_info);
369 Int32 receive_size = receive_info.size();
370 if (verbose_level >= 1)
371 info() << "RECEIVE_INFO size=" << receive_size << " rank2=" << sm->destination();
372 // Vérifie que la taille est un multiple de 2
373 if ((receive_size % 2) != 0)
374 ARCANE_FATAL("Size '{0}' is not a multiple of 2", receive_size);
375 Int32 buf_size = receive_size / 2;
376 for (Int32 z = 0; z < buf_size; ++z) {
377 Int64 item_uid = receive_info[z * 2];
378 Int32 item_owner = CheckedConvert::toInt32(receive_info[(z * 2) + 1]);
379 impl::ItemBase x = items_map.findItem(item_uid);
380 if (verbose_level >= 2)
381 info() << "SetOwner uid=" << item_uid << " new_owner" << item_owner;
382 x.toMutable().setOwner(item_owner, my_rank);
383 }
384 }
385}
386
387/*---------------------------------------------------------------------------*/
388/*---------------------------------------------------------------------------*/
389
390/*---------------------------------------------------------------------------*/
391/*---------------------------------------------------------------------------*/
392
393ItemsOwnerBuilder::
394ItemsOwnerBuilder(DynamicMesh* mesh)
395: m_p(std::make_unique<ItemsOwnerBuilderImpl>(mesh))
396{}
397
398ItemsOwnerBuilder::
399~ItemsOwnerBuilder()
400{
401 // Le destructeur doit être dans le '.cc' car 'ItemsOwnerBuilderImpl' n'est
402 // pas connu dans le '.h'.
403}
404
405void ItemsOwnerBuilder::
406computeFacesOwner()
407{
408 m_p->computeFacesOwner();
409}
410
411/*---------------------------------------------------------------------------*/
412/*---------------------------------------------------------------------------*/
413
414} // namespace Arcane::mesh
415
416/*---------------------------------------------------------------------------*/
417/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Maille d'un maillage.
Definition Item.h:1178
Vue sur les informations des faces.
Face d'une maille.
Definition Item.h:932
Cell cell(Int32 i) const
i-ème maille de la face
Definition Item.h:1617
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2)
Definition Item.h:1006
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.
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:210
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
Definition Item.h:229
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:216
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:149
Implementation of std::unordered_map.
Implémentation d'un maillage.
Definition DynamicMesh.h:97
IParallelMng * parallelMng() override
Gestionnaire de parallèlisme.
Famille de faces.
Definition FaceFamily.h:53
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.
Implémentation de l'algorithme de calcul des propriétaires.
void _sortInfos()
Tri les instances contenues dans m_items_owner_info replace les valeurs triées dans ce même tableau.
Requête d'un message.
Definition Request.h:77
TraceMessage info() const
Flot pour un message d'information.
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.
ConstArrayView< Byte > ByteConstArrayView
Equivalent C d'un tableau à une dimension de caractères.
Definition UtilsTypes.h:687
ArrayView< Byte > ByteArrayView
Equivalent C d'un tableau à une dimension de caractères.
Definition UtilsTypes.h:658