Arcane  v4.1.2.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
LegacyMeshBuilder.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/* LegacyMeshBuilder.cc (C) 2000-2025 */
9/* */
10/* Construction du maillage via la méthode "historique". */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/impl/internal/LegacyMeshBuilder.h"
15
16#include "arcane/utils/PlatformUtils.h"
17#include "arcane/utils/StringBuilder.h"
18
19#include "arcane/core/MeshKind.h"
20#include "arcane/core/ISubDomain.h"
21#include "arcane/core/CaseNodeNames.h"
22#include "arcane/core/ICaseDocument.h"
23#include "arcane/core/IParallelMng.h"
24#include "arcane/core/ServiceBuilder.h"
25#include "arcane/core/IMainFactory.h"
26#include "arcane/core/IPrimaryMesh.h"
27#include "arcane/core/IGhostLayerMng.h"
28#include "arcane/core/IMeshReader.h"
29#include "arcane/core/IMeshMng.h"
30#include "arcane/core/IMeshUniqueIdMng.h"
31
32#include "arcane_internal_config.h"
33
34/*---------------------------------------------------------------------------*/
35/*---------------------------------------------------------------------------*/
36
37namespace Arcane
38{
39
40/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------*/
42
43LegacyMeshBuilder::
44LegacyMeshBuilder(ISubDomain* sd,MeshHandle default_mesh_handle)
45: TraceAccessor(sd->traceMng())
46, m_sub_domain(sd)
47, m_default_mesh_handle(default_mesh_handle)
48, m_internal_partitioner_name(ARCANE_DEFAULT_PARTITIONER_STR)
49{
50}
51
52/*---------------------------------------------------------------------------*/
53/*---------------------------------------------------------------------------*/
54
55void LegacyMeshBuilder::
56readCaseMeshes()
57{
58 ISubDomain* sd = m_sub_domain;
59 Integer sub_domain_id = sd->subDomainId();
60 ICaseDocument* case_doc = sd->caseDocument();
61 CaseNodeNames* cnn = case_doc->caseNodeNames();
62 XmlNodeList mesh_elems(case_doc->meshElements());
63 bool has_mesh_file = true;
64 if (mesh_elems.empty()){
65 info() << "No mesh in the input data";
66 has_mesh_file = false;
67 }
68 Integer nb_mesh = mesh_elems.size();
69 m_meshes_build_info.resize(nb_mesh);
70 for( Integer i=0; i<nb_mesh; ++i ){
71 MeshBuildInfo& mbi = m_meshes_build_info[i];
72 mbi.m_dir_name = ".";
73 mbi.m_xml_node = mesh_elems[i];
74 XmlNodeList partitioner_elems = mesh_elems[i].children(cnn->mesh_partitioner) ;
75 m_use_partitioner_tester = false;
76 if(partitioner_elems.empty()) {
77 m_use_partitioner_tester = true;
78 m_internal_partitioner_name = ARCANE_DEFAULT_PARTITIONER_STR;
79 }
80 else{
81 m_internal_partitioner_name = partitioner_elems[0].value() ;
82 //check if the partitioner is parallel
83 m_use_partitioner_tester = partitioner_elems[0].attr("need-basic-partition-first").valueAsBoolean();
84 }
85
86 XmlNode meshfile_elem = mesh_elems[i].child(cnn->mesh_file);
87 String smesh_file = meshfile_elem.value();
88 StringBuilder mesh_file = smesh_file;
89 mbi.m_orig_file_name = smesh_file;
90 if (smesh_file.null()){
91 info() << "No mesh in the input data";
92 has_mesh_file = false;
93 }
94
95 String file_format = meshfile_elem.attrValue("format");
96 bool internal_cut = meshfile_elem.attr("internal-partition").valueAsBoolean();
97 String internal_partitioner = meshfile_elem.attr("partitioner").value();
98
99 // Si la variable d'environnement est définie, force le repartitionnement
100 // initial avec le service dont le nom est spécifié dans cette variable.
101 String internal_partitioner_env = platform::getEnvironmentVariable("ARCANE_INTERNAL_PARTITIONER");
102 if (!internal_partitioner_env.null()){
103 info() << "Forcing internal partitioner from environment variable";
104 internal_cut = true;
105 internal_partitioner = internal_partitioner_env;
106 }
107 IParallelMng* pm = sd->parallelMng();
108 // Dans le cas où Arcane est retranché à un coeur, on ne va pas chercher les CPU*.mli2
109 if (pm->isParallel() && (pm->commSize()>1)){
110 m_use_internal_mesh_partitioner = internal_cut;
111
112 if (!internal_partitioner.empty())
113 m_internal_partitioner_name = internal_partitioner;
114 Integer nb_sub_domain = pm->commSize();
115 info() << "Subdomain number is " << sub_domain_id << '/' << nb_sub_domain;
116
117 //check if the file mesh reader need a unique or multi file
118 bool use_unique_file = meshfile_elem.attr("unique").valueAsBoolean();
119 if (!use_unique_file){
120 //Integer nb_sub_domain = m_parallel_mng->commSize();
121 StringBuilder cut_dir_str("cut_");
122 cut_dir_str += nb_sub_domain;
123 String mesh_cut_dir = meshfile_elem.attrValue(cut_dir_str);
124 debug() << "MESH CUT DIR " << mesh_cut_dir << ' ' << cut_dir_str;
125 if (has_mesh_file && !internal_cut){
126 char buf[128];
127 String file_format_str = "mli2";
128 if (!file_format.null())
129 file_format_str = file_format;
130 sprintf(buf,"CPU%05d.%s",(int)sub_domain_id,file_format_str.localstr());
131 log() << "The original mesh file is " << mesh_file;
132 if (mesh_cut_dir.empty())
133 mesh_file = String(std::string_view(buf));
134 else{
135 mbi.m_dir_name = mesh_cut_dir;
136 mesh_file = mesh_cut_dir;
137 mesh_file += "/";
138 mesh_file += buf;
139 }
140 }
141 }
142 }
143 log() << "The mesh file is " << mesh_file;
144 mbi.m_file_name = mesh_file;
145 // Cette partie de la configuration doit être lue avant
146 // la création du maillage car elle peut contenir des options
147 // dont le générateur de maillage a besoin.
148 //m_case_config->read();
149 }
150
151 // Créé les MeshHandle pour les maillages.
152 // Cela permettra de les récupérer dans les points d'entrée 'Build'
153 _createMeshesHandle();
154}
155
156/*---------------------------------------------------------------------------*/
157/*---------------------------------------------------------------------------*/
158
159void LegacyMeshBuilder::
160readMeshes()
161{
162 // Construit les services de lecture de maillage. Ce sont
163 // ceux qui implémentent IMeshReader.
164 ServiceBuilder<IMeshReader> builder(m_sub_domain);
165 UniqueArray<Ref<IMeshReader>> mesh_readers(builder.createAllInstances());
166
167 for( const MeshBuildInfo& mbi : m_meshes_build_info ){
168 _readMesh(mesh_readers,mbi);
169 }
170}
171
172/*---------------------------------------------------------------------------*/
173/*---------------------------------------------------------------------------*/
174
175void LegacyMeshBuilder::
176createDefaultMesh()
177{
178 ISubDomain* sd = m_sub_domain;
179 String mesh_name = m_default_mesh_handle.meshName();
180 ICaseDocument* case_doc = sd->caseDocument();
181 if (!case_doc){
182 // Si aucun jeu de données n'est spécifié, créé un maillage
183 m_default_mesh_handle._setMesh(sd->mainFactory()->createMesh(sd,mesh_name));
184 return;
185 }
186
187 CaseNodeNames* cnn = case_doc->caseNodeNames();
188 XmlNodeList mesh_elems(case_doc->meshElements());
189 if (mesh_elems.empty()){
190 info() << "No mesh in the input data";
191 }
192 Integer nb_mesh = mesh_elems.size();
193 for( Integer i=0; i<nb_mesh; ++i ){
194 XmlNode meshfile_elem = mesh_elems[i].child(cnn->mesh_file);
195 String mesh_file = meshfile_elem.value();
196 if (mesh_file.null()){
197 info() << "No mesh in the input data";
198 }
199 }
200 // default_mesh is the mesh described by mesh_elems[0]
201 // Now that amr flag has to be known at mesh creation, check-it for default mesh
202 bool is_amr = mesh_elems[0].attr("amr").valueAsBoolean();
203 eMeshAMRKind amr_type = static_cast<eMeshAMRKind>(mesh_elems[0].attr("amr-type").valueAsInteger());
204 if(is_amr && amr_type == eMeshAMRKind::None) {
205 amr_type = eMeshAMRKind::Cell;
206 }
207
208 m_default_mesh_handle._setMesh(sd->mainFactory()->createMesh(sd,mesh_name, amr_type));
209}
210
211/*---------------------------------------------------------------------------*/
212/*---------------------------------------------------------------------------*/
213
214void LegacyMeshBuilder::
215_createMeshesHandle()
216{
217 IMeshMng* mesh_mng = m_sub_domain->meshMng();
218
219 // Le premier maillage est toujours celui par défaut
220 Integer nb_build_mesh = m_meshes_build_info.size();
221 if (nb_build_mesh>0){
222 m_meshes_build_info[0].m_mesh_handle = m_default_mesh_handle;
223 }
224
225 // Créé les autres maillages spécifiés dans le jeu de données
226 for( Integer z=1; z<nb_build_mesh; ++z ){
227 String name;
228 if(m_meshes_build_info[z].m_xml_node.attr("dual").valueAsBoolean())
229 name = "DualMesh";
230 else
231 name = "Mesh";
232 name = name + z;
233 MeshHandle handle = mesh_mng->createMeshHandle(name);
234 m_meshes_build_info[z].m_mesh_handle = handle;
235 }
236}
237
238/*---------------------------------------------------------------------------*/
239/*---------------------------------------------------------------------------*/
240
241void LegacyMeshBuilder::
242allocateMeshes()
243{
244 ISubDomain* sd = m_sub_domain;
245
246 // Le premier maillage est toujours celui par défaut
247 Integer nb_build_mesh = m_meshes_build_info.size();
248 if (nb_build_mesh>0){
249 m_meshes_build_info[0].m_mesh = m_default_mesh_handle.mesh()->toPrimaryMesh();
250 }
251
252 // Créé les autres maillages spécifiés dans le jeu de données
253 for( Integer z=1; z<nb_build_mesh; ++z ){
254 MeshHandle handle = m_meshes_build_info[z].m_mesh_handle;
255 if (handle.isNull())
256 ARCANE_FATAL("Invalid null MeshHandle for mesh index={0}",z);
257 // Depuis la 1.8.0 (modif IFP), cette methode
258 // appelle this->addMesh()
259 bool is_amr = m_meshes_build_info[z].m_xml_node.attr("amr").valueAsBoolean();
260 eMeshAMRKind amr_type = static_cast<eMeshAMRKind>(m_meshes_build_info[z].m_xml_node.attr("amr-type").valueAsInteger());
261 if(is_amr && amr_type == eMeshAMRKind::None) {
262 amr_type = eMeshAMRKind::Cell;
263 }
264
265 IPrimaryMesh* mesh = sd->mainFactory()->createMesh(sd,handle.meshName(),amr_type);
266 m_meshes_build_info[z].m_mesh = mesh;
267 }
268}
269
270/*---------------------------------------------------------------------------*/
271/*---------------------------------------------------------------------------*/
272
273void LegacyMeshBuilder::
274initializeMeshVariablesFromCaseFile()
275{
276 info() << "Initialization of the variable from the configuration file";
277 CaseNodeNames* cnn = m_sub_domain->caseDocument()->caseNodeNames();
278 for( const LegacyMeshBuilder::MeshBuildInfo& mbi : m_meshes_build_info ){
279 IMesh* mesh = mbi.m_mesh;
280 XmlNode node = mbi.m_xml_node;
281 XmlNode init_node = node.child(cnn->mesh_initialisation);
282 if (!init_node.null())
283 mesh->initializeVariables(init_node);
284 }
285}
286
287/*---------------------------------------------------------------------------*/
288/*---------------------------------------------------------------------------*/
289
290void LegacyMeshBuilder::
291_readMesh(ConstArrayView<Ref<IMeshReader>> mesh_readers,const MeshBuildInfo& mbi)
292{
293 IPrimaryMesh* mesh = mbi.m_mesh;
295
296 String mesh_file_name = mbi.m_file_name;
297 // Si un service de partitionnement est spécifié, il faut utiliser le fichier specifié
298 // dans le JDD et pas le nom du fichier éventuellement transformé dans readCaseMeshes()
299 bool use_internal_partitioner = m_use_internal_mesh_partitioner;
300 if (m_initial_partitioner.get()){
301 mesh_file_name = mbi.m_orig_file_name;
302 use_internal_partitioner = true;
303 }
304 // Permet de forcer la dimension au cas ou le format ne peut pas la reconnaitre.
305 Integer wanted_dimension = mbi.m_xml_node.attr("dimension").valueAsInteger();
306 if (wanted_dimension!=0){
307 info() << "Force mesh dimension to " << wanted_dimension;
308 mesh->setDimension(wanted_dimension);
309 }
310 log() << "Mesh file: " << mesh_file_name;
311
312 Integer nb_ghost_layer = -1;
313 XmlNode nbGhostLayerNode = mbi.m_xml_node.attr("nb-ghostlayer");
314 if (!nbGhostLayerNode.null()){
315 nb_ghost_layer = nbGhostLayerNode.valueAsInteger();
316 if (nb_ghost_layer>=0){
317 info() << "Set number of ghost layers to '" << nb_ghost_layer << "' from caseoption";
318 mesh->ghostLayerMng()->setNbGhostLayer(nb_ghost_layer);
319 }
320 }
321
322 Integer builder_version = mbi.m_xml_node.attr("ghostlayer-builder-version").valueAsInteger();
323 if (nb_ghost_layer>=0 && builder_version>=0){
324 info() << "Set ghostlayer builder version to '" << builder_version << "' from caseoption";
325 mesh->ghostLayerMng()->setBuilderVersion(builder_version);
326 }
327
328 XmlNode face_numbering_version_node = mbi.m_xml_node.attr("face-numbering-version");
329 if (!face_numbering_version_node.null()) {
330 Int32 v = face_numbering_version_node.valueAsInteger();
331 if (v >= 0) {
332 info() << "Set face numbering version to '" << v << "' from caseoption";
333 mesh->meshUniqueIdMng()->setFaceBuilderVersion(v);
334 }
335 }
336 bool is_bad = true;
337 String extension;
338 {
339 // Cherche l'extension du fichier et la conserve dans \a case_ext
340 std::string_view fview = mesh_file_name.toStdStringView();
341 debug() << " MF=" << fview;
342 std::size_t extension_pos = fview.find_last_of('.');
343 if (extension_pos!=std::string_view::npos){
344 fview.remove_prefix(extension_pos+1);
345 extension = fview;
346 }
347 }
348
349 for( auto& mesh_reader_ref : mesh_readers ){
350 IMeshReader* mesh_reader = mesh_reader_ref.get();
351 if (!mesh_reader->allowExtension(extension))
352 continue;
353
355 mbi.m_xml_node,
356 mesh_file_name,
357 mbi.m_dir_name,
358 use_internal_partitioner);
359 if (ret==IMeshReader::RTOk){
360 is_bad = false;
361 break;
362 }
363 if (ret==IMeshReader::RTError){
364 ARCANE_FATAL("Error while generating the mesh");
365 }
366 }
367
368 if (is_bad){
369 ARCANE_FATAL("Internal error: no mesh loaded or generated. \n",
370 "The mesh reader or generator required isn't available ",
371 "Recompile with the relevant options");
372 }
373
374 mesh->computeTiedInterfaces(mbi.m_xml_node);
376 //mesh->readAmrActivator(mbi.m_xml_node);
377
378#if 0
379 IMeshWriter* writer = ServiceFinderT<IMeshWriter>::find(serviceMng(),"VtkLegacyMeshWriter");
380 if (writer){
381 writer->writeMeshToFile(mesh,"test.vtk");
382 }
383 if (!parallelMng()->isParallel()){
384 mesh_utils::writeMeshConnectivity(mesh,"mesh-reference.xml");
385 }
386#endif
387}
388
389/*---------------------------------------------------------------------------*/
390/*---------------------------------------------------------------------------*/
391
392} // End namespace Arcane
393
394/*---------------------------------------------------------------------------*/
395/*---------------------------------------------------------------------------*/
#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.
void writeMeshConnectivity(IMesh *mesh, const String &file_name)
Ecrit sur le fichier file_name la connectivité du maillage mesh.
Definition MeshUtils.cc:829
Vue constante d'un tableau de type T.
Interface du service gérant la lecture d'un maillage.
Definition IMeshReader.h:32
virtual bool allowExtension(const String &str)=0
Vérifie si le service supporte les fichiers avec l'extension str.
virtual eReturnType readMeshFromFile(IPrimaryMesh *mesh, const XmlNode &mesh_element, const String &file_name, const String &dir_name, bool use_internal_partition)=0
Lit un maillage à partir d'un fichier.
eReturnType
Types des codes de retour d'une lecture ou écriture.
Definition IMeshReader.h:37
@ RTError
Erreur lors de l'opération.
Definition IMeshReader.h:39
@ RTOk
Opération effectuée avec succès.
Definition IMeshReader.h:38
Interface d'un service d'écriture d'un maillage.
Definition IMeshWriter.h:37
virtual bool writeMeshToFile(IMesh *mesh, const String &file_name)=0
Ecrit un maillage sur un fichier.
Interface du gestionnaire d'un sous-domaine.
Definition ISubDomain.h:74
ScopedPtrT< IInitialPartitioner > m_initial_partitioner
Partitionneur initial.
bool m_use_internal_mesh_partitioner
true si partitionne le maillage en interne
Handle sur un maillage.
Definition MeshHandle.h:47
Référence à une instance.
Chaîne de caractères unicode.
std::string_view toStdStringView() const
Retourne une vue de la STL sur la chaîne actuelle.
Definition String.cc:349
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flot pour un message de debug.
TraceMessage log() const
Flot pour un message de log.
TraceMessage info() const
Flot pour un message d'information.
Noeud d'un arbre DOM.
Definition XmlNode.h:51
XmlNode attr(const String &name, bool throw_exception=false) const
Retourne l'attribut de nom name.
Definition XmlNode.cc:248
bool null() const
Vrai si le noeud est nul.
Definition XmlNode.h:294
Integer valueAsInteger(bool throw_exception=false) const
Valeur du noeud convertie en entier.
Definition XmlNode.cc:432
__host__ __device__ double log(double v)
Logarithme népérien de v.
Definition Math.h:40
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Int32 Integer
Type représentant un entier.
eMeshAMRKind
Type de maillage AMR.
Definition MeshKind.h:48
std::int32_t Int32
Type entier signé sur 32 bits.