Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
ArcaneCaseMeshService.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/* ArcaneCaseMeshService.cc (C) 2000-2024 */
9/* */
10/* Service Arcane gérant un maillage du jeu de données. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ApplicationInfo.h"
15#include "arcane/utils/CommandLineArguments.h"
16
18#include "arcane/core/ServiceBuilder.h"
19#include "arcane/core/ICaseMeshService.h"
20#include "arcane/core/ICaseMeshReader.h"
21#include "arcane/core/IMeshBuilder.h"
22#include "arcane/core/IPrimaryMesh.h"
23#include "arcane/core/IItemFamily.h"
24#include "arcane/core/IMeshPartitionerBase.h"
25#include "arcane/core/IVariableMng.h"
26#include "arcane/core/IMeshModifier.h"
27#include "arcane/core/IMeshUtilities.h"
28#include "arcane/core/IParallelMng.h"
29#include "arcane/core/MeshBuildInfo.h"
30#include "arcane/core/IMeshMng.h"
31#include "arcane/core/IMeshFactoryMng.h"
32#include "arcane/core/IGhostLayerMng.h"
33#include "arcane/core/MeshPartInfo.h"
34#include "arcane/core/IMeshSubdivider.h"
35#include "arcane/core/internal/StringVariableReplace.h"
36
37#include "arcane/impl/ArcaneCaseMeshService_axl.h"
38
39/*---------------------------------------------------------------------------*/
40/*---------------------------------------------------------------------------*/
41
42namespace Arcane
43{
44
45/*---------------------------------------------------------------------------*/
46/*---------------------------------------------------------------------------*/
52{
53 public:
54
56
57 public:
58
59 void createMesh(const String& default_name) override;
60 void allocateMeshItems() override;
61 void partitionMesh() override;
62 void applyAdditionalOperations() override;
63
64 private:
65
66 ISubDomain* m_sub_domain = nullptr;
67 IPrimaryMesh* m_mesh = nullptr;
68 IMeshBuilder* m_mesh_builder = nullptr;
69 Ref<IMeshBuilder> m_mesh_builder_ref;
70 String m_mesh_file_name;
71 String m_partitioner_name;
72
73 private:
74
75 void _fillReadInfo(CaseMeshReaderReadInfo& read_info);
76 Ref<IMeshBuilder> _createBuilderFromFile(const CaseMeshReaderReadInfo& read_info);
77 void _initializeVariables();
78 void _doInitialPartition();
79 void _doInitialPartition2(const String& name);
80 void _setGhostLayerInfos();
81 void _checkMeshCreationAndAllocation(bool is_check_allocated);
82};
83
84/*---------------------------------------------------------------------------*/
85/*---------------------------------------------------------------------------*/
86
87ArcaneCaseMeshService::
88ArcaneCaseMeshService(const ServiceBuildInfo& sbi)
90, m_sub_domain(sbi.subDomain())
91{
92}
93
94/*---------------------------------------------------------------------------*/
95/*---------------------------------------------------------------------------*/
96
99{
100 if (m_mesh)
101 ARCANE_FATAL("Mesh is already created");
102
103 info() << "Creating mesh from 'ArcaneCaseMeshService'";
105 ISubDomain* sd = m_sub_domain;
106 String filename = options()->filename();
107 bool has_filename = options()->filename.isPresent();
108 bool has_generator = options()->generator.isPresent();
109
110 // Il faut spécifier soit le nom du fichier, soit le générateur mais pas les deux
112 ARCANE_FATAL("In '{0}': one and one only of <{1}> or <{2}> has to be specified",
113 options()->configList()->xpathFullName(),
114 options()->generator.rootTagName(),
115 options()->filename.name());
116 if (has_filename){
117 m_mesh_file_name = StringVariableReplace::replaceWithCmdLineArgs(m_sub_domain->applicationInfo().commandLineArguments().parameters(), options()->filename);
118 if (m_mesh_file_name.empty())
119 ARCANE_FATAL("Invalid filename '{0}' in option '{1}'",
120 m_mesh_file_name,options()->filename.xpathFullName());
122 _fillReadInfo(read_info);
123 auto& specific_reader = options()->specificReader;
124 if (specific_reader.isPresent()){
125 m_mesh_builder_ref = specific_reader()->createBuilder(read_info);
126 if (m_mesh_builder_ref.isNull())
127 ARCANE_FATAL("No 'IMeshBuilder' created by specific reader");
128 }
129 else{
130 m_mesh_builder_ref = _createBuilderFromFile(read_info);
131 }
132 m_mesh_builder = m_mesh_builder_ref.get();
133 }
134 else if (has_generator)
135 m_mesh_builder = options()->generator();
136 else
137 ARCANE_FATAL("Invalid operation");
138
139 ARCANE_CHECK_POINTER(m_mesh_builder);
140
141 m_mesh_builder->fillMeshBuildInfo(build_info);
142 // Le générateur peut forcer l'utilisation du partitionnement
143 if (build_info.isNeedPartitioning())
144 m_partitioner_name = options()->partitioner();
145
146 // Positionne avec des valeurs par défaut les champs non remplit.
147 if (build_info.factoryName().empty())
148 build_info.addFactoryName("ArcaneDynamicMeshFactory");
149 if (build_info.parallelMngRef().isNull())
150 build_info.addParallelMng(makeRef(sd->parallelMng()));
151 IPrimaryMesh* pm = sd->meshMng()->meshFactoryMng()->createMesh(build_info);
152 m_mesh = pm;
153}
154
155/*---------------------------------------------------------------------------*/
156/*---------------------------------------------------------------------------*/
157
160{
161 _checkMeshCreationAndAllocation(false);
162
163 ARCANE_CHECK_POINTER(m_mesh_builder);
164
165 _setGhostLayerInfos();
166
167 m_mesh_builder->allocateMeshItems(m_mesh);
168
169}
170
171/*---------------------------------------------------------------------------*/
172/*---------------------------------------------------------------------------*/
173
176{
177 _checkMeshCreationAndAllocation(true);
178
179 if (m_mesh->meshPartInfo().nbPart() > 1)
180 if (!m_partitioner_name.empty())
181 _doInitialPartition();
182}
183
184/*---------------------------------------------------------------------------*/
185/*---------------------------------------------------------------------------*/
186
189{
190 _checkMeshCreationAndAllocation(true);
191
192 IMeshSubdivider* subdivider = options()->subdivider();
193 if (subdivider)
194 subdivider->subdivideMesh(m_mesh);
195
196 _initializeVariables();
197}
198
199/*---------------------------------------------------------------------------*/
200/*---------------------------------------------------------------------------*/
201
202void ArcaneCaseMeshService::
203_checkMeshCreationAndAllocation(bool is_check_allocated)
204{
205 if (!m_mesh)
206 ARCANE_FATAL("Mesh is not created. You should call createMesh() before");
207 if (is_check_allocated && !m_mesh->isAllocated())
208 ARCANE_FATAL("Mesh is not allocated. You should call initializeMesh() before");
209}
210
211/*---------------------------------------------------------------------------*/
212/*---------------------------------------------------------------------------*/
213
214void ArcaneCaseMeshService::
215_fillReadInfo(CaseMeshReaderReadInfo& read_info)
216{
217 read_info.setFileName(m_mesh_file_name);
218
219 {
220 String extension;
221 // Cherche l'extension du fichier et la conserve dans \a case_ext
222 std::string_view fview = m_mesh_file_name.toStdStringView();
223 std::size_t extension_pos = fview.find_last_of('.');
224 if (extension_pos!=std::string_view::npos){
225 fview.remove_prefix(extension_pos+1);
226 extension = fview;
227 }
228 read_info.setFormat(extension);
229 }
230
231 String partitioner_name = options()->partitioner();
232 bool use_internal_partitioner = partitioner_name != "External";
233 if (use_internal_partitioner)
234 m_partitioner_name = partitioner_name;
235
236 info() << "Mesh filename=" << m_mesh_file_name
237 << " extension=" << read_info.format() << " partitioner=" << partitioner_name;
238
239 read_info.setParallelRead(use_internal_partitioner);
240}
241
242/*---------------------------------------------------------------------------*/
243/*---------------------------------------------------------------------------*/
244
245Ref<IMeshBuilder> ArcaneCaseMeshService::
246_createBuilderFromFile(const CaseMeshReaderReadInfo& read_info)
247{
248 // Construit les services potentiels de lecture de maillage. Ce sont
249 // ceux qui implémentent ICaseMeshReader. Construit une instance
250 // de chaque service et appelle la méthode createBuilder(). Dès que l'une
251 // de ces méthodes renvoie une référence non nulle, on l'utilise
252 // pour générer le maillage.
253 ServiceBuilder<ICaseMeshReader> builder(m_sub_domain);
254 UniqueArray<Ref<ICaseMeshReader>> mesh_readers(builder.createAllInstances());
255
256 for( auto& mesh_reader_ref : mesh_readers ){
257 ICaseMeshReader* mesh_reader = mesh_reader_ref.get();
258 Ref<IMeshBuilder> builder = mesh_reader->createBuilder(read_info);
259 if (!builder.isNull())
260 return builder;
261 }
262
263 // Pas de service trouvé pour ce format de fichier.
264 // Affiche la liste des services disponibles et fait un fatal.
265 StringUniqueArray valid_names;
266 builder.getServicesNames(valid_names);
267 String available_readers = String::join(", ",valid_names);
268 ARCANE_FATAL("The mesh reader required for format '{0}' is not available."
269 "The following reader services are available: {1}",
270 read_info.format(),available_readers);
271}
272
273/*---------------------------------------------------------------------------*/
274/*---------------------------------------------------------------------------*/
275
276void ArcaneCaseMeshService::
277_doInitialPartition()
278{
279 // N'utilise plus le service de partitionnement de test pour garantir
280 // avec ParMetis qu'on n'a pas de partitions vides car cela est maintenant
281 // normalement supporté.
282 const bool use_partitioner_tester = false;
283 String test_service = "MeshPartitionerTester";
284 if (use_partitioner_tester) {
285 Int64 nb_cell = m_mesh->nbCell();
286 Int64 min_nb_cell = m_mesh->parallelMng()->reduce(Parallel::ReduceMin,nb_cell);
287 info() << "Min nb cell=" << min_nb_cell;
288 if (min_nb_cell==0)
289 _doInitialPartition2(test_service);
290 else
291 info() << "Mesh name=" << m_mesh->name() << " have cells. Do not use " << test_service;
292 }
293 else
294 info() << "No basic partition first needed";
295 _doInitialPartition2(m_partitioner_name);
296}
297
298/*---------------------------------------------------------------------------*/
299/*---------------------------------------------------------------------------*/
300
301void ArcaneCaseMeshService::
302_doInitialPartition2(const String& partitioner_name)
303{
304 info() << "Doing initial partitioning service=" << partitioner_name;
305 // NOTE: Ce service n'utilise que les partionneurs qui implémentent
306 // IMeshPartitionerBase et pas ceux (historiques) qui n'implémentent que
307 // IMeshPartitioner.
308 ServiceBuilder<IMeshPartitionerBase> sbuilder(m_sub_domain);
309 auto mesh_partitioner = sbuilder.createReference(partitioner_name,m_mesh);
310
311 IMesh* mesh = m_mesh;
312 bool is_dynamic = mesh->isDynamic();
313 mesh->modifier()->setDynamic(true);
314 mesh->utilities()->partitionAndExchangeMeshWithReplication(mesh_partitioner.get(),true);
315 mesh->modifier()->setDynamic(is_dynamic);
316}
317
318/*---------------------------------------------------------------------------*/
319/*---------------------------------------------------------------------------*/
320
321void ArcaneCaseMeshService::
322_initializeVariables()
323{
324 IVariableMng* vm = m_sub_domain->variableMng();
325 const auto& vars_opt = options()->initialization().variable;
326 UniqueArray<String> errors;
327 for( Integer i=0, n=vars_opt.size(); i<n; ++i ){
328 const auto& o = vars_opt[i];
329 String var_name = o.name;
330 String group_name = o.group;
331 String value = o.value;
332 info() << "Initialize variable=" << var_name << " group=" << group_name << " value=" << value;
333 IVariable* var = vm->findMeshVariable(m_mesh,var_name);
334 if (!var){
335 errors.add(String::format("No variable named '{0}' exists",var_name));
336 continue;
337 }
338
339 // Alloue la variable si besoin.
340 if (!var->isUsed())
341 var->setUsed(true);
342 IItemFamily* var_family = var->itemFamily();
343 if (!var_family){
344 errors.add(String::format("Variable '{0}' has no family",var->fullName()));
345 continue;
346 }
347
348 ItemGroup group = var_family->findGroup(group_name);
349 if (group.null()){
350 errors.add(String::format("No group named '{0}' exists in family '{1}'",
351 group_name,var_family->name()));
352 continue;
353 }
354
355 bool ret = var->initialize(group,value);
356 if (ret){
357 errors.add(String::format("Bad value '{0}' for initializing variable '{1}'",
358 value,var->fullName()));
359 continue;
360 }
361 }
362 if (!errors.empty()){
363 for( String s : errors )
364 pinfo() << "ERROR: " << s;
365 ARCANE_FATAL("Variable initialization failed for option '{0}'",
366 vars_opt.xpathFullName());
367 }
368}
369
370/*---------------------------------------------------------------------------*/
371/*---------------------------------------------------------------------------*/
372
373void ArcaneCaseMeshService::
374_setGhostLayerInfos()
375{
376 IGhostLayerMng* gm = m_mesh->ghostLayerMng();
377 if (!gm)
378 return;
379
380 // Positionne les infos sur les mailles fantômes.
381 // TODO Cela est fait pour rester compatible avec le mode historique mais
382 // il faudrait pouvoir gérer cela autrement (via un service par exemple)
383 Integer nb_ghost_layer = options()->nbGhostLayer();
384 if (nb_ghost_layer>=0){
385 info() << "Set number of ghost layers to '" << nb_ghost_layer << "' from caseoption";
386 gm->setNbGhostLayer(nb_ghost_layer);
387 }
388
389 Integer builder_version = options()->ghostLayerBuilderVersion();
390 if (builder_version>=0){
391 info() << "Set ghostlayer builder version to '" << builder_version << "' from caseoption";
392 gm->setBuilderVersion(builder_version);
393 }
394}
395
396/*---------------------------------------------------------------------------*/
397/*---------------------------------------------------------------------------*/
398
399ARCANE_REGISTER_SERVICE_ARCANECASEMESHSERVICE(ArcaneCaseMeshService,
400 ArcaneCaseMeshService);
401
402/*---------------------------------------------------------------------------*/
403/*---------------------------------------------------------------------------*/
404
405} // End namespace Arcane
406
407/*---------------------------------------------------------------------------*/
408/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Ce fichier contient les différentes fabriques de services et macro pour enregistrer les services.
Generation de la classe de base du Service.
CaseOptionsArcaneCaseMeshService * options() const
Options du jeu de données du service.
Service Arcane un maillage du jeu de données.
void createMesh(const String &default_name) override
Créé le maillage avec le nom name.
void allocateMeshItems() override
Alloue les éléments du maillage.
void partitionMesh() override
Partitionne le maillage.
void applyAdditionalOperations() override
Applique les opérations après tout le reste.
Informations nécessaires pour la lecture d'un fichier de maillage.
bool isPresent() const
Retourne true si l'option est présente.
virtual String name() const
Retourne le nom de l'élément dans le langage du jeu de données.
virtual String name() const =0
Nom du maillage.
virtual Integer nbCell()=0
Nombre de mailles du maillage.
Interface d'un service de création/lecture du maillage.
virtual void allocateMeshItems(IPrimaryMesh *pm)=0
Alloue les entités du maillage géré par ce service.
virtual void fillMeshBuildInfo(MeshBuildInfo &build_info)=0
Remplit build_info avec les informations nécessaires pour créer le maillage.
virtual void subdivideMesh(IPrimaryMesh *mesh)=0
Subdivise le maillage mesh.
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual bool isAllocated()=0
Vrai si le maillage est allouée.
virtual IGhostLayerMng * ghostLayerMng() const =0
Gestionnare de couche fantômes associé
virtual bool isDynamic() const =0
Indique si le maillage est dynamique (peut évoluer)
virtual const MeshPartInfo & meshPartInfo() const =0
Informations sur les parties du maillage.
Interface du gestionnaire d'un sous-domaine.
Definition ISubDomain.h:74
virtual const ApplicationInfo & applicationInfo() const =0
Informations sur l'exécutable.
virtual IVariableMng * variableMng()=0
Retourne le gestionnaire de variables.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Paramètres nécessaires à la construction d'un maillage.
Structure contenant les informations pour créer un service.
static String replaceWithCmdLineArgs(const ParameterList &parameter_list, const String &string_with_symbols)
Chaîne de caractères unicode.
bool empty() const
Vrai si la chaîne est vide (nulle ou "")
Definition String.cc:315
std::string_view toStdStringView() const
Retourne une vue de la STL sur la chaîne actuelle.
Definition String.cc:348
TraceMessage pinfo() const
Flot pour un message d'information en parallèle.
TraceMessage info() const
Flot pour un message d'information.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
UniqueArray< String > StringUniqueArray
Tableau dynamique à une dimension de chaînes de caractères.
Definition UtilsTypes.h:525
Int32 Integer
Type représentant un entier.