Arcane  v3.15.0.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/IMeshUniqueIdMng.h"
36#include "arcane/core/internal/StringVariableReplace.h"
37
38#include "arcane/impl/ArcaneCaseMeshService_axl.h"
39
40/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------*/
42
43namespace Arcane
44{
45
46/*---------------------------------------------------------------------------*/
47/*---------------------------------------------------------------------------*/
53{
54 public:
55
57
58 public:
59
60 void createMesh(const String& default_name) override;
61 void allocateMeshItems() override;
62 void partitionMesh() override;
63 void applyAdditionalOperations() override;
64
65 private:
66
67 ISubDomain* m_sub_domain = nullptr;
68 IPrimaryMesh* m_mesh = nullptr;
69 IMeshBuilder* m_mesh_builder = nullptr;
70 Ref<IMeshBuilder> m_mesh_builder_ref;
71 String m_mesh_file_name;
72 String m_partitioner_name;
73
74 private:
75
76 void _fillReadInfo(CaseMeshReaderReadInfo& read_info);
77 Ref<IMeshBuilder> _createBuilderFromFile(const CaseMeshReaderReadInfo& read_info);
78 void _initializeVariables();
79 void _doInitialPartition();
80 void _doInitialPartition2(const String& name);
81 void _setGhostLayerInfos();
82 void _checkMeshCreationAndAllocation(bool is_check_allocated);
83 void _setUniqueIdNumberingVersion();
84};
85
86/*---------------------------------------------------------------------------*/
87/*---------------------------------------------------------------------------*/
88
89ArcaneCaseMeshService::
90ArcaneCaseMeshService(const ServiceBuildInfo& sbi)
92, m_sub_domain(sbi.subDomain())
93{
94}
95
96/*---------------------------------------------------------------------------*/
97/*---------------------------------------------------------------------------*/
98
101{
102 if (m_mesh)
103 ARCANE_FATAL("Mesh is already created");
104
105 info() << "Creating mesh from 'ArcaneCaseMeshService'";
107 ISubDomain* sd = m_sub_domain;
108 String filename = options()->filename();
109 bool has_filename = options()->filename.isPresent();
110 bool has_generator = options()->generator.isPresent();
111
112 // Il faut spécifier soit le nom du fichier, soit le générateur mais pas les deux
114 ARCANE_FATAL("In '{0}': one and one only of <{1}> or <{2}> has to be specified",
115 options()->configList()->xpathFullName(),
116 options()->generator.rootTagName(),
117 options()->filename.name());
118 if (has_filename){
119 m_mesh_file_name = StringVariableReplace::replaceWithCmdLineArgs(m_sub_domain->applicationInfo().commandLineArguments().parameters(), options()->filename);
120 if (m_mesh_file_name.empty())
121 ARCANE_FATAL("Invalid filename '{0}' in option '{1}'",
122 m_mesh_file_name,options()->filename.xpathFullName());
124 _fillReadInfo(read_info);
125 auto& specific_reader = options()->specificReader;
126 if (specific_reader.isPresent()){
127 m_mesh_builder_ref = specific_reader()->createBuilder(read_info);
128 if (m_mesh_builder_ref.isNull())
129 ARCANE_FATAL("No 'IMeshBuilder' created by specific reader");
130 }
131 else{
132 m_mesh_builder_ref = _createBuilderFromFile(read_info);
133 }
134 m_mesh_builder = m_mesh_builder_ref.get();
135 }
136 else if (has_generator)
137 m_mesh_builder = options()->generator();
138 else
139 ARCANE_FATAL("Invalid operation");
140
141 ARCANE_CHECK_POINTER(m_mesh_builder);
142
143 m_mesh_builder->fillMeshBuildInfo(build_info);
144 // Le générateur peut forcer l'utilisation du partitionnement
145 if (build_info.isNeedPartitioning())
146 m_partitioner_name = options()->partitioner();
147
148 // Positionne avec des valeurs par défaut les champs non remplit.
149 if (build_info.factoryName().empty())
150 build_info.addFactoryName("ArcaneDynamicMeshFactory");
151 if (build_info.parallelMngRef().isNull())
152 build_info.addParallelMng(makeRef(sd->parallelMng()));
153 IPrimaryMesh* pm = sd->meshMng()->meshFactoryMng()->createMesh(build_info);
154 m_mesh = pm;
155}
156
157/*---------------------------------------------------------------------------*/
158/*---------------------------------------------------------------------------*/
159
162{
163 _checkMeshCreationAndAllocation(false);
164
165 ARCANE_CHECK_POINTER(m_mesh_builder);
166
167 _setGhostLayerInfos();
168 _setUniqueIdNumberingVersion();
169
170 m_mesh_builder->allocateMeshItems(m_mesh);
171}
172
173/*---------------------------------------------------------------------------*/
174/*---------------------------------------------------------------------------*/
175
178{
179 _checkMeshCreationAndAllocation(true);
180
181 if (m_mesh->meshPartInfo().nbPart() > 1)
182 if (!m_partitioner_name.empty())
183 _doInitialPartition();
184}
185
186/*---------------------------------------------------------------------------*/
187/*---------------------------------------------------------------------------*/
188
191{
192 _checkMeshCreationAndAllocation(true);
193
194 IMeshSubdivider* subdivider = options()->subdivider();
195 if (subdivider)
196 subdivider->subdivideMesh(m_mesh);
197
198 _initializeVariables();
199}
200
201/*---------------------------------------------------------------------------*/
202/*---------------------------------------------------------------------------*/
203
204void ArcaneCaseMeshService::
205_checkMeshCreationAndAllocation(bool is_check_allocated)
206{
207 if (!m_mesh)
208 ARCANE_FATAL("Mesh is not created. You should call createMesh() before");
209 if (is_check_allocated && !m_mesh->isAllocated())
210 ARCANE_FATAL("Mesh is not allocated. You should call initializeMesh() before");
211}
212
213/*---------------------------------------------------------------------------*/
214/*---------------------------------------------------------------------------*/
215
216void ArcaneCaseMeshService::
217_fillReadInfo(CaseMeshReaderReadInfo& read_info)
218{
219 read_info.setFileName(m_mesh_file_name);
220
221 {
222 String extension;
223 // Cherche l'extension du fichier et la conserve dans \a case_ext
224 std::string_view fview = m_mesh_file_name.toStdStringView();
225 std::size_t extension_pos = fview.find_last_of('.');
226 if (extension_pos!=std::string_view::npos){
227 fview.remove_prefix(extension_pos+1);
228 extension = fview;
229 }
230 read_info.setFormat(extension);
231 }
232
233 String partitioner_name = options()->partitioner();
234 bool use_internal_partitioner = partitioner_name != "External";
235 if (use_internal_partitioner)
236 m_partitioner_name = partitioner_name;
237
238 info() << "Mesh filename=" << m_mesh_file_name
239 << " extension=" << read_info.format() << " partitioner=" << partitioner_name;
240
241 read_info.setParallelRead(use_internal_partitioner);
242}
243
244/*---------------------------------------------------------------------------*/
245/*---------------------------------------------------------------------------*/
246
247Ref<IMeshBuilder> ArcaneCaseMeshService::
248_createBuilderFromFile(const CaseMeshReaderReadInfo& read_info)
249{
250 // Construit les services potentiels de lecture de maillage. Ce sont
251 // ceux qui implémentent ICaseMeshReader. Construit une instance
252 // de chaque service et appelle la méthode createBuilder(). Dès que l'une
253 // de ces méthodes renvoie une référence non nulle, on l'utilise
254 // pour générer le maillage.
255 ServiceBuilder<ICaseMeshReader> builder(m_sub_domain);
256 UniqueArray<Ref<ICaseMeshReader>> mesh_readers(builder.createAllInstances());
257
258 for( auto& mesh_reader_ref : mesh_readers ){
259 ICaseMeshReader* mesh_reader = mesh_reader_ref.get();
260 Ref<IMeshBuilder> builder = mesh_reader->createBuilder(read_info);
261 if (!builder.isNull())
262 return builder;
263 }
264
265 // Pas de service trouvé pour ce format de fichier.
266 // Affiche la liste des services disponibles et fait un fatal.
267 StringUniqueArray valid_names;
268 builder.getServicesNames(valid_names);
269 String available_readers = String::join(", ",valid_names);
270 ARCANE_FATAL("The mesh reader required for format '{0}' is not available."
271 "The following reader services are available: {1}",
272 read_info.format(),available_readers);
273}
274
275/*---------------------------------------------------------------------------*/
276/*---------------------------------------------------------------------------*/
277
278void ArcaneCaseMeshService::
279_doInitialPartition()
280{
281 // N'utilise plus le service de partitionnement de test pour garantir
282 // avec ParMetis qu'on n'a pas de partitions vides car cela est maintenant
283 // normalement supporté.
284 const bool use_partitioner_tester = false;
285 String test_service = "MeshPartitionerTester";
286 if (use_partitioner_tester) {
287 Int64 nb_cell = m_mesh->nbCell();
288 Int64 min_nb_cell = m_mesh->parallelMng()->reduce(Parallel::ReduceMin,nb_cell);
289 info() << "Min nb cell=" << min_nb_cell;
290 if (min_nb_cell==0)
291 _doInitialPartition2(test_service);
292 else
293 info() << "Mesh name=" << m_mesh->name() << " have cells. Do not use " << test_service;
294 }
295 else
296 info() << "No basic partition first needed";
297 _doInitialPartition2(m_partitioner_name);
298}
299
300/*---------------------------------------------------------------------------*/
301/*---------------------------------------------------------------------------*/
302
303void ArcaneCaseMeshService::
304_doInitialPartition2(const String& partitioner_name)
305{
306 info() << "Doing initial partitioning service=" << partitioner_name;
307 // NOTE: Ce service n'utilise que les partionneurs qui implémentent
308 // IMeshPartitionerBase et pas ceux (historiques) qui n'implémentent que
309 // IMeshPartitioner.
310 ServiceBuilder<IMeshPartitionerBase> sbuilder(m_sub_domain);
311 auto mesh_partitioner = sbuilder.createReference(partitioner_name,m_mesh);
312
313 IMesh* mesh = m_mesh;
314 bool is_dynamic = mesh->isDynamic();
315 mesh->modifier()->setDynamic(true);
316 mesh->utilities()->partitionAndExchangeMeshWithReplication(mesh_partitioner.get(),true);
317 mesh->modifier()->setDynamic(is_dynamic);
318}
319
320/*---------------------------------------------------------------------------*/
321/*---------------------------------------------------------------------------*/
322
323void ArcaneCaseMeshService::
324_initializeVariables()
325{
326 IVariableMng* vm = m_sub_domain->variableMng();
327 const auto& vars_opt = options()->initialization().variable;
328 UniqueArray<String> errors;
329 for( Integer i=0, n=vars_opt.size(); i<n; ++i ){
330 const auto& o = vars_opt[i];
331 String var_name = o.name;
332 String group_name = o.group;
333 String value = o.value;
334 info() << "Initialize variable=" << var_name << " group=" << group_name << " value=" << value;
335 IVariable* var = vm->findMeshVariable(m_mesh,var_name);
336 if (!var){
337 errors.add(String::format("No variable named '{0}' exists",var_name));
338 continue;
339 }
340
341 // Alloue la variable si besoin.
342 if (!var->isUsed())
343 var->setUsed(true);
344 IItemFamily* var_family = var->itemFamily();
345 if (!var_family){
346 errors.add(String::format("Variable '{0}' has no family",var->fullName()));
347 continue;
348 }
349
350 ItemGroup group = var_family->findGroup(group_name);
351 if (group.null()){
352 errors.add(String::format("No group named '{0}' exists in family '{1}'",
353 group_name,var_family->name()));
354 continue;
355 }
356
357 bool ret = var->initialize(group,value);
358 if (ret){
359 errors.add(String::format("Bad value '{0}' for initializing variable '{1}'",
360 value,var->fullName()));
361 continue;
362 }
363 }
364 if (!errors.empty()){
365 for( String s : errors )
366 pinfo() << "ERROR: " << s;
367 ARCANE_FATAL("Variable initialization failed for option '{0}'",
368 vars_opt.xpathFullName());
369 }
370}
371
372/*---------------------------------------------------------------------------*/
373/*---------------------------------------------------------------------------*/
374
375void ArcaneCaseMeshService::
376_setGhostLayerInfos()
377{
378 IGhostLayerMng* gm = m_mesh->ghostLayerMng();
379 if (!gm)
380 return;
381
382 // Positionne les infos sur les mailles fantômes.
383 // TODO Cela est fait pour rester compatible avec le mode historique mais
384 // il faudrait pouvoir gérer cela autrement (via un service par exemple)
385 Integer nb_ghost_layer = options()->nbGhostLayer();
386 if (nb_ghost_layer >= 0) {
387 info() << "Set number of ghost layers to '" << nb_ghost_layer << "' from caseoption";
388 gm->setNbGhostLayer(nb_ghost_layer);
389 }
390
391 Integer builder_version = options()->ghostLayerBuilderVersion();
392 if (builder_version >= 0) {
393 info() << "Set ghostlayer builder version to '" << builder_version << "' from caseoption";
394 gm->setBuilderVersion(builder_version);
395 }
396}
397
398/*---------------------------------------------------------------------------*/
399/*---------------------------------------------------------------------------*/
400
401void ArcaneCaseMeshService::
402_setUniqueIdNumberingVersion()
403{
404 // NOTE: actuellement (12/2024) l'implémentation 'PolyedralMesh' lève une
405 // exception si on appelle meshUniqueIdMng(). On ne le fait que si
406 // l'option est présente.
407 if (options()->faceNumberingVersion.isPresent()) {
408 Int32 v = options()->faceNumberingVersion.value();
409 info() << "Set face uniqueId numbering version to '" << v << "' from caseoption";
410 IMeshUniqueIdMng* mum = m_mesh->meshUniqueIdMng();
411 mum->setFaceBuilderVersion(v);
412 }
413}
414
415/*---------------------------------------------------------------------------*/
416/*---------------------------------------------------------------------------*/
417
418ARCANE_REGISTER_SERVICE_ARCANECASEMESHSERVICE(ArcaneCaseMeshService,
419 ArcaneCaseMeshService);
420
421/*---------------------------------------------------------------------------*/
422/*---------------------------------------------------------------------------*/
423
424} // End namespace Arcane
425
426/*---------------------------------------------------------------------------*/
427/*---------------------------------------------------------------------------*/
#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.
const Type & value() const
Retourne la valeur de l'option.
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 IMeshUniqueIdMng * meshUniqueIdMng() const =0
Gestionnare de la numérotation des identifiants uniques.
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:149
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:570
Int32 Integer
Type représentant un entier.