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