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"
52 class ArcaneToMshTypeInfo
56 ArcaneToMshTypeInfo() =
default;
59 , m_msh_type(msh_type)
60 , m_reorder_infos(reorder_infos)
67 Int32 m_msh_type = -1;
71 class ItemFamilyWriteInfo
76 explicit ItemFamilyWriteInfo(
ITraceMng* tm)
86 Int32 m_dimension = -1;
87 Int32 m_physical_tag = -1;
96 , m_item_type(item_type)
97 , m_entity_tag(entity_tag)
105 m_physical_tag = tag;
106 m_physical_tag_name = name;
113 Int32 m_entity_tag = -1;
114 Int32 m_physical_tag = -1;
115 String m_physical_tag_name;
126 const ItemGroup& group()
const {
return m_item_group; }
148 IMesh* m_mesh =
nullptr;
161 bool m_has_periodic_info =
false;
169 std::pair<Int64, Int64> _getFamilyMinMaxUniqueId(
IItemFamily* family);
174 void _writePeriodic(std::ostream& ofile);
177 const ArcaneToMshTypeInfo& arcaneToMshTypeInfo(
ItemTypeId arcane_type)
const;
184MshMeshWriter(IMesh* mesh)
185: TraceAccessor(mesh->traceMng())
194void MshMeshWriter::ItemGroupWriteInfo::
197 m_item_group = group;
198 String group_name = group.name();
199 bool is_all_items = group.isAllItems();
200 IItemFamily* family = group.itemFamily();
201 IMesh* mesh = family->mesh();
202 ItemTypeMng* item_type_mng = mesh->itemTypeMng();
203 ITraceMng* tm = family->traceMng();
210 Int16 item_type = item.type();
211 if (item_type >= NB_BASIC_ITEM_TYPE || item_type <= 0)
212 ARCANE_FATAL(
"Only pre-defined Item type are supported (current item type is '{0}')",
213 item_type_mng->typeFromId(item_type)->typeName());
214 m_items_by_type[item_type].add(item.localId());
218 Int64 total_nb_item = 0;
219 for (
Int16 i = 0; i < NB_BASIC_ITEM_TYPE; ++i) {
220 Int64 nb_type = m_items_by_type[i].size();
222 m_existing_items_type.add(ItemTypeId(i));
223 total_nb_item += nb_type;
226 Int32 nb_existing_type = m_existing_items_type.size();
227 tm->info() <<
"NbExistingType=" << nb_existing_type;
228 for (
Int32 type_index = 0; type_index < nb_existing_type; ++type_index) {
229 ItemTypeId item_type = m_existing_items_type[type_index];
230 ItemTypeInfo* item_type_info = item_type_mng->typeFromId(item_type);
231 Int32 type_dimension = item_type_info->dimension();
232 EntityInfo entity_info(type_dimension, item_type, base_entity_index + type_index);
234 entity_info.setPhysicalTag(base_entity_index + type_index, group_name);
235 m_entities_by_type.add(entity_info);
241 if (nb_existing_type == 0 && !is_all_items) {
242 Int32 mesh_dim = mesh->dimension();
244 Int32 entity_dim = -1;
246 entity_dim = mesh_dim;
248 entity_dim = mesh_dim - 1;
250 entity_dim = mesh_dim - 2;
252 ARCANE_FATAL(
"Invalid item kind '{0}' for entity dimension", entity_dim);
254 EntityInfo entity_info(entity_dim, ITI_Tetraedron4, base_entity_index);
255 entity_info.setPhysicalTag(base_entity_index, group_name);
256 m_entities_by_type.add(entity_info);
273 bool has_group =
false;
276 if (group.isAllItems())
278 if (group.isAutoComputed())
280 info() <<
"Processing ItemGroup group=" << group.name() <<
" family=" << group.itemFamily()->name();
281 items_groups.
add(group);
308 m_item_type_mng =
mesh->itemTypeMng();
309 String mesh_file_name(file_name);
311 mesh_file_name = mesh_file_name +
".msh";
312 std::ofstream ofile(mesh_file_name.
localstr());
317 info() <<
"writing file '" << mesh_file_name <<
"'";
319 m_mesh_info = impl::MshMeshGenerationInfo::getReference(
mesh,
false);
321 m_has_periodic_info = m_mesh_info->m_periodic_info.hasValues();
322 info() <<
"Mesh has 'MSH' generation info has_periodic=" << m_has_periodic_info;
325 ofile <<
"$MeshFormat\n";
329 ofile <<
"4.1 0 " <<
sizeof(size_t) <<
"\n";
330 ofile <<
"$EndMeshFormat\n";
340 const Int32 entity_index_increment = 1000;
341 Int32 base_entity_index = entity_index_increment;
343 auto x(std::make_unique<ItemGroupWriteInfo>());
344 x->processGroup(group, base_entity_index);
346 base_entity_index += entity_index_increment;
356 Int64 total_nb_cell = 0;
358 for (
const EntityInfo& entity_info : ginfo->entitiesByType()) {
359 Int32 dim = entity_info.m_dim;
361 ++m_nb_entities_by_dim[dim];
363 Int32 item_type = entity_info.m_item_type;
364 Int32 nb_item = ginfo->itemsByType(item_type).size();
365 total_nb_cell += nb_item;
367 Int32 physical_tag = entity_info.m_physical_tag;
368 if (physical_tag > 0) {
369 m_physical_tags.add(
PhysicalTagInfo{ dim, physical_tag, entity_info.m_physical_tag_name });
382 ofile <<
"$PhysicalNames\n";
383 Int32 nb_tag = m_physical_tags.size();
384 ofile << nb_tag <<
"\n";
387 ofile << tag_info.m_dimension <<
" " << tag_info.m_physical_tag <<
" " <<
'"' << tag_info.m_name <<
'"' <<
"\n";
389 ofile <<
"$EndPhysicalNames\n";
395 _writePeriodic(ofile);
407 ItemGroup all_nodes = m_mesh->allNodes();
436 Real3 node_min_bounding_box;
437 Real3 node_max_bounding_box;
440 Real min_value = -max_value;
441 Real3 min_box(max_value, max_value, max_value);
442 Real3 max_box(min_value, min_value, min_value);
444 Real3 pos = nodes_coords[inode];
448 node_min_bounding_box = min_box;
449 node_max_bounding_box = max_box;
451 if (m_has_periodic_info)
452 m_nb_entities_by_dim[0] = 1;
454 ofile <<
"$Entities\n";
455 ofile << m_nb_entities_by_dim[0] <<
" " << m_nb_entities_by_dim[1]
456 <<
" " << m_nb_entities_by_dim[2] <<
" " << m_nb_entities_by_dim[3] <<
"\n";
461 if (m_has_periodic_info) {
462 ofile <<
"1 0.0 0.0 0.0 0\n";
465 for (
Int32 idim = 1; idim < 4; ++idim) {
467 for (
const EntityInfo& entity_info : ginfo->entitiesByType()) {
468 if (entity_info.m_dim != idim)
470 ofile << entity_info.m_entity_tag <<
" " << node_min_bounding_box.
x <<
" " << node_min_bounding_box.
y <<
" " << node_min_bounding_box.
z
471 <<
" " << node_max_bounding_box.
x <<
" " << node_max_bounding_box.
y <<
" " << node_max_bounding_box.
z;
473 Int32 physical_tag = entity_info.m_physical_tag;
474 if (physical_tag > 0) {
475 ofile <<
" 1 " << physical_tag;
485 ofile <<
"$EndEntities\n";
498 const Int32 mesh_nb_node = m_mesh->nbNode();
500 ItemGroup all_nodes = m_mesh->allNodes();
520 auto [node_min_uid, node_max_uid] = _getFamilyMinMaxUniqueId(node_family);
522 ofile <<
"1 " << mesh_nb_node <<
" " << node_min_uid <<
" " << node_max_uid <<
"\n";
524 ofile <<
"0 " <<
"100 " <<
"0 " << mesh_nb_node <<
"\n";
528 Int64 uid = inode->uniqueId();
529 ofile << uid <<
"\n";
535 Real3 coord = nodes_coords[inode];
536 ofile << coord.
x <<
" " << coord.
y <<
" " << coord.
z <<
"\n";
539 ofile <<
"$EndNodes\n";
554 auto [cell_min_uid, cell_max_uid] = _getFamilyMinMaxUniqueId(cell_family);
567 ofile <<
"$Elements\n";
569 Int32 nb_existing_type = m_nb_entities_by_dim[1] + m_nb_entities_by_dim[2] + m_nb_entities_by_dim[3];
570 ofile << nb_existing_type <<
" " << total_nb_cell <<
" " << cell_min_uid <<
" " << cell_max_uid <<
"\n";
574 for (
const EntityInfo& entity_info : ginfo->entitiesByType()) {
575 ItemTypeId cell_type = entity_info.m_item_type;
577 ItemTypeInfo* item_type_info = m_item_type_mng->typeFromId(cell_type);
578 Int32 type_dimension = entity_info.m_dim;
582 ofile << type_dimension <<
" " << entity_info.m_entity_tag <<
" " << atm_type_info.m_msh_type
583 <<
" " << items_of_current_type.
size() <<
"\n";
584 info() <<
"Writing items family=" << item_family->
name() <<
" type=" << item_type_info->
typeName()
585 <<
" n=" << items_of_current_type.
size()
586 <<
" dimension=" << type_dimension;
592 if (!reorder_infos.
empty()) {
593 for (
Int32 i = 0; i < nb_node_for_type; ++i)
597 for (
Int32 i = 0; i < nb_node_for_type; ++i)
604 ofile <<
"$EndElements\n";
611_writePeriodic(std::ostream& ofile)
627 if (!m_has_periodic_info)
632 Int32 nb_periodic = periodic_one_infos.
size();
633 ofile <<
"$Periodic\n";
634 ofile << nb_periodic <<
"\n";
640 for (
const MshPeriodicOneInfo& one_info : periodic_one_infos) {
650 for (
Int32 i = 0; i < nb_affine; ++i)
651 ofile <<
" " << affine_values[i];
657 Int32 nb_orig_node = one_info.m_nb_corresponding_node;
659 node_local_ids.
resize(nb_orig_node * 2);
661 corresponding_nodes.
reserve(nb_orig_node * 2);
662 corresponding_nodes.
clear();
663 for (
Int32 i = 0; i < nb_orig_node; ++i) {
664 Int32 slave_index = (i * 2);
665 Int32 master_index = slave_index + 1;
666 bool has_slave = node_local_ids[slave_index] != NULL_ITEM_LOCAL_ID;
667 bool has_master = node_local_ids[master_index] != NULL_ITEM_LOCAL_ID;
668 if (has_slave || has_master) {
669 corresponding_nodes.
add(orig_corresponding_nodes[slave_index]);
670 corresponding_nodes.
add(orig_corresponding_nodes[master_index]);
673 Int32 nb_new_node = corresponding_nodes.
size() / 2;
674 ofile << nb_new_node <<
"\n";
675 for (
Int32 i = 0; i < nb_new_node; ++i)
676 ofile << corresponding_nodes[(i * 2)] <<
" " << corresponding_nodes[(i * 2) + 1] <<
"\n";
679 ofile <<
"$EndPeriodic\n";
685std::pair<Int64, Int64> MshMeshWriter::
686_getFamilyMinMaxUniqueId(IItemFamily* family)
688 Int64 min_uid = INT64_MAX;
690 ENUMERATE_ (Item, iitem, family->allItems()) {
692 Int64 uid = item.uniqueId();
698 return { min_uid, max_uid };
710 _addArcaneTypeInfo(ITI_Vertex, MSH_PNT);
711 _addArcaneTypeInfo(ITI_Line2, MSH_LIN_2);
712 _addArcaneTypeInfo(ITI_Line3, MSH_LIN_3);
713 _addArcaneTypeInfo(ITI_Line4, MSH_LIN_4);
714 _addArcaneTypeInfo(ITI_Cell3D_Line2, MSH_LIN_2);
715 _addArcaneTypeInfo(ITI_Triangle3, MSH_TRI_3);
716 _addArcaneTypeInfo(ITI_Cell3D_Triangle3, MSH_TRI_3);
717 _addArcaneTypeInfo(ITI_Quad4, MSH_QUA_4);
718 _addArcaneTypeInfo(ITI_Cell3D_Quad4, MSH_QUA_4);
719 _addArcaneTypeInfo(ITI_Tetraedron4, MSH_TET_4);
720 _addArcaneTypeInfo(ITI_Hexaedron8, MSH_HEX_8);
721 _addArcaneTypeInfo(ITI_Pentaedron6, MSH_PRI_6);
722 _addArcaneTypeInfo(ITI_Pyramid5, MSH_PYR_5);
723 _addArcaneTypeInfo(ITI_Triangle6, MSH_TRI_6);
724 _addArcaneTypeInfo(ITI_Triangle10, MSH_TRI_10);
726 FixedArray<Int16, 10> x({ 0, 1, 2, 3, 4, 5, 6, 7, 9, 8 });
727 _addArcaneTypeInfo(ITI_Tetraedron10, MSH_TET_10, x.view());
730 FixedArray<Int16, 20> x({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 16, 9, 17, 10, 18, 19, 12, 15, 13, 14 });
731 _addArcaneTypeInfo(ITI_Hexaedron20, MSH_HEX_20, x.view());
739_addArcaneTypeInfo(ItemTypeId arcane_type,
Int32 msh_type, ConstArrayView<Int16> reorder_infos)
741 if (arcane_type.isNull())
751const MshMeshWriter::ArcaneToMshTypeInfo& MshMeshWriter::
752arcaneToMshTypeInfo(ItemTypeId arcane_type)
const
756 if (tx.m_msh_type > 0)
759 ARCANE_THROW(NotSupportedException,
"Arcane type '{0}' is not supported in MSH writer", arcane_type);
771class MshMeshWriterService
788MshMeshWriterService::
789MshMeshWriterService(
const ServiceBuildInfo& sbi)
790: AbstractService(sbi)
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro to declare an interface when registering a service.
Integer size() const
Number of elements in the vector.
AbstractService(const ServiceBuildInfo &)
Constructor from a ServiceBuildInfo.
Base class for 1D data vectors.
void resize(Int64 s)
Changes the number of elements in the array to s.
void clear()
Removes the elements from the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
constexpr bool empty() const noexcept
true if the array is empty (size()==0)
Information about the floating-point type.
Interface of an entity family.
virtual ItemGroupCollection groups() const =0
Collection of groups in this family.
virtual ItemGroup allItems() const =0
Group of all entities.
virtual String name() const =0
Family name.
virtual eItemKind itemKind() const =0
Entity kind.
virtual ItemVectorView view(Int32ConstArrayView local_ids)=0
View on the entities.
virtual void itemsUniqueIdToLocalId(Int32ArrayView local_ids, Int64ConstArrayView unique_ids, bool do_fatal=true) const =0
Converts an array of unique numbers to local numbers.
virtual IItemFamily * nodeFamily()=0
Returns the node family.
Interface of a mesh writing service.
Exception when an input/output error is detected.
IItemFamily * itemFamily() const
Entity family to which this group belongs (0 for the null group).
Type of an entity (Item).
Info on a mesh entity type.
Integer nbLocalNode() const
Number of nodes of the entity.
String typeName() const
Type name.
Mesh entity type manager.
Mesh element based on nodes (Edge,Face,Cell).
Node node(Int32 i) const
i-th node of the entity
ItemUniqueId uniqueId() const
Unique identifier across all domains.
Writing the mesh files in msh format.
void build() override
Build-level construction of the service.
bool writeMeshToFile(IMesh *mesh, const String &file_name) override
Writes a mesh to a file.
Information mapping between MSH type and Arcane type.
Writing mesh files in msh format.
void _writeEntities(std::ostream &ofile)
Writes the block containing the entities ($Entities).
void writeMesh(const String &file_name)
Writes in MSH V4 format.
void _writeNodes(std::ostream &ofile)
Writes the block containing the nodes ($Nodes).
void _addGroupsToProcess(IItemFamily *family, Array< ItemGroup > &items_groups)
Determines the list of groups to process for a family.
std::vector< std::unique_ptr< ItemGroupWriteInfo > > m_groups_write_info_list
List of information to write for each group.
UniqueArray< ArcaneToMshTypeInfo > m_arcane_to_msh_type_infos
Information on conversion between Arcane and MSH types for entities.
void _writeElements(std::ostream &ofile, Int64 total_nb_cell)
Writes the block containing the elements ($Elements).
Class managing a 3-dimensional real vector.
Structure containing the information to create a service.
Service creation properties.
Unicode character string.
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
bool endsWith(const String &s) const
Indicates if the string ends with the characters of s.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage info() const
Flow for an information message.
1D data vector with value semantics (STL style).
Brief information about a mesh derived from the 'msh' format.
__host__ __device__ Real2 min(Real2 a, Real2 b)
Returns the minimum of two Real2.
T max(const T &a, const T &b, const T &c)
Returns the maximum of three elements.
ItemGroupT< Cell > CellGroup
Group of cells.
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro for registering a service.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
@ ST_SubDomain
The service is used at the subdomain level.
eItemKind
Mesh entity type.
@ IK_Cell
Cell mesh entity.
@ IK_Face
Face mesh entity.
@ IK_Edge
Edge mesh entity.
std::int16_t Int16
Signed integer type of 16 bits.
double Real
Type representing a real number.
std::int32_t Int32
Signed integer type of 32 bits.
Real y
second component of the triplet
Real z
third component of the triplet
Real x
first component of the triplet