14#include "arcane/utils/IOException.h"
15#include "arcane/utils/FixedArray.h"
16#include "arcane/utils/Collection.h"
17#include "arcane/utils/ITraceMng.h"
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"
28#include "arcane/std/internal/IosGmsh.h"
51 class ArcaneToMshTypeInfo
55 ArcaneToMshTypeInfo() =
default;
58 , m_msh_type(msh_type)
59 , m_reorder_infos(reorder_infos)
66 Int32 m_msh_type = -1;
70 class ItemFamilyWriteInfo
75 explicit ItemFamilyWriteInfo(
ITraceMng* tm)
85 Int32 m_dimension = -1;
86 Int32 m_physical_tag = -1;
95 , m_item_type(item_type)
96 , m_entity_tag(entity_tag)
104 m_physical_tag = tag;
105 m_physical_tag_name = name;
112 Int32 m_entity_tag = -1;
113 Int32 m_physical_tag = -1;
114 String m_physical_tag_name;
125 const ItemGroup& group()
const {
return m_item_group; }
147 IMesh* m_mesh =
nullptr;
160 bool m_has_periodic_info =
false;
168 std::pair<Int64, Int64> _getFamilyMinMaxUniqueId(
IItemFamily* family);
173 void _writePeriodic(std::ostream& ofile);
176 const ArcaneToMshTypeInfo& arcaneToMshTypeInfo(
ItemTypeId arcane_type)
const;
183MshMeshWriter(IMesh* mesh)
184: TraceAccessor(mesh->traceMng())
193void MshMeshWriter::ItemGroupWriteInfo::
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();
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());
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();
221 m_existing_items_type.add(ItemTypeId(i));
222 total_nb_item += nb_type;
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);
233 entity_info.setPhysicalTag(base_entity_index + type_index, group_name);
234 m_entities_by_type.add(entity_info);
240 if (nb_existing_type == 0 && !is_all_items) {
241 Int32 mesh_dim = mesh->dimension();
243 Int32 entity_dim = -1;
245 entity_dim = mesh_dim;
247 entity_dim = mesh_dim - 1;
249 entity_dim = mesh_dim - 2;
251 ARCANE_FATAL(
"Invalid item kind '{0}' for entity dimension", entity_dim);
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);
271 bool has_group =
false;
274 if (group.isAllItems())
276 if (group.isAutoComputed())
278 info() <<
"Processing ItemGroup group=" << group.name() <<
" family=" << group.itemFamily()->name();
279 items_groups.
add(group);
306 m_item_type_mng =
mesh->itemTypeMng();
307 String mesh_file_name(file_name);
309 mesh_file_name = mesh_file_name +
".msh";
310 std::ofstream ofile(mesh_file_name.
localstr());
315 info() <<
"writing file '" << mesh_file_name <<
"'";
317 m_mesh_info = impl::MshMeshGenerationInfo::getReference(
mesh,
false);
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;
323 ofile <<
"$MeshFormat\n";
327 ofile <<
"4.1 0 " <<
sizeof(size_t) <<
"\n";
328 ofile <<
"$EndMeshFormat\n";
338 const Int32 entity_index_increment = 1000;
339 Int32 base_entity_index = entity_index_increment;
341 auto x(std::make_unique<ItemGroupWriteInfo>());
342 x->processGroup(group, base_entity_index);
344 base_entity_index += entity_index_increment;
355 Int64 total_nb_cell = 0;
357 for (
const EntityInfo& entity_info : ginfo->entitiesByType()) {
358 Int32 dim = entity_info.m_dim;
360 ++m_nb_entities_by_dim[dim];
362 Int32 item_type = entity_info.m_item_type;
363 Int32 nb_item = ginfo->itemsByType(item_type).size();
364 total_nb_cell += nb_item;
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 });
381 ofile <<
"$PhysicalNames\n";
382 Int32 nb_tag = m_physical_tags.size();
383 ofile << nb_tag <<
"\n";
386 ofile << tag_info.m_dimension <<
" " << tag_info.m_physical_tag <<
" " <<
'"' << tag_info.m_name <<
'"' <<
"\n";
388 ofile <<
"$EndPhysicalNames\n";
394 _writePeriodic(ofile);
405 ItemGroup all_nodes = m_mesh->allNodes();
434 Real3 node_min_bounding_box;
435 Real3 node_max_bounding_box;
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);
442 Real3 pos = nodes_coords[inode];
446 node_min_bounding_box = min_box;
447 node_max_bounding_box = max_box;
449 if (m_has_periodic_info)
450 m_nb_entities_by_dim[0] = 1;
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";
459 if (m_has_periodic_info) {
460 ofile <<
"1 0.0 0.0 0.0 0\n";
463 for (
Int32 idim = 1; idim < 4; ++idim) {
465 for (
const EntityInfo& entity_info : ginfo->entitiesByType()) {
466 if (entity_info.m_dim != idim)
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;
471 Int32 physical_tag = entity_info.m_physical_tag;
472 if (physical_tag > 0) {
473 ofile <<
" 1 " << physical_tag;
483 ofile <<
"$EndEntities\n";
495 const Int32 mesh_nb_node = m_mesh->nbNode();
497 ItemGroup all_nodes = m_mesh->allNodes();
517 auto [node_min_uid, node_max_uid] = _getFamilyMinMaxUniqueId(node_family);
519 ofile <<
"1 " << mesh_nb_node <<
" " << node_min_uid <<
" " << node_max_uid <<
"\n";
521 ofile <<
"0 " <<
"100 " <<
"0 " << mesh_nb_node <<
"\n";
525 Int64 uid = inode->uniqueId();
526 ofile << uid <<
"\n";
532 Real3 coord = nodes_coords[inode];
533 ofile << coord.
x <<
" " << coord.
y <<
" " << coord.
z <<
"\n";
536 ofile <<
"$EndNodes\n";
550 auto [cell_min_uid, cell_max_uid] = _getFamilyMinMaxUniqueId(cell_family);
563 ofile <<
"$Elements\n";
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";
570 for (
const EntityInfo& entity_info : ginfo->entitiesByType()) {
571 ItemTypeId cell_type = entity_info.m_item_type;
573 ItemTypeInfo* item_type_info = m_item_type_mng->typeFromId(cell_type);
574 Int32 type_dimension = entity_info.m_dim;
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;
588 if (!reorder_infos.
empty()) {
589 for (
Int32 i = 0; i < nb_node_for_type; ++i)
593 for (
Int32 i = 0; i < nb_node_for_type; ++i)
600 ofile <<
"$EndElements\n";
607_writePeriodic(std::ostream& ofile)
623 if (!m_has_periodic_info)
628 Int32 nb_periodic = periodic_one_infos.
size();
629 ofile <<
"$Periodic\n";
630 ofile << nb_periodic <<
"\n";
636 for (
const MshPeriodicOneInfo& one_info : periodic_one_infos) {
646 for (
Int32 i = 0; i < nb_affine; ++i)
647 ofile <<
" " << affine_values[i];
653 Int32 nb_orig_node = one_info.m_nb_corresponding_node;
655 node_local_ids.
resize(nb_orig_node * 2);
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]);
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";
675 ofile <<
"$EndPeriodic\n";
681std::pair<Int64, Int64> MshMeshWriter::
682_getFamilyMinMaxUniqueId(IItemFamily* family)
684 Int64 min_uid = INT64_MAX;
686 ENUMERATE_ (Item, iitem, family->allItems()) {
688 Int64 uid = item.uniqueId();
694 return { min_uid, max_uid };
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);
719 FixedArray<Int16, 10> x({ 0, 1, 2, 3, 4, 5, 6, 7, 9, 8 });
720 _addArcaneTypeInfo(ITI_Tetraedron10, MSH_TET_10, x.view());
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());
732_addArcaneTypeInfo(ItemTypeId arcane_type,
Int32 msh_type, ConstArrayView<Int16> reorder_infos)
734 if (arcane_type.isNull())
744const MshMeshWriter::ArcaneToMshTypeInfo& MshMeshWriter::
745arcaneToMshTypeInfo(ItemTypeId arcane_type)
const
749 if (tx.m_msh_type > 0)
752 ARCANE_THROW(NotSupportedException,
"Arcane type '{0}' is not supported in MSH writer", arcane_type);
763class MshMeshWriterService
780MshMeshWriterService::
781MshMeshWriterService(
const ServiceBuildInfo& sbi)
782: AbstractService(sbi)
#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 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.
Informations sur le type flottant.
Interface d'une famille d'entités.
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.
Exception lorsqu'une erreur d'entrée/sortie est détectée.
Interface du gestionnaire de traces.
Groupe d'entités de maillage.
IItemFamily * itemFamily() const
Famille d'entité à laquelle appartient ce groupe (0 pour le group nul)
Type d'une entité (Item).
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.
Elément de maillage s'appuyant sur des noeuds (Edge,Face,Cell).
Node node(Int32 i) const
i-ème noeud de l'entité
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
É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).
Classe gérant un vecteur de réel de dimension 3.
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.
bool endsWith(const String &s) const
Indique si la chaîne se termine par les caractères de s.
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.
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
ItemGroupT< Cell > CellGroup
Groupe de mailles.
#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
Real z
troisième composante du triplet
Real x
première composante du triplet