preCICE v3.2.0
Loading...
Searching...
No Matches
ExportXML.cpp
Go to the documentation of this file.
1#include "io/ExportXML.hpp"
2#include <Eigen/Core>
3#include <algorithm>
4#include <filesystem>
5#include <fstream>
6#include <memory>
7#include <string>
8#include "io/Export.hpp"
10#include "mesh/Data.hpp"
11#include "mesh/Edge.hpp"
12#include "mesh/Mesh.hpp"
14#include "mesh/Tetrahedron.hpp"
15#include "mesh/Triangle.hpp"
16#include "mesh/Vertex.hpp"
17#include "utils/Helpers.hpp"
18#include "utils/IntraComm.hpp"
19#include "utils/assertion.hpp"
20
21namespace precice::io {
22
24 std::string_view participantName,
25 std::string_view location,
26 const mesh::Mesh &mesh,
27 ExportKind kind,
28 int frequency,
29 int rank,
30 int size)
31 : Export(participantName, location, mesh, kind, frequency, rank, size) {};
32
33void ExportXML::doExport(int index, double time)
34{
35 PRECICE_TRACE(index, time, _mesh->getName());
36
37 if (!keepExport(index))
38 return;
39
40 const auto &mesh = *_mesh;
41
43 if (not _location.empty())
45
46 if (isParallel()) {
47 if (_rank == 0) {
48 writeParallelFile(index, time);
49 }
50 if (!mesh.isPartitionEmpty(_rank)) { // only procs at the coupling interface should write output (for performance reasons)
51 writeSubFile(index, time);
52 }
53 } else {
54 writeSubFile(index, time);
55 }
56}
57
59{
60 if (isParallel() && _rank > 0)
61 return;
62
64 writeSeriesFile(fmt::format("{}-{}.{}.series", _mesh->getName(), _participantName, ext));
65}
66
68{
69 _vectorDataNames.clear();
70 _scalarDataNames.clear();
71 const bool isThreeDim = (mesh.getDimensions() == 3);
72 for (const mesh::PtrData &data : mesh.data()) {
73 if (data->timeStepsStorage().empty()) {
74 continue;
75 }
76 int dataDimensions = data->getDimensions();
77 const bool hasGradient = data->hasGradient();
78 PRECICE_ASSERT(dataDimensions >= 1);
79 std::string dataName = data->getName();
80 if (dataDimensions == 1) {
81 _scalarDataNames.push_back(dataName);
82 if (hasGradient) {
83 _vectorDataNames.push_back(dataName + "_gradient");
84 }
85 } else {
86 _vectorDataNames.push_back(dataName);
87 if (hasGradient) {
88 _vectorDataNames.push_back(dataName + "_dx");
89 _vectorDataNames.push_back(dataName + "_dy");
90 if (isThreeDim) {
91 _vectorDataNames.push_back(dataName + "_dz");
92 }
93 }
94 }
95 }
96}
97
99{
101 return fmt::format("{}-{}.{}_{}.{}", _mesh->getName(), _participantName, formatIndex(index), rank, getPieceExtension());
102}
103
105{
107 return fmt::format("{}-{}.{}.{}", _mesh->getName(), _participantName, formatIndex(index), getPieceExtension());
108}
109
110void ExportXML::writeParallelFile(int index, double time)
111{
113
114 // Construct filename
115 // Mesh-Participant.it_2.pvtu
116 auto filename = fmt::format("{}-{}.{}.{}", _mesh->getName(), _participantName, formatIndex(index), getParallelExtension());
117 recordExport(filename, time);
118
119 namespace fs = std::filesystem;
120 fs::path outfile(_location);
121 outfile = outfile / filename;
122 std::ofstream outParallelFile(outfile.string(), std::ios::trunc);
123
124 PRECICE_CHECK(outParallelFile, "{} export failed to open primary file \"{}\"", getVTKFormat(), outfile.generic_string());
125
126 const auto formatType = getVTKFormat();
127 outParallelFile << "<?xml version=\"1.0\"?>\n";
128 outParallelFile << "<VTKFile type=\"P" << formatType << "\" version=\"0.1\" byte_order=\"";
129 outParallelFile << (utils::isMachineBigEndian() ? "BigEndian\">" : "LittleEndian\">") << '\n';
130 outParallelFile << " <P" << formatType << " GhostLevel=\"0\">\n";
131
132 outParallelFile << " <PPoints>\n";
133 outParallelFile << " <PDataArray type=\"Float64\" Name=\"Position\" NumberOfComponents=\"" << 3 << "\"/>\n";
134 outParallelFile << " </PPoints>\n";
135
136 writeParallelCells(outParallelFile);
137
138 writeParallelData(outParallelFile);
139
140 // const auto &offsets = _mesh->getVertexOffsets();
141 for (size_t rank : utils::IntraComm::allRanks()) {
142 if (!_mesh->isPartitionEmpty(rank)) {
143 // only non-empty subfiles
144 outParallelFile << " <Piece Source=\"" << parallelPieceFilenameFor(index, rank) << "\"/>\n";
145 }
146 }
147
148 outParallelFile << " </P" << formatType << ">\n";
149 outParallelFile << "</VTKFile>\n";
150
151 outParallelFile.close();
152}
153
154void ExportXML::writeSubFile(int index, double time)
155{
156 std::string filename;
157 if (isParallel()) {
158 filename = parallelPieceFilenameFor(index, _rank);
159 } else {
160 filename = serialPieceFilename(index);
161 recordExport(filename, time);
162 }
163
164 namespace fs = std::filesystem;
165 fs::path outfile(_location);
166 outfile /= filename;
167 std::ofstream outSubFile(outfile.string(), std::ios::trunc);
168
169 PRECICE_CHECK(outSubFile, "{} export failed to open secondary file \"{}\"", getVTKFormat(), outfile.generic_string());
170
171 const auto formatType = getVTKFormat();
172 outSubFile << "<?xml version=\"1.0\"?>\n";
173 outSubFile << "<VTKFile type=\"" << formatType << "\" version=\"0.1\" byte_order=\"";
174 outSubFile << (utils::isMachineBigEndian() ? "BigEndian\">" : "LittleEndian\">") << '\n';
175
176 outSubFile << " <" << formatType << ">\n";
177
178 outSubFile << " <Piece " << getPieceAttributes(*_mesh) << "> \n";
179 exportPoints(outSubFile, *_mesh);
180
181 // Write *_mesh
182 exportConnectivity(outSubFile, *_mesh);
183
184 // Write data
185 exportData(outSubFile, *_mesh);
186
187 outSubFile << " </Piece>\n";
188 outSubFile << " </" << formatType << "> \n";
189 outSubFile << "</VTKFile>\n";
190
191 outSubFile.close();
192}
193
194void ExportXML::exportGradient(const mesh::PtrData data, const int spaceDim, std::ostream &outFile) const
195{
196 const auto &gradients = data->timeStepsStorage().last().sample.gradients;
197 const int dataDimensions = data->getDimensions();
199 if (dataDimensions == 1) {
200 suffices = {"_gradient"};
201 } else if (spaceDim == 2) {
202 suffices = {"_dx", "_dy"};
203 } else if (spaceDim == 3) {
204 suffices = {"_dx", "_dy", "_dz"};
205 }
206 int counter = 0; // Counter for multicomponent
207 for (const auto &suffix : suffices) {
208 const std::string dataName(data->getName());
209 outFile << " <DataArray type=\"Float64\" Name=\"" << dataName << suffix << "\" NumberOfComponents=\"" << 3;
210 outFile << "\" format=\"ascii\">\n";
211 outFile << " ";
212 for (int i = counter; i < gradients.cols(); i += spaceDim) { // Loop over vertices
213 int j = 0;
214 for (; j < gradients.rows(); j++) { // Loop over components
215 outFile << gradients.coeff(j, i) << " ";
216 }
217 if (j < 3) { // If 2D data add additional zero as third component
218 outFile << "0.0"
219 << " ";
220 }
221 }
222 outFile << '\n'
223 << " </DataArray>\n";
224 counter++; // Increment counter for next component
225 }
226}
227
229 std::ostream &outFile,
230 const mesh::Mesh &mesh) const
231{
232 outFile << " <PointData Scalars=\"Rank ";
233 for (const auto &scalarDataName : _scalarDataNames) {
234 outFile << scalarDataName << ' ';
235 }
236 outFile << "\" Vectors=\"";
237 for (const auto &vectorDataName : _vectorDataNames) {
238 outFile << vectorDataName << ' ';
239 }
240 outFile << "\">\n";
241
242 // Export the current rank
243 outFile << " <DataArray type=\"UInt32\" Name=\"Rank\" NumberOfComponents=\"1\" format=\"ascii\">\n";
244 outFile << " ";
245 const auto rank = utils::IntraComm::getRank();
246 for (size_t count = 0; count < mesh.nVertices(); ++count) {
247 outFile << rank << ' ';
248 }
249 outFile << "\n </DataArray>\n";
250
251 for (const mesh::PtrData &data : mesh.data()) { // Plot vertex data
252 if (data->timeStepsStorage().empty()) {
253 continue;
254 }
255 const Eigen::VectorXd &values = data->timeStepsStorage().last().sample.values;
256 int dataDimensions = data->getDimensions();
257 std::string dataName(data->getName());
258 int numberOfComponents = (dataDimensions == 2) ? 3 : dataDimensions;
259 const bool hasGradient = data->hasGradient();
260 outFile << " <DataArray type=\"Float64\" Name=\"" << dataName << "\" NumberOfComponents=\"" << numberOfComponents;
261 outFile << "\" format=\"ascii\">\n";
262 outFile << " ";
263 if (dataDimensions > 1) {
264 Eigen::VectorXd viewTemp(dataDimensions);
265 for (size_t count = 0; count < mesh.nVertices(); count++) {
266 size_t offset = count * dataDimensions;
267 for (int i = 0; i < dataDimensions; i++) {
268 viewTemp[i] = values(offset + i);
269 }
270 for (int i = 0; i < dataDimensions; i++) {
271 outFile << viewTemp[i] << ' ';
272 }
273 if (dataDimensions == 2) {
274 outFile << "0.0" << ' '; // 2D data needs to be 3D for vtk
275 }
276 outFile << ' ';
277 }
278 } else if (dataDimensions == 1) {
279 for (size_t count = 0; count < mesh.nVertices(); count++) {
280 outFile << values(count) << ' ';
281 }
282 }
283 outFile << '\n'
284 << " </DataArray>\n";
285 if (hasGradient) {
286 exportGradient(data, dataDimensions, outFile);
287 }
288 }
289 outFile << " </PointData> \n";
290}
291
293 const Eigen::VectorXd &position,
294 std::ostream &outFile)
295{
296 outFile << " ";
297 for (int i = 0; i < position.size(); i++) {
298 outFile << position(i) << " ";
299 }
300 if (position.size() == 2) {
301 outFile << 0.0 << " "; // also for 2D scenario, vtk needs 3D data
302 }
303 outFile << '\n';
304}
305
307 const mesh::Triangle &triangle,
308 std::ostream &outFile)
309{
310 outFile << triangle.vertex(0).getID() << " ";
311 outFile << triangle.vertex(1).getID() << " ";
312 outFile << triangle.vertex(2).getID() << " ";
313}
314
316 const mesh::Tetrahedron &tetra,
317 std::ostream &outFile)
318{
319 outFile << tetra.vertex(0).getID() << " ";
320 outFile << tetra.vertex(1).getID() << " ";
321 outFile << tetra.vertex(2).getID() << " ";
322 outFile << tetra.vertex(3).getID() << " ";
323}
324
326 const mesh::Edge &edge,
327 std::ostream &outFile)
328{
329 outFile << edge.vertex(0).getID() << " ";
330 outFile << edge.vertex(1).getID() << " ";
331}
332
334 std::ostream &outFile,
335 const mesh::Mesh &mesh) const
336{
337 outFile << " <Points> \n";
338 outFile << " <DataArray type=\"Float64\" Name=\"Position\" NumberOfComponents=\"" << 3 << "\" format=\"ascii\"> \n";
339 for (const mesh::Vertex &vertex : mesh.vertices()) {
340 writeVertex(vertex.getCoords(), outFile);
341 }
342 outFile << " </DataArray>\n";
343 outFile << " </Points> \n\n";
344}
345
347{
348 // write scalar data names
349 out << " <PPointData Scalars=\"Rank ";
350 for (const auto &scalarDataName : _scalarDataNames) {
351 out << scalarDataName << ' ';
352 }
353 // write vector data names
354 out << "\" Vectors=\"";
355 for (const auto &vectorDataName : _vectorDataNames) {
356 out << vectorDataName << ' ';
357 }
358 out << "\">\n";
359
360 out << " <PDataArray type=\"Int32\" Name=\"Rank\" NumberOfComponents=\"1\"/>\n";
361
362 for (const auto &scalarDataName : _scalarDataNames) {
363 out << " <PDataArray type=\"Float64\" Name=\"" << scalarDataName << "\" NumberOfComponents=\"" << 1 << "\"/>\n";
364 }
365
366 for (const auto &vectorDataName : _vectorDataNames) {
367 out << " <PDataArray type=\"Float64\" Name=\"" << vectorDataName << "\" NumberOfComponents=\"" << 3 << "\"/>\n";
368 }
369 out << " </PPointData>\n";
370}
371
372} // namespace precice::io
#define PRECICE_TRACE(...)
Definition LogMacros.hpp:92
#define PRECICE_CHECK(check,...)
Definition LogMacros.hpp:32
#define PRECICE_ASSERT(...)
Definition assertion.hpp:85
virtual std::string getPieceExtension() const =0
virtual std::string getPieceAttributes(const mesh::Mesh &mesh) const =0
void writeParallelData(std::ostream &out) const
std::string parallelPieceFilenameFor(int index, int rank) const
Definition ExportXML.cpp:98
static void writeLine(const mesh::Edge &edge, std::ostream &outFile)
virtual std::string getVTKFormat() const =0
void exportData(std::ostream &outFile, const mesh::Mesh &mesh) const
virtual void exportConnectivity(std::ostream &outFile, const mesh::Mesh &mesh) const =0
void exportPoints(std::ostream &outFile, const mesh::Mesh &mesh) const
void writeParallelFile(int index, double time)
Writes the primary file (called only by the primary rank)
std::string serialPieceFilename(int index) const
void exportSeries() const final override
Definition ExportXML.cpp:58
static void writeTriangle(const mesh::Triangle &triangle, std::ostream &outFile)
std::vector< std::string > _scalarDataNames
List of names of all scalar data on mesh.
Definition ExportXML.hpp:56
virtual std::string getParallelExtension() const =0
static void writeTetrahedron(const mesh::Tetrahedron &tetra, std::ostream &outFile)
std::vector< std::string > _vectorDataNames
List of names of all vector data on mesh.
Definition ExportXML.hpp:59
void exportGradient(const mesh::PtrData data, const int dataDim, std::ostream &outFile) const
void writeSubFile(int index, double time)
Writes the sub file for each rank.
void processDataNamesAndDimensions(const mesh::Mesh &mesh)
Stores scalar and vector data names in string vectors Needed for writing primary file and sub files.
Definition ExportXML.cpp:67
static void writeVertex(const Eigen::VectorXd &position, std::ostream &outFile)
void doExport(int index, double time) final override
Export the mesh and writes files.
Definition ExportXML.cpp:33
ExportXML(std::string_view participantName, std::string_view location, const mesh::Mesh &mesh, ExportKind kind, int frequency, int rank, int size)
Definition ExportXML.cpp:23
virtual void writeParallelCells(std::ostream &out) const =0
Export(std::string_view participantName, std::string_view location, const mesh::Mesh &mesh, ExportKind kind, int frequency, int rank, int size)
Definition Export.hpp:23
void writeSeriesFile(std::string_view filename) const
Definition Export.cpp:21
std::string _location
Definition Export.hpp:65
bool isParallel() const
Definition Export.cpp:7
void recordExport(std::string filename, double time)
Definition Export.cpp:44
std::string _participantName
Definition Export.hpp:64
const mesh::Mesh *const _mesh
Definition Export.hpp:66
bool keepExport(int index) const
Definition Export.hpp:59
std::string formatIndex(int index) const
Definition Export.cpp:12
Linear edge of a mesh, defined by two Vertex objects.
Definition Edge.hpp:15
Vertex & vertex(int i)
Returns the edge's vertex with index 0 or 1.
Definition Edge.hpp:76
Container and creator for meshes.
Definition Mesh.hpp:38
Tetrahedron of a mesh, defined by 4 vertices.
Vertex & vertex(int i)
Returns tetrahedron vertex with index 0, 1, 2 or 3.
Triangle of a mesh, defined by three vertices.
Definition Triangle.hpp:24
Vertex & vertex(int i)
Returns triangle vertex with index 0, 1 or 2.
Definition Triangle.hpp:140
Vertex of a mesh.
Definition Vertex.hpp:16
VertexID getID() const
Returns the unique (among vertices of one mesh on one processor) ID of the vertex.
Definition Vertex.hpp:109
static Rank getRank()
Current rank.
Definition IntraComm.cpp:42
static auto allRanks()
Returns an iterable range over all ranks [0, _size)
Definition IntraComm.hpp:43
T close(T... args)
T create_directories(T... args)
T generic_string(T... args)
provides Import and Export of the coupling mesh and data.
provides Mesh, Data and primitives.
std::shared_ptr< Data > PtrData
contains the time interpolation logic.
Definition Sample.hpp:8
bool isMachineBigEndian()
Returns true if machine is big-endian needed for parallel vtk output.
Definition Helpers.cpp:5