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