Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/IO/GmshMeshWriter.cpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.,
7 : : 2022-2024 J. Bakosi
8 : : All rights reserved. See the LICENSE file for details.
9 : : \brief Gmsh mesh writer class definition
10 : : \details Gmsh mesh writer class definition. Currently, this class supports
11 : : line, triangle, tetrahedron, and point Gmsh element types.
12 : : */
13 : : // *****************************************************************************
14 : :
15 : : #include <iterator>
16 : : #include <iomanip>
17 : : #include <algorithm>
18 : : #include <cstddef>
19 : : #include <ostream>
20 : : #include <string>
21 : : #include <utility>
22 : :
23 : : #include "Exception.hpp"
24 : : #include "UnsMesh.hpp"
25 : : #include "PrintUtil.hpp"
26 : : #include "GmshMeshWriter.hpp"
27 : : #include "GmshMeshIO.hpp"
28 : :
29 : : using tk::GmshMeshWriter;
30 : :
31 : 6 : GmshMeshWriter::GmshMeshWriter( const std::string& filename,
32 : : GmshFileType type,
33 : : tk::real version,
34 : 6 : int datasize ) :
35 : 6 : Writer( filename ), m_type( type )
36 : : // *****************************************************************************
37 : : // Constructor: write mandatory "$MeshFormat" section
38 : : //! \param[in] filename File to open as a Gmsh file
39 : : //! \param[in] type Gmsh file type: ASCII or binary
40 : : //! \param[in] version Gmsh file version
41 : : //! \param[in] datasize Size of double precision number on machine
42 : : // *****************************************************************************
43 : : {
44 : : using tk::operator<<;
45 : :
46 : : // Write beginning of header: $MeshFormat
47 [ + - ]: 6 : m_outFile << "$MeshFormat\n";
48 [ + - ][ - + ]: 6 : ErrChk( !m_outFile.bad(), "Failed to write to file: " + m_filename );
[ - - ][ - - ]
[ - - ]
49 : :
50 : : // Write "version-number file-type data-size"
51 [ + - ][ + - ]: 6 : m_outFile << version << " " << type << " " << datasize << "\n";
[ + - ][ + - ]
[ + - ][ + - ]
52 [ + - ][ - + ]: 6 : ErrChk( !m_outFile.bad(), "Failed to write to file: " + m_filename );
[ - - ][ - - ]
[ - - ]
53 : :
54 [ + + ]: 6 : if (isBinary()) {
55 : 5 : int one = 1;
56 [ + - ]: 5 : m_outFile.write( reinterpret_cast<char*>(&one), sizeof(int) );
57 [ + - ]: 5 : m_outFile << std::endl;
58 : : }
59 : :
60 : : // Write end of header: $EndMeshFormat
61 [ + - ][ + - ]: 6 : m_outFile << "$EndMeshFormat" << std::endl;
62 [ + - ][ - + ]: 6 : ErrChk( !m_outFile.bad(), "Failed to write to file: " + m_filename );
[ - - ][ - - ]
[ - - ]
63 : 6 : }
64 : :
65 : : void
66 : 6 : GmshMeshWriter::writeMesh( const UnsMesh& mesh )
67 : : // *****************************************************************************
68 : : // Write Gmsh mesh file
69 : : //! \param[in] mesh Unstructured mesh object
70 : : // *****************************************************************************
71 : : {
72 : : // Write sections
73 : 6 : writeNodes( mesh );
74 : 6 : writeElements( mesh );
75 : 6 : }
76 : :
77 : : void
78 : 6 : GmshMeshWriter::writeNodes( const UnsMesh& mesh )
79 : : // *****************************************************************************
80 : : // Write "$Nodes--$EndNodes" section
81 : : //! \param[in] mesh Unstructured mesh object
82 : : // *****************************************************************************
83 : : {
84 : 6 : m_outFile << "$Nodes" << std::endl;
85 : :
86 : : // Write out number of nodes
87 : 6 : m_outFile << mesh.nnode() << std::endl;
88 : :
89 : : // Write node ids and coordinates: node-number x-coord y-coord z-coord
90 [ + + ]: 6 : if (isASCII()) {
91 [ + + ]: 15 : for (std::size_t i=0; i<mesh.nnode(); ++i) {
92 : 14 : m_outFile << i+1 << " " << std::setprecision(16)
93 : 14 : << mesh.x()[i] << " "
94 : 14 : << mesh.y()[i] << " "
95 : 14 : << mesh.z()[i] << std::endl;
96 : : }
97 : : } else {
98 [ + + ]: 19262 : for (std::size_t i=0; i<mesh.nnode(); ++i) {
99 : : // gmsh likes one-based node ids
100 : 19257 : int I = static_cast< int >( i+1 );
101 [ + - ]: 19257 : m_outFile.write(
102 : : reinterpret_cast<const char*>(&I), sizeof(int) );
103 [ + - ]: 19257 : m_outFile.write(
104 : 19257 : reinterpret_cast<const char*>(&mesh.x()[i]), sizeof(double) );
105 [ + - ]: 19257 : m_outFile.write(
106 : 19257 : reinterpret_cast<const char*>(&mesh.y()[i]), sizeof(double) );
107 [ + - ]: 19257 : m_outFile.write(
108 : 19257 : reinterpret_cast<const char*>(&mesh.z()[i]), sizeof(double) );
109 : : }
110 : 5 : m_outFile << std::endl;
111 : : }
112 : :
113 : 6 : m_outFile << "$EndNodes" << std::endl;
114 : 6 : }
115 : :
116 : : void
117 : 6 : GmshMeshWriter::writeElements( const UnsMesh& mesh )
118 : : // *****************************************************************************
119 : : // Write "$Elements--$EndElements" section
120 : : //! \param[in] mesh Unstructured mesh object
121 : : // *****************************************************************************
122 : : {
123 : 6 : m_outFile << "$Elements" << std::endl;
124 : :
125 : : // Write out number of elements
126 : 6 : m_outFile << mesh.triinpoel().size()/3 + mesh.tetinpoel().size()/4
127 : 6 : << std::endl;
128 : :
129 : : // Write out triangle element ids and connectivity (node list)
130 : 6 : writeElemBlock( 3, GmshElemType::TRI, mesh.triinpoel() );
131 : :
132 : : // Write out terahedron element ids and connectivity (node list)
133 : 6 : writeElemBlock( 4, GmshElemType::TET, mesh.tetinpoel() );
134 : :
135 [ + + ]: 6 : if (isBinary()) m_outFile << std::endl;
136 : 6 : m_outFile << "$EndElements" << std::endl;
137 : 6 : }
138 : :
139 : : void
140 : 12 : GmshMeshWriter::writeElemBlock( std::size_t nnpe,
141 : : GmshElemType type,
142 : : const std::vector< std::size_t >& inpoel )
143 : : // *****************************************************************************
144 : : // Write element block: element ids and connectivity (node list)
145 : : //! \param[in] nnpe Number of nodes per element
146 : : //! \param[in] type Element type
147 : : //! \param[in] inpoel Element connectivity (must be zero-based)
148 : : // *****************************************************************************
149 : : {
150 : : // Return if connectivity is empty, there is no such element block in mesh
151 [ + + ]: 12 : if (inpoel.empty()) return;
152 : :
153 : : // Make sure element connectivity starts with zero
154 [ + - ][ - + ]: 10 : Assert( *std::minmax_element( begin(inpoel), end(inpoel) ).first == 0,
[ - - ][ - - ]
[ - - ]
155 : : "node ids should start from zero" );
156 : :
157 : : // Get number of elements in mesh
158 : 10 : auto n = inpoel.size()/nnpe;
159 : :
160 : : // Ignore element tags
161 : 10 : std::vector< std::vector< int > > tg;
162 [ + - ]: 10 : tg.resize( n );
163 [ + - ][ + + ]: 109390 : for (auto& t : tg) t.push_back( 0 );
164 : :
165 [ + + ]: 10 : if (isASCII()) {
166 : :
167 [ + + ]: 25 : for (std::size_t i=0; i<n; i++) {
168 : : // elm-number elm-type number-of-tags < tag > ... node-number-list
169 [ + - ][ + - ]: 24 : m_outFile << i+1 << " " << type << " " << tg[i].size() << " ";
[ + - ][ + - ]
[ + - ][ + - ]
170 [ + - ]: 24 : copy( tg[i].begin(), tg[i].end()-1,
171 : 24 : std::ostream_iterator< int >( m_outFile, " " ) );
172 [ + - ][ + - ]: 24 : m_outFile << tg[i].back() << " ";
173 : :
174 : : // gmsh likes one-based node ids
175 [ + - ][ + - ]: 120 : for (std::size_t k=0; k<nnpe; k++) m_outFile << inpoel[i*nnpe+k]+1 << " ";
[ + + ]
176 [ + - ]: 24 : m_outFile << std::endl;
177 : : }
178 : :
179 : : } else {
180 : :
181 : 9 : int ntags = static_cast< int >( tg[0].size() );
182 : 9 : int nel = static_cast< int >( n );
183 : : // elm-type num-of-elm-follow number-of-tags
184 [ + - ]: 9 : m_outFile.write( reinterpret_cast<char*>(&type), sizeof(int) );
185 [ + - ]: 9 : m_outFile.write( reinterpret_cast<char*>(&nel), sizeof(int) );
186 [ + - ]: 9 : m_outFile.write( reinterpret_cast<char*>(&ntags), sizeof(int) );
187 [ + + ]: 109365 : for (std::size_t i=0; i<n; i++) {
188 : 109356 : int I = static_cast< int >( i );
189 : : // gmsh likes one-based node ids
190 : 109356 : std::vector< int > Inpoel;
191 [ + + ]: 536652 : for (std::size_t k=0; k<nnpe; ++k)
192 [ + - ]: 427296 : Inpoel.push_back( static_cast< int >( inpoel[i*nnpe+k]+1 ) );
193 : : // element id
194 [ + - ]: 109356 : m_outFile.write( reinterpret_cast<const char*>(&I), sizeof(int) );
195 : : // element tags
196 [ + - ]: 109356 : m_outFile.write( reinterpret_cast<const char*>(tg[i].data()),
197 : 109356 : static_cast<std::streamsize>(tg[i].size()*sizeof(int)) );
198 : : // element node list (i.e. connectivity)
199 [ + - ]: 109356 : m_outFile.write( reinterpret_cast<const char*>(Inpoel.data()),
200 : 109356 : static_cast<std::streamsize>(nnpe*sizeof(int)) );
201 : 109356 : }
202 : :
203 : : }
204 : 10 : }
|