Arcane  v3.15.3.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-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/* ArcaneCaseMeshService.cc (C) 2000-2025 */
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().view());
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 // Indique si les entités multi-dimension sont autorisées
144 bool is_non_manifold = options()->nonManifoldMesh;
145 if (is_non_manifold) {
146 MeshKind mesh_kind = build_info.meshKind();
147 mesh_kind.setIsNonManifold(true);
148 build_info.addMeshKind(mesh_kind);
149 }
150
151 m_mesh_builder->fillMeshBuildInfo(build_info);
152 // Le générateur peut forcer l'utilisation du partitionnement
153 if (build_info.isNeedPartitioning())
154 m_partitioner_name = options()->partitioner();
155
156 // Positionne avec des valeurs par défaut les champs non remplit.
157 if (build_info.factoryName().empty())
158 build_info.addFactoryName("ArcaneDynamicMeshFactory");
159 if (build_info.parallelMngRef().isNull())
160 build_info.addParallelMng(makeRef(sd->parallelMng()));
161 IPrimaryMesh* pm = sd->meshMng()->meshFactoryMng()->createMesh(build_info);
162 m_mesh = pm;
163}
164
165/*---------------------------------------------------------------------------*/
166/*---------------------------------------------------------------------------*/
167
170{
171 _checkMeshCreationAndAllocation(false);
172
173 ARCANE_CHECK_POINTER(m_mesh_builder);
174
175 _setGhostLayerInfos();
176 _setUniqueIdNumberingVersion();
177
178 m_mesh_builder->allocateMeshItems(m_mesh);
179}
180
181/*---------------------------------------------------------------------------*/
182/*---------------------------------------------------------------------------*/
183
186{
187 _checkMeshCreationAndAllocation(true);
188
189 if (m_mesh->meshPartInfo().nbPart() > 1)
190 if (!m_partitioner_name.empty())
191 _doInitialPartition();
192}
193
194/*---------------------------------------------------------------------------*/
195/*---------------------------------------------------------------------------*/
196
199{
200 _checkMeshCreationAndAllocation(true);
201
202 IMeshSubdivider* subdivider = options()->subdivider();
203 if (subdivider)
204 subdivider->subdivideMesh(m_mesh);
205
206 _initializeVariables();
207}
208
209/*---------------------------------------------------------------------------*/
210/*---------------------------------------------------------------------------*/
211
212void ArcaneCaseMeshService::
213_checkMeshCreationAndAllocation(bool is_check_allocated)
214{
215 if (!m_mesh)
216 ARCANE_FATAL("Mesh is not created. You should call createMesh() before");
217 if (is_check_allocated && !m_mesh->isAllocated())
218 ARCANE_FATAL("Mesh is not allocated. You should call initializeMesh() before");
219}
220
221/*---------------------------------------------------------------------------*/
222/*---------------------------------------------------------------------------*/
223
224void ArcaneCaseMeshService::
225_fillReadInfo(CaseMeshReaderReadInfo& read_info)
226{
227 read_info.setFileName(m_mesh_file_name);
228
229 {
230 String extension;
231 // Cherche l'extension du fichier et la conserve dans \a case_ext
232 std::string_view fview = m_mesh_file_name.toStdStringView();
233 std::size_t extension_pos = fview.find_last_of('.');
234 if (extension_pos!=std::string_view::npos){
235 fview.remove_prefix(extension_pos+1);
236 extension = fview;
237 }
238 read_info.setFormat(extension);
239 }
240
241 String partitioner_name = options()->partitioner();
242 bool use_internal_partitioner = partitioner_name != "External";
243 if (use_internal_partitioner)
244 m_partitioner_name = partitioner_name;
245
246 info() << "Mesh filename=" << m_mesh_file_name
247 << " extension=" << read_info.format() << " partitioner=" << partitioner_name;
248
249 read_info.setParallelRead(use_internal_partitioner);
250}
251
252/*---------------------------------------------------------------------------*/
253/*---------------------------------------------------------------------------*/
254
255Ref<IMeshBuilder> ArcaneCaseMeshService::
256_createBuilderFromFile(const CaseMeshReaderReadInfo& read_info)
257{
258 // Construit les services potentiels de lecture de maillage. Ce sont
259 // ceux qui implémentent ICaseMeshReader. Construit une instance
260 // de chaque service et appelle la méthode createBuilder(). Dès que l'une
261 // de ces méthodes renvoie une référence non nulle, on l'utilise
262 // pour générer le maillage.
263 ServiceBuilder<ICaseMeshReader> builder(m_sub_domain);
264 UniqueArray<Ref<ICaseMeshReader>> mesh_readers(builder.createAllInstances());
265
266 for( auto& mesh_reader_ref : mesh_readers ){
267 ICaseMeshReader* mesh_reader = mesh_reader_ref.get();
268 Ref<IMeshBuilder> builder = mesh_reader->createBuilder(read_info);
269 if (!builder.isNull())
270 return builder;
271 }
272
273 // Pas de service trouvé pour ce format de fichier.
274 // Affiche la liste des services disponibles et fait un fatal.
275 StringUniqueArray valid_names;
276 builder.getServicesNames(valid_names);
277 String available_readers = String::join(", ",valid_names);
278 ARCANE_FATAL("The mesh reader required for format '{0}' is not available."
279 "The following reader services are available: {1}",
280 read_info.format(),available_readers);
281}
282
283/*---------------------------------------------------------------------------*/
284/*---------------------------------------------------------------------------*/
285
286void ArcaneCaseMeshService::
287_doInitialPartition()
288{
289 // N'utilise plus le service de partitionnement de test pour garantir
290 // avec ParMetis qu'on n'a pas de partitions vides car cela est maintenant
291 // normalement supporté.
292 const bool use_partitioner_tester = false;
293 String test_service = "MeshPartitionerTester";
294 if (use_partitioner_tester) {
295 Int64 nb_cell = m_mesh->nbCell();
296 Int64 min_nb_cell = m_mesh->parallelMng()->reduce(Parallel::ReduceMin,nb_cell);
297 info() << "Min nb cell=" << min_nb_cell;
298 if (min_nb_cell==0)
299 _doInitialPartition2(test_service);
300 else
301 info() << "Mesh name=" << m_mesh->name() << " have cells. Do not use " << test_service;
302 }
303 else
304 info() << "No basic partition first needed";
305 _doInitialPartition2(m_partitioner_name);
306}
307
308/*---------------------------------------------------------------------------*/
309/*---------------------------------------------------------------------------*/
310
311void ArcaneCaseMeshService::
312_doInitialPartition2(const String& partitioner_name)
313{
314 info() << "Doing initial partitioning service=" << partitioner_name;
315 // NOTE: Ce service n'utilise que les partionneurs qui implémentent
316 // IMeshPartitionerBase et pas ceux (historiques) qui n'implémentent que
317 // IMeshPartitioner.
318 ServiceBuilder<IMeshPartitionerBase> sbuilder(m_sub_domain);
319 auto mesh_partitioner = sbuilder.createReference(partitioner_name,m_mesh);
320
321 IMesh* mesh = m_mesh;
322 bool is_dynamic = mesh->isDynamic();
323 mesh->modifier()->setDynamic(true);
324 mesh->utilities()->partitionAndExchangeMeshWithReplication(mesh_partitioner.get(),true);
325 mesh->modifier()->setDynamic(is_dynamic);
326}
327
328/*---------------------------------------------------------------------------*/
329/*---------------------------------------------------------------------------*/
330
331void ArcaneCaseMeshService::
332_initializeVariables()
333{
334 IVariableMng* vm = m_sub_domain->variableMng();
335 const auto& vars_opt = options()->initialization().variable;
336 UniqueArray<String> errors;
337 for( Integer i=0, n=vars_opt.size(); i<n; ++i ){
338 const auto& o = vars_opt[i];
339 String var_name = o.name;
340 String group_name = o.group;
341 String value = o.value;
342 info() << "Initialize variable=" << var_name << " group=" << group_name << " value=" << value;
343 IVariable* var = vm->findMeshVariable(m_mesh,var_name);
344 if (!var){
345 errors.add(String::format("No variable named '{0}' exists",var_name));
346 continue;
347 }
348
349 // Alloue la variable si besoin.
350 if (!var->isUsed())
351 var->setUsed(true);
352 IItemFamily* var_family = var->itemFamily();
353 if (!var_family){
354 errors.add(String::format("Variable '{0}' has no family",var->fullName()));
355 continue;
356 }
357
358 ItemGroup group = var_family->findGroup(group_name);
359 if (group.null()){
360 errors.add(String::format("No group named '{0}' exists in family '{1}'",
361 group_name,var_family->name()));
362 continue;
363 }
364
365 bool ret = var->initialize(group,value);
366 if (ret){
367 errors.add(String::format("Bad value '{0}' for initializing variable '{1}'",
368 value,var->fullName()));
369 continue;
370 }
371 }
372 if (!errors.empty()){
373 for( String s : errors )
374 pinfo() << "ERROR: " << s;
375 ARCANE_FATAL("Variable initialization failed for option '{0}'",
376 vars_opt.xpathFullName());
377 }
378}
379
380/*---------------------------------------------------------------------------*/
381/*---------------------------------------------------------------------------*/
382
383void ArcaneCaseMeshService::
384_setGhostLayerInfos()
385{
386 IGhostLayerMng* gm = m_mesh->ghostLayerMng();
387 if (!gm)
388 return;
389
390 // Positionne les infos sur les mailles fantômes.
391 // TODO Cela est fait pour rester compatible avec le mode historique mais
392 // il faudrait pouvoir gérer cela autrement (via un service par exemple)
393 Integer nb_ghost_layer = options()->nbGhostLayer();
394 if (nb_ghost_layer >= 0) {
395 info() << "Set number of ghost layers to '" << nb_ghost_layer << "' from caseoption";
396 gm->setNbGhostLayer(nb_ghost_layer);
397 }
398
399 Integer builder_version = options()->ghostLayerBuilderVersion();
400 if (builder_version >= 0) {
401 info() << "Set ghostlayer builder version to '" << builder_version << "' from caseoption";
402 gm->setBuilderVersion(builder_version);
403 }
404}
405
406/*---------------------------------------------------------------------------*/
407/*---------------------------------------------------------------------------*/
408
409void ArcaneCaseMeshService::
410_setUniqueIdNumberingVersion()
411{
412 // NOTE: actuellement (12/2024) l'implémentation 'PolyedralMesh' lève une
413 // exception si on appelle meshUniqueIdMng(). On ne le fait que si
414 // l'option est présente.
415 if (options()->faceNumberingVersion.isPresent()) {
416 Int32 v = options()->faceNumberingVersion.value();
417 info() << "Set face uniqueId numbering version to '" << v << "' from caseoption";
418 IMeshUniqueIdMng* mum = m_mesh->meshUniqueIdMng();
419 mum->setFaceBuilderVersion(v);
420 }
421}
422
423/*---------------------------------------------------------------------------*/
424/*---------------------------------------------------------------------------*/
425
426ARCANE_REGISTER_SERVICE_ARCANECASEMESHSERVICE(ArcaneCaseMeshService,
427 ArcaneCaseMeshService);
428
429/*---------------------------------------------------------------------------*/
430/*---------------------------------------------------------------------------*/
431
432} // End namespace Arcane
433
434/*---------------------------------------------------------------------------*/
435/*---------------------------------------------------------------------------*/
#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.
Caractéristiques d'un maillage.
Definition MeshKind.h:64
Structure contenant les informations pour créer un service.
static String replaceWithCmdLineArgs(const ParameterList &parameter_list, StringView string_with_symbols, bool fatal_if_not_found=false, bool fatal_if_invalid=true)
Méthode permettant de remplacer les symboles de la chaine de caractères string_with_symbols par leurs...
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:449
Int32 Integer
Type représentant un entier.