Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
VariableSynchronizerComputeList.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2023 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/* VariableSynchronizerComputeList.cc (C) 2000-2024 */
9/* */
10/* Calcule de la liste des entités à synchroniser. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/impl/internal/VariableSynchronizerComputeList.h"
15
16#include "arcane/utils/ITraceMng.h"
17#include "arcane/utils/FatalErrorException.h"
18#include "arcane/utils/PlatformUtils.h"
19#include "arcane/utils/OStringStream.h"
20#include "arcane/utils/ValueConvert.h"
21
22#include "arcane/core/IParallelMng.h"
23#include "arcane/core/IItemFamily.h"
24#include "arcane/core/ItemPrinter.h"
25
26#include "arcane/impl/DataSynchronizeInfo.h"
27#include "arcane/impl/internal/VariableSynchronizer.h"
28
29#include <algorithm>
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
33
34namespace Arcane
35{
36
37/*---------------------------------------------------------------------------*/
38/*---------------------------------------------------------------------------*/
39
40VariableSynchronizerComputeList::
41VariableSynchronizerComputeList(VariableSynchronizer* var_sync)
42: TraceAccessor(var_sync->traceMng())
43, m_synchronizer(var_sync)
44, m_parallel_mng(var_sync->m_parallel_mng)
45, m_item_group(var_sync->m_item_group)
46, m_is_verbose(var_sync->m_is_verbose)
47{
48 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_DEBUG_VARIABLESYNCHRONIZERCOMPUTELIST", true))
49 m_is_debug = (v.value() != 0);
50}
51
52/*---------------------------------------------------------------------------*/
53/*---------------------------------------------------------------------------*/
74void VariableSynchronizerComputeList::
75compute()
76{
77 const bool is_debug = m_is_debug;
78 IItemFamily* item_family = m_item_group.itemFamily();
79 Int32 my_rank = m_parallel_mng->commRank();
80 Int32 nb_rank = m_parallel_mng->commSize();
81
82 m_is_verbose = traceMng()->verbosityLevel() >= 4;
83
85
86 info() << "Compute synchronize informations group=" << m_item_group.name()
87 << " family=" << item_family->fullName()
88 << " group size=" << m_item_group.size()
89 << " is_verbose=" << m_is_verbose;
90
91 {
92 Integer nb_error = 0;
94 ENUMERATE_ITEM (i, m_item_group) {
95 Item item = *i;
97 Int32 owner = item_internal.owner();
98 if (owner == my_rank)
99 continue;
100 Int64 uid = item_internal.uniqueId().asInt64();
101 if (owner == A_NULL_RANK || owner >= nb_rank) {
102 ++nb_error;
103 if (nb_error < 10)
104 bad_items_uid.add(uid);
105 continue;
106 }
107 if (is_debug) {
108 info() << "Add entity uid=" << uid
109 << " lid=" << item_internal.localId() << " to the subdomain " << owner;
110 }
111 boundary_items[owner].add(item_internal.localId());
112 }
113 if (nb_error != 0) {
114 for (Int64 uid : bad_items_uid) {
115 info() << "ERROR: The entity uid=" << uid
116 << " group=" << m_item_group.name() << " doesn't belong to "
117 << "any subdomain or belong to an invalid subdomain";
118 }
119 ARCANE_FATAL("Error while creating synchronization information nb_error={0}", nb_error);
120 }
121 }
122
123 _createList(boundary_items);
124
125 if (is_debug)
126 _printSyncList();
127
128 info() << "End compute synchronize information group=" << m_item_group.name()
129 << " Date=" << platform::getCurrentDateTime();
130}
131
132/*---------------------------------------------------------------------------*/
133/*---------------------------------------------------------------------------*/
134
135void VariableSynchronizerComputeList::
137{
138 const bool is_debug = m_is_debug;
139 DataSynchronizeInfo* sync_info = m_synchronizer->m_sync_info.get();
140
141 sync_info->clear();
142
143 IItemFamily* item_family = m_item_group.itemFamily();
144 IParallelMng* pm = m_parallel_mng;
145 Int32 my_rank = pm->commRank();
146 Int32 nb_rank = pm->commSize();
147 info(4) << "VariableSynchronizer::createList() begin for group=" << m_item_group.name();
148
149 Real time_begin = platform::getRealTime();
150 Real time_before_all_gather = 0.0;
151 Real time_after_all_gather = 0.0;
152 Real time_before_sendrecv = 0.0;
153 Real time_after_sendrecv = 0.0;
154 Real time_after_sendrecv_wait = 0.0;
155
156 // Table du voisinage connu par items fantomes.
157 // Ceci n'est pas obligatoirement la liste finale pour sync_info->communicatingRanks() dans le cas
158 // de relation non symétrique ghost/shared entre processeurs (si l'un des deux vaut 0)
159 // Le traitement complémentaire apparaît après la section "Réciprocité des communications"
161 for (Integer i = 0; i < nb_rank; ++i) {
162 if (boundary_items[i].empty())
163 continue;
165 if (is_debug) {
167 for (Integer z = 0, zs = boundary_items[i].size(); z < zs; ++z) {
168 Item item = items_internal[boundary_items[i][z]];
169 info() << "Item uid=" << item.uniqueId() << ",lid=" << item.localId();
170 }
171 }
172 }
173
175
176 Int32UniqueArray nb_ghost(nb_rank);
177 Int32UniqueArray nb_share(nb_rank);
178 nb_ghost.fill(0);
179
180 // Nombre maximum de sous-domaines connectés. Sert pour dimensionner
181 // les tableaux pour le allGather()
182 Integer max_comm_rank = pm->reduce(Parallel::ReduceMax, nb_comm_rank);
183 debug() << "communicating sub domains my=" << nb_comm_rank
184 << " max=" << max_comm_rank;
185
186 // Liste des groupes des mailles fantômes.
188
189 // Récupère les listes des entités fantômes.
190 for (Integer i = 0; i < nb_comm_rank; ++i) {
195 }
196
199 {
200 Integer gather_size = 1 + (max_comm_rank * 2);
202 {
203 // Chaque sous-domaine construit un tableau indiquand pour
204 // chaque groupe d'éléments fantômes, le processeur concerné et
205 // le nombre d'éléments de ce groupe.
206 // Ce tableau sera ensuite regroupé sur l'ensemble des sous-domaines
207 // (par un allGather()) afin que chaque sous-domaine puisse le parcourir
208 // et ensuite savoir qui possède ses mailles partagés.
210 Integer pos = 0;
211 local_ghost_info[pos++] = nb_comm_rank; // Indique le nombre d'éléments du tableau
212 debug() << "Send local info " << nb_comm_rank;
213 for (Integer index = 0, s = communicating_ghost_ranks.size(); index < s; ++index) {
215 local_ghost_info[pos++] = ghost_group_list[index].size();
216 debug() << "Send local info i=" << index << " target=" << communicating_ghost_ranks[index]
217 << " nb=" << ghost_group_list[index].size();
218 }
219 time_before_all_gather = platform::getRealTime();
220 if (m_is_verbose) {
221 info() << "AllGather size() " << local_ghost_info.size()
222 << ' ' << global_ghost_info.size()
223 << " begin_date=" << platform::getCurrentDateTime();
224 }
226 time_after_all_gather = platform::getRealTime();
227 if (m_is_verbose) {
228 info() << "AllGather end_date=" << platform::getCurrentDateTime();
229 }
230 }
231 {
232 for (Integer index = 0, s = nb_rank; index < s; ++index) {
233 Integer pos = gather_size * index;
234 Integer sub_size = global_ghost_info[pos++];
235 for (Integer sub_index = 0; sub_index < sub_size; ++sub_index) {
236 Integer proc_id = global_ghost_info[pos++];
237 Integer nb_elem = global_ghost_info[pos++];
238 if (proc_id == my_rank) {
239 if (is_debug) {
240 info() << "Get for share group " << index << ' ' << nb_elem;
241 }
243 }
244 }
245 }
246 }
247
248 {
249 // Créé les infos concernant les mailles fantômes
250 Integer nb_send = communicating_ghost_ranks.size();
251 ghost_rank_info.resize(nb_send);
252 for (Integer i = 0; i < nb_send; ++i) {
255 }
256 }
257 }
258 //pm->barrier();
260 {
261 {
262 // Réciprocité des communications
263 // Pour que les synchronisations se fassent bien, il faut que
264 // 'share_rank_info' et 'ghost_rank_info' aient
265 // le même nombre d'éléments. Si ce n'est pas le cas, c'est
266 // qu'un processeur 'n' possède des mailles partagés avec le proc 'm'
267 // sans que cela soit réciproque. Si c'est le cas, on rajoute
268 // dans 'share_rank_info' une référence à ce sous-domaine
269 // avec aucun élément à envoyer.
270 Integer nb_recv = share_rank_info.size();
271 Integer nb_send = ghost_rank_info.size();
272
273 if (is_debug) {
274 info() << "Infos before auto add: send " << nb_send << " recv " << nb_recv;
275 for (Integer i = 0; i < ghost_rank_info.size(); ++i) {
277 info() << "Ghost: " << i << asdi.nbItem() << ' ' << asdi.rank();
278 }
279 for (Integer i = 0; i < share_rank_info.size(); ++i) {
281 info() << "Shared: " << i << ' ' << asdi.nbItem() << ' ' << asdi.rank();
282 }
283 }
284
285 for (Integer i = 0; i < nb_send; ++i) {
286 Integer proc_id = ghost_rank_info[i].rank();
287 Integer z = 0;
288 for (; z < nb_recv; ++z)
289 if (share_rank_info[z].rank() == proc_id)
290 break;
291 debug(Trace::Highest) << "CHECKS " << proc_id << ' ' << z << ' ' << nb_recv;
292 if (z == nb_recv) {
293 debug() << "Add communication with the subdomain " << proc_id;
295 }
296 }
297
298 for (Integer i = 0; i < nb_recv; ++i) {
299 Integer proc_id = share_rank_info[i].rank();
300 Integer z = 0;
301 for (; z < nb_send; ++z)
302 if (ghost_rank_info[z].rank() == proc_id)
303 break;
304 debug(Trace::Highest) << "CHECKR " << proc_id << ' ' << z << ' ' << nb_send;
305 if (z == nb_send) {
306 debug() << "Add communication with subdomain " << proc_id;
308 }
309 }
310
311 if (ghost_rank_info.size() != share_rank_info.size()) {
312 ARCANE_FATAL("Problem with the number of subdomain shared ({0}) and ghosts ({1})",
313 share_rank_info.size(), ghost_rank_info.size());
314 }
315 // Trie le tableau par numéro croissant de sous-domaine.
316 std::sort(std::begin(share_rank_info), std::end(share_rank_info));
317 std::sort(std::begin(ghost_rank_info), std::end(ghost_rank_info));
318 }
319
320 // Ok, maintenant on connait la liste des sous-domaines qui possèdent
321 // les mailles partagées de ce sous-domaine et réciproquement, la liste des
322 // sous-domaines intéressé par les mailles propres de ce sous-domaine.
323 // Il ne reste qu'à envoyer et recevoir les informations correspondantes.
324 // Pour cela, et afin d'éviter les blocages, on envoie d'abord les infos
325 // pour les sous-domaines dont le numéro est inférieur à ce sous-domaine.
326 Integer nb_comm_proc = ghost_rank_info.size();
327 info(4) << "Number of communicating processors: " << nb_comm_proc;
329 time_before_sendrecv = platform::getRealTime();
330 {
331 //Integer nb_recv = share_rank_info.size();
332
333 // Trie le tableau par numéro croissant de sous-domaine.
334 for (Integer i = 0; i < ghost_rank_info.size(); ++i) {
336 debug() << "Ghost: " << i << " " << asdi.nbItem() << ' ' << asdi.rank();
337 }
338 for (Integer i = 0; i < share_rank_info.size(); ++i) {
340 debug() << "Shared: " << i << " " << asdi.nbItem() << ' ' << asdi.rank();
341 }
342 Integer current_send_index = 0;
343 Integer current_recv_index = 0;
344 for (Integer i = 0; i < nb_comm_proc * 2; ++i) {
345 Integer send_proc = nb_rank;
346 Integer recv_proc = nb_rank;
351 bool do_send = true;
352 if (send_proc == recv_proc) {
353 if (send_proc < my_rank)
354 do_send = true;
355 else
356 do_send = false;
357 }
358 else if (send_proc < recv_proc)
359 do_send = true;
360 else
361 do_send = false;
362 if (do_send) {
364 asdi.resize();
365 Int64ArrayView uids = asdi.uniqueIds();
367 //Integer zindex = 0;
368 Integer nb_local = asdi_local_ids.size();
369 for (Integer z = 0, zs = nb_local; z < zs; ++z) {
370 //for( ItemGroup::const_iter z(asdi.group()); z.hasNext(); ++z, ++zindex ){
372 uids[z] = elem.uniqueId().asInt64();
373 }
374 if (is_debug) {
375 info() << "Number of elements that will be sent to the subdomain " << send_proc
376 << " " << nb_local << " éléments";
377 for (Integer z = 0; z < nb_local; ++z) {
378 info() << "Unique id " << uids[z];
379 }
380 }
381 debug() << "Send proc " << send_proc;
382 if (!uids.empty())
383 requests.add(pm->send(uids, send_proc, false));
385 }
386 else {
388 asdi.resize();
389 Int64ArrayView items_unique_id = asdi.uniqueIds();
390 debug() << "Recv proc " << recv_proc;
391 //TODO utiliser non bloquant.
392 if (!items_unique_id.empty())
394 //String group_name(share_name);
395 //group_name += recv_proc;
396
398 item_family->itemsUniqueIdToLocalId(items_local_id, items_unique_id);
400 debug() << "Creating shared entities for the subdomain " << recv_proc
401 << " with " << items_local_id.size() << " entities";
402 //ItemGroup share_group = mesh->itemFamily(item_kind)->createGroup(group_name,items_local_id,true);
403 //share_group.setLocalToSubDomain(true);
404 asdi.setLocalIds(share_group);
405 if (is_debug) {
406 for (Integer z = 0, zs = share_group.size(); z < zs; ++z) {
407 const Item& item = items_internal[share_group[z]];
408 info() << "Item uid=" << item.uniqueId() << ",lid=" << item.localId();
409 }
410 }
412 }
413 }
414 time_after_sendrecv = platform::getRealTime();
415 if (m_is_verbose) {
416 info() << "Wait requests n=" << requests.size()
417 << " begin_date=" << platform::getCurrentDateTime();
418 }
419 pm->waitAllRequests(requests);
420 time_after_sendrecv_wait = platform::getRealTime();
421 if (m_is_verbose) {
422 info() << "Wait requests end_date=" << platform::getCurrentDateTime();
423 }
424 }
425 }
426 _checkValid(ghost_rank_info, share_rank_info);
427 sync_info->recompute();
428
429 // Vérifie que l'on a trouvé tous les ghosts
430 for (Integer i = 0, n = sync_info->size(); i < n; ++i) {
431 Int32 target_rank = sync_info->targetRank(i);
432 if (sync_info->receiveInfo().nbItem(i) != boundary_items[target_rank].size())
433 ARCANE_FATAL("Inconsistent ghost count");
434 }
435
436 info() << "VariableSynchronize:: end compute list group=" << m_item_group.name()
437 << " t_init=" << Trace::Precision(4, time_before_all_gather - time_begin, true)
438 << " t_allgather=" << Trace::Precision(4, time_after_all_gather - time_before_all_gather, true)
439 << " t_sendrecv=" << Trace::Precision(4, time_after_sendrecv_wait - time_before_sendrecv, true)
441}
442
443/*---------------------------------------------------------------------------*/
444/*---------------------------------------------------------------------------*/
445
446void VariableSynchronizerComputeList::
449{
450 const bool is_debug = m_is_debug;
451 Integer nb_comm_proc = ghost_rank_info.size();
452 Integer nb_error = 0;
453 bool has_error = false;
454 const Integer max_error = 10; // Nombre max d'erreurs affichées.
455 Int32 my_rank = m_parallel_mng->commRank();
456 IItemFamily* item_family = m_item_group.itemFamily();
458
459 // Tableau servant à marquer les éléments qui sont soit
460 // propres au sous-domaine, soit fantômes.
461 // Normalement, si les données sont cohérentes cela devrait marquer
462 // tous les éléments.
463 // NOTE: ceci n'est utile que si \a itemGroup() vaut allItems()
465 marked_elem.fill(false);
466 // Marque les éléments propres au sous-domaine
467 ENUMERATE_ITEM (i_item, m_item_group) {
468 Item item = *i_item;
469 if (item.isOwn()) {
470 marked_elem[item.localId()] = true;
471 if (is_debug) {
472 info() << "Own Item " << ItemPrinter(item);
473 }
474 }
475 }
476
477 for (Integer i_comm = 0; i_comm < nb_comm_proc; ++i_comm) {
478 GhostRankInfo& ghost_info = ghost_rank_info[i_comm];
479 ShareRankInfo& share_info = share_rank_info[i_comm];
480 if (ghost_info.rank() != share_info.rank()) {
481 ARCANE_FATAL("Inconsistency between the subdomain numbers ghost_rank={0} share_rank={1}",
482 ghost_info.rank(), share_info.rank());
483 }
484 Integer current_proc = ghost_info.rank();
485 Int32ConstArrayView ghost_grp = ghost_info.localIds();
486 Int32ConstArrayView share_grp = share_info.localIds();
487
488 if (share_grp.empty() && ghost_grp.empty()) {
489 error() << "Shared and ghosts groups null for the subdomain " << current_proc;
490 has_error = true;
491 continue;
492 }
493 if (current_proc == my_rank) {
494 error() << "Error in the communication pattern: "
495 << "the processor can't communicate with itself";
496 has_error = true;
497 continue;
498 }
499
500 // Marque les éléments du groupe partagé
501 for (Integer z = 0, zs = ghost_grp.size(); z < zs; ++z) {
502 const Item& elem = items_internal[ghost_grp[z]];
503 bool is_marked = marked_elem[elem.localId()];
504 if (is_marked) {
505 // L'élément ne doit pas déjà être marqué.
506 if (nb_error < max_error)
507 error() << "The entity " << ItemPrinter(elem) << " belongs to another ghost group "
508 << "or is owned by the subdomain.";
509 ++nb_error;
510 continue;
511 }
512 marked_elem[elem.localId()] = true;
513 }
514
515 m_synchronizer->m_sync_info->add(VariableSyncInfo(share_grp, ghost_grp, current_proc));
516 }
517
518 // Vérifie que tous les éléments sont marqués
519 ENUMERATE_ITEM (i, m_item_group) {
520 Item item = *i;
521 if (!marked_elem[item.localId()]) {
522 if (nb_error < max_error) {
523 error() << "The entity " << ItemPrinter(item)
524 << " doesn't belong to the subdomain or any ghost group.";
525 }
526 ++nb_error;
527 }
528 }
529
530 // En cas d'erreur, on s'arrête.
531 if (nb_error != 0) {
532 has_error = true;
533 if (nb_error >= max_error)
534 error() << nb_error << " total elements are incorrectly dealt with";
535 }
536 if (has_error)
537 ARCANE_FATAL("Error while creating the exchange structures of the family={0}",
538 item_family->fullName());
539}
540
541/*---------------------------------------------------------------------------*/
542/*---------------------------------------------------------------------------*/
543
544void VariableSynchronizerComputeList::
545_printSyncList()
546{
547 DataSynchronizeInfo* sync_info = m_synchronizer->m_sync_info.get();
548 Integer nb_comm = sync_info->size();
549 info() << "SYNC LIST FOR GROUP : " << m_item_group.fullName() << " N=" << nb_comm;
550 OStringStream ostr;
551 IItemFamily* item_family = m_item_group.itemFamily();
552 ItemInfoListView items_internal(item_family);
553 for (Integer i = 0; i < nb_comm; ++i) {
554 Int32 target_rank = sync_info->targetRank(i);
555 ostr() << " TARGET=" << target_rank << '\n';
556 Int32ConstArrayView share_ids = sync_info->sendInfo().localIds(i);
557 ostr() << "\t\tSHARE(lid,uid) n=" << share_ids.size() << " :";
558 for (Integer z = 0, zs = share_ids.size(); z < zs; ++z) {
559 Item item = items_internal[share_ids[z]];
560 ostr() << " (" << item.localId() << "," << item.uniqueId() << ")";
561 }
562 ostr() << "\n";
563 Int32ConstArrayView ghost_ids = sync_info->receiveInfo().localIds(i);
564 ostr() << "\t\tGHOST(lid,uid) n=" << ghost_ids.size() << " :";
565 for (Integer z = 0, zs = ghost_ids.size(); z < zs; ++z) {
566 Item item = items_internal[ghost_ids[z]];
567 ostr() << " (" << item.localId() << "," << item.uniqueId() << ")";
568 }
569 ostr() << "\n";
570 }
571 info() << ostr.str();
572}
573
574/*---------------------------------------------------------------------------*/
575/*---------------------------------------------------------------------------*/
576
577} // namespace Arcane
578
579/*---------------------------------------------------------------------------*/
580/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_ITEM(name, group)
Enumérateur générique d'un groupe de noeuds.
Informations nécessaires pour synchroniser les entités sur un groupe.
Interface d'une famille d'entités.
virtual String fullName() const =0
Nom complet de la famille (avec celui du maillage)
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 allGather(ConstArrayView< char > send_buf, ArrayView< char > recv_buf)=0
Effectue un regroupement sur tous les processeurs. Il s'agit d'une opération collective....
virtual void waitAllRequests(ArrayView< Request > rvalues)=0
Bloque en attendant que les requêtes rvalues soient terminées.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
Classe de base pour les entités du maillage.
Vue sur une liste pour obtenir des informations sur les entités.
Classe utilitaire pour imprimer les infos sur une entité.
Definition ItemPrinter.h:35
Classe de base d'un élément de maillage.
Definition Item.h:83
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:210
bool isOwn() const
true si l'entité est appartient au sous-domaine
Definition Item.h:244
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:216
impl::ItemBase itemBase() const
Partie interne de l'entité.
Definition Item.h:354
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Vue modifiable d'un tableau d'un type T.
constexpr bool empty() const noexcept
Retourne true si le tableau est vide (dimension nulle)
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Formattage des réels avec une précision donnée.
Vecteur 1D de données avec sémantique par valeur (style STL).
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
ConstArrayView< Int32 > Int32ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:640
Int32 Integer
Type représentant un entier.