Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
DynamicMeshMerger.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/* DynamicMeshMerger.cc (C) 2000-2023 */
9/* */
10/* Fusion de plusieurs maillages. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/mesh/DynamicMeshMerger.h"
15#include "arcane/mesh/DynamicMesh.h"
16
17#include "arcane/utils/ITraceMng.h"
18#include "arcane/utils/ScopedPtr.h"
19
20#include "arcane/IParallelSuperMng.h"
21#include "arcane/IParallelMng.h"
22#include "arcane/ServiceBuilder.h"
23#include "arcane/IArcaneMain.h"
24#include "arcane/IMainFactory.h"
25
26#include "arcane/mesh/MeshExchanger.h"
27#include "arcane/mesh/MeshExchangeMng.h"
28#include "arcane/mesh/MeshExchanger.h"
29#include "arcane/IMeshExchanger.h"
30#include "arcane/IMeshExchangeMng.h"
31#include "arcane/IItemFamilyExchanger.h"
32#include "arcane/ItemPrinter.h"
33#include "arcane/MeshVisitor.h"
34
35#include "arccore/base/ReferenceCounter.h"
36
37#include <thread>
38
39/*---------------------------------------------------------------------------*/
40/*---------------------------------------------------------------------------*/
41
42namespace Arcane::mesh
43{
44
45/*---------------------------------------------------------------------------*/
46/*---------------------------------------------------------------------------*/
47
49: public TraceAccessor
50{
51 public:
53 IParallelMng* pm,Int32 local_rank)
54 : TraceAccessor(tm), m_mesh(mesh), m_parallel_mng(pm), m_local_rank(local_rank) {}
55 public:
56 void doMerge();
57 private:
58 DynamicMesh* m_mesh;
59 IParallelMng* m_parallel_mng;
60 Int32 m_local_rank;
61};
62
63/*---------------------------------------------------------------------------*/
64/*---------------------------------------------------------------------------*/
65
66DynamicMeshMerger::
67DynamicMeshMerger(DynamicMesh* mesh)
68: TraceAccessor(mesh->traceMng())
69 , m_mesh(mesh)
70{
71}
72
73/*---------------------------------------------------------------------------*/
74/*---------------------------------------------------------------------------*/
75
76DynamicMeshMerger::
77~DynamicMeshMerger()
78{
79}
80
81/*---------------------------------------------------------------------------*/
82/*---------------------------------------------------------------------------*/
83
84namespace
85{
86class LauncherThreadInfo
87{
88 public:
89 LauncherThreadInfo() : m_mesh(nullptr), m_local_rank(-1), m_has_error(false){}
90 public:
91 DynamicMesh* m_mesh;
92 Int32 m_local_rank;
93 bool m_has_error;
94 ReferenceCounter<ITraceMng> m_trace_mng;
95 Ref<IParallelMng> m_parallel_mng;
96};
97
98void
99_doLaunch(LauncherThreadInfo* lti)
100{
101 Int32 local_rank = lti->m_local_rank;
102 IParallelMng* pm = lti->m_parallel_mng.get();
103 ITraceMng* tm = lti->m_trace_mng.get();
104 pm->barrier();
105 tm->info() << "BEGIN LAUNCHER rank=" << local_rank << "!\n";
106 pm->barrier();
107 DynamicMeshMergerHelper helper(lti->m_trace_mng.get(),lti->m_mesh,pm,local_rank);
108 helper.doMerge();
109 tm->info() << "END EXCHANGE!\n";
110 pm->barrier();
111}
112
113void
114_Launcher(LauncherThreadInfo* lti)
115{
116 ITraceMng* tm = lti->m_trace_mng.get();
117 try{
118 _doLaunch(lti);
119 }
120 catch(const Exception& ex){
121 tm->info() << "FATAL: " << tm->traceId()
122 << " ex=" << ex
123 << " stack=" << ex.stackTrace();
124 lti->m_has_error = true;
125 throw;
126 }
127 catch(const std::exception& ex){
128 tm->info() << "FATAL: " << ex.what();
129 lti->m_has_error = true;
130 throw;
131 }
132 catch(...){
133 tm->info() << "UNKNOWN FATAL";
134 lti->m_has_error = true;
135 throw;
136 }
137}
138class MergeMeshExchanger
139: public MeshExchanger
140{
141 public:
142 // TODO: faire son propre timeStats()
143 MergeMeshExchanger(DynamicMesh* mesh,Int32 local_rank)
144 : MeshExchanger(mesh,mesh->subDomain()->timeStats()), m_local_rank(local_rank){}
145 public:
152 bool computeExchangeInfos() override
153 {
154 mesh()->traceMng()->info() << "OVERRIDE COMPUTE EXCHANGE INFOS";
155 // Si je ne suis pas le rang local 0, je donne toutes mes entités.
156 UniqueArray<std::set<Int32>> items_to_send;
157 Int32 nb_rank = mesh()->parallelMng()->commSize();
158 items_to_send.resize(nb_rank);
159
160 for( IItemFamily* family : mesh()->itemFamilies() ){
161 IItemFamilyExchanger* family_exchanger = this->findExchanger(family);
162 if (m_local_rank!=0){
163 items_to_send[0].clear();
164 ItemGroup all_items = family->allItems();
165 // Change les propriétaires pour correspondre au nouveau découpage.
166 ENUMERATE_ITEM(iitem,all_items){
167 Item ii = *iitem;
168 items_to_send[0].insert(iitem.itemLocalId());
169 // Les entités transférées seront supprimées.
170 // NOTE: il serait possible de rendre cela optionnel si on
171 // ne souhaite pas modifier le maillage qui est fusionné.
172 ii.mutableItemBase().addFlags(ItemFlags::II_NeedRemove);
173 }
174 family_exchanger->setExchangeItems(items_to_send);
175 }
176 family_exchanger->computeExchangeInfos();
177 }
178
179 _setNextPhase(ePhase::ProcessExchange);
180 return false;
181 }
182 private:
183 Int32 m_local_rank;
184};
185
186class MergerExchangeMng
187: public MeshExchangeMng
188{
189 public:
190 MergerExchangeMng(DynamicMesh* mesh,Int32 local_rank)
191 : MeshExchangeMng(mesh), m_mesh(mesh), m_local_rank(local_rank){}
192 protected:
193 IMeshExchanger* _createExchanger() override
194 {
195 m_mesh->traceMng()->info() << "CREATE MERGE MESH_EXCHANGER";
196 MeshExchanger* ex = new MergeMeshExchanger(m_mesh,m_local_rank);
197 ex->build();
198 return ex;
199 }
200 private:
201 DynamicMesh* m_mesh;
202 Int32 m_local_rank;
203};
204}
205
206/*---------------------------------------------------------------------------*/
207/*---------------------------------------------------------------------------*/
208
209void DynamicMeshMergerHelper::
210doMerge()
211{
212 // TODO: cette routine est similaire à DynamicMesh::_exchangeItemsNew()
213 // et il faudrait fusionner les deux. Cela sera plus facile lorsque les
214 // anciennes connectivités auront disparues.
215
216 // Surcharge temporairement le IParallelMng
217 // TODO: Vérifier que c'est bien remis à la bonne valeur en sortie en cas
218 // d'exception
219
220 IParallelMng* old_parallel_mng = m_mesh->m_parallel_mng;
221 m_mesh->m_parallel_mng = this->m_parallel_mng;
222
223 // TODO: Vérifier que tout le monde a les mêmes familles et dans le même ordre.
224 info() << "DOING MERGE pm_rank=" << m_mesh->parallelMng()->commRank()
225 << " sd_part=" << m_mesh->meshPartInfo().partRank();
226
227 // Cascade tous les maillages associés à ce maillage
228 typedef Collection<DynamicMesh*> DynamicMeshCollection;
229 DynamicMeshCollection all_cascade_meshes = List<DynamicMesh*>();
230 all_cascade_meshes.add(m_mesh);
231 for(Integer i=0;i<m_mesh->m_child_meshes.size();++i)
232 all_cascade_meshes.add(m_mesh->m_child_meshes[i]);
233
234 MergerExchangeMng exchange_mng(m_mesh,m_local_rank);
235 IMeshExchanger* iexchanger = exchange_mng.beginExchange();
236 IMeshExchanger* mesh_exchanger = iexchanger;
237
238 // S'il n'y a aucune entité à échanger, on arrête immédiatement l'échange.
239 if (mesh_exchanger->computeExchangeInfos()){
240 pwarning() << "No load balance is performed";
241 exchange_mng.endExchange();
242 m_mesh->m_parallel_mng = old_parallel_mng;
243 return;
244 }
245
246 // Éffectue l'échange des infos
247 mesh_exchanger->processExchange();
248
249 // Supprime les entités qui ne doivent plus être dans notre sous-domaine.
250 mesh_exchanger->removeNeededItems();
251
252 // Réajuste les groupes en supprimant les entités qui ne sont plus dans le maillage ou en
253 // invalidant les groupes calculés.
254 // TODO: faire une méthode de la famille qui fait cela.
255 {
256 auto action = [](ItemGroup& group)
257 {
258 if (group.internal()->hasComputeFunctor() || group.isLocalToSubDomain())
259 group.invalidate();
260 else
261 group.internal()->removeSuppressedItems();
262 };
263 for( DynamicMesh* mesh : all_cascade_meshes ){
264 meshvisitor::visitGroups(mesh,action);
265 }
266 }
267
268 // Créé les entités qu'on a recu des autres sous-domaines.
269 mesh_exchanger->allocateReceivedItems();
270
271 // On reprend maintenant un cycle standard de endUpdate
272 // mais en entrelaçant les niveaux de sous-maillages
273 for( DynamicMesh* mesh : all_cascade_meshes )
274 mesh->_internalEndUpdateInit(true);
275
276 mesh_exchanger->updateItemGroups();
277
278 // Recalcule des synchroniseurs sur groupes.
279 for( DynamicMesh* mesh : all_cascade_meshes )
280 mesh->_computeGroupSynchronizeInfos();
281
282 // Met à jour les valeurs des variables des entités receptionnées
283 mesh_exchanger->updateVariables();
284
285 // Finalise les modifications dont le triage et compactage
286 for( DynamicMesh* mesh : all_cascade_meshes ){
287 // Demande l'affichage des infos pour le maillage actuel
288 bool print_info = (mesh==m_mesh);
289 mesh->_internalEndUpdateFinal(print_info);
290 }
291
292 // Finalize les échanges
293 // Pour l'instante cela n'est utile que pour les TiedInterface mais il
294 // faudrait supprimer cela.
295 mesh_exchanger->finalizeExchange();
296
297 // TODO: garantir cet appel en cas d'exception.
298 exchange_mng.endExchange();
299
300 m_mesh->endUpdate();
301
302 m_mesh->m_parallel_mng = old_parallel_mng;
303}
304
305/*---------------------------------------------------------------------------*/
306/*---------------------------------------------------------------------------*/
307
308void DynamicMeshMerger::
309mergeMeshes(ConstArrayView<DynamicMesh*> meshes)
310{
311 UniqueArray<DynamicMesh*> all_meshes;
312 // Le premier maillage de \a all_meshes est celui qui contiendra
313 // à la fin la fusion des maillages de \a meshes.
314 all_meshes.add(m_mesh);
315 for( auto mesh : meshes )
316 all_meshes.add(mesh);
317
318 // L'algorithme de fusion utilise le même mécanisme que pour les échanges
319 // d'entités (MeshExchanger). Pour pouvoir fonctionner, il faut créer
320 // un IParallelMng par maillage fusionné. On utilise donc un
321 // IParallelMng en mémoire partagé, et on lance un thread par
322 // maillage. Le maillage de rang 0 recevra toutes les entités.
323
324 IArcaneMain* am = IArcaneMain::arcaneMain();
325 Int32 nb_local_rank = all_meshes.size();
326 // Recherche le service utilisé pour le parallélisme
327 String message_passing_service = "SharedMemoryParallelMngContainerFactory";
328 ServiceBuilder<IParallelMngContainerFactory> sf(am->application());
329 auto pbf = sf.createReference(message_passing_service,SB_AllowNull);
330 if (!pbf)
331 ARCANE_FATAL("Can not find service '{0}' implementing IParallelMngContainerFactory",message_passing_service);
332 Parallel::Communicator comm = m_mesh->parallelMng()->communicator();
333 Ref<IParallelMngContainer> parallel_builder(pbf->_createParallelMngBuilder(nb_local_rank,comm));
334
335 IApplication* app = am->application();
336 UniqueArray<LauncherThreadInfo> launch_infos(nb_local_rank);
337 for( Integer i=0; i<nb_local_rank; ++i ){
338 LauncherThreadInfo& lti = launch_infos[i];
339
340 Int32 local_rank = i;
341 Int32 mesh_part_rank = all_meshes[i]->meshPartInfo().partRank();
342 String file_suffix = String::format("mm_{0}",mesh_part_rank);
343 lti.m_trace_mng = app->createAndInitializeTraceMng(m_mesh->traceMng(),file_suffix);
344 ITraceMng* tm = lti.m_trace_mng.get();
345 lti.m_parallel_mng = parallel_builder->_createParallelMng(local_rank,tm);
346 tm->setTraceId(String::format("Exchanger part={0} pm_rank={1}",mesh_part_rank,local_rank));
347
348 lti.m_mesh = all_meshes[i];
349 lti.m_local_rank = local_rank;
350 }
351
352 UniqueArray<std::thread*> gths(nb_local_rank);
353 for( Integer i=0; i<nb_local_rank; ++i ){
354 gths[i] = new std::thread(_Launcher,&launch_infos[i]);
355 }
356 bool has_error = false;
357 for( Integer i=0; i<nb_local_rank; ++i ){
358 gths[i]->join();
359 if (launch_infos[i].m_has_error)
360 has_error = true;
361 delete gths[i];
362 }
363 // TODO: propager l'exception via std::exception_ptr
364 if (has_error)
365 ARCANE_FATAL("Error during mesh merge");
366}
367
368/*---------------------------------------------------------------------------*/
369/*---------------------------------------------------------------------------*/
370
371} // End namespace Arcane::mesh
372
373/*---------------------------------------------------------------------------*/
374/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_ITEM(name, group)
Enumérateur générique d'un groupe de noeuds.
static IArcaneMain * arcaneMain()
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual Parallel::Communicator communicator() const =0
Communicateur MPI associé à ce gestionnaire.
virtual void barrier()=0
Effectue une barière.
@ II_NeedRemove
L'entité doit être supprimé
Definition ItemFlags.h:55
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Implémentation d'un maillage.
Definition DynamicMesh.h:97
ITraceMng * traceMng() override
Gestionnaire de message associé
IParallelMng * parallelMng() override
Gestionnaire de parallèlisme.
const MeshPartInfo & meshPartInfo() const override
Informations sur les parties du maillage.
void endUpdate() override
Notifie l'instance de la fin de la modification du maillage.
Interface du gestionnaire de traces.
virtual TraceMessage info()=0
Flot pour un message d'information.
TraceMessage pwarning() const
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage info() const
Flot pour un message d'information.
void add(ArrayView< T > lhs, ConstArrayView< T > copy_array)
Ajoute le tableau copy_array dans l'instance.
Definition MathUtils.h:885
@ SB_AllowNull
Autorise l'absence du service.