Arcane  v4.1.0.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.
ARCCORE_BASE_EXPORT String getCurrentDateTime()
Date et l'heure courante sous la forme ISO 8601.
ARCCORE_BASE_EXPORT double getMemoryUsed()
Mémoire utilisée em octets.
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.