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