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