Arcane  v3.16.2.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
MshMeshWriter.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* MshMeshWriter.cc (C) 2000-2025 */
9/* */
10/* Lecture/Écriture d'un fichier au format MSH. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/IOException.h"
15#include "arcane/utils/FixedArray.h"
16#include "arcane/utils/Collection.h"
17#include "arcane/utils/ITraceMng.h"
18
19#include "arcane/core/FactoryService.h"
20#include "arcane/core/IMesh.h"
21#include "arcane/core/VariableTypes.h"
22#include "arcane/core/AbstractService.h"
23#include "arcane/core/IMeshWriter.h"
24#include "arcane/core/ItemTypeMng.h"
25#include "arcane/core/SharedVariable.h"
26#include "arcane/core/internal/MshMeshGenerationInfo.h"
27
28#include "arcane/std/internal/IosGmsh.h"
29
30#include <tuple>
31
32/*---------------------------------------------------------------------------*/
33/*---------------------------------------------------------------------------*/
34
35namespace Arcane
36{
37
38/*---------------------------------------------------------------------------*/
39/*---------------------------------------------------------------------------*/
43class MshMeshWriter
44: public TraceAccessor
45{
46 using MshPeriodicOneInfo = impl::MshMeshGenerationInfo::MshPeriodicOneInfo;
47
48 public:
49
51 class ArcaneToMshTypeInfo
52 {
53 public:
54
55 ArcaneToMshTypeInfo() = default;
56 ArcaneToMshTypeInfo(ItemTypeId iti, Int32 msh_type, ConstArrayView<Int16> reorder_infos)
57 : m_arcane_type(iti)
58 , m_msh_type(msh_type)
59 , m_reorder_infos(reorder_infos)
60 {
61 }
62
63 public:
64
65 ItemTypeId m_arcane_type;
66 Int32 m_msh_type = -1;
67 UniqueArray<Int16> m_reorder_infos;
68 };
69
70 class ItemFamilyWriteInfo
71 : public TraceAccessor
72 {
73 public:
74
75 explicit ItemFamilyWriteInfo(ITraceMng* tm)
76 : TraceAccessor(tm)
77 {
78 }
79 };
80
82 {
83 public:
84
85 Int32 m_dimension = -1;
86 Int32 m_physical_tag = -1;
87 String m_name;
88 };
89 struct EntityInfo
90 {
91 public:
92
93 EntityInfo(Int32 dim, ItemTypeId item_type, Int32 entity_tag)
94 : m_dim(dim)
95 , m_item_type(item_type)
96 , m_entity_tag(entity_tag)
97 {
98 }
99
100 public:
101
102 void setPhysicalTag(Int32 tag, const String& name)
103 {
104 m_physical_tag = tag;
105 m_physical_tag_name = name;
106 }
107
108 public:
109
110 Int32 m_dim = -1;
111 ItemTypeId m_item_type;
112 Int32 m_entity_tag = -1;
113 Int32 m_physical_tag = -1;
114 String m_physical_tag_name;
115 };
116
118 {
119 public:
120
121 void processGroup(ItemGroup group, Int32 base_entity_index);
122
123 public:
124
125 const ItemGroup& group() const { return m_item_group; }
126 ConstArrayView<EntityInfo> entitiesByType() const { return m_entities_by_type; }
127 ConstArrayView<Int32> itemsByType(Int32 item_type) const { return m_items_by_type[item_type]; }
128
129 private:
130
131 ItemGroup m_item_group;
132 UniqueArray<EntityInfo> m_entities_by_type;
133 FixedArray<UniqueArray<Int32>, NB_BASIC_ITEM_TYPE> m_items_by_type;
134 UniqueArray<ItemTypeId> m_existing_items_type;
135 };
136
137 public:
138
139 explicit MshMeshWriter(IMesh* mesh);
140
141 public:
142
143 void writeMesh(const String& file_name);
144
145 private:
146
147 IMesh* m_mesh = nullptr;
148 ItemTypeMng* m_item_type_mng = nullptr;
149
150 // Liste des tags physiques
151 UniqueArray<PhysicalTagInfo> m_physical_tags;
152
153 // Nombre d'entités par dimension
154 FixedArray<Int32, 4> m_nb_entities_by_dim;
155
157 std::vector<std::unique_ptr<ItemGroupWriteInfo>> m_groups_write_info_list;
158
159 impl::MshMeshGenerationInfo* m_mesh_info = nullptr;
160 bool m_has_periodic_info = false;
161
164
165 private:
166
167 bool _writeMeshToFileV4(IMesh* mesh, const String& file_name);
168 std::pair<Int64, Int64> _getFamilyMinMaxUniqueId(IItemFamily* family);
169 void _addGroupsToProcess(IItemFamily* family, Array<ItemGroup>& items_groups);
170 void _writeEntities(std::ostream& ofile);
171 void _writeNodes(std::ostream& ofile);
172 void _writeElements(std::ostream& ofile, Int64 total_nb_cell);
173 void _writePeriodic(std::ostream& ofile);
174 void _initTypes();
175 void _addArcaneTypeInfo(ItemTypeId arcane_type, Int32 msh_type, ConstArrayView<Int16> reorder_infos = {});
176 const ArcaneToMshTypeInfo& arcaneToMshTypeInfo(ItemTypeId arcane_type) const;
177};
178
179/*---------------------------------------------------------------------------*/
180/*---------------------------------------------------------------------------*/
181
182MshMeshWriter::
183MshMeshWriter(IMesh* mesh)
184: TraceAccessor(mesh->traceMng())
185, m_mesh(mesh)
186{
187 _initTypes();
188}
189
190/*---------------------------------------------------------------------------*/
191/*---------------------------------------------------------------------------*/
192
193void MshMeshWriter::ItemGroupWriteInfo::
194processGroup(ItemGroup group, Int32 base_entity_index)
195{
196 m_item_group = group;
197 String group_name = group.name();
198 bool is_all_items = group.isAllItems();
199 IItemFamily* family = group.itemFamily();
200 IMesh* mesh = family->mesh();
201 ItemTypeMng* item_type_mng = mesh->itemTypeMng();
202 ITraceMng* tm = family->traceMng();
203
204 // Pour GMSH, il faut trier les mailles par leur type (Triangle, Quadrangle, ...)
205 // On fait une entity MSH par type d'entité Arcane.
206
207 ENUMERATE_ (Item, iitem, group) {
208 Item item = *iitem;
209 Int16 item_type = item.type();
210 if (item_type >= NB_BASIC_ITEM_TYPE || item_type <= 0)
211 ARCANE_FATAL("Only pre-defined Item type are supported (current item type is '{0}')",
212 item_type_mng->typeFromId(item_type)->typeName());
213 m_items_by_type[item_type].add(item.localId());
214 }
215
216 // Conserve les types pré-définis qui ont des éléments
217 Int64 total_nb_item = 0;
218 for (Int16 i = 0; i < NB_BASIC_ITEM_TYPE; ++i) {
219 Int64 nb_type = m_items_by_type[i].size();
220 if (nb_type > 0)
221 m_existing_items_type.add(ItemTypeId(i));
222 total_nb_item += nb_type;
223 }
224
225 Int32 nb_existing_type = m_existing_items_type.size();
226 tm->info() << "NbExistingType=" << nb_existing_type;
227 for (Int32 type_index = 0; type_index < nb_existing_type; ++type_index) {
228 ItemTypeId item_type = m_existing_items_type[type_index];
229 ItemTypeInfo* item_type_info = item_type_mng->typeFromId(item_type);
230 Int32 type_dimension = item_type_info->dimension();
231 EntityInfo entity_info(type_dimension, item_type, base_entity_index + type_index);
232 if (!is_all_items)
233 entity_info.setPhysicalTag(base_entity_index + type_index, group_name);
234 m_entities_by_type.add(entity_info);
235 }
236
237 // Si le groupe est vide, il faut quand même un tag physique pour que le
238 // groupe soit créé en lecture et ainsi en parallèle garantir que tous
239 // les sous-domaines ont les mêmes groupes.
240 if (nb_existing_type == 0 && !is_all_items) {
241 Int32 mesh_dim = mesh->dimension();
242 eItemKind ik = family->itemKind();
243 Int32 entity_dim = -1;
244 if (ik == IK_Cell)
245 entity_dim = mesh_dim;
246 else if (ik == IK_Face)
247 entity_dim = mesh_dim - 1;
248 else if (ik == IK_Edge)
249 entity_dim = mesh_dim - 2;
250 else
251 ARCANE_FATAL("Invalid item kind '{0}' for entity dimension", entity_dim);
252 // TODO: prendre un type qui correspond à la dimension
253 EntityInfo entity_info(entity_dim, ITI_Tetraedron4, base_entity_index);
254 entity_info.setPhysicalTag(base_entity_index, group_name);
255 m_entities_by_type.add(entity_info);
256 }
257}
258
259/*---------------------------------------------------------------------------*/
260/*---------------------------------------------------------------------------*/
270{
271 bool has_group = false;
272 // Parcours tous les groupes de la famille
273 for (ItemGroup group : family->groups()) {
274 if (group.isAllItems())
275 continue;
276 if (group.isAutoComputed())
277 continue;
278 info() << "Processing ItemGroup group=" << group.name() << " family=" << group.itemFamily()->name();
279 items_groups.add(group);
280 has_group = true;
281 }
282 // Si pas de groupes dans la famille, on prend celui de toutes les entités
283 // si la famille est celle des mailles.
284 if (!has_group && (family->itemKind() == IK_Cell))
285 items_groups.add(family->allItems());
286
287 // TODO: si les groupe traités ne forment pas une partition et qu'il y a
288 // des entités qui ne sont pas dans ces groupes, il faudrait tout de même
289 // les sauver sous la forme d'une $Entity sans groupe physique associé.
290}
291
292/*---------------------------------------------------------------------------*/
293/*---------------------------------------------------------------------------*/
303writeMesh(const String& file_name)
304{
305 IMesh* mesh = m_mesh;
306 m_item_type_mng = mesh->itemTypeMng();
307 String mesh_file_name(file_name);
308 if (!file_name.endsWith(".msh"))
309 mesh_file_name = mesh_file_name + ".msh";
310 std::ofstream ofile(mesh_file_name.localstr());
311 ofile.precision(20);
312 if (!ofile)
313 ARCANE_THROW(IOException, "Unable to open file '{0}' for writing", mesh_file_name);
314
315 info() << "writing file '" << mesh_file_name << "'";
316
317 m_mesh_info = impl::MshMeshGenerationInfo::getReference(mesh, false);
318 if (m_mesh_info) {
319 m_has_periodic_info = m_mesh_info->m_periodic_info.hasValues();
320 info() << "Mesh has 'MSH' generation info has_periodic=" << m_has_periodic_info;
321 }
322
323 ofile << "$MeshFormat\n";
324 // 4.1 pour le format
325 // 0 pour ASCII (1 pour binaire)
326 // 8 pour sizeof(size_t)
327 ofile << "4.1 0 " << sizeof(size_t) << "\n";
328 ofile << "$EndMeshFormat\n";
329
330 IItemFamily* cell_family = mesh->cellFamily();
331 IItemFamily* face_family = mesh->faceFamily();
332 CellGroup all_cells = mesh->allCells();
333
334 UniqueArray<ItemGroup> items_groups;
335 _addGroupsToProcess(cell_family, items_groups);
336 _addGroupsToProcess(face_family, items_groups);
337
338 const Int32 entity_index_increment = 1000;
339 Int32 base_entity_index = entity_index_increment;
340 for (ItemGroup group : items_groups) {
341 auto x(std::make_unique<ItemGroupWriteInfo>());
342 x->processGroup(group, base_entity_index);
343 m_groups_write_info_list.emplace_back(std::move(x));
344 base_entity_index += entity_index_increment;
345 }
346
347 // Pour GMSH, il faut commencer par les 'Entities'.
348 // Il faut une entité par type de maille.
349 // On commence donc par calculer les types de mailles.
350 // Pour les maillages non-manifold les mailles peuvent être de dimension
351 // différentes
352
353 // Calcule le nombre total d'éléments.
354 // Toutes les entités qui ne sont pas de dimension 0 sont des éléments.
355 Int64 total_nb_cell = 0;
356 for (const auto& ginfo : m_groups_write_info_list) {
357 for (const EntityInfo& entity_info : ginfo->entitiesByType()) {
358 Int32 dim = entity_info.m_dim;
359 if (dim >= 0)
360 ++m_nb_entities_by_dim[dim];
361 if (dim > 0) {
362 Int32 item_type = entity_info.m_item_type;
363 Int32 nb_item = ginfo->itemsByType(item_type).size();
364 total_nb_cell += nb_item;
365
366 Int32 physical_tag = entity_info.m_physical_tag;
367 if (physical_tag > 0) {
368 m_physical_tags.add(PhysicalTagInfo{ dim, physical_tag, entity_info.m_physical_tag_name });
369 }
370 }
371 }
372 }
373
374 // $PhysicalNames // same as MSH version 2
375 // numPhysicalNames(ASCII int)
376 // dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
377 // ...
378 // $EndPhysicalNames
379
380 {
381 ofile << "$PhysicalNames\n";
382 Int32 nb_tag = m_physical_tags.size();
383 ofile << nb_tag << "\n";
384 for (const PhysicalTagInfo& tag_info : m_physical_tags) {
385 // TODO: vérifier que le nom ne dépasse pas 127 caractères.
386 ofile << tag_info.m_dimension << " " << tag_info.m_physical_tag << " " << '"' << tag_info.m_name << '"' << "\n";
387 }
388 ofile << "$EndPhysicalNames\n";
389 }
390
391 _writeEntities(ofile);
392 _writeNodes(ofile);
393 _writeElements(ofile, total_nb_cell);
394 _writePeriodic(ofile);
395}
396
397/*---------------------------------------------------------------------------*/
398/*---------------------------------------------------------------------------*/
403_writeEntities(std::ostream& ofile)
404{
405 ItemGroup all_nodes = m_mesh->allNodes();
406
407 // $Entities
408 // numPoints(size_t) numCurves(size_t)
409 // numSurfaces(size_t) numVolumes(size_t)
410 // pointTag(int) X(double) Y(double) Z(double)
411 // numPhysicalTags(size_t) physicalTag(int) ...
412 // ...
413 // curveTag(int) minX(double) minY(double) minZ(double)
414 // maxX(double) maxY(double) maxZ(double)
415 // numPhysicalTags(size_t) physicalTag(int) ...
416 // numBoundingPoints(size_t) pointTag(int; sign encodes orientation) ...
417 // ...
418 // surfaceTag(int) minX(double) minY(double) minZ(double)
419 // maxX(double) maxY(double) maxZ(double)
420 // numPhysicalTags(size_t) physicalTag(int) ...
421 // numBoundingCurves(size_t) curveTag(int; sign encodes orientation) ...
422 // ...
423 // volumeTag(int) minX(double) minY(double) minZ(double)
424 // maxX(double) maxY(double) maxZ(double)
425 // numPhysicalTags(size_t) physicalTag(int) ...
426 // numBoundngSurfaces(size_t) surfaceTag(int; sign encodes orientation) ...
427 // ...
428 // $EndEntities
429
430 // On a besoin de la bouding box de chaque entity.
431 // Pour faire simple, on prend celle de tout le maillage mais à terme
432 // ce serait mieux de calculer directement la bonne valeur.
433 const VariableNodeReal3& nodes_coords = m_mesh->nodesCoordinates();
434 Real3 node_min_bounding_box;
435 Real3 node_max_bounding_box;
436 {
437 Real max_value = FloatInfo<Real>::maxValue();
438 Real min_value = -max_value;
439 Real3 min_box(max_value, max_value, max_value);
440 Real3 max_box(min_value, min_value, min_value);
441 ENUMERATE_ (Node, inode, all_nodes) {
442 Real3 pos = nodes_coords[inode];
443 min_box = math::min(min_box, pos);
444 max_box = math::max(max_box, pos);
445 }
446 node_min_bounding_box = min_box;
447 node_max_bounding_box = max_box;
448 }
449 if (m_has_periodic_info)
450 m_nb_entities_by_dim[0] = 1;
451 {
452 ofile << "$Entities\n";
453 ofile << m_nb_entities_by_dim[0] << " " << m_nb_entities_by_dim[1]
454 << " " << m_nb_entities_by_dim[2] << " " << m_nb_entities_by_dim[3] << "\n";
455
456 // Si on a des informations de périodicité,
457 // on créé une entité de dimension 0 pour que les informations de
458 // périodicité y fassent référence. On lui donne le tag 1.
459 if (m_has_periodic_info) {
460 ofile << "1 0.0 0.0 0.0 0\n";
461 }
462
463 for (Int32 idim = 1; idim < 4; ++idim) {
464 for (const auto& ginfo : m_groups_write_info_list) {
465 for (const EntityInfo& entity_info : ginfo->entitiesByType()) {
466 if (entity_info.m_dim != idim)
467 continue;
468 ofile << entity_info.m_entity_tag << " " << node_min_bounding_box.x << " " << node_min_bounding_box.y << " " << node_min_bounding_box.z
469 << " " << node_max_bounding_box.x << " " << node_max_bounding_box.y << " " << node_max_bounding_box.z;
470 // Pas de tag pour l'instant
471 Int32 physical_tag = entity_info.m_physical_tag;
472 if (physical_tag > 0) {
473 ofile << " 1 " << physical_tag;
474 }
475 else
476 ofile << " 0";
477 // Pas de boundary pour l'instant
478 ofile << " 0";
479 ofile << "\n";
480 }
481 }
482 }
483 ofile << "$EndEntities\n";
484 }
485}
486
487/*---------------------------------------------------------------------------*/
488/*---------------------------------------------------------------------------*/
493_writeNodes(std::ostream& ofile)
494{
495 const Int32 mesh_nb_node = m_mesh->nbNode();
496 IItemFamily* node_family = m_mesh->nodeFamily();
497 ItemGroup all_nodes = m_mesh->allNodes();
498
499 // $Nodes
500 // numEntityBlocks(size_t) numNodes(size_t)
501 // minNodeTag(size_t) maxNodeTag(size_t)
502 // entityDim(int) entityTag(int) parametric(int; 0 or 1)
503 // numNodesInBlock(size_t)
504 // nodeTag(size_t)
505 // ...
506 // x(double) y(double) z(double)
507 // < u(double; if parametric and entityDim >= 1) >
508 // < v(double; if parametric and entityDim >= 2) >
509 // < w(double; if parametric and entityDim == 3) >
510 // ...
511 // ...
512 // $EndNodes
513
514 // Bloc contenant les noeuds
515 ofile << "$Nodes\n";
516
517 auto [node_min_uid, node_max_uid] = _getFamilyMinMaxUniqueId(node_family);
518
519 ofile << "1 " << mesh_nb_node << " " << node_min_uid << " " << node_max_uid << "\n";
520 // entityDim(int) entityTag(int) parametric(int; 0 or 1) numNodesInBlock(size_t)
521 ofile << "0 " << "100 " << "0 " << mesh_nb_node << "\n";
522
523 // Sauve les uniqueId() des noeuds
524 ENUMERATE_ (Node, inode, all_nodes) {
525 Int64 uid = inode->uniqueId();
526 ofile << uid << "\n";
527 }
528
529 // Sauve les coordonnées
530 VariableNodeReal3& nodes_coords = m_mesh->nodesCoordinates();
531 ENUMERATE_ (Node, inode, all_nodes) {
532 Real3 coord = nodes_coords[inode];
533 ofile << coord.x << " " << coord.y << " " << coord.z << "\n";
534 }
535
536 ofile << "$EndNodes\n";
537}
538
539/*---------------------------------------------------------------------------*/
540/*---------------------------------------------------------------------------*/
545_writeElements(std::ostream& ofile, Int64 total_nb_cell)
546{
547 IItemFamily* cell_family = m_mesh->cellFamily();
548
549 // TODO: regarder s'il faut prendre en compte les uniqueId() des faces.
550 auto [cell_min_uid, cell_max_uid] = _getFamilyMinMaxUniqueId(cell_family);
551
552 // $Elements
553 // numEntityBlocks(size_t) numElements(size_t)
554 // minElementTag(size_t) maxElementTag(size_t)
555 // entityDim(int) entityTag(int) elementType(int; see below)
556 // numElementsInBlock(size_t)
557 // elementTag(size_t) nodeTag(size_t) ...
558 // ...
559 // ...
560 // $EndElements
561
562 // Bloc contenant les mailles
563 ofile << "$Elements\n";
564
565 Int32 nb_existing_type = m_nb_entities_by_dim[1] + m_nb_entities_by_dim[2] + m_nb_entities_by_dim[3];
566 ofile << nb_existing_type << " " << total_nb_cell << " " << cell_min_uid << " " << cell_max_uid << "\n";
567 for (const auto& ginfo : m_groups_write_info_list) {
568 ItemGroup item_group = ginfo->group();
569 IItemFamily* item_family = item_group.itemFamily();
570 for (const EntityInfo& entity_info : ginfo->entitiesByType()) {
571 ItemTypeId cell_type = entity_info.m_item_type;
572 ConstArrayView<Int32> items_of_current_type = ginfo->itemsByType(cell_type);
573 ItemTypeInfo* item_type_info = m_item_type_mng->typeFromId(cell_type);
574 Int32 type_dimension = entity_info.m_dim;
575 ofile << "\n";
576 const ArcaneToMshTypeInfo& atm_type_info = arcaneToMshTypeInfo(cell_type);
577 ConstArrayView<Int16> reorder_infos = atm_type_info.m_reorder_infos;
578 ofile << type_dimension << " " << entity_info.m_entity_tag << " " << atm_type_info.m_msh_type
579 << " " << items_of_current_type.size() << "\n";
580 info() << "Writing items family=" << item_family->name() << " type=" << item_type_info->typeName()
581 << " n=" << items_of_current_type.size()
582 << " dimension=" << type_dimension;
583 Int32 nb_node_for_type = item_type_info->nbLocalNode();
584 ENUMERATE_ (ItemWithNodes, iitem, item_family->view(items_of_current_type)) {
585 ItemWithNodes item = *iitem;
586 ofile << item.uniqueId();
587 // Traite l'éventuelle permutation entre numérotation MSH et Arcane
588 if (!reorder_infos.empty()) {
589 for (Int32 i = 0; i < nb_node_for_type; ++i)
590 ofile << " " << item.node(reorder_infos[i]).uniqueId();
591 }
592 else {
593 for (Int32 i = 0; i < nb_node_for_type; ++i)
594 ofile << " " << item.node(i).uniqueId();
595 }
596 ofile << "\n";
597 }
598 }
599 }
600 ofile << "$EndElements\n";
601}
602
603/*---------------------------------------------------------------------------*/
604/*---------------------------------------------------------------------------*/
605
606void MshMeshWriter::
607_writePeriodic(std::ostream& ofile)
608{
609 IItemFamily* node_family = m_mesh->nodeFamily();
610
611 // $Periodic
612 // numPeriodicLinks(size_t)
613 // entityDim(int) entityTag(int) entityTagMaster(int)
614 // numAffine(size_t) value(double) ...
615 // numCorrespondingNodes(size_t)
616 // nodeTag(size_t) nodeTagMaster(size_t)
617 // ...
618 // ...
619 // $EndPeriodic
620
621 // Les informations de périodicité sont conservées dans \a m_mesh_info
622 // qui n'existe pas si on n'est pas issu d'un maillage MSH.
623 if (!m_has_periodic_info)
624 return;
625 ARCANE_CHECK_POINTER(m_mesh_info);
626
627 ConstArrayView<MshPeriodicOneInfo> periodic_one_infos = m_mesh_info->m_periodic_info.m_periodic_list;
628 Int32 nb_periodic = periodic_one_infos.size();
629 ofile << "$Periodic\n";
630 ofile << nb_periodic << "\n";
631
632 UniqueArray<Int64> corresponding_nodes;
633 UniqueArray<Int32> node_local_ids;
634 ;
635 // Sauve chaque lien de périodicité.
636 for (const MshPeriodicOneInfo& one_info : periodic_one_infos) {
637 // On ne sauve pas les entités associées au lien, donc on considère
638 // que l'entité est de dimension zéro et les tags valent aussi zéro.
639 ofile << "\n";
640 ofile << "0 1 1\n";
641
642 // Sauve les valeurs affines associées
643 ConstArrayView<double> affine_values = one_info.m_affine_values;
644 Int32 nb_affine = affine_values.size();
645 ofile << nb_affine;
646 for (Int32 i = 0; i < nb_affine; ++i)
647 ofile << " " << affine_values[i];
648 ofile << "\n";
649
650 // Sauve les couples de noeuds (esclave/maitre)
651 // On ne sauve que les couples dont au moins l'un de des deux noeuds
652 // est présent dans notre sous-domaine.
653 Int32 nb_orig_node = one_info.m_nb_corresponding_node;
654 ConstArrayView<Int64> orig_corresponding_nodes = one_info.m_corresponding_nodes;
655 node_local_ids.resize(nb_orig_node * 2);
656 node_family->itemsUniqueIdToLocalId(node_local_ids, orig_corresponding_nodes, false);
657 corresponding_nodes.reserve(nb_orig_node * 2);
658 corresponding_nodes.clear();
659 for (Int32 i = 0; i < nb_orig_node; ++i) {
660 Int32 slave_index = (i * 2);
661 Int32 master_index = slave_index + 1;
662 bool has_slave = node_local_ids[slave_index] != NULL_ITEM_LOCAL_ID;
663 bool has_master = node_local_ids[master_index] != NULL_ITEM_LOCAL_ID;
664 if (has_slave || has_master) {
665 corresponding_nodes.add(orig_corresponding_nodes[slave_index]);
666 corresponding_nodes.add(orig_corresponding_nodes[master_index]);
667 }
668 }
669 Int32 nb_new_node = corresponding_nodes.size() / 2;
670 ofile << nb_new_node << "\n";
671 for (Int32 i = 0; i < nb_new_node; ++i)
672 ofile << corresponding_nodes[(i * 2)] << " " << corresponding_nodes[(i * 2) + 1] << "\n";
673 }
674
675 ofile << "$EndPeriodic\n";
676}
677
678/*---------------------------------------------------------------------------*/
679/*---------------------------------------------------------------------------*/
680
681std::pair<Int64, Int64> MshMeshWriter::
682_getFamilyMinMaxUniqueId(IItemFamily* family)
683{
684 Int64 min_uid = INT64_MAX;
685 Int64 max_uid = -1;
686 ENUMERATE_ (Item, iitem, family->allItems()) {
687 Item item = *iitem;
688 Int64 uid = item.uniqueId();
689 if (uid < min_uid)
690 min_uid = uid;
691 if (uid > max_uid)
692 max_uid = uid;
693 }
694 return { min_uid, max_uid };
695}
696
697/*---------------------------------------------------------------------------*/
698/*---------------------------------------------------------------------------*/
699
700void MshMeshWriter::
701_initTypes()
702{
703 m_arcane_to_msh_type_infos.resize(NB_BASIC_ITEM_TYPE);
704 // Initialise les types.
705 // Il faut le faire au début de la lecture et ne plus en ajouter après.
706 _addArcaneTypeInfo(ITI_Vertex, MSH_PNT);
707 _addArcaneTypeInfo(ITI_Line2, MSH_LIN_2);
708 _addArcaneTypeInfo(ITI_Cell3D_Line2, MSH_LIN_2);
709 _addArcaneTypeInfo(ITI_Triangle3, MSH_TRI_3);
710 _addArcaneTypeInfo(ITI_Cell3D_Triangle3, MSH_TRI_3);
711 _addArcaneTypeInfo(ITI_Quad4, MSH_QUA_4);
712 _addArcaneTypeInfo(ITI_Cell3D_Quad4, MSH_QUA_4);
713 _addArcaneTypeInfo(ITI_Tetraedron4, MSH_TET_4);
714 _addArcaneTypeInfo(ITI_Hexaedron8, MSH_HEX_8);
715 _addArcaneTypeInfo(ITI_Pentaedron6, MSH_PRI_6);
716 _addArcaneTypeInfo(ITI_Pyramid5, MSH_PYR_5);
717 _addArcaneTypeInfo(ITI_Triangle6, MSH_TRI_6);
718 {
719 FixedArray<Int16, 10> x({ 0, 1, 2, 3, 4, 5, 6, 7, 9, 8 });
720 _addArcaneTypeInfo(ITI_Tetraedron10, MSH_TET_10, x.view());
721 }
722 {
723 FixedArray<Int16, 20> x({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 16, 9, 17, 10, 18, 19, 12, 15, 13, 14 });
724 _addArcaneTypeInfo(ITI_Hexaedron20, MSH_HEX_20, x.view());
725 }
726}
727
728/*---------------------------------------------------------------------------*/
729/*---------------------------------------------------------------------------*/
730
731void MshMeshWriter::
732_addArcaneTypeInfo(ItemTypeId arcane_type, Int32 msh_type, ConstArrayView<Int16> reorder_infos)
733{
734 if (arcane_type.isNull())
735 ARCANE_FATAL("Null Arcane Type {0}", arcane_type);
736 if (arcane_type >= m_arcane_to_msh_type_infos.size())
737 ARCANE_FATAL("Invalid Arcane type '{0}'", arcane_type);
738 m_arcane_to_msh_type_infos[arcane_type] = ArcaneToMshTypeInfo(arcane_type, msh_type, reorder_infos);
739}
740
741/*---------------------------------------------------------------------------*/
742/*---------------------------------------------------------------------------*/
743
744const MshMeshWriter::ArcaneToMshTypeInfo& MshMeshWriter::
745arcaneToMshTypeInfo(ItemTypeId arcane_type) const
746{
747 if (arcane_type < m_arcane_to_msh_type_infos.size()) {
748 const ArcaneToMshTypeInfo& tx = m_arcane_to_msh_type_infos[arcane_type];
749 if (tx.m_msh_type > 0)
750 return tx;
751 }
752 ARCANE_THROW(NotSupportedException, "Arcane type '{0}' is not supported in MSH writer", arcane_type);
753}
754
755/*---------------------------------------------------------------------------*/
756/*---------------------------------------------------------------------------*/
757
758/*---------------------------------------------------------------------------*/
759/*---------------------------------------------------------------------------*/
763class MshMeshWriterService
764: public AbstractService
765, public IMeshWriter
766{
767 public:
768
769 explicit MshMeshWriterService(const ServiceBuildInfo& sbi);
770
771 public:
772
773 void build() override {}
774 bool writeMeshToFile(IMesh* mesh, const String& file_name) override;
775};
776
777/*---------------------------------------------------------------------------*/
778/*---------------------------------------------------------------------------*/
779
780MshMeshWriterService::
781MshMeshWriterService(const ServiceBuildInfo& sbi)
782: AbstractService(sbi)
783{
784}
785
786/*---------------------------------------------------------------------------*/
787/*---------------------------------------------------------------------------*/
788
790writeMeshToFile(IMesh* mesh, const String& file_name)
791{
792 MshMeshWriter writer(mesh);
793 writer.writeMesh(file_name);
794 return false;
795}
796
797/*---------------------------------------------------------------------------*/
798/*---------------------------------------------------------------------------*/
799
800// Obsolète. Utiliser 'MshMeshReader' à la place
802 ServiceProperty("MshNewMeshWriter", ST_SubDomain),
804
806 ServiceProperty("MshMeshWriter", ST_SubDomain),
808
809/*---------------------------------------------------------------------------*/
810/*---------------------------------------------------------------------------*/
811
812} // End namespace Arcane
813
814/*---------------------------------------------------------------------------*/
815/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_(type, name, group)
Enumérateur générique d'un groupe d'entité
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro pour déclarer une interface lors de l'enregistrement d'un service.
Integer size() const
Nombre d'éléments du vecteur.
AbstractService(const ServiceBuildInfo &)
Constructeur à partir d'un ServiceBuildInfo.
Tableau d'items de types quelconques.
void clear()
Supprime les éléments du tableau.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void reserve(Int64 new_capacity)
Réserve le mémoire pour new_capacity éléments.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
constexpr bool empty() const noexcept
true si le tableau est vide (size()==0)
Tableau 1D de taille fixe.
Definition FixedArray.h:45
Informations sur le type flottant.
Definition Limits.h:48
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual ItemGroupCollection groups() const =0
Liste des groupes de cette famille.
virtual ItemGroup allItems() const =0
Groupe de toutes les entités.
virtual String name() const =0
Nom de la famille.
virtual eItemKind itemKind() const =0
Genre des entités.
virtual ItemVectorView view(Int32ConstArrayView local_ids)=0
Vue sur les entités.
virtual void itemsUniqueIdToLocalId(Int32ArrayView local_ids, Int64ConstArrayView unique_ids, bool do_fatal=true) const =0
Converti un tableau de numéros uniques en numéros locaux.
virtual IItemFamily * nodeFamily()=0
Retourne la famille des noeuds.
Interface d'un service d'écriture d'un maillage.
Definition IMeshWriter.h:36
Exception lorsqu'une erreur d'entrée/sortie est détectée.
Definition IOException.h:32
Interface du gestionnaire de traces.
Groupe d'entités de maillage.
Definition ItemGroup.h:49
IItemFamily * itemFamily() const
Famille d'entité à laquelle appartient ce groupe (0 pour le group nul)
Definition ItemGroup.h:123
Type d'une entité (Item).
Definition ItemTypeId.h:32
Infos sur un type d'entité du maillage.
Integer nbLocalNode() const
Nombre de noeuds de l'entité
String typeName() const
Nom du type.
Gestionnaire des types d'entités d'un maillage.
Definition ItemTypeMng.h:65
Elément de maillage s'appuyant sur des noeuds (Edge,Face,Cell).
Definition Item.h:727
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:782
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:225
Écriture des fichiers de maillage au format msh.
void build() override
Construction de niveau build du service.
bool writeMeshToFile(IMesh *mesh, const String &file_name) override
Ecrit un maillage sur un fichier.
Informations de correspondance entre le type MSH et le type Arcane.
Écriture des fichiers de maillage au format msh.
void _writeEntities(std::ostream &ofile)
Écrit le bloc contenant les entités ($Entities).
void writeMesh(const String &file_name)
Ecrit au format MSH V4.
void _writeNodes(std::ostream &ofile)
Écrit le bloc contenant les noeuds ($Nodes).
void _addGroupsToProcess(IItemFamily *family, Array< ItemGroup > &items_groups)
Détermine la liste des groupes à traiter pour une famille.
std::vector< std::unique_ptr< ItemGroupWriteInfo > > m_groups_write_info_list
Liste des informations à écrire pour chaque groupe.
UniqueArray< ArcaneToMshTypeInfo > m_arcane_to_msh_type_infos
Informations de conversion entre les types Arcane et MSH pour les entités.
void _writeElements(std::ostream &ofile, Int64 total_nb_cell)
Écrit le bloc contenant les élements ($Elements).
Noeud d'un maillage.
Definition Item.h:576
Classe gérant un vecteur de réel de dimension 3.
Definition Real3.h:132
Structure contenant les informations pour créer un service.
Propriétés de création d'un service.
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:227
bool endsWith(const String &s) const
Indique si la chaîne se termine par les caractères de s.
Definition String.cc:1083
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessage info() const
Flot pour un message d'information.
Vecteur 1D de données avec sémantique par valeur (style STL).
Informations d'un maillage issu du format 'msh'.
__host__ __device__ Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
Definition MathUtils.h:336
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
ItemGroupT< Cell > CellGroup
Groupe de mailles.
Definition ItemTypes.h:183
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
std::int64_t Int64
Type entier signé sur 64 bits.
@ ST_SubDomain
Le service s'utilise au niveau du sous-domaine.
eItemKind
Genre d'entité de maillage.
@ IK_Cell
Entité de maillage de genre maille.
@ IK_Face
Entité de maillage de genre face.
@ IK_Edge
Entité de maillage de genre arête.
std::int16_t Int16
Type entier signé sur 16 bits.
double Real
Type représentant un réel.
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