1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236 | // *****************************************************************************
/*!
\file src/IO/MeshWriter.cpp
\copyright 2012-2015 J. Bakosi,
2016-2018 Los Alamos National Security, LLC.,
2019-2021 Triad National Security, LLC.,
2022-2025 J. Bakosi
All rights reserved. See the LICENSE file for details.
\brief Charm++ group for outputing mesh data to file
\details Charm++ group definition used to output data associated to
unstructured meshes to file(s). Charm++ chares (work units) send mesh and
field data associated to mesh entities to the MeshWriter class defined here
to write the data to file(s).
*/
// *****************************************************************************
#include "XystBuildConfig.hpp"
#include "MeshWriter.hpp"
#include "Reorder.hpp"<--- Include file: "Reorder.hpp" not found.
#include "ExodusIIMeshWriter.hpp"
using tk::MeshWriter;
void
MeshWriter::nchare( std::size_t meshid, int n )
// *****************************************************************************
// Set the total number of chares
//! \param[in] meshid Mesh whose number of chares to set
//! \param[in] n Total number of chares across the whole problem (for a mesh)
// *****************************************************************************
{
Assert( meshid < m_nchare.size(), "Size mismatch" );
m_nchare[ meshid ] = n;
}
void
MeshWriter::write(
std::size_t meshid,
bool meshoutput,
bool fieldoutput,
uint64_t itr,
uint64_t itf,
tk::real time,
int chareid,
const std::string& basefilename,
const std::vector< std::size_t >& inpoel,
const UnsMesh::Coords& coord,
const std::map< int, std::vector< std::size_t > >& bface,
const std::map< int, std::vector< std::size_t > >& bnode,
const std::vector< std::size_t >& triinpoel,
const std::vector< std::string >& elemfieldnames,
const std::vector< std::string >& nodefieldnames,
const std::vector< std::string >& elemsurfnames,
const std::vector< std::string >& nodesurfnames,
const std::vector< std::vector< tk::real > >& elemfields,
const std::vector< std::vector< tk::real > >& nodefields,
const std::vector< std::vector< tk::real > >& elemsurfs,
const std::vector< std::vector< tk::real > >& nodesurfs,
const std::set< int >& outsets,
CkCallback c )
// *****************************************************************************
// Output unstructured mesh into file
//! \param[in] meshid Mesh Id
//! \param[in] meshoutput True if mesh is to be written
//! \param[in] fieldoutput True if field data is to be written
//! \param[in] itr Iteration count since a new mesh. New mesh in this context
//! means that either the mesh is moved and/or its topology has changed.
//! \param[in] itf Field output iteration count
//! \param[in] time Physical time this at this field output dump
//! \param[in] chareid The chare id the write-to-file request is coming from
//! \param[in] basefilename String to use as the base of the filename
//! \param[in] inpoel Mesh connectivity for the mesh chunk to be written with
//! local ids
//! \param[in] coord Node coordinates of the mesh chunk to be written
//! \param[in] bface Map of boundary-face lists mapped to corresponding side set
//! ids for this mesh chunk
//! \param[in] bnode Map of boundary-node lists mapped to corresponding side set
//! ids for this mesh chunk with local ids
//! \param[in] triinpoel Interconnectivity of points and boundary-face in this
//! mesh chunk with local ids
//! \param[in] elemfieldnames Names of element fields to be output to file
//! \param[in] nodefieldnames Names of node fields to be output to file
//! \param[in] elemsurfnames Names of eleme surface fields to be output to file
//! \param[in] nodesurfnames Names of node surface fields to be output to file
//! \param[in] elemfields Field data in mesh elements to output to file
//! \param[in] nodefields Field data in mesh nodes to output to file
//! \param[in] elemsurfs Surface field data in mesh elements to output to file
//! \param[in] nodesurfs Surface field data in mesh nodes to output to file
//! \param[in] outsets Unique set of surface side set ids along which to save
//! solution field variables
//! \param[in] c Function to continue with after the write
// *****************************************************************************
{
if (m_benchmark) { c.send(); return; }
// Generate filenames for volume and surface field output
auto vf = filename( basefilename, meshid, itr, chareid );
if (meshoutput) {
// Write volume mesh and field names
ExodusIIMeshWriter ev( vf, ExoWriter::CREATE );
// Write chare mesh (do not write side sets in parallel)
if (m_nchare[meshid] == 1) {
ev.writeMesh( tk::UnsMesh( inpoel, coord, bnode ) );
} else {
ev.writeMesh< 4 >( inpoel, coord );
}
ev.writeElemVarNames( elemfieldnames );
Assert( nodefieldnames.size() == nodefields.size(), "Size mismatch" );
ev.writeNodeVarNames( nodefieldnames );
// Write surface meshes and surface variable field names
for (auto s : outsets) {
auto sf = filename( basefilename, meshid, itr, chareid, s );
ExodusIIMeshWriter es( sf, ExoWriter::CREATE );
auto b = bface.find(s);
if (b == end(bface)) {
// If a side set does not exist on a chare, write out a
// connectivity for a single triangle with its node coordinates of
// zero. This is so the paraview series reader can load side sets
// distributed across multiple files. See also
// https://www.paraview.org/Wiki/Restarted_Simulation_Readers.
es.writeMesh< 3 >( std::vector< std::size_t >{1,2,3},
UnsMesh::Coords{{ {{0,0,0}}, {{0,0,0}}, {{0,0,0}} }} );
es.writeElemVarNames( elemsurfnames );
es.writeNodeVarNames( nodesurfnames );
continue;
}
std::vector< std::size_t > nodes;
for (auto f : b->second) {
nodes.push_back( triinpoel[f*3+0] );
nodes.push_back( triinpoel[f*3+1] );
nodes.push_back( triinpoel[f*3+2] );
}
auto [inp,gid,lid] = tk::global2local( nodes );
tk::unique( nodes );
auto nnode = nodes.size();
UnsMesh::Coords scoord;
scoord[0].resize( nnode );
scoord[1].resize( nnode );
scoord[2].resize( nnode );
std::size_t j = 0;
for (auto i : nodes) {
scoord[0][j] = coord[0][i];
scoord[1][j] = coord[1][i];
scoord[2][j] = coord[2][i];
++j;
}
es.writeMesh< 3 >( inp, scoord );
es.writeElemVarNames( elemsurfnames );
es.writeNodeVarNames( nodesurfnames );
}
}
if (fieldoutput) {
// Write volume variable fields
ExodusIIMeshWriter ev( vf, ExoWriter::OPEN );
ev.writeTimeStamp( itf, time );
// Write volume element variable fields
int varid = 0;
for (const auto& v : elemfields) ev.writeElemScalar( itf, ++varid, v );
// Write volume node variable fields
varid = 0;
for (const auto& v : nodefields) ev.writeNodeScalar( itf, ++varid, v );
// Write surface node variable fields
std::size_t j = 0;
std::size_t k = 0;
auto nvar = static_cast< int >( nodesurfnames.size() ) ;
auto nevar = static_cast< int >( elemsurfnames.size() ) ;
for (auto s : outsets) {
auto sf = filename( basefilename, meshid, itr, chareid, s );
ExodusIIMeshWriter es( sf, ExoWriter::OPEN );
es.writeTimeStamp( itf, time );
if (bface.find(s) == end(bface)) {
// If a side set does not exist on a chare, write out a
// a node field for a single triangle with zeros. This is so the
// paraview series reader can load side sets distributed across
// multiple files. See also
// https://www.paraview.org/Wiki/Restarted_Simulation_Readers.
for (int i=1; i<=nvar; ++i) es.writeNodeScalar( itf, i, {0,0,0} );
for (int i=1; i<=nevar; ++i) es.writeElemScalar( itf, i, {0} );
continue;
}
for (int i=1; i<=nvar; ++i)
es.writeNodeScalar( itf, i, nodesurfs[j++] );
for (int i=1; i<=nevar; ++i)
es.writeElemScalar( itf, i, elemsurfs[k++] );
}
}
c.send();
}
std::string
MeshWriter::filename( const std::string& basefilename,
std::size_t meshid,
uint64_t itr,
int chareid,
int surfid ) const
// *****************************************************************************
// Compute filename
//! \param[in] basefilename String use as the base filename.
//! \param[in] meshid Mesh Id
//! \param[in] itr Iteration count since a new mesh. New mesh in this context
//! means that either the mesh is moved and/or its topology has changed.
//! \param[in] chareid The chare id the write-to-file request is coming from
//! \param[in] surfid Surface ID if computing a surface filename
//! \details We use a file naming convention for large field output data that
//! allows ParaView to glue multiple files into a single simulation output by
//! only loading a single file. The base filename is followed by ".e-s.",
//! which probably stands for Exodus Sequence, followed by 3 integers:
//! (1) {RS}: counts the number of "restart dumps", but we use this for
//! counting the number of outputs with a different mesh, e.g., due to
//! mesh refinement, thus if this first number is new the mesh is new
//! compared to the previous (first) number afer ".e-s.",
//! (2) {NP}: total number of partitions (workers, chares), this is more than
//! the number of PEs with nonzero virtualization (overdecomposition), and
//! (3) {RANK}: worker (chare) id.
//! Thus {RANK} does spatial partitioning, while {RS} partitions in time, but
//! a single {RS} id may contain multiple time steps, which equals to the
//! number of time steps at which field output is saved without refining the
//! mesh.
//! \return Filename computed
//! \see https://www.paraview.org/Wiki/Restarted_Simulation_Readers
// *****************************************************************************
{
return basefilename + (surfid ? "-surf." + std::to_string(surfid) : "")
+ (m_nchare.size() > 1 ? '.' + std::to_string(meshid) : "")
+ ".e-s"
+ '.' + std::to_string( itr ) // iteration count with new mesh
+ '.' + std::to_string( m_nchare[meshid] ) // total number of workers
+ '.' + std::to_string( chareid ); // new file per worker
}
#include "NoWarning/meshwriter.def.h"<--- Include file: "NoWarning/meshwriter.def.h" not found.
|