Arcane  4.1.11.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
Lima.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 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/* Lima.cc (C) 2000-2026 */
9/* */
10/* Lecture/Ecriture d'un fichier au format Lima. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/Iostream.h"
15#include "arcane/utils/StdHeader.h"
16#include "arcane/utils/HashTableMap.h"
17#include "arcane/utils/ValueConvert.h"
18#include "arcane/utils/ScopedPtr.h"
19#include "arcane/utils/ArcanePrecomp.h"
20#include "arcane/utils/ITraceMng.h"
21#include "arcane/utils/Collection.h"
22#include "arcane/utils/Enumerator.h"
23#include "arcane/utils/PlatformUtils.h"
24#include "arcane/utils/Real3.h"
25#include "arcane/utils/OStringStream.h"
26#include "arcane/utils/CheckedConvert.h"
27#include "arcane/utils/StringBuilder.h"
28
29#include "arcane/core/IMeshReader.h"
30#include "arcane/core/IGhostLayerMng.h"
31#include "arcane/core/ISubDomain.h"
32#include "arcane/core/IIOMng.h"
33#include "arcane/core/IParallelMng.h"
34#include "arcane/core/IPrimaryMesh.h"
35#include "arcane/core/Item.h"
36#include "arcane/core/ItemTypeMng.h"
37#include "arcane/core/ItemGroup.h"
38#include "arcane/core/ArcaneException.h"
39#include "arcane/core/Service.h"
40#include "arcane/core/Timer.h"
42#include "arcane/core/ServiceInfo.h"
43#include "arcane/core/CaseOptionsMain.h"
46#include "arcane/core/VariableTypes.h"
47#include "arcane/core/ServiceBuildInfo.h"
48#include "arcane/core/XmlNodeList.h"
49#include "arcane/core/IXmlDocumentHolder.h"
50#include "arcane/core/IItemFamily.h"
51#include "arcane/core/FactoryService.h"
52#include "arcane/core/IMeshWriter.h"
53#include "arcane/core/AbstractService.h"
54#include "arcane/core/ICaseDocument.h"
55#include "arcane/core/ICaseMeshReader.h"
56#include "arcane/core/IMeshBuilder.h"
57
58#include "arcane/lima/LimaCutInfosReader.h"
59#include "arcane/lima/internal/LimaUtils.h"
60
61#include <Lima/lima++.h>
62
63#include <memory>
64#include <algorithm>
65#include <mutex>
66
67/*---------------------------------------------------------------------------*/
68/*---------------------------------------------------------------------------*/
69
70namespace Arcane
71{
72
73/*---------------------------------------------------------------------------*/
74/*---------------------------------------------------------------------------*/
75
76namespace
77{
78
79// Mutex pour protéger les appels à Lima dans le cas où on utilise MLI2
80// car ce format utilise HDF5 qui n'est thread-safe dans la plupart des cas
81// (cela dépend des options de compilation de HDF5 mais la version thread-safe
82// est incompatible avec la version MPI et en général on a besoin de cette
83// dernière)
84std::mutex global_lima_mutex;
85class GlobalLimaMutex
86{
87 public:
88
89 explicit GlobalLimaMutex(bool is_active)
90 : m_is_active(is_active)
91 {
92 if (m_is_active)
93 global_lima_mutex.lock();
94 }
95 ~GlobalLimaMutex()
96 {
97 if (m_is_active)
98 global_lima_mutex.unlock();
99 }
100
101 private:
102
103 bool m_is_active = false;
104};
105
106}
107
108/*---------------------------------------------------------------------------*/
109/*---------------------------------------------------------------------------*/
113class LimaMeshBase
114: public TraceAccessor
115{
116 public:
117
118 LimaMeshBase(ISubDomain* sub_domain)
119 : TraceAccessor(sub_domain->traceMng()), m_sub_domain(sub_domain) {}
120 virtual ~LimaMeshBase() {}
121
122 public:
123
124 virtual bool readMesh(Lima::Maillage& lima,IPrimaryMesh* mesh,const String& filename,
125 const String& dir_name,bool use_internal_partition,Real length_multiplier) =0;
126
127 ISubDomain* subDomain() const { return m_sub_domain; }
128
129 protected:
130
131 private:
132
133 ISubDomain* m_sub_domain;
134
135 private:
136};
137
138/*---------------------------------------------------------------------------*/
139/*---------------------------------------------------------------------------*/
146template<typename ReaderWrapper>
147class LimaWrapper
148: public LimaMeshBase
149{
150 public:
151
152 LimaWrapper(ISubDomain* sub_domain)
153 : LimaMeshBase(sub_domain), m_cut_infos_reader(new LimaCutInfosReader(sub_domain->parallelMng())) {}
154
155 ~LimaWrapper()
156 {
157 delete m_cut_infos_reader;
158 }
159
160 public:
161
162 virtual bool readMesh(Lima::Maillage& lima,IPrimaryMesh* mesh,const String& filename,
163 const String& dir_name,bool use_internal_partition,Real length_multiplier);
164
165 private:
166
167 LimaCutInfosReader* m_cut_infos_reader;
168 ReaderWrapper m_wrapper;
169
170 bool _readMesh(Lima::Maillage& lima,IPrimaryMesh* mesh,const String& filename,
171 const String& dir_name,bool use_internal_partition,Real length_multiplier);
172
173 void _getProcList(UniqueArray<Integer>& proc_list,const String& dir_name);
174};
175
176/*---------------------------------------------------------------------------*/
177/*---------------------------------------------------------------------------*/
178
180{
181 public:
182
183 void setLima(const Lima::Maillage& lima_mesh)
184 {
185 m_lima_mesh = lima_mesh;
186 }
187
188 protected:
189
190 Lima::Maillage m_lima_mesh;
191};
192
193/*---------------------------------------------------------------------------*/
194/*---------------------------------------------------------------------------*/
195
198{
199 public:
200 typedef Lima::Surface LimaCellGroup;
201 typedef Lima::Polygone LimaCell;
202 typedef Lima::Ligne LimaFaceGroup;
203 typedef Lima::Bras LimaFace;
204 public:
205 Integer nbCellGroup()
206 {
207 return CheckedConvert::toInteger(m_lima_mesh.nb_surfaces());
208 }
209 Integer nbFaceGroup()
210 {
211 return CheckedConvert::toInteger(m_lima_mesh.nb_lignes());
212 }
213 LimaCellGroup cellGroup(Integer i)
214 {
215 return m_lima_mesh.surface(i);
216 }
217 LimaFaceGroup faceGroup(Integer i)
218 {
219 return m_lima_mesh.ligne(i);
220 }
221 Integer faceGroupNbFace(const LimaFaceGroup& group)
222 {
223 return CheckedConvert::toInteger(group.nb_bras());
224 }
225 LimaFace faceFaceGroup(const LimaFaceGroup& group,Integer i)
226 {
227 return group.bras(i);
228 }
229 Integer cellGroupNbCell(const LimaCellGroup& group)
230 {
231 return CheckedConvert::toInteger(group.nb_polygones());
232 }
233 LimaCell cellCellGroup(const LimaCellGroup& group,Integer i)
234 {
235 return group.polygone(i);
236 }
237 LimaCell cell(Integer i)
238 {
239 return m_lima_mesh.polygone(i);
240 }
241 LimaFace face(Integer i)
242 {
243 return m_lima_mesh.bras(i);
244 }
245 Integer nbCell()
246 {
247 return CheckedConvert::toInteger(m_lima_mesh.nb_polygones());
248 }
249 Integer nbFace()
250 {
251 return CheckedConvert::toInteger(m_lima_mesh.nb_bras());
252 }
253 int limaDimension()
254 {
255 return Lima::D2;
256 }
257 const char* strDimension()
258 {
259 return "2D";
260 }
261 static Integer cellToType(Integer nb_node)
262 {
263 switch(nb_node){
264 case 3: return IT_Triangle3;
265 case 4: return IT_Quad4;
266 case 5: return IT_Pentagon5;
267 case 6: return IT_Hexagon6;
268 default:
269 break;
270 }
271 return IT_NullType;
272 }
273};
274
275/*---------------------------------------------------------------------------*/
276/*---------------------------------------------------------------------------*/
277
280{
281 public:
282 typedef Lima::Volume LimaCellGroup;
283 typedef Lima::Polyedre LimaCell;
284 typedef Lima::Surface LimaFaceGroup;
285 typedef Lima::Polygone LimaFace;
286
287 Integer nbCellGroup()
288 {
289 return CheckedConvert::toInteger(m_lima_mesh.nb_volumes());
290 }
291 Integer nbFaceGroup()
292 {
293 return CheckedConvert::toInteger(m_lima_mesh.nb_surfaces());
294 }
295 LimaCellGroup cellGroup(Integer i)
296 {
297 return m_lima_mesh.volume(i);
298 }
299 LimaFaceGroup faceGroup(Integer i)
300 {
301 return m_lima_mesh.surface(i);
302 }
303 Integer faceGroupNbFace(const LimaFaceGroup& group)
304 {
305 return CheckedConvert::toInteger(group.nb_polygones());
306 }
307 LimaFace faceFaceGroup(const LimaFaceGroup& group,Integer i)
308 {
309 return group.polygone(i);
310 }
311 Integer cellGroupNbCell(const LimaCellGroup& group)
312 {
313 return CheckedConvert::toInteger(group.nb_polyedres());
314 }
315 LimaCell cellCellGroup(const LimaCellGroup& group,Integer i)
316 {
317 return group.polyedre(i);
318 }
319 LimaCell cell(Integer i)
320 {
321 return m_lima_mesh.polyedre(i);
322 }
323 LimaFace face(Integer i)
324 {
325 return m_lima_mesh.polygone(i);
326 }
327 Integer nbCell()
328 {
329 return CheckedConvert::toInteger(m_lima_mesh.nb_polyedres());
330 }
331 Integer nbFace()
332 {
333 return CheckedConvert::toInteger(m_lima_mesh.nb_polygones());
334 }
335 int limaDimension()
336 {
337 return Lima::D3;
338 }
339 const char* strDimension()
340 {
341 return "3D";
342 }
343 static Integer cellToType(Integer nb_node)
344 {
345 switch(nb_node){
346 case 4: return IT_Tetraedron4;
347 case 5: return IT_Pyramid5;
348 case 6: return IT_Pentaedron6;
349 case 8: return IT_Hexaedron8;
350 case 10: return IT_Heptaedron10;
351 case 12: return IT_Octaedron12;
352 default:
353 break;
354 }
355 return IT_NullType;
356 }
357};
358
359/*---------------------------------------------------------------------------*/
360/*---------------------------------------------------------------------------*/
364class LimaMeshReader
365: public TraceAccessor
366{
367 public:
368
369 LimaMeshReader(ISubDomain* sd)
370 : TraceAccessor(sd->traceMng()), m_sub_domain(sd){}
371
372 public:
373
374 auto readMesh(IPrimaryMesh* mesh, const String& file_name,
375 const String& dir_name,bool use_internal_partition,
376 bool use_length_unit) -> IMeshReader::eReturnType;
377
378 private:
379
380 ISubDomain* m_sub_domain;
381};
382
383/*---------------------------------------------------------------------------*/
384/*---------------------------------------------------------------------------*/
388class LimaMeshReaderService
389: public AbstractService
390, public IMeshReader
391{
392 public:
393
394 explicit LimaMeshReaderService(const ServiceBuildInfo& sbi);
395
396 public:
397
398 void build() {}
399
400 public:
401
402 bool allowExtension(const String& str) override
403 {
404 return str=="unf" || str=="mli" || str=="mli2" || str=="ice" || str=="uns" || str=="unv";
405 }
406
408 const String& file_name,
409 const String& dir_name,bool use_internal_partition) override;
410 ISubDomain* subDomain() { return m_sub_domain; }
411
412 private:
413
414 ISubDomain* m_sub_domain;
415
416 private:
417};
418
419/*---------------------------------------------------------------------------*/
420/*---------------------------------------------------------------------------*/
421
425
426/*---------------------------------------------------------------------------*/
427/*---------------------------------------------------------------------------*/
428
429LimaMeshReaderService::
430LimaMeshReaderService(const ServiceBuildInfo& sbi)
431: AbstractService(sbi)
432, m_sub_domain(sbi.subDomain())
433{
434}
435
436/*---------------------------------------------------------------------------*/
437/*---------------------------------------------------------------------------*/
438
440readMeshFromFile(IPrimaryMesh* mesh,const XmlNode& mesh_node,
441 const String& filename,const String& dir_name,
442 bool use_internal_partition)
443{
444 ISubDomain* sd = subDomain();
445
446 String case_doc_lang = "en";
447 ICaseDocument* case_doc = sd->caseDocument();
448 if (case_doc)
449 case_doc_lang = case_doc->language();
450
451 // Regarde si on souhaite utiliser l'unité de longueur dans le fichier de maillage.
452 String use_unit_attr_name = "utilise-unite";
453 String use_unit_str = mesh_node.attrValue(use_unit_attr_name);
454 if (case_doc_lang=="en"){
455 // Pour des raisons de compatiblité, regarde si 'utilise-unite' est présent
456 // auquel cas on le prend. Sinon, on prend le terme anglais.
457 if (!use_unit_str.empty()){
458 warning() << "'utilise-unite' ne doit être utilisé que pour les JDD en francais."
459 << "Utilisez 'use-unit' à la place";
460 }
461 use_unit_attr_name = "use-unit";
462 }
463 else{
464 // Si non anglais et que 'utilise-unite' n'est pas trouvé,
465 // essaie d'utiliser 'use-unit'. Cela est nécessaire pour prendre en compte
466 // MeshReaderMng::isUseMeshUnit().
467 if (use_unit_str.null()){
468 info() << "Attribute '" << use_unit_attr_name << "' is not found. Trying with 'use-unit'";
469 use_unit_attr_name = "use-unit";
470 }
471 }
472
473 // Depuis la 2.8.0 de Arcane, on lit par défaut les unités de longueur si
474 // si la variable d'environnement ARCANE_LIMA_DEFAULT_NO_UNIT est définie.
475 bool use_length_unit = true;
476 if (!platform::getEnvironmentVariable("ARCANE_LIMA_DEFAULT_NO_UNIT").null())
477 use_length_unit = false;
478 info() << "Default value for unit usage: " << use_length_unit;
479
480 if (use_unit_str.empty())
481 use_unit_str = mesh_node.attrValue(use_unit_attr_name);
482 info() << "Checking for attribute '" << use_unit_attr_name << "' value='" << use_unit_str << "'";
483 if (!use_unit_str.empty()){
484 if (use_unit_str=="1" || use_unit_str=="true")
485 use_length_unit = true;
486 else if (use_unit_str=="0" || use_unit_str=="false")
487 use_length_unit = false;
488 else
489 ARCANE_FATAL("Invalid value boolean value '{0}' for '{1}' attribute."
490 " Valid values are '0', '1' 'true' or 'false'",
491 use_unit_str,use_unit_attr_name);
492 }
493
494 info() << "Utilise l'unité de longueur de Lima: " << use_length_unit << " (lang=" << case_doc_lang << ")";
495
496 LimaMeshReader reader(sd);
497 return reader.readMesh(mesh,filename,dir_name,use_internal_partition,use_length_unit);
498}
499
500/*---------------------------------------------------------------------------*/
501/*---------------------------------------------------------------------------*/
502
503IMeshReader::eReturnType LimaMeshReader::
504readMesh(IPrimaryMesh* mesh,const String& filename,const String& dir_name,
505 bool use_internal_partition, bool use_length_unit)
506{
507 if (filename.null() || filename.empty())
509
510 ISubDomain* sd = m_sub_domain;
511 ITimerMng* timer_mng = sd->timerMng();
512 LimaMeshBase* lm = 0;
513 ICaseDocument* case_doc = sd->caseDocument();
514
515 info() << "Lima: use_length_unit=" << use_length_unit
516 << " use_internal_partition=" << use_internal_partition;
517 Real length_multiplier = 0.0;
518 if (use_length_unit){
519 String code_system;
520 if (case_doc)
521 code_system = case_doc->codeUnitSystem();
522 if (code_system.null() || code_system.empty()){
523 info() << "No unit system configured. Use MKS unit system.";
524 length_multiplier = 1.0;
525 }
526 else if (code_system=="CGS"){
527 length_multiplier = 100.0;
528 }
529 else if (code_system=="MKS"){
530 length_multiplier = 1.0;
531 }
532 else{
533 ARCANE_FATAL("Unknown unit system '{0}' (valid values are: 'CGS' ou 'MKS'",code_system);
534 }
535 }
536
537 std::string loc_file_name = filename.localstr();
538 size_t rpos = loc_file_name.rfind(".mli");
539 size_t rpos2 = loc_file_name.rfind(".mli2");
540 const bool need_mutex = rpos2 != std::string::npos;
541 info() << " FILE_NAME=" << loc_file_name;
542 info() << " RPOS MLI=" << rpos << " s=" << loc_file_name.length();
543 info() << " RPOS MLI2=" << rpos2 << " s=" << loc_file_name.length();
544
545 // Si chaque PE lit le maillage et qu'on utilise la mémoire partagée,
546 // la lecture des fichiers Lima se fera en concurrence.
547 // Comme l'API 'Malipp' de Lima ne supporte pas le multi-threading,
548 // on bascule vers l'API classique dans ce cas.
549 // Même avec l'API classique, il y a des plantages avec certaines
550 // versions de Lima (au moins la 7.11.2) lorsqu'on utilise le format MLI2
551 // (car il utilise HDF5). Pour éviter tout problème on met un verrou
552 // autour de la lecture/écriture dans ce cas.
553 bool has_thread = !use_internal_partition && mesh->parallelMng()->isThreadImplementation();
554 // On ne peut pas utiliser l'api mali pp avec les threads
555 if (!has_thread && use_internal_partition && ((rpos+4)==loc_file_name.length())){
556 info() << "Use direct partitioning with mli";
557#ifdef ARCANE_LIMA_HAS_MLI
558 return LimaUtils::_directLimaPartitionMalipp(timer_mng, mesh, filename, length_multiplier);
559#else
560 ARCANE_FATAL("Can not use 'mli' files because Lima is not compiled with 'mli' support");
561#endif
562 }
563 else if (!has_thread && use_internal_partition && ((rpos2+5)==loc_file_name.length())){
564 info() << "Use direct partitioning with mli2";
565#ifdef ARCANE_LIMA_HAS_MLI2
566 return LimaUtils::_directLimaPartitionMalipp2(timer_mng, mesh, filename, length_multiplier);
567#else
568 ARCANE_FATAL("Can not use 'mli2' files because Lima is not compiled with 'mli2' support");
569#endif
570 }
571 else {
572 info() << "Chargement Lima du fichier '" << filename << "'";
573
574 const char* version = Lima::lima_version();
575 info() << "Utilisation de la version " << version << " de Lima";
576
577 Timer time_to_read(sd,"ReadLima",Timer::TimerReal);
578
579 // Aucune préparation spécifique à faire
580 LM_TYPEMASQUE preparation = LM_ORIENTATION | LM_COMPACTE;
581
582 log() << "Début lecture fichier " << filename;
583
584 Lima::Maillage lima(filename.localstr());
585
586 try{
587 {
588 Timer::Sentry sentry(&time_to_read);
589 Timer::Phase t_action(sd, TP_InputOutput);
590 GlobalLimaMutex sc(need_mutex);
591 lima.lire(filename.localstr(),Lima::SUFFIXE,true);
592 //warning() << "Preparation lima supprimée";
593 lima.preparation_parametrable(preparation);
594 }
595 }
596 catch(const Lima::erreur& ex){
597 ARCANE_FATAL("Can not read lima file '{0}' error is '{1}'",filename,ex.what());
598 }
599 catch(...){
600 ARCANE_FATAL("Can not read lima file '{0}'",filename);
601 }
602
603 info() << "Temps de lecture et préparation du maillage (unité: seconde): "
604 << time_to_read.lastActivationTime();
605 // Si la dimension n'est pas encore positionnée, utilise celle
606 // donnée par Lima.
607 if (mesh->dimension()<=0){
608 if (lima.dimension()==Lima::D3){
609 mesh->setDimension(3);
610 info() << "Maillage 3D";
611 }
612 else if (lima.dimension()==Lima::D2){
613 mesh->setDimension(2);
614 info() << "Maillage 2D";
615 }
616 }
617
618 if (mesh->dimension()==3){
619 lm = new LimaWrapper<Lima3DReaderWrapper>(sd);
620 }
621 else if (mesh->dimension()==2){
622 lm = new LimaWrapper<Lima2DReaderWrapper>(sd);
623 }
624 if (!lm){
625 log() << "Dimension du maillage non reconnue par lima";
627 }
628
629 bool ret = lm->readMesh(lima,mesh,filename,dir_name,use_internal_partition,length_multiplier);
630 if (ret)
632
633 // A faire si plusieurs couches de mailles fantomes
634 {
635 Integer nb_ghost_layer = mesh->ghostLayerMng()->nbGhostLayer();
636 if (nb_ghost_layer>1)
638 }
639
640 delete lm;
641 }
642
643 return IMeshReader::RTOk;
644}
645
646/*---------------------------------------------------------------------------*/
647/*---------------------------------------------------------------------------*/
648
649template<typename ReaderWrapper> bool LimaWrapper<ReaderWrapper>::
650readMesh(Lima::Maillage& lima,IPrimaryMesh* mesh,const String& filename,
651 const String& dir_name,bool use_internal_partition,Real length_multiplier)
652{
653 return _readMesh(lima,mesh,filename,dir_name,use_internal_partition,length_multiplier);
654}
655
656/*---------------------------------------------------------------------------*/
657/*---------------------------------------------------------------------------*/
658
659template<typename ReaderWrapper> bool LimaWrapper<ReaderWrapper>::
660_readMesh(Lima::Maillage& lima,IPrimaryMesh* mesh,const String& file_name,
661 const String& dir_name,bool use_internal_partition,Real length_multiplier)
662{
663 ARCANE_UNUSED(file_name);
664
665 // Il faut utiliser le parallelMng du maillage qui peut être différent
666 // de celui du sous-domaine, par exemple si le maillage est séquentiel.
667 IParallelMng* pm = mesh->parallelMng();
668
669 bool is_parallel = pm->isParallel();
670 Integer sid = pm->commRank();
671
672 Integer mesh_nb_node = 0;
673 Integer nb_edge = 0;
674 Integer lima_nb_face = 0;
675 Integer mesh_nb_cell = 0;
676
677 m_wrapper.setLima(lima);
678
679 mesh_nb_node = CheckedConvert::toInteger(lima.nb_noeuds());
680 mesh_nb_cell = m_wrapper.nbCell(); //lima.nb_polyedres();
681 lima_nb_face = m_wrapper.nbFace(); //lima.nb_polygones();
682 nb_edge = 0; //lima.nb_bras();
683
684 info() << "-- Informations sur le maillage (Interne):";
685 info() << "Nombre de noeuds " << mesh_nb_node;
686 info() << "Nombre d'arêtes " << nb_edge;
687 info() << "Nombre de faces " << lima_nb_face;
688 info() << "Nombre de mailles " << mesh_nb_cell;
689 info() << "-- Informations sur le maillage (Lima):";
690 info() << "Nombre de noeuds " << lima.nb_noeuds();
691 info() << "Nombre d'arêtes " << lima.nb_bras();
692 info() << "Nombre de polygones " << lima.nb_polygones();
693 info() << "Nombre de polyedres " << lima.nb_polyedres();
694 info() << "Nombre de surfaces " << lima.nb_surfaces();
695 info() << "Nombre de volumes " << lima.nb_volumes();
696
697 info() << "Unité de longueur du fichier: " << lima.unite_longueur();
698 // Si 0.0, indique qu'on ne souhaite pas utiliser l'unité du fichier.
699 // Dans ce, cela correspond à un multiplicateur de 1.0
700 if (length_multiplier==0.0)
701 length_multiplier = 1.0;
702 else
703 length_multiplier *= lima.unite_longueur();
704
705 if (mesh_nb_node==0){
706 ARCANE_FATAL("No node in mesh");
707 }
708
709 // ------------------------------------------------------------
710 // -------------------------------- Création des mailles
711 // ------------------------------------------------------------
712
713
714 // Lit les numéros uniques des entités (en parallèle)
715 UniqueArray<Int64> nodes_unique_id(mesh_nb_node);
716 UniqueArray<Int64> cells_unique_id(mesh_nb_cell);
717 if (is_parallel && !use_internal_partition && pm->commSize()>1){
718 m_cut_infos_reader->readItemsUniqueId(nodes_unique_id,cells_unique_id,dir_name);
719 }
720 else{
721 for( Integer i=0; i<mesh_nb_node; ++i )
722 nodes_unique_id[i] = i;
723 for( Integer i=0; i<mesh_nb_cell; ++i )
724 cells_unique_id[i] = i;
725 }
726
727 // Pour l'instant, laisse à false.
728 // Si true, les uid sont incrémentés pour commencer à un.
729 bool first_uid_is_one = false;
730 if (!platform::getEnvironmentVariable("ARCANE_LIMA_UNIQUE_ID").null()){
731 first_uid_is_one = true;
732 info() << "WARNING: UniqueId begin at 1";
733 }
734 if (first_uid_is_one){
735 for( Integer i=0; i<mesh_nb_node; ++i )
736 ++nodes_unique_id[i];
737 for( Integer i=0; i<mesh_nb_cell; ++i )
738 ++cells_unique_id[i];
739 }
740
741 HashTableMapT<Int64,Real3> nodes_coords(mesh_nb_node,true);
742 if (!math::isEqual(length_multiplier,1.0)){
743 info() << "Using length multiplier v=" << length_multiplier;
744 for( Integer i=0; i<mesh_nb_node; ++i ){
745 const Lima::Noeud& node = lima.noeud(i);
746 Real3 coord(node.x(),node.y(),node.z());
747 coord *= length_multiplier;
748 nodes_coords.nocheckAdd(nodes_unique_id[i],coord);
749 }
750 }
751 else{
752 for( Integer i=0; i<mesh_nb_node; ++i ){
753 const Lima::Noeud& node = lima.noeud(i);
754 Real3 coord(node.x(),node.y(),node.z());
755 nodes_coords.nocheckAdd(nodes_unique_id[i],coord);
756 }
757 }
758
759 Integer cells_infos_index = 0;
760
761 UniqueArray<Integer> cells_filter;
762
763 bool use_own_mesh = false;
764
765 if (is_parallel && pm->commSize()>1){
766 use_own_mesh = true;
767 if (use_internal_partition)
768 use_own_mesh = false;
769 }
770
771 typedef typename ReaderWrapper::LimaCellGroup LimaCellGroup;
772 typedef typename ReaderWrapper::LimaCell LimaCell;
773 typedef typename ReaderWrapper::LimaFaceGroup LimaFaceGroup;
774 typedef typename ReaderWrapper::LimaFace LimaFace;
775
776 if (use_own_mesh){
777 Integer nb = m_wrapper.nbCellGroup();
778 for( Integer i=0; i<nb; ++i ){
779 const LimaCellGroup& lima_group = m_wrapper.cellGroup(i);
780 std::string group_name = lima_group.nom();
781 if (group_name=="LOCAL" || group_name=="local"){
782 Integer nb_own_cell = m_wrapper.cellGroupNbCell(lima_group);
783 cells_filter.resize(nb_own_cell);
784 for( Integer z=0; z<nb_own_cell; ++z ){
785 cells_filter[z] = CheckedConvert::toInteger(m_wrapper.cellCellGroup(lima_group,z).id() - 1);
786 }
787 }
788 }
789 }
790 else{
791 if (use_internal_partition && sid!=0){
792 mesh_nb_cell = 0;
793 mesh_nb_node = 0;
794 lima_nb_face = 0;
795 }
796 cells_filter.resize(mesh_nb_cell);
797 for( Integer i=0; i<mesh_nb_cell; ++i )
798 cells_filter[i] = i;
799 }
800
801 // Calcul le nombre de mailles/noeuds
802 Integer mesh_nb_cell_node = 0;
803 for( Integer j=0, js=cells_filter.size(); j<js; ++j ){
804 mesh_nb_cell_node += CheckedConvert::toInteger(m_wrapper.cell(cells_filter[j]).nb_noeuds());
805 }
806
807 // Tableau contenant les infos aux mailles (voir IMesh::allocateMesh())
808 UniqueArray<Int64> cells_infos(mesh_nb_cell_node+cells_filter.size()*2);
809
810 // Remplit le tableau contenant les infos des mailles
811 for( Integer i_cell=0, s_cell=cells_filter.size(); i_cell<s_cell; ++i_cell ){
812
813 Integer cell_indirect_id = cells_filter[i_cell];
814 LimaCell lima_cell = m_wrapper.cell(cell_indirect_id);
815 Integer n = CheckedConvert::toInteger(lima_cell.nb_noeuds());
816
817 Integer ct = ReaderWrapper::cellToType(n);
818 if (ct==IT_NullType)
819 throw UnknownItemTypeException("Lima::readFile: Cell",n,cell_indirect_id);
820 // Stocke le type de la maille
821 cells_infos[cells_infos_index] = ct;
822 ++cells_infos_index;
823 // Stocke le numéro unique de la maille
824 cells_infos[cells_infos_index] = cells_unique_id[cell_indirect_id];
825 ++cells_infos_index;
826
827 // Rempli la liste des numéros des noeuds de la maille
828 for( Integer z=0, sz=n; z<sz; ++z ){
829 Int64 node_uid = nodes_unique_id[CheckedConvert::toInteger(lima_cell.noeud(z).id()-1)];
830 cells_infos[cells_infos_index+z] = node_uid;
831 }
832
833#if 0
834 cout << "CELL LIMA1 " << cells_unique_id[cell_indirect_id] << " ";
835 for( Integer z=0; z<n; ++z )
836 cout << " " << cells_infos[cells_infos_index+z];
837 cout << '\n';
838#endif
839
840 cells_infos_index += n;
841 }
842
843 logdate() << "Début allocation du maillage nb_cell=" << cells_filter.size();
844 mesh->allocateCells(cells_filter.size(),cells_infos,false);
845 logdate() << "Fin allocation du maillage";
846
847 // Positionne les propriétaires des noeuds à partir des groupes de noeuds de Lima
848 if (use_internal_partition){
849 ItemInternalList nodes(mesh->itemsInternal(IK_Node));
850 for( Integer i=0, is=nodes.size(); i<is; ++i )
851 nodes[i]->setOwner(sid,sid);
852 ItemInternalList cells(mesh->itemsInternal(IK_Cell));
853 for( Integer i=0, is=cells.size(); i<is; ++i )
854 cells[i]->setOwner(sid,sid);
855 }
856 else{
857 Int64UniqueArray unique_ids;
858 Int32UniqueArray local_ids;
859 Integer sub_domain_id = subDomain()->subDomainId();
860 Integer nb = CheckedConvert::toInteger(lima.nb_nuages());
861 for( Integer i=0; i<nb; ++i ){
862 const Lima::Nuage& lima_group = lima.nuage(i);
863 Integer nb_item_in_group = CheckedConvert::toInteger(lima_group.nb_noeuds());
864 std::string group_name = lima_group.nom();
865 unique_ids.resize(nb_item_in_group);
866 local_ids.resize(nb_item_in_group);
867 for( Integer z=0; z<nb_item_in_group; ++z ){
868 unique_ids[z] = nodes_unique_id[CheckedConvert::toInteger(lima_group.noeud(z).id() - 1)];
869 }
870 mesh->nodeFamily()->itemsUniqueIdToLocalId(local_ids,unique_ids,false);
871 bool remove_group = false;
872 if (group_name=="LOCALN" || group_name=="localn"){
873 info() << "Utilisation du groupe 'LOCALN' pour indiquer que les "
874 << "noeuds appartiennent au sous-domaine";
875 ItemInternalList nodes(mesh->itemsInternal(IK_Node));
876 for( Integer z=0, sz=nb_item_in_group; z<sz; ++z ){
877 Integer local_id = local_ids[z];
878 if (local_id!=NULL_ITEM_ID)
879 nodes[local_id]->setOwner(sub_domain_id,sub_domain_id);
880 }
881 remove_group = true;
882 }
883 debug() << "Vérification du groupe '" << group_name << "'";
884 if (group_name.length()>3 && !remove_group){
885 String grp = group_name; //.c_str();
886 if (grp.startsWith("NF_")){
887 grp = grp.substring(3);
888 Int32 ghost_sub_domain_id = 0;
889 bool is_bad = builtInGetValue(ghost_sub_domain_id,grp);
890 debug() << "Vérification du groupe '" << group_name << "' (3) " << is_bad;
891 if (!is_bad){
892 info() << "Utilisation du groupe " << group_name << " pour indiquer que le "
893 << "sous-domaine " << ghost_sub_domain_id << " est propriétaire de ses noeuds";
894 ItemInternalList nodes(mesh->itemsInternal(IK_Node));
895 for( Integer z=0, sz=nb_item_in_group; z<sz; ++z ){
896 Integer local_id = local_ids[z];
897 if (local_id!=NULL_ITEM_ID)
898 nodes[local_ids[z]]->setOwner(ghost_sub_domain_id,sub_domain_id);
899 }
900 remove_group = true;
901 }
902 }
903 }
904 }
905 }
906
907 mesh->endAllocate();
908
909 // Comme le maillage créé lui même ses faces sans tenir compte de celles qui
910 // existent éventuellement dans Lima, il faut maintenant déterminer le numéro
911 // local dans notre maillage de chaque face de Lima.
912 UniqueArray<Integer> faces_id(lima_nb_face); // Numéro de la face lima dans le maillage \a mesh
913 {
914 // Nombre de faces/noeuds
915 Integer face_nb_node = 0;
916 for( Integer i_face=0; i_face<lima_nb_face; ++i_face ){
917 const LimaFace& lima_face = m_wrapper.face(i_face);
918 face_nb_node += CheckedConvert::toInteger(lima_face.nb_noeuds());
919 }
920
921 UniqueArray<Int64> faces_first_node_unique_id(lima_nb_face);
922 UniqueArray<Int32> faces_first_node_local_id(lima_nb_face);
923 UniqueArray<Int64> faces_nodes_unique_id(face_nb_node);
924 Integer faces_nodes_unique_id_index = 0;
925
926 UniqueArray<Int64> orig_nodes_id;
927 orig_nodes_id.reserve(100);
928
929 UniqueArray<Integer> face_nodes_index;
930 face_nodes_index.reserve(100);
931
932 ItemInternalList mesh_nodes(mesh->itemsInternal(IK_Node));
933
934 for( Integer i_face=0; i_face<lima_nb_face; ++i_face ){
935 const LimaFace& lima_face = m_wrapper.face(i_face);
936 Integer n = CheckedConvert::toInteger(lima_face.nb_noeuds());
937 orig_nodes_id.resize(n);
938 face_nodes_index.resize(n);
939 for( Integer z=0; z<n; ++z )
940 orig_nodes_id[z] = nodes_unique_id[CheckedConvert::toInteger(lima_face.noeud(z).id() - 1)];
941 //face_orig_nodes_id[z] = lima_face.noeud(z).id() - 1;
942
943#if 0
944 cout << "FACE LIMA1 " << lima_face.id()-1 << " ";
945 for( Integer z=0; z<n; ++z )
946 cout << " " << orig_nodes_id[z];
947 cout << '\n';
948#endif
949
950 mesh_utils::reorderNodesOfFace2(orig_nodes_id,face_nodes_index);
951 for( Integer z=0; z<n; ++z )
952 faces_nodes_unique_id[faces_nodes_unique_id_index+z] = orig_nodes_id[face_nodes_index[z]];
953 faces_first_node_unique_id[i_face] = orig_nodes_id[face_nodes_index[0]];
954 faces_nodes_unique_id_index += n;
955 }
956
957 mesh->nodeFamily()->itemsUniqueIdToLocalId(faces_first_node_local_id,faces_first_node_unique_id);
958
959 faces_nodes_unique_id_index = 0;
960 for( Integer i_face=0; i_face<lima_nb_face; ++i_face ){
961 const LimaFace& lima_face = m_wrapper.face(i_face);
962 Integer n = CheckedConvert::toInteger(lima_face.nb_noeuds());
963 Int64ConstArrayView face_nodes_id(n,&faces_nodes_unique_id[faces_nodes_unique_id_index]);
964 Node current_node(mesh_nodes[faces_first_node_local_id[i_face]]);
965 Face face = mesh_utils::getFaceFromNodesUnique(current_node,face_nodes_id);
966
967 if (face.null()){
968 OStringStream ostr;
969 ostr() << "(Nodes:";
970 for( Integer z=0; z<n; ++z )
971 ostr() << ' ' << face_nodes_id[z];
972 ostr() << " - " << current_node.localId() << ")";
973 ARCANE_FATAL("INTERNAL: Lima face index={0} with nodes '{1}' is not in node/face connectivity",
974 i_face,ostr.str());
975 }
976 faces_id[i_face] = face.localId();
977
978 faces_nodes_unique_id_index += n;
979 }
980 }
981
982 IItemFamily* node_family = mesh->nodeFamily();
983 IItemFamily* face_family = mesh->faceFamily();
984 IItemFamily* cell_family = mesh->cellFamily();
985
986 // Création des groupes
987 if (use_internal_partition && sid!=0){
988 {
989 Integer nb = CheckedConvert::toInteger(lima.nb_nuages());
990 for( Integer i=0; i<nb; ++i ){
991 const Lima::Nuage& lima_group = lima.nuage(i);
992 std::string group_name = lima_group.nom();
993 LimaUtils::createGroup(node_family,group_name,Int32ArrayView());
994 }
995 }
996 {
997 Integer nb = m_wrapper.nbFaceGroup();
998 for( Integer i=0; i<nb; ++i ){
999 const LimaFaceGroup& lima_group = m_wrapper.faceGroup(i);
1000 std::string group_name = lima_group.nom();
1001 LimaUtils::createGroup(face_family,group_name,Int32ArrayView());
1002 }
1003 }
1004 {
1005 Integer nb = m_wrapper.nbCellGroup();
1006 for( Integer i=0; i<nb; ++i ){
1007 const LimaCellGroup& lima_group = m_wrapper.cellGroup(i);
1008 std::string group_name = lima_group.nom();
1009 LimaUtils::createGroup(cell_family,group_name,Int32ArrayView());
1010 }
1011 }
1012 }
1013 else{
1014 UniqueArray<Int64> unique_ids;
1015 UniqueArray<Int32> local_ids;
1016 Integer sub_domain_id = subDomain()->subDomainId();
1017 // Création des groupes de noeuds
1018 {
1019 Integer nb = CheckedConvert::toInteger(lima.nb_nuages());
1020 for( Integer i=0; i<nb; ++i ){
1021 const Lima::Nuage& lima_group = lima.nuage(i);
1022 Integer nb_item_in_group = CheckedConvert::toInteger(lima_group.nb_noeuds());
1023 std::string group_name = lima_group.nom();
1024 unique_ids.resize(nb_item_in_group);
1025 local_ids.resize(nb_item_in_group);
1026 for( Integer z=0; z<nb_item_in_group; ++z ){
1027 Integer lima_node_id = CheckedConvert::toInteger(lima_group.noeud(z).id());
1028 unique_ids[z] = nodes_unique_id[lima_node_id - 1];
1029 }
1030 mesh->nodeFamily()->itemsUniqueIdToLocalId(local_ids,unique_ids);
1031 bool remove_group = false;
1032 if (group_name=="LOCALN" || group_name=="localn"){
1033 remove_group = true;
1034 }
1035 debug() << "Vérification du groupe '" << group_name << "'";
1036 if (group_name.length()>3 && !remove_group){
1037 String grp = group_name.c_str();
1038 //grp.left(3);
1039 debug() << "Vérification du groupe '" << group_name << "' (2) '" << grp << "'";
1040 if (grp.startsWith("NF_")){
1041 //grp = group_name.c_str();
1042 //grp.right(group_name.length()-3);
1043 grp = grp.substring(3);
1044 Integer ghost_sub_domain_id = 0;
1045 bool is_bad = builtInGetValue(ghost_sub_domain_id,grp);
1046 debug() << "Vérification du groupe '" << group_name << "' (3) " << is_bad;
1047 if (!is_bad){
1048 remove_group = true;
1049 }
1050 }
1051 }
1052 if (!remove_group){
1053 log() << "NodeGroup Name <" << group_name << "> (" << nb_item_in_group << " elements)";
1054 LimaUtils::createGroup(node_family,group_name,local_ids);
1055 }
1056 }
1057 }
1058 // Création des groupes de faces
1059 {
1060 Integer nb = m_wrapper.nbFaceGroup();
1061 for( Integer i=0; i<nb; ++i ){
1062 const LimaFaceGroup& lima_group = m_wrapper.faceGroup(i);
1063 Integer nb_item_in_group = m_wrapper.faceGroupNbFace(lima_group);
1064 local_ids.resize(nb_item_in_group);
1065 // Comme les numéros des faces données par Lima ne correspondent
1066 // pas à celles créées dans Arcane, on utilise le tableau de correspondance
1067 for( Integer z=0; z<nb_item_in_group; ++z ){
1068 local_ids[z] = faces_id[CheckedConvert::toInteger(m_wrapper.faceFaceGroup(lima_group,z).id() - 1)];
1069 }
1070 std::string group_name = lima_group.nom();
1071 log() << "FaceGroup Name <" << group_name << "> (" << nb_item_in_group << " elements)";
1072 LimaUtils::createGroup(face_family,group_name,local_ids);
1073 }
1074 }
1075 // Création des groupes de mailles
1076 {
1077 Integer nb = m_wrapper.nbCellGroup();
1078 for( Integer i=0; i<nb; ++i ){
1079 const LimaCellGroup& lima_group = m_wrapper.cellGroup(i);
1080 Integer nb_item_in_group = m_wrapper.cellGroupNbCell(lima_group);
1081 std::string group_name = lima_group.nom();
1082 unique_ids.resize(nb_item_in_group);
1083 local_ids.resize(nb_item_in_group);
1084 for( Integer z=0; z<nb_item_in_group; ++z ){
1085 unique_ids[z] = cells_unique_id[CheckedConvert::toInteger(m_wrapper.cellCellGroup(lima_group,z).id() - 1)];
1086 }
1087 mesh->cellFamily()->itemsUniqueIdToLocalId(local_ids,unique_ids);
1088 bool remove_group = false;
1089 if (group_name=="LOCAL" || group_name=="local"){
1090 ItemInternalList cells(mesh->itemsInternal(IK_Cell));
1091 for( Integer z=0, sz=nb_item_in_group; z<sz; ++z )
1092 cells[local_ids[z]]->setOwner(sub_domain_id,sub_domain_id);
1093 remove_group = true;
1094 }
1095 if (!remove_group){
1096 String grp(group_name.c_str());
1097 if (grp.startsWith("MF_")){
1098 info() << "Le groupe de mailles " << group_name << " n'est pas utilisé";
1099 remove_group = true;
1100 }
1101 }
1102 if (!remove_group){
1103 log() << "CellGroup Name <" << group_name << "> (" << nb_item_in_group << " elements)";
1104 LimaUtils::createGroup(cell_family,group_name,local_ids);
1105 }
1106 }
1107 }
1108 }
1109
1110
1111 {
1112 // Remplit la variable contenant les coordonnées des noeuds
1113 // En parallèle avec le maillage déjà découpé par Decoupe3D, le
1114 // maillage contient déjà une couche de mailles fantomes. Pour
1115 // avoir les coordonnées des noeuds si on a besoin que d'une couche
1116 // de mailles fantomes, il suffit donc de parcourir tous
1117 // les noeuds. Si on a besoin de plusieurs couches de mailles fantomes,
1118 // il faut faire une synchronisation.
1119 VariableNodeReal3& nodes_coord_var(mesh->nodesCoordinates());
1120 NodeGroup nodes = mesh->allNodes();
1121 Integer nb_ghost_layer = mesh->ghostLayerMng()->nbGhostLayer();
1122 if (nb_ghost_layer>1)
1123 nodes = mesh->ownNodes();
1124 ENUMERATE_NODE(i,nodes){
1125 const Node& node = *i;
1126 nodes_coord_var[node] = nodes_coords.lookupValue(node.uniqueId());
1127 //info() << "Coord: " << node.uniqueId() << " v=" << nodes_coord_var[node];
1128 }
1129 if (nb_ghost_layer>1)
1130 nodes_coord_var.synchronize();
1131 }
1132
1133
1134 // -------------------------------- Lecture des groupes
1135 info() << "Nombre de nuages " << lima.nb_nuages();
1136 info() << "Nombre de lignes " << lima.nb_lignes();
1137 info() << "Nombre de surfaces " << lima.nb_surfaces();
1138 info() << "Nombre de volumes " << lima.nb_volumes();
1139
1140 // -------------------------------- Création des structures internes.
1141
1142 //_buildInternalMesh();
1143
1144 logdate() << "Fin de lecture du fichier";
1145 return false;
1146}
1147
1148/*---------------------------------------------------------------------------*/
1149/*---------------------------------------------------------------------------*/
1150
1151template<typename ReaderWrapper> void LimaWrapper<ReaderWrapper>::
1152_getProcList(UniqueArray<Integer>& proc_list,const String& dir_name)
1153{
1154 ISubDomain* sd = subDomain();
1155 StringBuilder comm_file_nameb;
1156 if (!dir_name.empty()){
1157 comm_file_nameb += dir_name;
1158 comm_file_nameb += "/";
1159 }
1160 comm_file_nameb += "Communications";
1161 String comm_file_name = comm_file_nameb.toString();
1162
1163 // Lecture du fichier de communication
1164 ScopedPtrT<IXmlDocumentHolder> doc_holder(sd->ioMng()->parseXmlFile(comm_file_name));
1165 if (!doc_holder.get())
1166 ARCANE_FATAL("Invalid file '{0}'",comm_file_name);
1167
1168 XmlNode root_elem = doc_holder->documentNode().documentElement();
1169 XmlNode cpu_elem;
1170 XmlNodeList cpu_list = root_elem.child(String("cpus")).children(String("cpu-from"));
1171
1172 String ustr_buf = String::fromNumber(sd->subDomainId());
1173 String ustr_id(String("id"));
1174 for( Integer i=0, s=cpu_list.size(); i<s; ++i ){
1175 String id_str = cpu_list[i].attrValue(ustr_id);
1176 if (id_str==ustr_buf){
1177 cpu_elem = cpu_list[i];
1178 break;
1179 }
1180 }
1181 if (cpu_elem.null())
1182 ARCANE_FATAL("No element <cpus/cpu-from[@id=\"{0}\"]>",sd->subDomainId());
1183 {
1184 cpu_list = cpu_elem.children(String("cpu-to"));
1185 debug() << "Nb procs " << cpu_list.size();
1186 for( Integer i=0; i<cpu_list.size(); ++i ){
1187 Integer v = cpu_list[i].valueAsInteger();
1188 proc_list.add(v);
1189 debug() << "Read proc " << v;
1190 }
1191 }
1192}
1193
1194/*---------------------------------------------------------------------------*/
1195/*---------------------------------------------------------------------------*/
1196
1197class LimaCaseMeshReader
1198: public AbstractService
1199, public ICaseMeshReader
1200{
1201 public:
1202
1203 class Builder
1204 : public IMeshBuilder
1205 {
1206 public:
1207
1208 explicit Builder(ISubDomain* sd, const CaseMeshReaderReadInfo& read_info)
1209 : m_sub_domain(sd)
1210 , m_trace_mng(sd->traceMng())
1211 , m_read_info(read_info)
1212 {}
1213
1214 public:
1215
1216 void fillMeshBuildInfo(MeshBuildInfo& build_info) override
1217 {
1218 ARCANE_UNUSED(build_info);
1219 }
1221 {
1222 LimaMeshReader reader(m_sub_domain);
1223 String fname = m_read_info.fileName();
1224 m_trace_mng->info() << "Lima Reader (ICaseMeshReader) file_name=" << fname;
1225 bool use_length_unit = true; // Avec le ICaseMeshReader on utilise toujours le système d'unité.
1226 String directory_name = m_read_info.directoryName();
1227 IMeshReader::eReturnType ret = reader.readMesh(pm, fname, directory_name, m_read_info.isParallelRead(), use_length_unit);
1228 if (ret != IMeshReader::RTOk)
1229 ARCANE_FATAL("Can not read MSH File");
1230 }
1231
1232 private:
1233
1234 ISubDomain* m_sub_domain;
1235 ITraceMng* m_trace_mng;
1236 CaseMeshReaderReadInfo m_read_info;
1237 };
1238
1239 public:
1240
1241 explicit LimaCaseMeshReader(const ServiceBuildInfo& sbi)
1242 : AbstractService(sbi), m_sub_domain(sbi.subDomain())
1243 {}
1244
1245 public:
1246
1248 {
1249 IMeshBuilder* builder = nullptr;
1250 String str = read_info.format();
1251 if (str=="unf" || str=="mli" || str=="mli2" || str=="ice" || str=="uns" || str=="unv")
1252 builder = new Builder(m_sub_domain, read_info);
1253 return makeRef(builder);
1254 }
1255
1256 private:
1257
1258 ISubDomain* m_sub_domain = nullptr;
1259};
1260
1261/*---------------------------------------------------------------------------*/
1262/*---------------------------------------------------------------------------*/
1263
1264ARCANE_REGISTER_SERVICE(LimaCaseMeshReader,
1265 ServiceProperty("LimaCaseMeshReader", ST_SubDomain),
1266 ARCANE_SERVICE_INTERFACE(ICaseMeshReader));
1267
1268/*---------------------------------------------------------------------------*/
1269/*---------------------------------------------------------------------------*/
1270
1271/*---------------------------------------------------------------------------*/
1272/*---------------------------------------------------------------------------*/
1273
1274class LimaMeshWriter
1275: public AbstractService
1276, public IMeshWriter
1277{
1278 public:
1279 LimaMeshWriter(const ServiceBuildInfo& sbi)
1280 : AbstractService(sbi), m_sub_domain(sbi.subDomain()) {}
1281 public:
1282 virtual void build() {}
1283 virtual bool writeMeshToFile(IMesh* mesh,const String& file_name);
1284
1285 private:
1286 ISubDomain* m_sub_domain;
1287 void _writeItem(Lima::Maillage& lima_mesh,ConstArrayView<Lima::Noeud> nodes,
1288 ItemWithNodes item);
1289};
1290
1291/*---------------------------------------------------------------------------*/
1292/*---------------------------------------------------------------------------*/
1293
1294ARCANE_REGISTER_SERVICE(LimaMeshWriter,
1295 ServiceProperty("Lima",ST_SubDomain),
1296 ARCANE_SERVICE_INTERFACE(IMeshWriter));
1297
1298/*---------------------------------------------------------------------------*/
1299/*---------------------------------------------------------------------------*/
1300
1301void LimaMeshWriter::
1302_writeItem(Lima::Maillage& m,ConstArrayView<Lima::Noeud> nodes,ItemWithNodes c)
1303{
1304 switch(c.type()){
1305 case IT_Octaedron12:
1306 m.ajouter(Lima::Polyedre(nodes[c.node(0).localId()],nodes[c.node(1).localId()],
1307 nodes[c.node(2).localId()],nodes[c.node(3).localId()],
1308 nodes[c.node(4).localId()],nodes[c.node(5).localId()],
1309 nodes[c.node(6).localId()],nodes[c.node(7).localId()],
1310 nodes[c.node(8).localId()],nodes[c.node(9).localId()],
1311 nodes[c.node(10).localId()],nodes[c.node(11).localId()]));
1312 break;
1313 case IT_Heptaedron10:
1314 m.ajouter(Lima::Polyedre(nodes[c.node(0).localId()],nodes[c.node(1).localId()],
1315 nodes[c.node(2).localId()],nodes[c.node(3).localId()],
1316 nodes[c.node(4).localId()],nodes[c.node(5).localId()],
1317 nodes[c.node(6).localId()],nodes[c.node(7).localId()],
1318 nodes[c.node(8).localId()],nodes[c.node(9).localId()]));
1319 break;
1320 case IT_Hexaedron8:
1321 m.ajouter(Lima::Polyedre(nodes[c.node(0).localId()],nodes[c.node(1).localId()],
1322 nodes[c.node(2).localId()],nodes[c.node(3).localId()],
1323 nodes[c.node(4).localId()],nodes[c.node(5).localId()],
1324 nodes[c.node(6).localId()],nodes[c.node(7).localId()]));
1325 break;
1326 case IT_Pentaedron6:
1327 m.ajouter(Lima::Polyedre(nodes[c.node(0).localId()],nodes[c.node(1).localId()],
1328 nodes[c.node(2).localId()],nodes[c.node(3).localId()],
1329 nodes[c.node(4).localId()],nodes[c.node(5).localId()]));
1330 break;
1331 case IT_Pyramid5:
1332 m.ajouter(Lima::Polyedre(nodes[c.node(0).localId()],nodes[c.node(1).localId()],
1333 nodes[c.node(2).localId()],nodes[c.node(3).localId()],
1334 nodes[c.node(4).localId()]));
1335 break;
1336 case IT_Tetraedron4:
1337 m.ajouter(Lima::Polyedre(nodes[c.node(0).localId()],nodes[c.node(1).localId()],
1338 nodes[c.node(2).localId()],nodes[c.node(3).localId()]));
1339 break;
1340 case IT_Hexagon6:
1341 m.ajouter(Lima::Polygone(nodes[c.node(0).localId()],nodes[c.node(1).localId()],
1342 nodes[c.node(2).localId()],nodes[c.node(3).localId()],
1343 nodes[c.node(4).localId()],nodes[c.node(5).localId()]));
1344 break;
1345 case IT_Pentagon5:
1346 m.ajouter(Lima::Polygone(nodes[c.node(0).localId()],nodes[c.node(1).localId()],
1347 nodes[c.node(2).localId()],nodes[c.node(3).localId()],
1348 nodes[c.node(4).localId()]));
1349 break;
1350 case IT_Quad4:
1351 m.ajouter(Lima::Polygone(nodes[c.node(0).localId()],nodes[c.node(1).localId()],
1352 nodes[c.node(2).localId()],nodes[c.node(3).localId()]));
1353 break;
1354 case IT_Triangle3:
1355 m.ajouter(Lima::Polygone(nodes[c.node(0).localId()],nodes[c.node(1).localId()],
1356 nodes[c.node(2).localId()]));
1357 break;
1358 case IT_Line2:
1359 m.ajouter(Lima::Bras(nodes[c.node(0).localId()],nodes[c.node(1).localId()]));
1360 break;
1361 }
1362}
1363
1364/*---------------------------------------------------------------------------*/
1365/*---------------------------------------------------------------------------*/
1372writeMeshToFile(IMesh* mesh,const String& file_name)
1373{
1374 ITraceMng* trace = mesh->traceMng();
1375 int dimension = mesh->dimension();
1376
1377 std::string std_file_name = file_name.localstr();
1378 //TODO: FAIRE EXTENSION si non presente
1379 // Regarde si le fichier a l'extension '.unf', '.mli' ou '.mli2'.
1380 // Sinon, ajoute '.mli2'
1381 const size_t rpos2 = std_file_name.rfind(".mli2");
1382 std::string::size_type std_end = std::string::npos;
1383 bool need_mutex = rpos2!=std_end;
1384 if (rpos2==std_end && std_file_name.rfind(".mli")==std_end && std_file_name.rfind(".unf")==std_end){
1385 std_file_name += ".mli2";
1386 need_mutex = true;
1387 }
1388 info() << "FINAL_FILE_NAME=" << std_file_name;
1389 Lima::Maillage lima(std_file_name);
1390
1391 if (dimension==3)
1392 lima.dimension(Lima::D3);
1393 else if (dimension==2)
1394 lima.dimension(Lima::D2);
1395
1396 IItemFamily* node_family = mesh->nodeFamily();
1397 IItemFamily* edge_family = mesh->edgeFamily();
1398 IItemFamily* face_family = mesh->faceFamily();
1399 IItemFamily* cell_family = mesh->cellFamily();
1400
1401 Integer mesh_nb_node = node_family->nbItem();
1402 Integer mesh_nb_edge = edge_family->nbItem();
1403 Integer mesh_nb_face = face_family->nbItem();
1404 Integer mesh_nb_cell = cell_family->nbItem();
1405
1406 NodeInfoListView nodes(node_family);
1407 EdgeInfoListView edges(edge_family);
1408 FaceInfoListView faces(face_family);
1409 CellInfoListView cells(cell_family);
1410
1411 UniqueArray<Lima::Noeud> lm_nodes(mesh_nb_node);
1412
1413 VariableItemReal3& nodes_coords = mesh->nodesCoordinates();
1414
1415 // Sauve les noeuds
1416 for( Integer i=0; i<mesh_nb_node; ++i ){
1417 Node node = nodes[i];
1418 Real3 coord = nodes_coords[node];
1419 lm_nodes[i].set_x(Convert::toDouble(coord.x));
1420 lm_nodes[i].set_y(Convert::toDouble(coord.y));
1421 lm_nodes[i].set_z(Convert::toDouble(coord.z));
1422 lima.ajouter(lm_nodes[i]);
1423 }
1424
1425 // Sauve les arêtes
1426 for( Integer i=0; i<mesh_nb_edge; ++i ){
1427 _writeItem(lima,lm_nodes,edges[i]);
1428 }
1429
1430 // Sauve les faces
1431 for( Integer i=0; i<mesh_nb_face; ++i ){
1432 _writeItem(lima,lm_nodes,faces[i]);
1433 }
1434
1435 // Sauve les mailles
1436 for( Integer i=0; i<mesh_nb_cell; ++i ){
1437 _writeItem(lima,lm_nodes,cells[i]);
1438 }
1439
1440 try{
1441
1442 // Sauve les groupes de noeuds
1443 for( ItemGroupCollection::Enumerator i(node_family->groups()); ++i; ){
1444 ItemGroup group = *i;
1445 if (group.isAllItems())
1446 continue;
1447 Lima::Nuage lm_group(group.name().localstr());
1448 lima.ajouter(lm_group);
1449 ENUMERATE_ITEM(iitem,group){
1450 lm_group.ajouter(lima.noeud(iitem.localId()));
1451 }
1452 }
1453
1454 // Sauve les groupes d'arêtes
1455 for( ItemGroupCollection::Enumerator i(edge_family->groups()); ++i; ){
1456 ItemGroup group = *i;
1457 if (group.isAllItems())
1458 continue;
1459 Lima::Ligne lm_group(group.name().localstr());
1460 lima.ajouter(lm_group);
1461 ENUMERATE_ITEM(iitem,group){
1462 lm_group.ajouter(lima.bras(iitem.localId()));
1463 }
1464 }
1465
1466 // Sauve les groupes de face
1467 for( ItemGroupCollection::Enumerator i(face_family->groups()); ++i; ){
1468 ItemGroup group = *i;
1469 if (group.isAllItems())
1470 continue;
1471 if (dimension==3){
1472 Lima::Surface lm_group(group.name().localstr());
1473 lima.ajouter(lm_group);
1474 ENUMERATE_ITEM(iitem,group){
1475 lm_group.ajouter(lima.polygone(iitem.localId()));
1476 }
1477 }
1478 else if (dimension==2){
1479 Lima::Ligne lm_group(group.name().localstr());
1480 lima.ajouter(lm_group);
1481 ENUMERATE_ITEM(iitem,group){
1482 lm_group.ajouter(lima.bras(iitem.localId()));
1483 }
1484 }
1485 }
1486
1487 // Sauve les groupes de maille
1488 for( ItemGroupCollection::Enumerator i(cell_family->groups()); ++i; ){
1489 ItemGroup group = *i;
1490 if (group.isAllItems())
1491 continue;
1492 if (dimension==3){
1493 Lima::Volume lm_group(group.name().localstr());
1494 lima.ajouter(lm_group);
1495 ENUMERATE_ITEM(iitem,group){
1496 lm_group.ajouter(lima.polyedre(iitem.localId()));
1497 }
1498 }
1499 else if (dimension==2){
1500 Lima::Surface lm_group(group.name().localstr());
1501 lima.ajouter(lm_group);
1502 ENUMERATE_ITEM(iitem,group){
1503 lm_group.ajouter(lima.polygone(iitem.localId()));
1504 }
1505 }
1506 }
1507 info(4) << "Writing file '" << std_file_name << "'";
1508
1509 {
1510 GlobalLimaMutex sc(need_mutex);
1511 lima.ecrire(std_file_name);
1512 }
1513 }
1514 catch(const std::exception& ex){
1515 trace->warning() << "Exception (std::exception) in LIMA: Can not write file <" << std_file_name << ">"
1516 << " Exception: " << ex.what() << '\n';
1517 return true;
1518 }
1519 catch(...){
1520 trace->warning() << "Exception (unknown) in LIMA: Can not write file <" << std_file_name << ">";
1521 return true;
1522 }
1523
1524 return false;
1525}
1526
1527/*---------------------------------------------------------------------------*/
1528/*---------------------------------------------------------------------------*/
1529
1530} // End namespace Arcane
1531
1532/*---------------------------------------------------------------------------*/
1533/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Types et macros pour itérer sur les entités du maillage.
#define ENUMERATE_ITEM(name, group)
Enumérateur générique d'un groupe de noeuds.
#define ENUMERATE_NODE(name, group)
Enumérateur générique d'un groupe de noeuds.
Fonctions utilitaires sur le maillage.
bool reorderNodesOfFace2(Int64ConstArrayView nodes_unique_id, Int32ArrayView new_index)
Réordonne les noeuds d'une face.
Ce fichier contient les différentes fabriques de services et macro pour enregistrer les services.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro pour déclarer une interface lors de l'enregistrement d'un service.
Classe de base d'un service.
AbstractService(const ServiceBuildInfo &)
Constructeur à partir d'un ServiceBuildInfo.
void reserve(Int64 new_capacity)
Réserve le mémoire pour new_capacity éléments.
Informations nécessaires pour la lecture d'un fichier de maillage.
Vue sur les informations des mailles.
Vue constante d'un tableau de type T.
Vue sur les informations des arêtes.
Vue sur les informations des faces.
Face d'une maille.
Definition Item.h:964
Table de hachage pour tableaux associatifs.
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
virtual String language() const =0
Langage utilisé dans le jeu de données.
Interface d'une classe gérant un document XML du jeu de données.
virtual String codeUnitSystem() const =0
Nom du système d'unité du document.
Interface du service de lecture du maillage à partir du jeu de données.
virtual Integer nbGhostLayer() const =0
Nombre de couches fantômes.
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual ItemGroupCollection groups() const =0
Liste des groupes de cette famille.
virtual Integer nbItem() const =0
Nombre d'entités.
virtual Integer dimension()=0
Dimension du maillage (1D, 2D ou 3D).
Interface d'un service de création/lecture du maillage.
Interface du service gérant la lecture d'un maillage.
Definition IMeshReader.h:32
eReturnType
Types des codes de retour d'une lecture ou écriture.
Definition IMeshReader.h:37
@ RTIrrelevant
Non concerné par l'opération. Cela signifie que le format de fichier ne correspond pas à ce lecteur o...
Definition IMeshReader.h:45
@ 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 IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual void synchronizeGroupsAndVariables()=0
Synchronise tous les groupes et les variables du maillage.
virtual IGhostLayerMng * ghostLayerMng() const =0
Gestionnare de couche fantômes associé
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual bool isThreadImplementation() const =0
Indique si l'implémentation utilise les threads.
virtual void setDimension(Integer dim)=0
Positionne la dimension du maillage (1D, 2D ou 3D).
Interface du gestionnaire d'un sous-domaine.
Definition ISubDomain.h:74
virtual ICaseDocument * caseDocument()=0
Document XML du cas.
virtual IParallelMng * parallelMng()=0
Retourne le gestionnaire de parallélisme.
virtual ITimerMng * timerMng() const =0
Retourne le gestionnaire de timers.
Interface d'un gestionnaire de timer.
Definition ITimerMng.h:49
Interface du gestionnaire de traces.
virtual TraceMessage warning()=0
Flot pour un message d'avertissement.
Groupe d'entités de maillage.
Definition ItemGroup.h:49
const String & name() const
Nom du groupe.
Definition ItemGroup.h:76
bool isAllItems() const
Indique si le groupe est celui de toutes les entités.
Definition ItemGroup.cc:610
Elément de maillage s'appuyant sur des noeuds (Edge,Face,Cell).
Definition Item.h:736
void fillMeshBuildInfo(MeshBuildInfo &build_info) override
Remplit build_info avec les informations nécessaires pour créer le maillage.
Definition Lima.cc:1216
void allocateMeshItems(IPrimaryMesh *pm) override
Alloue les entités du maillage géré par ce service.
Definition Lima.cc:1220
Ref< IMeshBuilder > createBuilder(const CaseMeshReaderReadInfo &read_info) const override
Retourne un builder pour créer et lire le maillage dont les informations sont spécifiées dans read_in...
Definition Lima.cc:1247
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:115
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:391
eReturnType readMeshFromFile(IPrimaryMesh *mesh, const XmlNode &mesh_node, const String &file_name, const String &dir_name, bool use_internal_partition) override
Lit un maillage à partir d'un fichier.
Definition Lima.cc:440
void build()
Construction de niveau build du service.
Definition Lima.cc:398
bool allowExtension(const String &str) override
Vérifie si le service supporte les fichiers avec l'extension str.
Definition Lima.cc:402
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:366
virtual bool writeMeshToFile(IMesh *mesh, const String &file_name)
Ecriture du maillage au format Lima.
Definition Lima.cc:1372
virtual void build()
Construction de niveau build du service.
Definition Lima.cc:1282
static void createGroup(IItemFamily *family, const String &name, Int32ArrayView local_ids)
Créé un groupe d'entités.
Definition LimaUtils.cc:43
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:149
Paramètres nécessaires à la construction d'un maillage.
Vue sur les informations des noeuds.
Noeud d'un maillage.
Definition Item.h:582
Flot de sortie lié à une String.
Classe gérant un vecteur de réel de dimension 3.
Definition Real3.h:132
Référence à une instance.
Encapsulation d'un pointeur qui se détruit automatiquement.
Definition ScopedPtr.h:44
ISubDomain * subDomain() const
Accès au ISubDomain associé.
Structure contenant les informations pour créer un service.
Propriétés de création d'un service.
Constructeur de chaîne de caractère unicode.
Chaîne de caractères unicode.
bool null() const
Retourne true si la chaîne est nulle.
Definition String.cc:305
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:228
bool empty() const
Vrai si la chaîne est vide (nulle ou "")
Definition String.cc:316
@ TimerReal
Timer utilisant le temps réel.
Definition Timer.h:76
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessage log() const
Flot pour un message de log.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage warning() const
Flot pour un message d'avertissement.
Vecteur 1D de données avec sémantique par valeur (style STL).
Exception lorsqu'une entité du maillage n'est pas d'un type connu.
Liste de noeuds d'un arbre DOM.
Definition XmlNodeList.h:35
Noeud d'un arbre DOM.
Definition XmlNode.h:51
XmlNode documentElement() const
Retourne le noeud élément du document.
Definition XmlNode.cc:556
String attrValue(const String &name, bool throw_exception=false) const
Valeur de l'attribut name.
Definition XmlNode.cc:225
ItemGroupT< Node > NodeGroup
Groupe de noeuds.
Definition ItemTypes.h:167
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
ItemVariableScalarRefT< Real3 > VariableItemReal3
Grandeur de type coordonn?es 3D.
double toDouble(Real r)
Converti un Real en double.
__host__ __device__ double log(double v)
Logarithme népérien de v.
Definition Math.h:40
constexpr __host__ __device__ bool isEqual(const _Type &a, const _Type &b)
Teste l'égalité bit à bit entre deux valeurs.
Definition Numeric.h:253
String getEnvironmentVariable(const String &name)
Variable d'environnement du nom name.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:339
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
ConstArrayView< ItemInternal * > ItemInternalList
Type de la liste interne des entités.
Definition ItemTypes.h:466
@ ST_SubDomain
Le service s'utilise au niveau du sous-domaine.
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:480
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:341
ArrayView< Int32 > Int32ArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:453
@ IK_Node
Entité de maillage de genre noeud.
@ IK_Cell
Entité de maillage de genre maille.
double Real
Type représentant un réel.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
std::int32_t Int32
Type entier signé sur 32 bits.
Real y
deuxième composante du triplet
Definition Real3.h:36
Real z
troisième composante du triplet
Definition Real3.h:37
Real x
première composante du triplet
Definition Real3.h:35