OGS
PVD2XDMF.cpp
Go to the documentation of this file.
1
10#include <tclap/CmdLine.h>
11
12#ifdef USE_PETSC
13#include <mpi.h>
14#endif
15
16#include <array>
17#include <boost/property_tree/ptree.hpp>
18#include <boost/property_tree/xml_parser.hpp>
19#include <string>
20
21#include "BaseLib/FileTools.h"
22#include "BaseLib/Logging.h"
23#include "BaseLib/MemWatch.h"
24#include "BaseLib/RunTime.h"
25#include "BaseLib/StringTools.h"
26#include "InfoLib/GitInfo.h"
30#include "MeshLib/Mesh.h"
31
32// TODO (naumov) use std::filesystem::path
33std::vector<std::pair<double, std::string>> readPvd(
34 std::string const& pvd_filename)
35{
36 DBUG("Start reading the PVD file {:s}", pvd_filename);
37 boost::property_tree::ptree pvd;
38 read_xml(pvd_filename, pvd,
39 boost::property_tree::xml_parser::trim_whitespace);
40
41 std::vector<std::pair<double, std::string>> timeseries;
42 for (auto const& dataset : pvd.get_child("VTKFile.Collection"))
43 {
44 if (dataset.first != "DataSet")
45 {
46 OGS_FATAL("Expected DataSet tag but got '{:s}'", dataset.first);
47 }
48
49 auto const time = dataset.second.get<double>("<xmlattr>.timestep");
50 auto const file = dataset.second.get<std::string>("<xmlattr>.file");
51 timeseries.emplace_back(time, file);
52 }
53 DBUG("Finished reading the PVD file {:s}", pvd_filename);
54
55 return timeseries;
56}
57
58template <typename T>
60 MeshLib::PropertyVectorBase* destination_pv)
61{
62 if (!dynamic_cast<MeshLib::PropertyVector<T>*>(destination_pv))
63 {
64 return false;
65 }
66
67 auto const* pv = properties.getPropertyVector<T>(
68 destination_pv->getPropertyName(), destination_pv->getMeshItemType(),
69 destination_pv->getNumberOfGlobalComponents());
70
71 assert(pv != nullptr);
72
73 std::copy(
74 std::begin(*pv), std::end(*pv),
75 std::begin(dynamic_cast<MeshLib::PropertyVector<T>&>(*destination_pv)));
76
77 return true;
78}
79
81 MeshLib::Mesh const& main_mesh,
82 std::string error_message)
83{
84 if (mesh.getDimension() != main_mesh.getDimension())
85 {
87 "{:s}The mesh has dimension {} which is different from the "
88 "dimension {} of in the main mesh.",
89 error_message, mesh.getDimension(), main_mesh.getDimension());
90 }
91 if (mesh.getNumberOfElements() != main_mesh.getNumberOfElements())
92 {
94 "{:s}The mesh has {} elements which is different from the number "
95 "of elements ({}) in the main mesh.",
96 error_message, mesh.getNumberOfElements(),
97 main_mesh.getNumberOfElements());
98 }
99 if (mesh.getNumberOfNodes() != main_mesh.getNumberOfNodes())
100 {
101 OGS_FATAL(
102 "{:s}The mesh has {} nodes which is different from the number of "
103 "nodes ({}) in the main mesh.",
104 error_message, mesh.getNumberOfNodes(),
105 main_mesh.getNumberOfNodes());
106 }
107}
108
109int main(int argc, char* argv[])
110{
111 TCLAP::CmdLine cmd(
112 "Converts a time series from PVD to XDMF format.\n\n"
113 "OpenGeoSys-6 software, version " +
115 ".\n"
116 "Copyright (c) 2012-2024, OpenGeoSys Community "
117 "(http://www.opengeosys.org)",
119
120 TCLAP::ValueArg<std::string> log_level_arg(
121 "l", "log-level",
122 "the verbosity of logging messages: none, error, warn, info, "
123 "debug, "
124 "all",
125 false,
126#ifdef NDEBUG
127 "info",
128#else
129 "all",
130#endif
131 "LOG_LEVEL");
132 cmd.add(log_level_arg);
133
134 TCLAP::UnlabeledValueArg<std::string> pvd_file_arg("pvd-file", "pvd file",
135 true, "", "file");
136 cmd.add(pvd_file_arg);
137
138 TCLAP::ValueArg<std::string> outdir_arg("o", "output-directory",
139 "the output directory to write to",
140 false, ".", "PATH");
141 cmd.add(outdir_arg);
142
143 cmd.parse(argc, argv);
144#ifdef USE_PETSC
145 MPI_Init(&argc, &argv);
146#endif
147 BaseLib::setConsoleLogLevel(log_level_arg.getValue());
148
149 auto const pvd_file_dir = BaseLib::extractPath(pvd_file_arg.getValue());
150
151 auto const timeseries = readPvd(pvd_file_arg.getValue());
152
153 if (timeseries.empty())
154 {
155 OGS_FATAL("Empty time series.");
156 }
157
158 // Initialized from the first timeseries entry and data is updated for each
159 // subsequent time step.
160 std::unique_ptr<MeshLib::Mesh> main_mesh;
161
162 std::filesystem::path const output_file{
163 BaseLib::extractBaseNameWithoutExtension(pvd_file_arg.getValue()) +
164 ".xdmf"};
165 std::filesystem::path output_file_path{outdir_arg.getValue()};
166 if (outdir_arg.getValue() != "")
167 {
168 output_file_path =
169 BaseLib::joinPaths(outdir_arg.getValue(), output_file.string());
170 }
171 std::set<std::string> variable_output_names;
172 std::unique_ptr<MeshLib::IO::XdmfHdfWriter> mesh_xdmf_hdf_writer;
173 // read first file in the time series; it is determining variables.
174 {
175 auto [time, filename] = timeseries[0];
176 DBUG("{} - {}", time, filename);
177
178 main_mesh.reset(MeshLib::IO::readMeshFromFile(
179 BaseLib::joinPaths(pvd_file_dir, filename)));
180 if (main_mesh == nullptr)
181 {
182 OGS_FATAL("Could not read mesh from '{:s}'.",
183 BaseLib::joinPaths(pvd_file_dir, filename));
184 }
185
186 for (auto const& p : main_mesh->getProperties())
187 {
188 variable_output_names.insert(std::string(p.first));
189 }
190 mesh_xdmf_hdf_writer = std::make_unique<MeshLib::IO::XdmfHdfWriter>(
191 std::vector{std::cref(*main_mesh)}, output_file_path,
192 0 /*timestep*/, time, variable_output_names,
193 true /*output_file.compression*/, 1 /*output_file.n_files*/,
194 1048576 /*chunk_size_bytes*/);
195 }
196
197 for (std::size_t timestep = 1; timestep < timeseries.size(); ++timestep)
198 {
199 auto [time, filename] = timeseries[timestep];
200 DBUG("{} - {}", time, filename);
201
202 std::unique_ptr<MeshLib::Mesh> mesh{MeshLib::IO::readMeshFromFile(
203 BaseLib::joinPaths(pvd_file_dir, filename))};
204 if (mesh == nullptr)
205 {
206 OGS_FATAL("Could not read mesh from '{:s}'.",
207 BaseLib::joinPaths(pvd_file_dir, filename));
208 }
209
211 *mesh, *main_mesh,
212 fmt::format("Error in comparison of mesh from file '{:s}' to the "
213 "main mesh:\n",
214 BaseLib::joinPaths(pvd_file_dir, filename)));
215
216 // We have to copy the values because the xdmf writer remembers the data
217 // pointers. Therefore replacing the properties will not work.
218 for (auto& [name, pv] : main_mesh->getProperties())
219 {
220 if (copyPropertyVector<double>(mesh->getProperties(), pv) ||
221 copyPropertyVector<float>(mesh->getProperties(), pv) ||
222 copyPropertyVector<int>(mesh->getProperties(), pv) ||
223 copyPropertyVector<long>(mesh->getProperties(), pv) ||
224 copyPropertyVector<unsigned>(mesh->getProperties(), pv) ||
225 copyPropertyVector<unsigned long>(mesh->getProperties(), pv) ||
226 copyPropertyVector<std::size_t>(mesh->getProperties(), pv) ||
227 copyPropertyVector<char>(mesh->getProperties(), pv) ||
228 copyPropertyVector<unsigned char>(mesh->getProperties(), pv))
229 {
230 continue;
231 }
232 OGS_FATAL(
233 "Could not copy property vector '{:s}' from '{:s}' mesh to the "
234 "main_mesh.",
235 name, BaseLib::joinPaths(pvd_file_dir, filename));
236 }
237
238 mesh_xdmf_hdf_writer->writeStep(time);
239 }
240#ifdef USE_PETSC
241 MPI_Finalize();
242#endif
243 return EXIT_SUCCESS;
244}
Definition of the Element class.
#define OGS_FATAL(...)
Definition Error.h:26
Filename manipulation routines.
Git information.
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:30
Definition of the MemWatch class.
Definition of the Mesh class.
int main(int argc, char *argv[])
Definition PVD2XDMF.cpp:109
void testIfMeshesAreEqual(MeshLib::Mesh const &mesh, MeshLib::Mesh const &main_mesh, std::string error_message)
Definition PVD2XDMF.cpp:80
std::vector< std::pair< double, std::string > > readPvd(std::string const &pvd_filename)
Definition PVD2XDMF.cpp:33
bool copyPropertyVector(MeshLib::Properties const &properties, MeshLib::PropertyVectorBase *destination_pv)
Definition PVD2XDMF.cpp:59
Definition of the RunTime class.
Definition of string helper functions.
XdmfWriter which create contiguous data for geometry and topology and writes this and all attributes ...
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition Mesh.h:88
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition Mesh.h:100
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:97
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
Definition Properties.h:36
PropertyVector< T > const * getPropertyVector(std::string_view name) const
MeshItemType getMeshItemType() const
int getNumberOfGlobalComponents() const
std::string const & getPropertyName() const
void setConsoleLogLevel(std::string const &level_string)
Definition Logging.cpp:37
std::string extractPath(std::string const &pathname)
std::string extractBaseNameWithoutExtension(std::string const &pathname)
std::string joinPaths(std::string const &pathA, std::string const &pathB)
GITINFOLIB_EXPORT const std::string ogs_version
MeshLib::Mesh * readMeshFromFile(const std::string &file_name, bool const compute_element_neighbors)
Definition of readMeshFromFile function.