Arcane  4.1.11.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
MeshExchanger.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 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/* MeshExchanger.cc (C) 2000-2025 */
9/* */
10/* Gestion d'un échange de maillage entre sous-domaines. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/FatalErrorException.h"
15#include "arcane/utils/TraceInfo.h"
16#include "arcane/utils/PlatformUtils.h"
17#include "arcane/utils/ValueConvert.h"
18
19#include "arcane/IParallelMng.h"
20#include "arcane/Timer.h"
21#include "arcane/IItemFamilyPolicyMng.h"
22#include "arcane/IItemFamilyExchanger.h"
23#include "arcane/IParticleFamily.h"
24
25#include "arcane/mesh/MeshExchanger.h"
26#include "arcane/mesh/DynamicMesh.h"
27#include "arcane/mesh/MeshExchange.h"
28#include "arcane/core/internal/IMeshModifierInternal.h"
29#include "arcane/core/internal/IItemFamilySerializerMngInternal.h"
30#include "arcane/core/internal/IMeshInternal.h"
31
32/*---------------------------------------------------------------------------*/
33/*---------------------------------------------------------------------------*/
34
35namespace Arcane::mesh
36{
37
38/*---------------------------------------------------------------------------*/
39/*---------------------------------------------------------------------------*/
40
41MeshExchanger::
42MeshExchanger(IMesh* mesh,ITimeStats* stats)
43: TraceAccessor(mesh->traceMng())
44, m_mesh(mesh)
45, m_time_stats(stats)
46, m_phase(ePhase::Init)
47{
48 // Temporairement utilise une variable d'environnement pour spécifier le
49 // nombre maximum de messages en vol ou si on souhaite utiliser les collectives
50 String max_pending_str = platform::getEnvironmentVariable("ARCANE_MESH_EXCHANGE_MAX_PENDING_MESSAGE");
51 if (!max_pending_str.null()){
52 Int32 max_pending = 0;
53 if (!builtInGetValue(max_pending,max_pending_str))
54 m_exchanger_option.setMaxPendingMessage(max_pending);
55 }
56
57 String use_collective_str = platform::getEnvironmentVariable("ARCANE_MESH_EXCHANGE_USE_COLLECTIVE");
58 if (use_collective_str=="1" || use_collective_str=="TRUE")
59 m_exchanger_option.setExchangeMode(ParallelExchangerOptions::EM_Collective);
60
61 m_exchanger_option.setVerbosityLevel(1);
62}
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
66
67MeshExchanger::
68~MeshExchanger()
69{
70 for( IItemFamilyExchanger* exchanger : m_family_exchangers )
71 delete exchanger;
72}
73
74/*---------------------------------------------------------------------------*/
75/*---------------------------------------------------------------------------*/
76
77/*---------------------------------------------------------------------------*/
78/*---------------------------------------------------------------------------*/
79
80void MeshExchanger::
81build()
82{
83 if ( !m_mesh->itemFamilyNetwork() || !IItemFamilyNetwork::plug_serializer )
84 { // handle family order by hand
85 // Liste ordonnée des familles triée spécifiquement pour garantir un certain ordre
86 // dans les échanges. Pour l'instant l'ordre est déterminé comme suit:
87 // - d'abord Cell, puis Face, Edge et Node
88 // - ensuite, les Particles doivent être gérées avant les familles de DualNode.
89 UniqueArray<IItemFamily*> sorted_families;
90 IItemFamilyCollection families(m_mesh->itemFamilies());
91 sorted_families.reserve(families.count());
92 sorted_families.add(m_mesh->cellFamily());
93 sorted_families.add(m_mesh->faceFamily());
94 sorted_families.add(m_mesh->edgeFamily());
95 sorted_families.add(m_mesh->nodeFamily());
96 for( IItemFamily* family : families )
97 {
98 IParticleFamily* particle_family = family->toParticleFamily();
99 if (particle_family)
100 sorted_families.add(family);
101 }
102
103 // Liste des instances gérant les échanges d'une famille.
104 // ATTENTION: il faut garantir la libération des pointeurs associés.
105 //m_family_exchangers.reserve(families.count());
106
107 // Création de chaque échangeur associé à une famille.
108 std::map<IItemFamily*,IItemFamilyExchanger*> family_exchanger_map;
109 for( IItemFamily* family : sorted_families ){
110 _addItemFamilyExchanger(family);
111 }
112 }
113 else
114 {
115 if(m_mesh->useMeshItemFamilyDependencies())
116 {
117 _buildWithItemFamilyNetwork();
118 }
119 else
120 {
121 std::set<String> family_set ;
122 UniqueArray<IItemFamily*> sorted_families;
123 IItemFamilyCollection families(m_mesh->itemFamilies());
124 sorted_families.reserve(families.count());
125 sorted_families.add(m_mesh->cellFamily());
126 family_set.insert(m_mesh->cellFamily()->name()) ;
127 sorted_families.add(m_mesh->faceFamily());
128 family_set.insert(m_mesh->faceFamily()->name()) ;
129 sorted_families.add(m_mesh->edgeFamily());
130 family_set.insert(m_mesh->edgeFamily()->name()) ;
131 sorted_families.add(m_mesh->nodeFamily());
132 family_set.insert(m_mesh->nodeFamily()->name()) ;
133 for( IItemFamily* family : families )
134 {
135 IParticleFamily* particle_family = family->toParticleFamily();
136 if (particle_family)
137 {
138 sorted_families.add(family);
139 family_set.insert(family->name()) ;
140 }
141 }
142
143 for( auto family : m_mesh->itemFamilyNetwork()->getFamilies(IItemFamilyNetwork::InverseTopologicalOrder) )
144 {
145 auto value = family_set.insert(family->name()) ;
146 if(value.second)
147 {
148 sorted_families.add(family) ;
149 }
150 }
151
152 // Liste des instances gérant les échanges d'une famille.
153 // ATTENTION: il faut garantir la libération des pointeurs associés.
154 //m_family_exchangers.reserve(families.count());
155
156 // Création de chaque échangeur associé à une famille.
157 std::map<IItemFamily*,IItemFamilyExchanger*> family_exchanger_map;
158 for( IItemFamily* family : sorted_families ){
159 _addItemFamilyExchanger(family);
160 }
161 }
162 }
163 m_phase = ePhase::ComputeInfos;
164}
165
166/*---------------------------------------------------------------------------*/
167/*---------------------------------------------------------------------------*/
168
169void MeshExchanger::
170_buildWithItemFamilyNetwork()
171{
172 m_mesh->itemFamilyNetwork()->schedule([&](IItemFamily* family) {
173 _addItemFamilyExchanger(family);
174 }, IItemFamilyNetwork::InverseTopologicalOrder);
175 // Particle should be handled soon
176 for( IItemFamily* family : m_mesh->itemFamilies() ){
177 IParticleFamily* particle_family = family->toParticleFamily();
178 if (particle_family)
179 _addItemFamilyExchanger(family);
180 }
181}
182
183/*---------------------------------------------------------------------------*/
184/*---------------------------------------------------------------------------*/
185
186void MeshExchanger::
187_addItemFamilyExchanger(IItemFamily* family)
188{
189 IItemFamilyExchanger* exchanger = family->policyMng()->createExchanger();
190 m_family_exchangers.add(exchanger);
191 m_family_exchanger_map.insert(std::make_pair(family,exchanger));
192 exchanger->setParallelExchangerOption(m_exchanger_option);
193}
194
195/*---------------------------------------------------------------------------*/
196/*---------------------------------------------------------------------------*/
197
198void MeshExchanger::
199_checkPhase(ePhase wanted_phase)
200{
201 if (m_phase!=wanted_phase)
202 ARCANE_FATAL("Invalid exchange phase wanted={0} current={1}",
203 (int)wanted_phase,(int)m_phase);
204}
205
206/*---------------------------------------------------------------------------*/
207/*---------------------------------------------------------------------------*/
208
209bool MeshExchanger::
210computeExchangeInfos()
211{
212 _checkPhase(ePhase::ComputeInfos);
213
214 // TODO: faire en sorte de pouvoir customiser le calcul de l'échange
215 // et faire cela par famille si possible.
216 MeshExchange mesh_exchange(m_mesh);
217 info() << "MeshExchange begin date=" << platform::getCurrentDateTime();
218 {
219 Timer::Action ts_action1(m_time_stats,"MeshExchangeComputeInfos",true);
220 mesh_exchange.computeInfos();
221 // MeshExchange a mise une marque NeedRemove sur les cellules partant complètement de ce proc
222 }
223
224 IItemFamily* cell_family = m_mesh->cellFamily();
225 IItemFamilyExchanger* cell_exchanger = findExchanger(cell_family);
226
227 // Détermine d'abord les infos à échanger sur les mailles car s'il n'y a aucune maille
228 // à échanger le partitionnement s'arête.
229 // NOTE GG: il faut voir si cela reste le cas avec les liens et les noeuds duaux.
230 cell_exchanger->setExchangeItems(mesh_exchange.getItemsToSend(cell_family));
231 if (cell_exchanger->computeExchangeInfos()){
232 pwarning() << "No load balance is performed";
233 return true;
234 }
235
236 // Détermine pour chaque famille la liste des informations à échanger.
237 for( IItemFamilyExchanger* exchanger : m_family_exchangers ){
238 // L'échange des mailles a déjà été fait.
239 if (exchanger==cell_exchanger)
240 continue;
241 IItemFamily* family = exchanger->itemFamily();
242 info() << "ComputeExchange family=" << family->name()
243 << " date=" << platform::getCurrentDateTime();
244 // Pour les familles de particules qui ne supportent pas la notion
245 // de fantôme, il faut déterminer explicitement la liste des entités à échanger
246 // via l'appel à computeExchangeItems().
247 // Pour les autres familles où les familles de particules qui on la notion
248 // de fantôme, cette liste à déjà été déterminée lors de l'appel à
249 // mesh_exchange.computeInfos().
250 IParticleFamily* particle_family = family->toParticleFamily() ;
251 if (particle_family && particle_family->getEnableGhostItems()==false)
252 exchanger->computeExchangeItems();
253 else
254 exchanger->setExchangeItems(mesh_exchange.getItemsToSend(family));
255 exchanger->computeExchangeInfos();
256 }
257
258 // Recopie le champ owner() dans les ItemInternal pour qu'il
259 // soit cohérent avec la variable correspondante
260
261 // ATTENTION: Il faut absolument que les owner() des ItemInternal
262 // soient corrects avant qu'on envoie les mailles qui nous appartenaient
263 // aux sous-domaines à qui elles vont ensuite appartenir.
264
265 // A noter qu'on ne peut pas fusionner cette boucle avec la précédente car
266 // les familles ont besoin des infos des autres familles pour déterminer
267 // la liste des entités à envoyer.
268 Int32 rank = m_mesh->meshPartInfo().partRank();
269 for( IItemFamilyExchanger* exchanger : m_family_exchangers ){
270 IItemFamily* family = exchanger->itemFamily();
271 VariableItemInt32& owners(family->itemsNewOwner());
272 ENUMERATE_ITEM(i,family->allItems()){
273 Item item = *i;
274 Integer new_owner = owners[item];
275 item.mutableItemBase().setOwner(new_owner,rank);
276 }
277 family->notifyItemsOwnerChanged();
278 }
279
280 m_phase = ePhase::ProcessExchange;
281
282 return false;
283}
284
285/*---------------------------------------------------------------------------*/
286/*---------------------------------------------------------------------------*/
287
288void MeshExchanger::
289processExchange()
290{
291 _checkPhase(ePhase::ProcessExchange);
292
293 info() << "ExchangeItems date=" << platform::getCurrentDateTime()
294 << " MemUsed=" << platform::getMemoryUsed();
295
296 Timer::Action ts_action1(m_time_stats,"MessagesExchange",true);
297 for( IItemFamilyExchanger* e : m_family_exchangers ){
298 // NOTE: Pour pouvoir envoyer tous les messages en même temps et les réceptions
299 // aussi, il faudra peut être prévoir d'utiliser des tags MPI.
300 e->prepareToSend(); // Préparation de toutes les données à envoyer puis sérialisation
301 e->processExchange(); // Envoi effectif
302 e->releaseBuffer();
303 }
304 m_phase = ePhase::RemoveItems;
305}
306
307/*---------------------------------------------------------------------------*/
308/*---------------------------------------------------------------------------*/
309
310void MeshExchanger::
311removeNeededItems()
312{
313 _checkPhase(ePhase::RemoveItems);
314
315 // Maintenant que tous les messages avec le maillage avant modification
316 // sont envoyés et réceptionnés, on peut modifier ce maillage en lui
317 // supprimant les éléments qui ne lui appartiennent plus et en ajoutant
318 // les nouveaux.
319
320 // TODO: faire la méthode de supression par famille.
321
322 // Pour les familles autres que les particules sans fantômes, cela
323 // se fait dans le DynamicMeshIncrementalBuilder.
324 // Pour les particules sans fantôme, cela se fait ici.
325 info() << "RemoveItems date=" << platform::getCurrentDateTime();
326 Timer::Action ts_action1(m_time_stats,"RemoveSendedItems",true);
327
328 for( IItemFamilyExchanger* exchanger : m_family_exchangers ){
329 IParticleFamily* particle_family = exchanger->itemFamily()->toParticleFamily() ;
330 if (particle_family && particle_family->getEnableGhostItems()==false)
331 exchanger->removeSentItems(); // integre le traitemaint des sous-maillages (pour les particules)
332 }
333
334 // Supprime les entités qui ne sont plus liées au sous-domaine
335 m_mesh->modifier()->_modifierInternalApi()->removeNeedRemoveMarkedItems();
336
337 m_phase = ePhase::AllocateItems;
338}
339
340/*---------------------------------------------------------------------------*/
341/*---------------------------------------------------------------------------*/
342
343void MeshExchanger::
344allocateReceivedItems()
345{
346 _checkPhase(ePhase::AllocateItems);
347 {
348 info() << "AllocItems date=" << platform::getCurrentDateTime();
349 Timer::Action ts_action1(m_time_stats,"ReadAndAllocItems",true);
350 // Il faut faire en premier l'échange de mailles
351 // Cela est garanti par le fait que le premier élément de family_exchangers
352 // est celui de la famille de maille.
353 for( IItemFamilyExchanger* e : m_family_exchangers ){
354 e->readAndAllocItems(); // Attention, ne procède plus sur les différents sous-maillages
355 }
356 // If needed, finalize item allocations (for polyhedral meshes)
357 auto* family_serializer_mng = m_mesh->_internalApi()->familySerializerMng();
358 if (family_serializer_mng) family_serializer_mng->finalizeItemAllocation();
359
360 // Build item relations (only dependencies are build in readAndAllocItems)
361 // only for families registered in the graph
362 if (m_mesh->itemFamilyNetwork() && m_mesh->itemFamilyNetwork()->isActivated())
363 {
364 auto family_set = m_mesh->itemFamilyNetwork()->getFamilies();
365 for (auto family : family_set) {
366 m_family_exchanger_map[family]->readAndAllocItemRelations();
367 }
368 }
369
370 // Separate mesh and submesh
371 for( IItemFamilyExchanger* e : m_family_exchangers ){
372 e->readAndAllocSubMeshItems(); // Procède sur les différents sous-maillages
373 }
374 }
375
376 // Il est possible que les propriétaires des entités aient changés
377 // suite a readAndAllocItems() même si aucune entité n'a été ajoutée.
378 // Il faut donc l'indiquer aux familles.
379 for( IItemFamilyExchanger* e : m_family_exchangers ){
380 e->itemFamily()->notifyItemsOwnerChanged(); // appliqué jusqu'à un niveau de sous-maillage
381 }
382
383 m_phase = ePhase::UpdateItemGroups;
384}
385
386/*---------------------------------------------------------------------------*/
387/*---------------------------------------------------------------------------*/
388
389void MeshExchanger::
390updateItemGroups()
391{
392 _checkPhase(ePhase::UpdateItemGroups);
393
394 info() << "ReadGroups date=" << platform::getCurrentDateTime();
395 // Maintenant que le nouveau maillage est créé on lit les groupes
396 for( IItemFamilyExchanger* e : m_family_exchangers )
397 e->readGroups();
398
399 m_phase = ePhase::UpdateVariables;
400}
401
402/*---------------------------------------------------------------------------*/
403/*---------------------------------------------------------------------------*/
404
405void MeshExchanger::
406updateVariables()
407{
408 _checkPhase(ePhase::UpdateVariables);
409
410 info() << "ReadVariables date=" << platform::getCurrentDateTime();
411 Timer::Action ts(m_time_stats,"ReadVariables",true);
412 // Maintenant que les entités sont créées et les groupes mis à jour,
413 // on peut mettre à jour les variables.
414 for( IItemFamilyExchanger* e : m_family_exchangers )
415 e->readVariables();
416
417 m_phase = ePhase::Finalize;
418}
419
420/*---------------------------------------------------------------------------*/
421/*---------------------------------------------------------------------------*/
422
423void MeshExchanger::
424finalizeExchange()
425{
426 _checkPhase(ePhase::Finalize);
427
428 // Finalize les échanges
429 // Cela doit etre fait apres le compactage car dans le cas des interfaces liees,
430 // il ne faut plus changer la numérotation des localId() une fois les
431 // structures TiedInterface mises à jour.
432 // TODO: il faudra supprimer cela en faisant ce traitement avant mais
433 // pour cela il faut que TiedInterfaceMng soit notifié du compactage pour
434 // mettre à jour les localId() de ses faces et de ses noeuds
435 for( IItemFamilyExchanger* e : m_family_exchangers )
436 e->finalizeExchange();
437
438 m_phase = ePhase::Ended;
439}
440
441/*---------------------------------------------------------------------------*/
442/*---------------------------------------------------------------------------*/
443
444IItemFamilyExchanger* MeshExchanger::
445findExchanger(IItemFamily* family)
446{
447 auto x = m_family_exchanger_map.find(family);
448 if (x==m_family_exchanger_map.end())
449 ARCANE_FATAL("No exchanger for family name={0}",family->name());
450 return x->second;
451}
452
453/*---------------------------------------------------------------------------*/
454/*---------------------------------------------------------------------------*/
455
456IPrimaryMesh* MeshExchanger::
457mesh() const
458{
459 return m_mesh->toPrimaryMesh();
460}
461
462/*---------------------------------------------------------------------------*/
463/*---------------------------------------------------------------------------*/
464
465void MeshExchanger::
466_setNextPhase(ePhase next_phase)
467{
468 m_phase = next_phase;
469}
470
471/*---------------------------------------------------------------------------*/
472/*---------------------------------------------------------------------------*/
473
474} // End namespace Arcane::mesh
475
476/*---------------------------------------------------------------------------*/
477/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_ITEM(name, group)
Enumérateur générique d'un groupe de noeuds.
Échange des entités et leurs caractéristiques pour une famille donnée.
virtual bool computeExchangeInfos()=0
Détermine les informations nécessaires pour les échanges.
virtual void setExchangeItems(ConstArrayView< std::set< Int32 > > items_to_send)=0
Positionne la liste des entités à échanger.
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual IParticleFamily * toParticleFamily()=0
Retourne l'interface de la famille de particule de cette famille.
virtual ItemGroup allItems() const =0
Groupe de toutes les entités.
virtual String name() const =0
Nom de la famille.
virtual void notifyItemsOwnerChanged()=0
Notifie que les entités propres au sous-domaine de la famille ont été modifiées.
virtual VariableItemInt32 & itemsNewOwner()=0
Variable contenant le numéro du nouveau sous-domaine propriétaire de l'entité.
virtual IPrimaryMesh * toPrimaryMesh()=0
Retourne l'instance sous la forme d'un IPrimaryMesh.
Interface d'une famille de particules.
virtual bool getEnableGhostItems() const =0
récupère le flag pour gérer les particules ghost de la famille
virtual IItemFamily * itemFamily()=0
Interface sur la famille.
Classe de base d'un élément de maillage.
Definition Item.h:83
impl::MutableItemBase mutableItemBase() const
Partie interne modifiable de l'entité.
Definition Item.h:380
void setOwner(Integer suid, Int32 current_sub_domain)
Positionne le numéro du sous-domaine propriétaire de l'entité.
Postionne le nom de l'action en cours d'exécution.
Definition Timer.h:110
TraceMessage info() const
Flot pour un message d'information.
TraceMessage pwarning() const
Echange des entités de maillages entre entre sous-domaines.
ConstArrayView< std::set< Int32 > > getItemsToSend(IItemFamily *family) const
Liste par sous-domaine des entités à envoyer pour la famille family.
void computeInfos()
Calcule les infos.
IItemFamilyExchanger * findExchanger(IItemFamily *family) override
Échangeur associé à la famille family. Lance une exception si non trouvé
ItemVariableScalarRefT< Int32 > VariableItemInt32
Grandeur de type entier 32 bits.
double getMemoryUsed()
Mémoire utilisée em octets.
String getCurrentDateTime()
Date et l'heure courante sous la forme ISO 8601.
Int32 Integer
Type représentant un entier.
Collection< IItemFamily * > IItemFamilyCollection
Collection de familles d'entités.
std::int32_t Int32
Type entier signé sur 32 bits.