Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/IO/ExodusIIMeshReader.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 ExodusII mesh reader
10 : : \details ExodusII mesh reader class definition.
11 : : */
12 : : // *****************************************************************************
13 : :
14 : : #include <numeric>
15 : :
16 : : #include "ExodusIIMeshReader.hpp"
17 : : #include "ContainerUtil.hpp"
18 : : #include "Exception.hpp"
19 : : #include "UnsMesh.hpp"
20 : : #include "Reorder.hpp"
21 : :
22 : : using tk::ExodusIIMeshReader;
23 : :
24 : 1030 : ExodusIIMeshReader::ExodusIIMeshReader( const std::string& filename,
25 : : int cpuwordsize,
26 : 1030 : int iowordsize ) :
27 : 1030 : m_filename( filename ),
28 : 1030 : m_cpuwordsize( cpuwordsize ),
29 : 1030 : m_iowordsize( iowordsize ),
30 : 1030 : m_inFile( 0 ),
31 : 1030 : m_nnode( 0 ),
32 : 1030 : m_neblk( 0 ),
33 : 1030 : m_neset( 0 ),
34 : 1030 : m_from( 0 ),
35 [ + - ]: 1030 : m_till( 0 ),
36 : : m_blockid(),
37 [ + - ][ - - ]: 1030 : m_blockid_by_type( ExoNnpe.size() ),
38 [ + - ][ + - ]: 1030 : m_nel( ExoNnpe.size() ),
39 : : m_elemblocks(),
40 [ + - ]: 1030 : m_tri()
41 : : // *****************************************************************************
42 : : // Constructor: open Exodus II file
43 : : //! \param[in] filename File to open as ExodusII file
44 : : //! \param[in] cpuwordsize Set CPU word size, see ExodusII documentation
45 : : //! \param[in] iowordsize Set I/O word size, see ExodusII documentation
46 : : // *****************************************************************************
47 : : {
48 : : // Increase verbosity from ExodusII library in debug mode
49 : : #ifndef NDEBUG
50 : : ex_opts( EX_DEBUG | EX_VERBOSE );
51 : : #endif
52 : :
53 : : float version;
54 : :
55 [ + - ]: 1030 : m_inFile = ex_open( filename.c_str(), EX_READ, &cpuwordsize, &iowordsize,
56 : : &version );
57 : :
58 [ - + ][ - - ]: 1030 : ErrChk( m_inFile > 0, "Failed to open ExodusII file: " + filename );
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
59 : 1030 : }
60 : :
61 : 1029 : ExodusIIMeshReader::~ExodusIIMeshReader() noexcept
62 : : // *****************************************************************************
63 : : // Destructor
64 : : // *****************************************************************************
65 : : {
66 [ - + ]: 1029 : if ( ex_close(m_inFile) < 0 )
67 : 0 : printf( ">>> WARNING: Failed to close ExodusII file: %s\n",
68 : : m_filename.c_str() );
69 : 1029 : }
70 : :
71 : : void
72 : 36 : ExodusIIMeshReader::readMesh( UnsMesh& mesh )
73 : : // *****************************************************************************
74 : : // Read ExodusII mesh file
75 : : //! \param[in] mesh Unstructured mesh object
76 : : // *****************************************************************************
77 : : {
78 : 36 : readHeader( mesh );
79 : 36 : readAllElements( mesh );
80 : 36 : readAllNodes( mesh );
81 : 36 : readSidesetFaces( mesh.bface(), mesh.faceid() );
82 : 36 : readTimeValues( mesh.vartimes() );
83 : 36 : readNodeVarNames( mesh.nodevarnames() );
84 : 36 : readNodeScalars( mesh.vartimes().size(),
85 : : mesh.nodevarnames().size(),
86 : : mesh.nodevars() );
87 : 36 : }
88 : :
89 : : void
90 : 748 : ExodusIIMeshReader::readMeshPart(
91 : : std::vector< std::size_t >& ginpoel,
92 : : std::vector< std::size_t >& inpoel,
93 : : std::vector< std::size_t >& triinp,
94 : : std::unordered_map< std::size_t, std::size_t >& lid,
95 : : tk::UnsMesh::Coords& coord,
96 : : int numpes, int mype )
97 : : // *****************************************************************************
98 : : // Read a part of the mesh (graph and coordinates) from ExodusII file
99 : : //! \param[in,out] ginpoel Container to store element connectivity of this PE's
100 : : //! chunk of the mesh (global ids)
101 : : //! \param[in,out] inpoel Container to store element connectivity with local
102 : : //! node IDs of this PE's mesh chunk
103 : : //! \param[in,out] triinp Container to store triangle element connectivity
104 : : //! (if exists in file) with global node indices
105 : : //! \param[in,out] lid Container to store global->local node IDs of elements of
106 : : //! this PE's mesh chunk
107 : : //! \param[in,out] coord Container to store coordinates of mesh nodes of this
108 : : //! PE's mesh chunk
109 : : //! \param[in] numpes Total number of PEs (default n = 1, for a single-CPU read)
110 : : //! \param[in] mype This PE (default m = 0, for a single-CPU read)
111 : : // *****************************************************************************
112 : : {
113 : : Assert( mype < numpes, "Invalid input: PE id must be lower than NumPEs" );
114 : : Assert( ginpoel.empty() && inpoel.empty() && lid.empty() &&
115 : : coord[0].empty() && coord[1].empty() && coord[2].empty(),
116 : : "Containers to store mesh must be empty" );
117 : :
118 : : // Read info on element blocks from ExodusII file
119 : 748 : readElemBlockIDs();
120 : : // Get number of number of tetrahedron elements in file
121 : 748 : auto nel = nelem( tk::ExoElemType::TET );
122 : :
123 : : // Compute extents of element IDs of this PE's mesh chunk to read
124 : 748 : auto npes = static_cast< std::size_t >( numpes );
125 : 748 : auto pe = static_cast< std::size_t >( mype );
126 : 748 : auto chunk = nel / npes;
127 : 748 : m_from = pe * chunk;
128 : 748 : m_till = m_from + chunk;
129 [ + + ]: 748 : if (pe == npes-1) m_till += nel % npes;
130 : :
131 : : // Read tetrahedron connectivity between from and till
132 [ + - ]: 748 : readElements( {{m_from, m_till-1}}, tk::ExoElemType::TET, ginpoel );
133 : :
134 : : // Compute local data from global mesh connectivity
135 : : std::vector< std::size_t > gid;
136 [ + - ]: 1496 : std::tie( inpoel, gid, lid ) = tk::global2local( ginpoel );
137 : :
138 : : // Read this PE's chunk of the mesh node coordinates from file
139 [ + - ][ - - ]: 1496 : coord = readCoords( gid );
140 : :
141 : : // Generate set of unique faces
142 : : tk::UnsMesh::FaceSet faces;
143 [ + + ]: 918548 : for (std::size_t e=0; e<ginpoel.size()/4; ++e)
144 [ + + ]: 4589000 : for (std::size_t f=0; f<4; ++f) {
145 : : const auto& tri = tk::expofa[f];
146 [ + - ]: 3671200 : faces.insert( {{{ ginpoel[ e*4+tri[0] ],
147 : 3671200 : ginpoel[ e*4+tri[1] ],
148 [ + - ]: 3671200 : ginpoel[ e*4+tri[2] ] }}} );
149 : : }
150 : :
151 : : // Read triangle element connectivity (all triangle blocks in file)
152 [ + - ]: 748 : auto ntri = nelem( tk::ExoElemType::TRI );
153 [ + + ][ + - ]: 748 : if ( ntri !=0 ) readElements( {{0,ntri-1}}, tk::ExoElemType::TRI, triinp );
154 : :
155 : : // Keep triangles shared in (partially-read) tetrahedron mesh
156 : : std::vector< std::size_t > triinp_own;
157 : : std::size_t ltrid = 0; // local triangle id
158 [ + + ]: 549485 : for (std::size_t e=0; e<triinp.size()/3; ++e) {
159 : 548737 : auto i = faces.find( {{ triinp[e*3+0], triinp[e*3+1], triinp[e*3+2] }} );
160 [ + + ]: 548737 : if (i != end(faces)) {
161 [ + - ][ + - ]: 185226 : m_tri[e] = ltrid++; // generate global->local triangle ids
162 [ + - ]: 185226 : triinp_own.push_back( triinp[e*3+0] );
163 [ + - ]: 185226 : triinp_own.push_back( triinp[e*3+1] );
164 [ + - ]: 185226 : triinp_own.push_back( triinp[e*3+2] );
165 : : }
166 : : }
167 : : triinp = std::move(triinp_own);
168 : 748 : }
169 : :
170 : : std::array< std::vector< tk::real >, 3 >
171 : 748 : ExodusIIMeshReader::readCoords( const std::vector< std::size_t >& gid ) const
172 : : // *****************************************************************************
173 : : // Read coordinates of a number of mesh nodes from ExodusII file
174 : : //! \param[in] gid Global node IDs whose coordinates to read
175 : : //! \return Vector of node coordinates read from file
176 : : // *****************************************************************************
177 : : {
178 : : // Read node coordinates from file with global node IDs given in gid
179 : 748 : return readNodes( gid );
180 : : }
181 : :
182 : : std::size_t
183 : 1594 : ExodusIIMeshReader::readHeader()
184 : : // *****************************************************************************
185 : : // Read ExodusII header without setting mesh size
186 : : //! \return Number of nodes in mesh
187 : : // *****************************************************************************
188 : : {
189 : : char title[MAX_LINE_LENGTH+1];
190 : : int ndim, n, nnodeset, nelemset, nnode, neblk;
191 : :
192 [ - + ][ - - ]: 1594 : ErrChk(
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
193 : : ex_get_init( m_inFile, title, &ndim, &nnode, &n, &neblk, &nnodeset,
194 : : &nelemset ) == 0,
195 : : "Failed to read header from ExodusII file: " + m_filename );
196 : :
197 [ - + ][ - - ]: 1594 : ErrChk( nnode > 0,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
198 : : "Number of nodes read from ExodusII file must be larger than zero" );
199 [ - + ][ - - ]: 1594 : ErrChk( neblk > 0,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
200 : : "Number of element blocks read from ExodusII file must be larger "
201 : : "than zero" );
202 [ - + ][ - - ]: 1594 : ErrChk( ndim == 3, "Need a 3D mesh from ExodusII file " + m_filename );
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
203 : :
204 : 1594 : m_neblk = static_cast< std::size_t >( neblk );
205 : 1594 : m_neset = static_cast< std::size_t >( nelemset );
206 : :
207 : 1594 : return static_cast< std::size_t >( nnode );
208 : : }
209 : :
210 : : void
211 : 36 : ExodusIIMeshReader::readHeader( UnsMesh& mesh )
212 : : // *****************************************************************************
213 : : // Read ExodusII header with setting mesh size
214 : : //! \param[in] mesh Unstructured mesh object
215 : : // *****************************************************************************
216 : : {
217 : : // Read ExodusII file header and set mesh graph size
218 : 36 : mesh.size() = m_nnode = static_cast< std::size_t >( readHeader() );
219 : 36 : }
220 : :
221 : : void
222 : 36 : ExodusIIMeshReader::readAllNodes( UnsMesh& mesh ) const
223 : : // *****************************************************************************
224 : : // Read all node coordinates from ExodusII file
225 : : //! \param[in] mesh Unstructured mesh object
226 : : // *****************************************************************************
227 : : {
228 : 36 : mesh.x().resize( m_nnode );
229 : 36 : mesh.y().resize( m_nnode );
230 : 36 : mesh.z().resize( m_nnode );
231 : :
232 [ - + ][ - - ]: 36 : ErrChk( ex_get_coord( m_inFile, mesh.x().data(), mesh.y().data(),
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
233 : : mesh.z().data() ) == 0,
234 : : "Failed to read coordinates from ExodusII file: " + m_filename );
235 : 36 : }
236 : :
237 : : void
238 : 382426 : ExodusIIMeshReader::readNode( std::size_t fid,
239 : : std::size_t mid,
240 : : std::vector< tk::real >& x,
241 : : std::vector< tk::real >& y,
242 : : std::vector< tk::real >& z ) const
243 : : // *****************************************************************************
244 : : // Read coordinates of a single mesh node from ExodusII file
245 : : //! \param[in] fid Node id in file whose coordinates to read
246 : : //! \param[in] mid Node id in memory to which to put new cordinates
247 : : //! \param[in,out] x Vector of x coordinates to push to
248 : : //! \param[in,out] y Vector of y coordinates to push to
249 : : //! \param[in,out] z Vector of z coordinates to push to
250 : : // *****************************************************************************
251 : : {
252 : : Assert( x.size() == y.size() && x.size() == z.size(), "Size mismatch" );
253 : : Assert( mid < x.size() && mid < y.size() && mid < z.size(),
254 : : "Indexing out of bounds" );
255 : :
256 : 382426 : readNode( fid, x[mid], y[mid], z[mid] );
257 : 382426 : }
258 : :
259 : : void
260 : 0 : ExodusIIMeshReader::readNode( std::size_t id,
261 : : std::array< tk::real, 3 >& coord ) const
262 : : // *****************************************************************************
263 : : // Read coordinates of a single mesh node from ExodusII file
264 : : //! \param[in] id Node id whose coordinates to read
265 : : //! \param[in,out] coord Array of x, y, and z coordinates
266 : : // *****************************************************************************
267 : : {
268 : 0 : readNode( id, coord[0], coord[1], coord[2] );
269 : 0 : }
270 : :
271 : : void
272 : 382426 : ExodusIIMeshReader::readNode( std::size_t id,
273 : : tk::real& x,
274 : : tk::real& y,
275 : : tk::real& z ) const
276 : : // *****************************************************************************
277 : : // Read coordinates of a single mesh node from file
278 : : //! \param[in] id Node id whose coordinates to read
279 : : //! \param[in,out] x X coordinate to write to
280 : : //! \param[in,out] y Y coordinate to write to
281 : : //! \param[in,out] z Z coordinate to write to
282 : : // *****************************************************************************
283 : : {
284 [ - + ][ - - ]: 382426 : ErrChk(
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
285 : : ex_get_partial_coord( m_inFile, static_cast<int64_t>(id)+1, 1,
286 : : &x, &y, &z ) == 0,
287 : : "Failed to read coordinates of node " + std::to_string(id) +
288 : : " from ExodusII file: " + m_filename );
289 : 382426 : }
290 : :
291 : : std::array< std::vector< tk::real >, 3 >
292 : 748 : ExodusIIMeshReader::readNodes( const std::vector< std::size_t >& gid ) const
293 : : // *****************************************************************************
294 : : // Read coordinates of a number of mesh nodes from ExodusII file
295 : : //! \param[in] gid Node IDs whose coordinates to read
296 : : //! \return Mesh node coordinates
297 : : // *****************************************************************************
298 : : {
299 [ + - ][ + - ]: 748 : std::vector< tk::real > px( gid.size() ), py( gid.size() ), pz( gid.size() );
[ - - ][ - - ]
300 : :
301 : : std::size_t i=0;
302 [ + - ][ + + ]: 383174 : for (auto g : gid) readNode( g, i++, px, py, pz );
303 : :
304 : 748 : return {{ std::move(px), std::move(py), std::move(pz) }};
305 : : }
306 : :
307 : : std::size_t
308 : 1073 : ExodusIIMeshReader::readElemBlockIDs()
309 : : // *****************************************************************************
310 : : // Read element block IDs from ExodusII file
311 : : //! \return Total number of nodes in mesh
312 : : // *****************************************************************************
313 : : {
314 : : // Read ExodusII file header
315 : : // cppcheck-suppress unreadVariable
316 : 1073 : auto nnode = readHeader();
317 : :
318 [ + - ]: 1073 : std::vector< int > bid( m_neblk );
319 : :
320 : : // Read element block ids
321 [ + - ][ - + ]: 1073 : ErrChk( ex_get_ids( m_inFile, EX_ELEM_BLOCK, bid.data()) == 0,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
322 : : "Failed to read element block ids from ExodusII file: " +
323 : : m_filename );
324 : :
325 [ + + ]: 1073 : m_elemblocks.clear();
326 [ + - ]: 1073 : m_nel.clear();
327 [ + - ]: 1073 : m_nel.resize( ExoNnpe.size() );
328 [ + - ]: 1073 : m_blockid_by_type.clear();
329 [ + - ]: 1073 : m_blockid_by_type.resize( ExoNnpe.size() );
330 : :
331 : : // Fill element block ID vector
332 [ + + ]: 3141 : for (auto id : bid) {
333 : : char eltype[MAX_STR_LENGTH+1];
334 : : int n, nnpe, nattr;
335 : :
336 : : // Read element block information
337 [ + - ][ - + ]: 2069 : ErrChk( ex_get_block( m_inFile, EX_ELEM_BLOCK, id, eltype, &n, &nnpe,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
338 : : &nattr, nullptr, nullptr ) == 0,
339 : : "Failed to read element block information from ExodusII file: " +
340 : : m_filename );
341 : :
342 [ + + ]: 2069 : if (!nnpe) continue; // ignore nnpe == 0
343 : :
344 : : // Store ExodusII element block ID
345 [ + - ]: 2053 : m_blockid.push_back( id );
346 : :
347 : 2053 : auto nel = static_cast< std::size_t >( n );
348 : :
349 : : // Store info on ExodusII element blocks
350 [ + + ]: 2053 : if (nnpe == 4) { // tetrahedra
351 : :
352 [ + - ]: 1032 : m_elemblocks.push_back( { ExoElemType::TET, nel } );
353 : : auto e = static_cast< std::size_t >( ExoElemType::TET );
354 [ + - ]: 1032 : m_blockid_by_type[ e ].push_back( id );
355 [ + - ]: 1032 : m_nel[ e ].push_back( nel );
356 : : Assert( m_blockid_by_type[e].size() == m_nel[e].size(), "Size mismatch" );
357 : :
358 [ + + ]: 1021 : } else if (nnpe == 3) { // triangles
359 : :
360 [ + - ][ - - ]: 1020 : m_elemblocks.push_back( { ExoElemType::TRI, nel } );
361 : : auto e = static_cast< std::size_t >( ExoElemType::TRI );
362 [ + - ]: 1020 : m_blockid_by_type[ e ].push_back( id );
363 [ + - ]: 1020 : m_nel[ e ].push_back( nel );
364 : : Assert( m_blockid_by_type[e].size() == m_nel[e].size(), "Size mismatch" );
365 : :
366 : : } else {
367 : :
368 [ + - ][ + - ]: 2 : Throw( "Exodus mesh must only contain TRI and/or TETRA element blocks" );
[ + - ][ - + ]
[ - + ][ - - ]
[ - - ]
369 : :
370 : : }
371 : : }
372 : :
373 : 1072 : return nnode;
374 : : }
375 : :
376 : : void
377 : 36 : ExodusIIMeshReader::readAllElements( UnsMesh& mesh )
378 : : // *****************************************************************************
379 : : // Read all element blocks and mesh connectivity from ExodusII file
380 : : //! \param[inout] mesh Unstructured mesh object to store mesh in
381 : : // *****************************************************************************
382 : : {
383 : : // Read element block ids
384 : 36 : readElemBlockIDs();
385 : :
386 [ + + ]: 83 : for (auto id : m_blockid) {
387 : : char eltype[MAX_STR_LENGTH+1];
388 : : int nel, nnpe, nattr;
389 : :
390 : : // Read element block information
391 [ - + ][ - - ]: 47 : ErrChk( ex_get_block( m_inFile, EX_ELEM_BLOCK, id, eltype, &nel, &nnpe,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
392 : : &nattr, nullptr, nullptr ) == 0,
393 : : "Failed to read element block information from ExodusII file: " +
394 : : m_filename );
395 : :
396 : : // Read element connectivity
397 : 47 : auto connectsize = static_cast< std::size_t >( nel*nnpe );
398 [ + + ]: 47 : if (nnpe == 4) { // tetrahedra
399 : :
400 [ + - ]: 14 : std::vector< int > inpoel( connectsize );
401 [ + - ][ - + ]: 14 : ErrChk( ex_get_conn( m_inFile, EX_ELEM_BLOCK, id, inpoel.data(),
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
402 : : nullptr, nullptr ) == 0,
403 : : "Failed to read " + std::string(eltype) + " element connectivity from "
404 : : "ExodusII file: " + m_filename );
405 [ + - ][ + + ]: 200778 : for (auto n : inpoel)
406 [ + - ][ - - ]: 200764 : mesh.tetinpoel().push_back( static_cast< std::size_t >( n ) );
407 : :
408 [ + - ]: 33 : } else if (nnpe == 3) { // triangles
409 : :
410 [ + - ]: 33 : std::vector< int > inpoel( connectsize );
411 [ + - ][ - + ]: 33 : ErrChk( ex_get_conn( m_inFile, EX_ELEM_BLOCK, id, inpoel.data(),
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
412 : : nullptr, nullptr ) == 0,
413 : : "Failed to read " + std::string(eltype) + " element connectivity from "
414 : : "ExodusII file: " + m_filename );
415 [ + - ][ + + ]: 191364 : for (auto n : inpoel)
416 [ + - ][ - - ]: 191331 : mesh.triinpoel().push_back( static_cast< std::size_t >( n ) );
417 : :
418 : : }
419 : : }
420 : :
421 : : // Shift node IDs to start from zero
422 : 36 : shiftToZero( mesh.triinpoel() );
423 : 36 : shiftToZero( mesh.tetinpoel() );
424 : 36 : }
425 : :
426 : : void
427 : 7102 : ExodusIIMeshReader::readElements( const std::array< std::size_t, 2 >& ext,
428 : : tk::ExoElemType elemtype,
429 : : std::vector< std::size_t >& conn ) const
430 : : // *****************************************************************************
431 : : // Read element connectivity of a number of mesh cells from ExodusII file
432 : : //! \param[in] ext Extents of element IDs whose connectivity to read:
433 : : //! [from...till), using zero-based element IDs, where 'from' >=0, inclusive
434 : : //! and 'till < 'maxelements', where 'maxelements' is the total number of
435 : : //! elements of all element blocks in the file of the requested cell type.
436 : : //! Note that 'maxelements' can be queried by nelem().
437 : : //! \param[in] elemtype Element type
438 : : //! \param[inout] conn Connectivity vector to push to
439 : : //! \note Must be preceded by a call to readElemBlockIDs()
440 : : //! \details This function takes the extents of element IDs in a zero-based
441 : : //! fashion. These input extents can be thought of "absolute" extents that
442 : : //! denote lowest and the largest-1 element IDs to be read from file.
443 : : // *****************************************************************************
444 : : {
445 : : Assert( tk::sumsize(m_blockid_by_type) > 0,
446 : : "A call to this function must be preceded by a call to "
447 : : "ExodusIIMeshReader::readElemBlockIDs()" );
448 : : Assert( ext[0] <= ext[1] &&
449 : : ext[0] < nelem(elemtype) &&
450 : : ext[1] < nelem(elemtype),
451 : : "Invalid element ID extents. Of the requested extents [from...till), "
452 : : "'from' must be lower than or equal to 'till', and they must be in "
453 : : "the range [0...maxelements), where 'maxelements' is the total "
454 : : "number of elements of all element blocks in the file of the "
455 : : "requested cell type. Requested element ID extents: ["
456 : : + std::to_string(ext[0]) + "..." + std::to_string(ext[1])
457 : : + "), 'maxelements' of cell type with "
458 : : + std::to_string( ExoNnpe[ static_cast<std::size_t>(elemtype) ] )
459 : : + " nodes per cell in file '" + m_filename + "': "
460 : : + std::to_string( nelem( elemtype ) ) );
461 : :
462 : 7102 : auto e = static_cast< std::size_t >( elemtype );
463 : : // List of number of elements of all blocks of element type requested
464 : : const auto& nel = m_nel[e];
465 : : // List of element block IDs for element type requested
466 : : const auto& bid = m_blockid_by_type[e];
467 : :
468 : : // Compute lower and upper element block ids to read from based on extents
469 : : std::size_t lo_bid = 0, hi_bid = 0, offset = 0;
470 [ + + ]: 35628 : for (std::size_t b=0; b<nel.size(); ++b) {
471 : : std::size_t lo = offset; // lo (min) elem ID in block
472 : 28526 : std::size_t hi = offset + nel[b] - 1; // hi (max) elem ID in block
473 [ + + ][ + + ]: 28526 : if (ext[0] >= lo && ext[0] <= hi) lo_bid = b;
474 [ + + ][ + + ]: 28526 : if (ext[1] >= lo && ext[1] <= hi) hi_bid = b;
475 : : offset += nel[b];
476 : : }
477 : :
478 : : Assert( lo_bid < nel.size() && lo_bid < bid.size(),
479 : : "Invalid start block ID" );
480 : : Assert( hi_bid < nel.size() && hi_bid < bid.size(),
481 : : "Invalid end block ID" );
482 : :
483 : : // Compute relative extents based on absolute ones for each block to read from
484 : : std::vector< std::array< std::size_t, 2 > > rext;
485 : : offset = 0;
486 [ + + ]: 13550 : for (std::size_t b=0; b<lo_bid; ++b) offset += nel[b];
487 [ + + ]: 22732 : for (std::size_t b=lo_bid; b<=hi_bid; ++b) {
488 : : std::size_t lo = offset;
489 : 15630 : std::size_t hi = offset + nel[b] - 1;
490 : : std::size_t le = 1, he = nel[b];
491 [ + + ][ + + ]: 15630 : if (ext[0] >= lo && ext[0] <= hi) le = ext[0] - lo + 1;
492 [ + - ][ + + ]: 15630 : if (ext[1] >= lo && ext[1] <= hi) he = ext[1] - lo + 1;
493 : : Assert( le >= 1 && le <= nel[b] && he >= 1 && he <= nel[b],
494 : : "Relative index out of block" );
495 [ + - ][ - - ]: 15630 : rext.push_back( {{ le, he }} );
496 : 15630 : offset += nel[b];
497 : : }
498 : :
499 : : Assert( std::accumulate(
500 : : std::next(rext.cbegin()), rext.cend(), rext[0][1]-rext[0][0]+1,
501 : : []( std::size_t n, const std::array< std::size_t, 2 >& r )
502 : : { return n + r[1] - r[0] + 1; }
503 : : ) == ext[1]-ext[0]+1,
504 : : "Total number of elements to read incorrect, requested extents: " +
505 : : std::to_string(ext[0]) + " ... " + std::to_string(ext[1]) );
506 : :
507 : : std::vector< int > inpoel;
508 : :
509 : : // Read element connectivity from file
510 : : std::size_t B = 0;
511 [ + + ]: 22732 : for (auto b=lo_bid; b<=hi_bid; ++b, ++B) {
512 : : const auto& r = rext[B];
513 [ + - ][ + - ]: 15630 : std::vector< int > c( (r[1]-r[0]+1) * ExoNnpe[e] );
[ - - ]
514 [ + - ][ - + ]: 15630 : ErrChk( ex_get_partial_conn( m_inFile,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
515 : : EX_ELEM_BLOCK,
516 : : bid[b],
517 : : static_cast< int64_t >( r[0] ),
518 : : static_cast< int64_t >( r[1]-r[0]+1 ),
519 : : c.data(),
520 : : nullptr,
521 : : nullptr ) == 0,
522 : : "Failed to read element connectivity of elements [" +
523 : : std::to_string(r[0]) + "..." + std::to_string(r[1]) +
524 : : "] from element block " + std::to_string(bid[b]) + " in ExodusII "
525 : : "file: " + m_filename );
526 [ + - ]: 15630 : inpoel.reserve( inpoel.size() + c.size() );
527 : : std::move( begin(c), end(c), std::back_inserter(inpoel) );
528 : : }
529 : :
530 : : Assert( inpoel.size() == (ext[1]-ext[0]+1)*ExoNnpe[e],
531 : : "Failed to read element connectivity of elements [" +
532 : : std::to_string(ext[0]) + "..." + std::to_string(ext[1]) + ") from "
533 : : "ExodusII file: " + m_filename );
534 : :
535 : : // Put in element connectivity using zero-based node indexing
536 [ + + ]: 12658180 : for (auto& i : inpoel) --i;
537 [ + - ]: 7102 : conn.reserve( conn.size() + inpoel.size() );
538 : : std::move( begin(inpoel), end(inpoel), std::back_inserter(conn) );
539 : 7102 : }
540 : :
541 : : void
542 : 1 : ExodusIIMeshReader::readFaces( std::vector< std::size_t >& conn ) const
543 : : // *****************************************************************************
544 : : // Read face connectivity of a number of boundary faces from ExodusII file
545 : : //! \param[inout] conn Connectivity vector to push to
546 : : //! \details This function reads in the total number of boundary faces,
547 : : //! also called triangle-elements in the EXO2 file, and their connectivity.
548 : : // *****************************************************************************
549 : : {
550 : : // Return quietly if no triangle elements in file
551 [ + - ]: 1 : if (nelem(tk::ExoElemType::TRI) == 0) return;
552 : :
553 : : // Read triangle boundary-face connectivity (all the triangle element block)
554 : 1 : readElements( {{0,nelem(tk::ExoElemType::TRI)-1}}, tk::ExoElemType::TRI,
555 : : conn );
556 : : }
557 : :
558 : : std::vector< std::size_t >
559 : 1 : ExodusIIMeshReader::readNodemap()
560 : : // *****************************************************************************
561 : : // Read local to global node-ID map from ExodusII file
562 : : //! \return node_map Vector mapping the local Exodus node-IDs to global node-IDs
563 : : //! \details The node-map is required to get the "Exodus-global" node-IDs from
564 : : //! the "Exodus-internal" node-IDs, which are returned from the exodus APIs.
565 : : //! The node-IDs in the exodus file are referred to as the "Exodus-global"
566 : : //! node-IDs or "fileIDs".
567 : : // *****************************************************************************
568 : : {
569 : : // Read triangle boundary-face connectivity
570 : 1 : auto nnode = readElemBlockIDs();
571 : :
572 : : // Create array to store node-number map
573 [ + - ]: 1 : std::vector< int > node_map( nnode );
574 : :
575 : : // Read in the node number map to map the above nodes to the global node-IDs
576 [ + - ][ - + ]: 1 : ErrChk( ex_get_id_map( m_inFile, EX_NODE_MAP, node_map.data() ) == 0,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
577 : : "Failed to read node map length from ExodusII file: " );
578 : :
579 [ + - ][ - - ]: 1 : std::vector< std::size_t > node_map1( nnode );
580 : :
581 [ + + ]: 15 : for (std::size_t i=0; i<nnode; ++i)
582 : : {
583 : 14 : node_map1[i] = static_cast< std::size_t >(node_map[i]-1);
584 : : }
585 : :
586 : 1 : return node_map1;
587 : : }
588 : :
589 : : std::map< int, std::vector< std::size_t > >
590 : 242 : ExodusIIMeshReader::readSidesetNodes()
591 : : // *****************************************************************************
592 : : // Read node list of all side sets from ExodusII file
593 : : //! \return Node lists mapped to side set ids
594 : : // *****************************************************************************
595 : : {
596 : : // Read ExodusII file header (fills m_neset)
597 : 242 : readHeader();
598 : :
599 : : // Node lists mapped to side set ids
600 : : std::map< int, std::vector< std::size_t > > side;
601 : :
602 [ + - ]: 242 : if (m_neset > 0) {
603 : : // Read all side set ids from file
604 [ + - ][ + - ]: 242 : std::vector< int > ids( m_neset );
605 [ + - ][ - + ]: 242 : ErrChk( ex_get_ids( m_inFile, EX_SIDE_SET, ids.data() ) == 0,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
606 : : "Failed to read side set ids from ExodusII file: " + m_filename );
607 : : // Read in node list for all side sets
608 [ + + ]: 1602 : for (auto i : ids) {
609 : : int nface, nnode;
610 : : // Read number of faces and number of distribution factors in side set i
611 [ + - ][ - + ]: 1360 : ErrChk( ex_get_set_param( m_inFile, EX_SIDE_SET, i, &nface, &nnode ) == 0,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
612 : : "Failed to read side set " + std::to_string(i) + " parameters "
613 : : "from ExodusII file: " + m_filename );
614 : : // Read number of nodes in side set i (overwrite nnode)
615 [ + - ][ - + ]: 1360 : ErrChk( ex_get_side_set_node_list_len( m_inFile, i, &nnode ) == 0,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
616 : : "Failed to read side set " + std::to_string(i) + " node list "
617 : : "length from ExodusII file: " + m_filename );
618 : : Assert(nnode > 0, "Number of nodes = 0 in side set" + std::to_string(i));
619 [ + - ][ - - ]: 1360 : std::vector< int > df( static_cast< std::size_t >( nface ) );
620 [ + - ][ + - ]: 1360 : std::vector< int > nodes( static_cast< std::size_t >( nnode ) );
[ - - ]
621 : : // Read in node list for side set i
622 [ + - ][ - + ]: 1360 : ErrChk( ex_get_side_set_node_list( m_inFile, i, df.data(), nodes.data() )
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
623 : : == 0, "Failed to read node list of side set " +
624 : : std::to_string(i) + " from ExodusII file: " +
625 : : m_filename );
626 : : // Make node list unique
627 [ + - ]: 1360 : tk::unique( nodes );
628 : : // Store 0-based node ID list as std::size_t vector instead of ints
629 [ + - ]: 1360 : auto& list = side[ i ];
630 : : // cppcheck-suppress useStlAlgorithm
631 [ + - ][ + + ]: 140333 : for (auto n : nodes) list.push_back( static_cast<std::size_t>(n-1) );
[ - - ]
632 : : }
633 : : }
634 : :
635 : 242 : return side;
636 : : }
637 : :
638 : : void
639 : 286 : ExodusIIMeshReader::readSidesetFaces(
640 : : std::map< int, std::vector< std::size_t > >& bface,
641 : : std::map< int, std::vector< std::size_t > >& faces )
642 : : // *****************************************************************************
643 : : // Read side sets from ExodusII file
644 : : //! \param[in,out] bface Elem ids of side sets to read into
645 : : //! \param[in,out] faces Elem-relative face ids of tets of side sets
646 : : // *****************************************************************************
647 : : {
648 : : // Read element block ids
649 : 286 : readElemBlockIDs();
650 : :
651 [ + + ]: 285 : if (m_neset > 0) {
652 : : // Read side set ids from file
653 [ + - ]: 249 : std::vector< int > ids( m_neset );
654 [ + - ][ - + ]: 249 : ErrChk( ex_get_ids( m_inFile, EX_SIDE_SET, ids.data() ) == 0,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
655 : : "Failed to read side set ids from ExodusII file: " + m_filename );
656 : :
657 : : // Read all side sets from file
658 [ + + ]: 1616 : for (auto i : ids) {
659 : : int nface, nnode;
660 : :
661 : : // Read number of faces in side set
662 [ + - ][ - + ]: 1367 : ErrChk( ex_get_set_param( m_inFile, EX_SIDE_SET, i, &nface, &nnode ) == 0,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
663 : : "Failed to read side set " + std::to_string(i) + " parameters "
664 : : "from ExodusII file: " + m_filename );
665 : :
666 : : Assert(nface > 0, "Number of faces = 0 in side set" + std::to_string(i));
667 : :
668 [ + - ][ - - ]: 1367 : std::vector< int > exoelem( static_cast< std::size_t >( nface ) );
669 [ + - ][ + - ]: 1367 : std::vector< int > exoface( static_cast< std::size_t >( nface ) );
[ - - ]
670 : :
671 : : // Read in file-internal element ids and relative face ids for side set
672 [ + - ][ - + ]: 1367 : ErrChk( ex_get_set( m_inFile, EX_SIDE_SET, i, exoelem.data(),
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
673 : : exoface.data() ) == 0,
674 : : "Failed to read side set " + std::to_string(i) );
675 : :
676 : : // Store file-internal element ids of side set
677 [ + - ]: 1367 : auto& elem = bface[i];
678 [ + - ]: 1367 : elem.resize( exoelem.size() );
679 : : std::size_t j = 0;
680 [ + + ]: 227373 : for (auto e : exoelem) elem[j++] = static_cast< std::size_t >( e-1 );
681 : :
682 : : // Store zero-based relative face ids of side set
683 [ + - ]: 1367 : auto& face = faces[i];
684 [ + - ]: 1367 : face.resize( exoface.size() );
685 : : j = 0;
686 [ + + ]: 227373 : for (auto n : exoface) face[j++] = static_cast< std::size_t >( n-1 );
687 : :
688 : : Assert( std::all_of( begin(face), end(face),
689 : : [](std::size_t f){ return f<4; } ),
690 : : "Relative face id of side set must be between 0 and 3" );
691 : : Assert( elem.size() == face.size(), "Size mismatch" );
692 : : }
693 : : }
694 : 285 : }
695 : :
696 : : std::pair< tk::ExoElemType, std::size_t >
697 : 608894 : ExodusIIMeshReader::blkRelElemId( std::size_t id ) const
698 : : // *****************************************************************************
699 : : // Compute element-block-relative element id and element type
700 : : //! \param[in] id (ExodusII) file-internal element id
701 : : //! \return Element type the internal id points to and element id relative to
702 : : //! cell-type
703 : : //! \details This function takes an internal element id, which in general can
704 : : //! point to any element block in the ExodusII file and thus we do not know
705 : : //! which element type a block contains. It then computes which cell type the
706 : : //! id points to and computes the relative index for the given cell type. This
707 : : //! is necessary because elements are read in from file by from potentially
708 : : //! multiple blocks by cell type.
709 : : //! \note Must be preceded by a call to readElemBlockIDs()
710 : : // *****************************************************************************
711 : : {
712 : : auto TRI = tk::ExoElemType::TRI;
713 : : auto TET = tk::ExoElemType::TET;
714 : :
715 : : std::size_t e = 0; // counts elements (independent of cell type)
716 : : std::size_t ntri = 0; // counts triangle elements
717 : : std::size_t ntet = 0; // counts tetrahedron elements
718 : :
719 [ + - ]: 803910 : for (const auto& b : m_elemblocks) { // walk all element blocks in order
720 : 803910 : e += b.second; // increment file-internal element id
721 [ + + ]: 803910 : if (e > id) { // found element block for internal id
722 [ + + ]: 608894 : if (b.first == TRI) { // if triangle block
723 : 547954 : return { TRI, id-ntet }; // return cell type and triangle id
724 [ + - ]: 60940 : } else if (b.first == TET) { // if tetrahedron block
725 : 60940 : return { TET, id-ntri }; // return cell type and tetrahedron id
726 : : }
727 : : }
728 : : // increment triangle and tetrahedron elements independently
729 [ - + ]: 195016 : if (b.first == TRI)
730 : 0 : ntri += b.second;
731 [ + - ]: 195016 : else if (b.first == TET)
732 : 195016 : ntet += b.second;
733 : : }
734 : :
735 [ - - ][ - - ]: 0 : Throw( " Exodus internal element id not found" );
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
736 : : }
737 : :
738 : : std::vector< std::size_t >
739 : 739 : ExodusIIMeshReader::triinpoel(
740 : : std::map< int, std::vector< std::size_t > >& belem,
741 : : const std::map< int, std::vector< std::size_t > >& faces,
742 : : const std::vector< std::size_t >& ginpoel,
743 : : const std::vector< std::size_t >& triinp ) const
744 : : // *****************************************************************************
745 : : // Generate triangle face connectivity for side sets
746 : : //! \param[in,out] belem File-internal elem ids of side sets
747 : : //! \param[in] faces Elem-relative face ids of side sets
748 : : //! \param[in] ginpoel Tetrahedron element connectivity with global nodes
749 : : //! \param[in] triinp Triangle element connectivity with global nodes
750 : : //! (if exists in file)
751 : : //! \return Triangle face connectivity with global node IDs of side sets
752 : : //! \details This function takes lists of file-internal element ids (in belem)
753 : : //! for side sets and does two things: (1) generates face connectivity (with
754 : : //! global node IDs) for side sets, and (2) converts the (ExodusII)
755 : : //! file-internal element IDs to face ids so that they can be used to index
756 : : //! into the face connectivity. The IDs in belem are modified and the face
757 : : //! connectivity (for boundary faces only) is returned.
758 : : //! \note Must be preceded by a call to readElemBlockIDs()
759 : : // *****************************************************************************
760 : : {
761 : : Assert( !(m_from == 0 && m_till == 0),
762 : : "Lower and upper tetrahedron id bounds must not both be zero" );
763 : :
764 : : // This will contain one of our final results: face (triangle) connectivity
765 : : // for the side sets only. The difference between bnd_triinpoel and triinpoel
766 : : // is that triinpoel is a triangle element connectivity, independent of side
767 : : // sets, while bnd_triinpoel is a triangle connectivity only for side sets.
768 : : std::vector< std::size_t > bnd_triinpoel;
769 : :
770 : : // Storage for boundary face lists for each side set on this PE
771 : : std::map< int, std::vector< std::size_t > > belem_own;
772 : :
773 : : std::size_t f = 0; // counts all faces
774 [ + + ]: 4936 : for (auto& ss : belem) { // for all side sets
775 : :
776 : : // insert side set id into new map
777 [ + - ]: 4197 : auto& b = belem_own[ ss.first ];
778 : : // get element-relative face ids for side set
779 : : const auto& face = tk::cref_find( faces, ss.first );
780 : : std::size_t s = 0; // counts side set faces
781 [ + + ]: 613091 : for (auto& i : ss.second) { // for all faces on side set
782 : :
783 : : // compute element-block-relative element id and element type
784 [ + - ]: 608894 : auto r = blkRelElemId( i );
785 : :
786 : : // extract boundary face connectivity based on element type
787 : : bool localface = false;
788 [ + + ]: 608894 : if (r.first == tk::ExoElemType::TRI) {
789 : :
790 : : auto t = m_tri.find(r.second);
791 [ + + ]: 547954 : if (t != end(m_tri)) { // only if triangle id exists on this PE
792 : : Assert( t->second < triinp.size()/3,
793 : : "Indexing out of triangle connectivity" );
794 : : // generate triangle (face) connectivity using global node ids
795 [ + - ]: 184478 : bnd_triinpoel.push_back( triinp[ t->second*3 + 0 ] );
796 [ + - ]: 184478 : bnd_triinpoel.push_back( triinp[ t->second*3 + 1 ] );
797 [ + - ]: 184478 : bnd_triinpoel.push_back( triinp[ t->second*3 + 2 ] );
798 : : localface = true;
799 : : }
800 : :
801 [ + - ]: 60940 : } else if (r.first == tk::ExoElemType::TET) {
802 : :
803 [ + + ][ + + ]: 60940 : if (r.second >= m_from && r.second < m_till) { // if tet is on this PE
804 [ + - ]: 41360 : auto t = r.second - m_from;
805 : : Assert( t < ginpoel.size()/4,
806 : : "Indexing out of tetrahedron connectivity" );
807 : : // get ExodusII face-node numbering for side sets, see ExodusII
808 : : // manual figure on "Sideset side Numbering"
809 [ + - ]: 41360 : const auto& tri = tk::expofa[ face[s] ];
810 : : // generate triangle (face) connectivity using global node ids, note
811 : : // the switched node order, 0,2,1, as lpofa is different from expofa
812 [ + - ]: 41360 : bnd_triinpoel.push_back( ginpoel[ t*4 + tri[0] ] );
813 [ + - ]: 41360 : bnd_triinpoel.push_back( ginpoel[ t*4 + tri[1] ] );
814 [ + - ]: 41360 : bnd_triinpoel.push_back( ginpoel[ t*4 + tri[2] ] );
815 : : localface = true;
816 : : }
817 : :
818 : : }
819 : :
820 : 608894 : ++s;
821 : :
822 : : // generate PE-local face id for side set (this is to be used to index
823 : : // into triinpoel)
824 [ + - ]: 225838 : if (localface) b.push_back( f++ );
825 : : }
826 : :
827 : : // if no faces on this side set (on this PE), remove side set id
828 [ + + ]: 4197 : if (b.empty()) belem_own.erase( ss.first );
829 : : }
830 : :
831 : : belem = std::move(belem_own);
832 : :
833 : 739 : return bnd_triinpoel;
834 : : }
835 : :
836 : : void
837 : 36 : ExodusIIMeshReader::readNodeVarNames( std::vector< std::string >& nv ) const
838 : : // *****************************************************************************
839 : : // Read the names of nodal output variables from ExodusII file
840 : : //! \param[in,out] nv Nodal variable names
841 : : // *****************************************************************************
842 : : {
843 : : #if defined(__clang__)
844 : : #pragma clang diagnostic push
845 : : #pragma clang diagnostic ignored "-Wvla"
846 : : #pragma clang diagnostic ignored "-Wvla-extension"
847 : : #elif defined(STRICT_GNUC)
848 : : #pragma GCC diagnostic push
849 : : #pragma GCC diagnostic ignored "-Wvla"
850 : : #endif
851 : :
852 : 36 : int numvars = 0;
853 : :
854 [ - + ][ - - ]: 36 : ErrChk(
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
855 : : ex_get_variable_param( m_inFile, EX_NODE_BLOCK, &numvars ) == 0,
856 : : "Failed to read nodal output variable parameters from ExodusII file: " +
857 : : m_filename );
858 : :
859 [ + + ]: 36 : if (numvars) {
860 : :
861 : 30 : char* names[ static_cast< std::size_t >( numvars ) ];
862 [ + + ]: 210 : for (int i=0; i<numvars; ++i)
863 : 180 : names[i] = static_cast<char*>( calloc((MAX_STR_LENGTH+1), sizeof(char)) );
864 : :
865 [ - + ][ - - ]: 30 : ErrChk( ex_get_variable_names( m_inFile,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
866 : : EX_NODAL,
867 : : numvars,
868 : : names ) == 0,
869 : : "Failed to read nodal variable names from ExodusII file: " +
870 : : m_filename );
871 : :
872 : 30 : nv.resize( static_cast< std::size_t >( numvars ) );
873 : : std::size_t i = 0;
874 : : // cppcheck-suppress useStlAlgorithm
875 [ + + ]: 210 : for (auto& n : nv) n = names[ i++ ];
876 : :
877 : 30 : }
878 : :
879 : : #if defined(__clang__)
880 : : #pragma clang diagnostic pop
881 : : #elif defined(STRICT_GNUC)
882 : : #pragma GCC diagnostic pop
883 : : #endif
884 : 36 : }
885 : :
886 : : void
887 : 36 : ExodusIIMeshReader::readTimeValues( std::vector< tk::real >& tv ) const
888 : : // *****************************************************************************
889 : : // Read time values from ExodusII file
890 : : //! \param[in] tv Vector of time values at which field data is saved
891 : : // *****************************************************************************
892 : : {
893 : : auto num_time_steps =
894 : 36 : static_cast< std::size_t >( ex_inquire_int( m_inFile, EX_INQ_TIME ) );
895 : :
896 [ + + ]: 36 : if (num_time_steps) {
897 : 30 : tv.resize( num_time_steps, 0.0 );
898 [ - + ][ - - ]: 30 : ErrChk( ex_get_all_times( m_inFile, tv.data() ) == 0,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
899 : : "Failed to read time values from ExodusII file: " + m_filename );
900 : : }
901 : 36 : }
902 : :
903 : : void
904 : 36 : ExodusIIMeshReader::readNodeScalars(
905 : : std::size_t ntime,
906 : : std::size_t nvar,
907 : : std::vector< std::vector< std::vector< tk::real > > >& var ) const
908 : : // *****************************************************************************
909 : : // Read node scalar fields from ExodusII file
910 : : //! \param[in] ntime Number of time steps to read
911 : : //! \param[in] nvar Number of variables to read
912 : : //! \param[in] var Vector of nodal variables to read to: inner vector: nodes,
913 : : //! middle vector: (physics) variable, outer vector: time step
914 : : // *****************************************************************************
915 : : {
916 : 36 : var.resize( ntime );
917 [ + + ]: 126 : for (auto& v : var) {
918 : 90 : v.resize( nvar );
919 [ + + ]: 630 : for (auto& n : v) n.resize( m_nnode );
920 : : }
921 : :
922 [ + + ]: 126 : for (std::size_t t=0; t<var.size(); ++t) {
923 [ + + ]: 630 : for (std::size_t id=0; id<var[t].size(); ++id) {
924 [ - + ][ - - ]: 540 : ErrChk( ex_get_var( m_inFile,
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
925 : : static_cast< int >( t+1 ),
926 : : EX_NODAL,
927 : : static_cast< int >( id+1 ),
928 : : 1,
929 : : static_cast< int64_t >( var[t][id].size() ),
930 : : var[t][id].data() ) == 0,
931 : : "Failed to read node scalar from ExodusII file: " + m_filename );
932 : : }
933 : : }
934 : 36 : }
935 : :
936 : : std::size_t
937 : 1501 : ExodusIIMeshReader::nelem( tk::ExoElemType elemtype ) const
938 : : // *****************************************************************************
939 : : // Return number of elements in all mesh blocks for a given elem type in file
940 : : //! \param[in] elemtype Element type
941 : : //! \return Number of elements in all blocks for the elem type
942 : : //! \note Must be preceded by a call to readElemBlockIDs()
943 : : // *****************************************************************************
944 : : {
945 : 1501 : auto e = static_cast< std::size_t >( elemtype );
946 : 1501 : return std::accumulate( m_nel[e].cbegin(), m_nel[e].cend(), 0u );
947 : : }
|