GCC Code Coverage Report


Directory: gridformat/
File: gridformat/gridformat.hpp
Date: 2025-03-26 17:08:15
Exec Total Coverage
Lines: 191 230 83.0%
Functions: 206 282 73.0%
Branches: 136 347 39.2%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2022-2023 Dennis Glรคser <dennis.glaeser@iws.uni-stuttgart.de>
2 // SPDX-License-Identifier: MIT
3 /*!
4 * \file
5 * \ingroup API
6 * \brief This file is the entrypoint to the high-level API exposing all provided
7 * readers/writers through a unified interface.
8 *
9 * The individual writer can also be used directly, for instance, if one
10 * wants to minimize compile times. All available writers can be seen in
11 * the lists of includes of this file. For instructions on how to use the
12 * API, have a look at the readme or the provided examples.
13 */
14 #ifndef GRIDFORMAT_GRIDFORMAT_HPP_
15 #define GRIDFORMAT_GRIDFORMAT_HPP_
16
17 #include <memory>
18 #include <optional>
19 #include <type_traits>
20
21 #include <gridformat/reader.hpp>
22 #include <gridformat/writer.hpp>
23
24 #include <gridformat/grid/converter.hpp>
25 #include <gridformat/grid/image_grid.hpp>
26
27 #include <gridformat/common/exceptions.hpp>
28 #include <gridformat/parallel/communication.hpp>
29
30 #include <gridformat/vtk/vti_reader.hpp>
31 #include <gridformat/vtk/vti_writer.hpp>
32 #include <gridformat/vtk/pvti_writer.hpp>
33
34 #include <gridformat/vtk/vtr_reader.hpp>
35 #include <gridformat/vtk/vtr_writer.hpp>
36 #include <gridformat/vtk/pvtr_writer.hpp>
37
38 #include <gridformat/vtk/vts_reader.hpp>
39 #include <gridformat/vtk/vts_writer.hpp>
40 #include <gridformat/vtk/pvts_writer.hpp>
41
42 #include <gridformat/vtk/vtp_reader.hpp>
43 #include <gridformat/vtk/vtp_writer.hpp>
44 #include <gridformat/vtk/pvtp_writer.hpp>
45
46 #include <gridformat/vtk/vtu_writer.hpp>
47 #include <gridformat/vtk/vtu_reader.hpp>
48 #include <gridformat/vtk/pvtu_writer.hpp>
49
50 #include <gridformat/vtk/pvd_reader.hpp>
51 #include <gridformat/vtk/pvd_writer.hpp>
52
53 #include <gridformat/vtk/xml_time_series_writer.hpp>
54
55 #ifndef DOXYGEN
56 namespace GridFormat::APIDetail {
57
58 template<typename... T>
59 inline constexpr bool always_false = false;
60
61 template<typename... T>
62 struct DefaultAsserter {
63 static constexpr bool do_assert() {
64 static_assert(
65 always_false<T...>,
66 "Requested reader/writer is unavailable due to missing dependency"
67 );
68 return false;
69 }
70 };
71
72 // Derive from GridWriter to make this a "valid" writer (and abuse some valid grid impl for that)
73 template<template<typename...> typename Asserter = DefaultAsserter>
74 class UnavailableWriter : public GridWriter<ImageGrid<2, double>> {
75 public:
76 template<typename... Args>
77 UnavailableWriter(Args&&...) { static_assert(Asserter<Args...>::do_assert()); }
78 private:
79 void _throw() const { throw GridFormat::NotImplemented("Writer unavailable"); }
80 void _write(std::ostream&) const { _throw(); }
81 };
82
83 // Derive from TimeSeriesGridWriter to make this a "valid" writer (and abuse some valid grid impl for that)
84 template<template<typename...> typename Asserter = DefaultAsserter>
85 class UnavailableTimeSeriesWriter : public TimeSeriesGridWriter<ImageGrid<2, double>> {
86 public:
87 template<typename... Args>
88 UnavailableTimeSeriesWriter(Args&&...) { static_assert(Asserter<Args...>::do_assert()); }
89 private:
90 void _throw() const { throw GridFormat::NotImplemented("Writer unavailable"); }
91 std::string _write(double) override { _throw(); return ""; }
92 };
93
94 // Derive from Reader to make this a "valid" reader
95 template<template<typename...> typename Asserter = DefaultAsserter>
96 class UnavailableReader : public GridReader {
97 public:
98 template<typename... Args>
99 UnavailableReader(Args&&...) { static_assert(Asserter<Args...>::do_assert()); }
100 private:
101 void _throw() const { throw GridFormat::NotImplemented("Reader unavailable"); }
102 std::string _name() const override { _throw(); return ""; }
103 void _open(const std::string&, typename GridReader::FieldNames&) override { _throw(); }
104 void _close() override { _throw(); }
105 std::size_t _number_of_cells() const override { _throw(); return 0; }
106 std::size_t _number_of_points() const override { _throw(); return 0; }
107 FieldPtr _cell_field(std::string_view) const override { _throw(); return nullptr; }
108 FieldPtr _point_field(std::string_view) const override { _throw(); return nullptr; }
109 FieldPtr _meta_data_field(std::string_view) const override { _throw(); return nullptr; }
110 bool _is_sequence() const override { _throw(); return false; }
111 };
112
113 } // namespace GridFormat::APIDetail
114
115 #if GRIDFORMAT_HAVE_HIGH_FIVE
116 #include <gridformat/vtk/hdf_writer.hpp>
117 #include <gridformat/vtk/hdf_reader.hpp>
118 inline constexpr bool _gfmt_api_have_high_five = true;
119 #else
120 #include <gridformat/vtk/hdf_common.hpp>
121 inline constexpr bool _gfmt_api_have_high_five = false;
122 namespace GridFormat {
123
124 template<typename... T>
125 struct VTKHDFAsserter {
126 static constexpr bool do_assert() {
127 static_assert(
128 APIDetail::always_false<T...>,
129 "VTKHDF reader/writers require HighFive"
130 );
131 return false;
132 }
133 };
134
135 using VTKHDFWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
136 using VTKHDFTimeSeriesWriter = APIDetail::UnavailableTimeSeriesWriter<VTKHDFAsserter>;
137 using VTKHDFImageGridWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
138 using VTKHDFUnstructuredGridWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
139 using VTKHDFImageGridTimeSeriesWriter = APIDetail::UnavailableTimeSeriesWriter<VTKHDFAsserter>;
140 using VTKHDFUnstructuredTimeSeriesWriter = APIDetail::UnavailableTimeSeriesWriter<VTKHDFAsserter>;
141
142 using VTKHDFImageGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
143 template<typename T = void> using VTKHDFUnstructuredGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
144 template<typename T = void> using VTKHDFReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
145
146 } // namespace GridFormat
147 #endif // GRIDFORMAT_HAVE_HIGH_FIVE
148 #endif // DOXYGEN
149
150
151 namespace GridFormat {
152
153 //! Null communicator that can be used e.g. to read parallel file formats sequentially
154 inline constexpr GridFormat::NullCommunicator null_communicator;
155
156 //! Factory class to create a writer for the given file format
157 template<typename FileFormat> struct WriterFactory;
158
159 //! Factory class to create a reader for the given file format
160 template<typename FileFormat> struct ReaderFactory;
161
162 namespace FileFormat {
163
164 //! Base class for formats taking options
165 template<typename Format, typename Opts>
166 struct FormatWithOptions {
167 using Options = Opts;
168 std::optional<Options> opts = {};
169
170 //! Construct a new instance of this format with the given options
171 31 constexpr Format operator()(Options _opts) const {
172 31 return with(std::move(_opts));
173 }
174
175 //! Construct a new instance of this format with the given options
176 33 constexpr Format with(Options _opts) const {
177 33 Format f;
178 33 f.opts = std::move(_opts);
179 33 return f;
180 }
181 };
182
183 //! Base class for VTK-XML formats
184 template<typename VTKFormat>
185 struct VTKXMLFormatBase : public FormatWithOptions<VTKFormat, VTK::XMLOptions> {
186 //! Construct a new instance of this format with modified encoding option
187 constexpr auto with_encoding(VTK::XML::Encoder e) const {
188 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
189 Variant::unwrap_to(cur_opts.encoder, e);
190 return this->with(std::move(cur_opts));
191 }
192
193 //! Construct a new instance of this format with modified data format option
194 constexpr auto with_data_format(VTK::XML::DataFormat f) const {
195 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
196 Variant::unwrap_to(cur_opts.data_format, f);
197 return this->with(std::move(cur_opts));
198 }
199
200 //! Construct a new instance of this format with modified compression option
201 constexpr auto with_compression(VTK::XML::Compressor c) const {
202 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
203 Variant::unwrap_to(cur_opts.compressor, c);
204 return this->with(std::move(cur_opts));
205 }
206 };
207
208
209 /*!
210 * \ingroup API
211 * \ingroup FileFormats
212 * \brief Selector for an unspecified file format. When using this format, GridFormat will
213 * automatically select a format or deduce from a file being read, for instance.
214 */
215 struct Any {};
216
217
218 /*!
219 * \ingroup API
220 * \ingroup FileFormats
221 * \brief Time series variant of the Any format selector
222 */
223 struct AnyTimeSeries {};
224
225
226 /*!
227 * \ingroup API
228 * \ingroup FileFormats
229 * \brief Selector for the .vti/.pvti image grid file format to be passed to the Writer.
230 * \details For more details on the file format, see
231 * <a href="https://examples.vtk.org/site/VTKFileFormats/#imagedata">here</a>
232 * or <a href="https://examples.vtk.org/site/VTKFileFormats/#pimagedata">here</a>
233 * for the parallel variant.
234 * \note The parallel variant (.pvti) is only available if MPI is found on the system.
235 */
236 struct VTI : VTKXMLFormatBase<VTI> {};
237
238 /*!
239 * \ingroup API
240 * \ingroup FileFormats
241 * \brief Selector for the .vtr/.pvtr rectilinear grid file format to be passed to the Writer.
242 * \details For more details on the file format, see
243 * <a href="https://examples.vtk.org/site/VTKFileFormats/#rectilineargrid">here</a> or
244 * <a href="https://examples.vtk.org/site/VTKFileFormats/#prectilineargrid">here</a>
245 * for the parallel variant.
246 * \note The parallel variant (.pvtr) is only available if MPI is found on the system.
247 */
248 struct VTR : VTKXMLFormatBase<VTR> {};
249
250 /*!
251 * \ingroup API
252 * \ingroup FileFormats
253 * \brief Selector for the .vts/.pvts structured grid file format to be passed to the Writer.
254 * \details For more details on the file format, see
255 * <a href="https://examples.vtk.org/site/VTKFileFormats/#structuredgrid">here</a> or
256 * <a href="https://examples.vtk.org/site/VTKFileFormats/#pstructuredgrid">here</a>
257 * for the parallel variant.
258 * \note The parallel variant (.pvts) is only available if MPI is found on the system.
259 */
260 struct VTS : VTKXMLFormatBase<VTS> {};
261
262 /*!
263 * \ingroup API
264 * \ingroup FileFormats
265 * \brief Selector for the .vtp/.pvtp file format for two-dimensional unstructured grids.
266 * \details For more details on the file format, see
267 * <a href="https://examples.vtk.org/site/VTKFileFormats/#polydata">here</a> or
268 * <a href="https://examples.vtk.org/site/VTKFileFormats/#ppolydata">here</a>
269 * for the parallel variant.
270 * \note The parallel variant (.pvtp) is only available if MPI is found on the system.
271 */
272 struct VTP : VTKXMLFormatBase<VTP> {};
273
274 /*!
275 * \ingroup API
276 * \ingroup FileFormats
277 * \brief Selector for the .vtu/.pvtu file format for general unstructured grids.
278 * \details For more details on the file format, see
279 * <a href="https://examples.vtk.org/site/VTKFileFormats/#unstructuredgrid">here</a> or
280 * <a href="https://examples.vtk.org/site/VTKFileFormats/#punstructuredgrid">here</a>
281 * for the parallel variant.
282 * \note The parallel variant (.pvtu) is only available if MPI is found on the system.
283 */
284 struct VTU : VTKXMLFormatBase<VTU> {};
285
286 /*!
287 * \ingroup API
288 * \ingroup FileFormats
289 * \brief Selector for a time series of any VTK-XML format.
290 */
291 template<typename VTX>
292 struct VTKXMLTimeSeries : VTKXMLFormatBase<VTKXMLTimeSeries<VTX>> {};
293
294
295 /*!
296 * \ingroup API
297 * \ingroup FileFormats
298 * \brief Selector for the vtk-hdf file format for image grids.
299 * For more information, see
300 * <a href="https://examples.vtk.org/site/VTKFileFormats/#image-data">here</a>.
301 * \note This file format is only available if HighFive is found on the system. If libhdf5 is found on the system,
302 * Highfive is automatically included when pulling the repository recursively, or, when using cmake's
303 * FetchContent mechanism.
304 * \note A bug in VTK/ParaView related to reading cell data arrays has been fixed in
305 * <a href="https://gitlab.kitware.com/vtk/vtk/-/merge_requests/10147">VTK merge request 10147</a>.
306 * The fix is included in VTK>9.2.6 and ParaView>5.11.0.
307 */
308 struct VTKHDFImage {};
309
310 /*!
311 * \ingroup API
312 * \ingroup FileFormats
313 * \brief Transient variant of the vtk-hdf image data format
314 */
315 struct VTKHDFImageTransient
316 : FormatWithOptions<VTKHDFImageTransient, VTK::HDFTransientOptions> {};
317
318 /*!
319 * \ingroup API
320 * \ingroup FileFormats
321 * \brief Selector for the vtk-hdf file format for unstructured grids.
322 * For more information, see
323 * <a href="https://examples.vtk.org/site/VTKFileFormats/#unstructured-grid">here</a>.
324 * \note This file format is only available if HighFive is found on the system. If libhdf5 is found on the system,
325 * Highfive is automatically included when pulling the repository recursively, or, when using cmake's
326 * FetchContent mechanism.
327 */
328 struct VTKHDFUnstructured {};
329
330 /*!
331 * \ingroup API
332 * \ingroup FileFormats
333 * \brief Transient variant of the vtk-hdf unstructured grid format
334 */
335 struct VTKHDFUnstructuredTransient
336 : FormatWithOptions<VTKHDFUnstructuredTransient, VTK::HDFTransientOptions> {};
337
338 /*!
339 * \ingroup API
340 * \ingroup FileFormats
341 * \brief Selector for the transient vtk-hdf file format with automatic deduction of the flavour.
342 * If the grid for which a writer is constructed is an image grid, it selects the image-grid flavour, otherwise
343 * it selects the flavour for unstructured grids (which requires the respective traits to be specialized).
344 * \note This file format is only available if HighFive is found on the system. If libhdf5 is found on the system,
345 * Highfive is automatically included when pulling the repository recursively, or, when using cmake's
346 * FetchContent mechanism.
347 */
348 struct VTKHDFTransient : FormatWithOptions<VTKHDFTransient, VTK::HDFTransientOptions> {
349 template<typename Grid>
350 6 constexpr auto from(const Grid&) const {
351 // TODO: Once the VTKHDFImageGridReader is stable, use image format for image grids
352 6 return VTKHDFUnstructuredTransient{this->opts};
353 }
354 };
355
356 /*!
357 * \ingroup API
358 * \ingroup FileFormats
359 * \brief Selector for the vtk-hdf file format with automatic deduction of the flavour.
360 * If the grid for which a writer is constructed is an image grid, it selects the image-grid flavour, otherwise
361 * it selects the flavour for unstructured grids (which requires the respective traits to be specialized).
362 * \note This file format is only available if HighFive is found on the system. If libhdf5 is found on the system,
363 * Highfive is automatically included when pulling the repository recursively, or, when using cmake's
364 * FetchContent mechanism.
365 */
366 struct VTKHDF {
367 template<typename Grid>
368 6 static constexpr auto from(const Grid&) {
369 // TODO: Once the VTKHDFImageGridReader is stable, use image format for image grids
370 6 return VTKHDFUnstructured{};
371 }
372
373 //! Return the transient variant of this format with the given options
374 constexpr VTKHDFTransient with(VTK::HDFTransientOptions opts) {
375 return {std::move(opts)};
376 }
377 };
378
379 #ifndef DOXYGEN
380 namespace Detail {
381
382 template<typename F> struct IsVTKXMLFormat : public std::false_type {};
383 template<> struct IsVTKXMLFormat<VTI> : public std::true_type {};
384 template<> struct IsVTKXMLFormat<VTR> : public std::true_type {};
385 template<> struct IsVTKXMLFormat<VTS> : public std::true_type {};
386 template<> struct IsVTKXMLFormat<VTP> : public std::true_type {};
387 template<> struct IsVTKXMLFormat<VTU> : public std::true_type {};
388
389 } // namespace Detail
390 #endif // DOXYGEN
391
392 /*!
393 * \ingroup API
394 * \ingroup FileFormats
395 * \brief Selector for the .pvd file format for a time series.
396 * For more information, see <a href="https://www.paraview.org/Wiki/ParaView/Data_formats#PVD_File_Format">here</a>.
397 * \tparam PieceFormat The underlying file format used for each time step.
398 * \note ParaView only supports reading .pvd series if the file format for pieces is one of the VTK-XML formats.
399 */
400 template<typename PieceFormat = Any>
401 struct PVD {
402 PieceFormat piece_format;
403 };
404
405 /*!
406 * \ingroup API
407 * \ingroup FileFormats
408 * \brief Closure for selecting the .pvd file format. Takes a VTK-XML format and returns an instance of PVD.
409 */
410 struct PVDClosure {
411 template<typename Format>
412 39 constexpr auto operator()(const Format& f) const {
413 static_assert(
414 Detail::IsVTKXMLFormat<Format>::value,
415 "The PVD format is only available with vtk-xml file formats"
416 );
417 39 return PVD<Format>{f};
418 }
419 };
420
421 /*!
422 * \ingroup API
423 * \ingroup FileFormats
424 * \brief Closure for time series format selection. Takes a sequential format and returns a time series variant.
425 */
426 struct TimeSeriesClosure {
427 template<typename Format>
428 42 constexpr auto operator()(const Format& f) const {
429 if constexpr (Detail::IsVTKXMLFormat<Format>::value)
430 18 return VTKXMLTimeSeries<Format>{f.opts};
431 else if constexpr (std::same_as<VTKHDFImage, Format>)
432 6 return VTKHDFImageTransient{};
433 else if constexpr (std::same_as<VTKHDFUnstructured, Format>)
434 6 return VTKHDFUnstructuredTransient{};
435 else if constexpr (std::same_as<VTKHDF, Format>)
436 6 return VTKHDFTransient{};
437 else if constexpr (std::same_as<Any, Format>)
438 6 return AnyTimeSeries{};
439 else {
440 static_assert(
441 APIDetail::always_false<Format>,
442 "Cannot create a time series variant for the given format. This means the format does not "
443 "define a variant for time series, or, the selected format is already time series format."
444 );
445 }
446 }
447 };
448
449 } // namespace FileFormat
450
451
452 #ifndef DOXYGEN
453 namespace APIDetail {
454
455 // Meta-Reader for file formats that have different format flavours in parallel/sequential
456 template<typename SeqReader, typename ParReader>
457 class SequentialOrParallelReader : public GridReader {
458 template<typename R> using CommunicatorAccess = Traits::CommunicatorAccess<R>;
459 template<typename R> using Communicator = decltype(CommunicatorAccess<R>::get(std::declval<const R&>()));
460 using ParCommunicator = Communicator<ParReader>;
461 using SeqCommunicator = Communicator<SeqReader>;
462
463 public:
464 516 SequentialOrParallelReader(SeqReader&& seq, ParReader&& par)
465 516 : _seq_reader{std::move(seq)}
466 1032 , _par_reader{std::move(par)}
467 516 {}
468
469 ParCommunicator communicator() const {
470 const bool is_parallel = !_use_sequential.value_or(true);
471 if (!is_parallel) {
472 if constexpr (!std::is_same_v<ParCommunicator, SeqCommunicator>)
473 throw InvalidState("Cannot access communicator for sequential variant of the reader");
474 else
475 return CommunicatorAccess<SeqReader>::get(_seq_reader);
476 }
477 return CommunicatorAccess<ParReader>::get(_par_reader);
478 }
479
480 private:
481 SeqReader _seq_reader;
482 ParReader _par_reader;
483 std::optional<bool> _use_sequential = {};
484
485 84 std::string _name() const override {
486
4/12
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 42 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 42 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
84 return _is_set() ? _access().name() : std::string{"undefined"};
487 }
488
489 516 void _open(const std::string& filename, typename GridReader::FieldNames& names) override {
490
1/2
✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
516 _close();
491 516 std::string seq_error;
492 try {
493
2/2
✓ Branch 1 taken 256 times.
✓ Branch 2 taken 8 times.
516 _seq_reader.open(filename);
494 508 _use_sequential = true;
495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 } catch (const std::exception& e) {
496
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 seq_error = e.what();
497 8 _use_sequential.reset();
498
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 _seq_reader.close();
499 try {
500
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 _par_reader.open(filename);
501 8 _use_sequential = false;
502 } catch (const std::exception& par_err) {
503 _use_sequential.reset();
504 _par_reader.close();
505 throw IOError(
506 "Could not read '" + filename + "' neither as sequential nor parallel format.\n"
507 "Error with sequential format (" + _seq_reader.name() + "): " + seq_error + "\n"
508 "Error with parallel format (" + _par_reader.name() + "): " + par_err.what()
509 );
510 }
511 }
512
513
2/4
✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 264 times.
✗ Branch 5 not taken.
516 ReaderDetail::copy_field_names(_access(), names);
514 516 }
515
516 1032 void _close() override {
517
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 528 times.
1032 if (_is_set())
518 _access().close();
519 1032 }
520
521 432 std::size_t _number_of_cells() const override { return _access().number_of_cells(); }
522 432 std::size_t _number_of_points() const override { return _access().number_of_points(); }
523 std::size_t _number_of_pieces() const override { return _access().number_of_pieces(); }
524
525 420 FieldPtr _cell_field(std::string_view n) const override { return _access().cell_field(n); }
526 432 FieldPtr _point_field(std::string_view n) const override { return _access().point_field(n); }
527 FieldPtr _meta_data_field(std::string_view n) const override { return _access().meta_data_field(n); }
528
529 420 FieldPtr _points() const override { return _access().points(); }
530 420 void _visit_cells(const typename GridReader::CellVisitor& v) const override { _access().visit_cells(v); }
531 std::vector<double> _ordinates(unsigned int i) const override { return _access().ordinates(i); }
532
533 typename GridReader::PieceLocation _location() const override { return _access().location(); }
534 typename GridReader::Vector _spacing() const override { return _access().spacing(); }
535 typename GridReader::Vector _origin() const override { return _access().origin(); }
536 typename GridReader::Vector _basis_vector(unsigned int i) const override { return _access().basis_vector(i); }
537
538 420 bool _is_sequence() const override { return _access().is_sequence(); }
539 std::size_t _number_of_steps() const override { return _access().number_of_steps(); }
540 double _time_at_step(std::size_t i) const override { return _access().time_at_step(i); }
541 void _set_step(std::size_t i, typename GridReader::FieldNames& names) override {
542 _access().set_step(i);
543 names.clear();
544 ReaderDetail::copy_field_names(_access(), names);
545 }
546
547 4692 bool _is_set() const { return _use_sequential.has_value(); }
548 3576 void _throw_if_not_set() const {
549
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1812 times.
3576 if (!_is_set())
550 throw IOError("No data has been read");
551 3576 }
552
553 516 GridReader& _access() {
554 516 _throw_if_not_set();
555 516 return _use_sequential.value()
556 ? static_cast<GridReader&>(_seq_reader)
557
2/2
✓ Branch 0 taken 256 times.
✓ Branch 1 taken 8 times.
516 : static_cast<GridReader&>(_par_reader);
558 }
559
560 3060 const GridReader& _access() const {
561 3060 _throw_if_not_set();
562 3060 return _use_sequential.value()
563 ? static_cast<const GridReader&>(_seq_reader)
564
2/2
✓ Branch 0 taken 1524 times.
✓ Branch 1 taken 24 times.
3060 : static_cast<const GridReader&>(_par_reader);
565 }
566 };
567
568 template<typename S, typename P>
569 SequentialOrParallelReader(S&&, P&&) -> SequentialOrParallelReader<std::remove_cvref_t<S>, std::remove_cvref_t<P>>;
570
571 template<typename Format, typename SeqReader, typename ParReader>
572 struct SequentialOrParallelReaderFactory {
573 template<Concepts::Communicator C = NullCommunicator>
574 516 static auto make(const Format&, const C& comm = null_communicator) {
575
5/8
✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 256 times.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 256 times.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
516 return SequentialOrParallelReader{SeqReader{}, ParReader{comm}};
576 }
577 };
578
579 template<typename Format, typename SequentialReader, typename ParallelReader>
580 struct DefaultReaderFactory {
581 static auto make(const Format&) { return SequentialReader{}; }
582 static auto make(const Format&, const Concepts::Communicator auto& comm) { return ParallelReader{comm}; }
583 };
584
585 // Specialization for cases where the parallel reader is templated on the communicator
586 template<typename F, typename S, template<typename> typename P>
587 struct DefaultTemplatedReaderFactory {
588 29 static auto make(const F&) { return S{}; }
589 template<Concepts::Communicator Communicator>
590 82 static auto make(const F&, const Communicator& comm) { return P<Communicator>{comm}; }
591 };
592
593 } // namespace APIDetail
594 #endif // DOXYGEN
595
596 // Traits specializations for SequentialOrParallelReader
597 namespace Traits {
598
599 template<typename S, typename P>
600 struct WritesConnectivity<APIDetail::SequentialOrParallelReader<S, P>>
601 : public std::bool_constant<WritesConnectivity<S>::value || WritesConnectivity<P>::value>
602 {};
603
604 } // namespace Traits
605
606 //! Specialization of the WriterFactory for the .vti format
607 template<> struct WriterFactory<FileFormat::VTI> {
608 9 static auto make(const FileFormat::VTI& format,
609 const Concepts::ImageGrid auto& grid) {
610
1/2
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
9 return VTIWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
611 }
612
613 14 static auto make(const FileFormat::VTI& format,
614 const Concepts::ImageGrid auto& grid,
615 const Concepts::Communicator auto& comm) {
616
1/2
✓ Branch 8 taken 14 times.
✗ Branch 9 not taken.
14 return PVTIWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
617 }
618 };
619
620 //! Specialization of the ReaderFactory for the .vti format
621 template<>
622 struct ReaderFactory<FileFormat::VTI> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTI, VTIReader, PVTIReader> {};
623
624 //! Specialization of the WriterFactory for the .vtr format
625 template<> struct WriterFactory<FileFormat::VTR> {
626 4 static auto make(const FileFormat::VTR& format,
627 const Concepts::RectilinearGrid auto& grid) {
628
1/2
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
4 return VTRWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
629 }
630 8 static auto make(const FileFormat::VTR& format,
631 const Concepts::RectilinearGrid auto& grid,
632 const Concepts::Communicator auto& comm) {
633
1/2
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
8 return PVTRWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
634 }
635 };
636
637 //! Specialization of the ReaderFactory for the .vtr format
638 template<>
639 struct ReaderFactory<FileFormat::VTR> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTR, VTRReader, PVTRReader> {};
640
641 //! Specialization of the WriterFactory for the .vts format
642 template<> struct WriterFactory<FileFormat::VTS> {
643 3 static auto make(const FileFormat::VTS& format,
644 const Concepts::StructuredGrid auto& grid) {
645
1/2
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
3 return VTSWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
646 }
647 6 static auto make(const FileFormat::VTS& format,
648 const Concepts::StructuredGrid auto& grid,
649 const Concepts::Communicator auto& comm) {
650
1/2
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
6 return PVTSWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
651 }
652 };
653
654 //! Specialization of the ReaderFactory for the .vts format
655 template<>
656 struct ReaderFactory<FileFormat::VTS> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTS, VTSReader, PVTSReader> {};
657
658 //! Specialization of the WriterFactory for the .vtp format
659 template<> struct WriterFactory<FileFormat::VTP> {
660 3 static auto make(const FileFormat::VTP& format,
661 const Concepts::UnstructuredGrid auto& grid) {
662
1/2
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
3 return VTPWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
663 }
664 8 static auto make(const FileFormat::VTP& format,
665 const Concepts::UnstructuredGrid auto& grid,
666 const Concepts::Communicator auto& comm) {
667
1/2
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
8 return PVTPWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
668 }
669 };
670
671 //! Specialization of the ReaderFactory for the .vtp format
672 template<>
673 struct ReaderFactory<FileFormat::VTP> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTP, VTPReader, PVTPReader> {};
674
675 //! Specialization of the WriterFactory for the .vtu format
676 template<> struct WriterFactory<FileFormat::VTU> {
677 26 static auto make(const FileFormat::VTU& format,
678 const Concepts::UnstructuredGrid auto& grid) {
679
1/2
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
26 return VTUWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
680 }
681 44 static auto make(const FileFormat::VTU& format,
682 const Concepts::UnstructuredGrid auto& grid,
683 const Concepts::Communicator auto& comm) {
684
1/2
✓ Branch 8 taken 26 times.
✗ Branch 9 not taken.
44 return PVTUWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
685 }
686 };
687
688 //! Specialization of the ReaderFactory for the .vtu format
689 template<>
690 struct ReaderFactory<FileFormat::VTU> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTU, VTUReader, PVTUReader> {};
691
692 //! Specialization of the WriterFactory for vtk-xml time series.
693 template<typename F> struct WriterFactory<FileFormat::VTKXMLTimeSeries<F>> {
694 3 static auto make(const FileFormat::VTKXMLTimeSeries<F>& format,
695 const Concepts::UnstructuredGrid auto& grid,
696 const std::string& base_filename) {
697 return VTKXMLTimeSeriesWriter{
698
1/2
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
6 WriterFactory<F>::make(F{format.opts.value_or(VTK::XMLOptions{})}, grid),
699 base_filename
700
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 };
701 }
702 6 static auto make(const FileFormat::VTKXMLTimeSeries<F>& format,
703 const Concepts::UnstructuredGrid auto& grid,
704 const Concepts::Communicator auto& comm,
705 const std::string& base_filename) {
706 return VTKXMLTimeSeriesWriter{
707
1/2
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
12 WriterFactory<F>::make(F{format.opts.value_or(VTK::XMLOptions{})}, grid, comm),
708 base_filename
709
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
12 };
710 }
711 };
712
713 //! Specialization of the WriterFactory for the vtk-hdf image grid format
714 template<> struct WriterFactory<FileFormat::VTKHDFImage> {
715 1 static auto make(const FileFormat::VTKHDFImage&,
716 const Concepts::ImageGrid auto& grid) {
717
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return VTKHDFImageGridWriter{grid};
718 }
719 2 static auto make(const FileFormat::VTKHDFImage&,
720 const Concepts::ImageGrid auto& grid,
721 const Concepts::Communicator auto& comm) {
722
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 return VTKHDFImageGridWriter{grid, comm};
723 }
724 };
725
726 //! Specialization of the ReaderFactory for the vtk-hdf image grid format
727 template<>
728 struct ReaderFactory<FileFormat::VTKHDFImage>
729 : APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImage,
730 VTKHDFImageGridReader,
731 VTKHDFImageGridReader>
732 {};
733
734 //! Specialization of the WriterFactory for the transient vtk-hdf image grid format
735 template<> struct WriterFactory<FileFormat::VTKHDFImageTransient> {
736 2 static auto make(const FileFormat::VTKHDFImageTransient& f,
737 const Concepts::ImageGrid auto& grid,
738 const std::string& base_filename) {
739
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (f.opts.has_value())
740 return VTKHDFImageGridTimeSeriesWriter{grid, base_filename, f.opts.value()};
741
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 return VTKHDFImageGridTimeSeriesWriter{grid, base_filename};
742 }
743 4 static auto make(const FileFormat::VTKHDFImageTransient& f,
744 const Concepts::ImageGrid auto& grid,
745 const Concepts::Communicator auto& comm,
746 const std::string& base_filename) {
747
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (f.opts.has_value())
748 return VTKHDFImageGridTimeSeriesWriter{grid, comm, base_filename, f.opts.value()};
749
2/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
4 return VTKHDFImageGridTimeSeriesWriter{grid, comm, base_filename};
750 }
751 };
752
753 //! Specialization of the ReaderFactory for the transient vtk-hdf image grid format
754 template<>
755 struct ReaderFactory<FileFormat::VTKHDFImageTransient>
756 : APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImageTransient,
757 VTKHDFImageGridReader,
758 VTKHDFImageGridReader>
759 {};
760
761 //! Specialization of the WriterFactory for the vtk-hdf unstructured grid format
762 template<> struct WriterFactory<FileFormat::VTKHDFUnstructured> {
763 5 static auto make(const FileFormat::VTKHDFUnstructured&,
764 const Concepts::UnstructuredGrid auto& grid) {
765
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
5 return VTKHDFUnstructuredGridWriter{grid};
766 }
767 12 static auto make(const FileFormat::VTKHDFUnstructured&,
768 const Concepts::UnstructuredGrid auto& grid,
769 const Concepts::Communicator auto& comm) {
770
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
12 return VTKHDFUnstructuredGridWriter{grid, comm};
771 }
772 };
773
774 //! Specialization of the ReaderFactory for the vtk-hdf unstructured grid format
775 template<>
776 struct ReaderFactory<FileFormat::VTKHDFUnstructured>
777 : APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructured,
778 VTKHDFUnstructuredGridReader<>,
779 VTKHDFUnstructuredGridReader>
780 {};
781
782 //! Specialization of the WriterFactory for the transient vtk-hdf unstructured grid format
783 template<> struct WriterFactory<FileFormat::VTKHDFUnstructuredTransient> {
784 4 static auto make(const FileFormat::VTKHDFUnstructuredTransient& f,
785 const Concepts::ImageGrid auto& grid,
786 const std::string& base_filename) {
787
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (f.opts.has_value())
788 return VTKHDFUnstructuredTimeSeriesWriter{grid, base_filename, f.opts.value()};
789
2/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
4 return VTKHDFUnstructuredTimeSeriesWriter{grid, base_filename};
790 }
791 8 static auto make(const FileFormat::VTKHDFUnstructuredTransient& f,
792 const Concepts::ImageGrid auto& grid,
793 const Concepts::Communicator auto& comm,
794 const std::string& base_filename) {
795
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if (f.opts.has_value())
796 return VTKHDFUnstructuredTimeSeriesWriter{grid, comm, base_filename, f.opts.value()};
797
2/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
8 return VTKHDFUnstructuredTimeSeriesWriter{grid, comm, base_filename};
798 }
799 };
800
801 //! Specialization of the ReaderFactory for the vtk-hdf unstructured grid format
802 template<>
803 struct ReaderFactory<FileFormat::VTKHDFUnstructuredTransient>
804 : APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructuredTransient,
805 VTKHDFUnstructuredGridReader<>,
806 VTKHDFUnstructuredGridReader>
807 {};
808
809 //! Specialization of the WriterFactory for the vtk-hdf file format with automatic flavour selection.
810 template<> struct WriterFactory<FileFormat::VTKHDF> {
811 2 static auto make(const FileFormat::VTKHDF& format,
812 const Concepts::Grid auto& grid) {
813
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 return _make(format.from(grid), grid);
814 }
815 4 static auto make(const FileFormat::VTKHDF& format,
816 const Concepts::Grid auto& grid,
817 const Concepts::Communicator auto& comm) {
818
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 return _make(format.from(grid), grid, comm);
819 }
820 private:
821 template<typename F, typename... Args>
822 6 static auto _make(F&& format, Args&&... args) {
823 6 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
824 }
825 };
826
827 //! Specialization of the ReaderFactory for the vtk-hdf file format with automatic flavour selection
828 template<>
829 struct ReaderFactory<FileFormat::VTKHDF>
830 : APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDF, VTKHDFReader<>, VTKHDFReader>
831 {};
832
833 //! Specialization of the WriterFactory for the transient vtk-hdf file format with automatic flavour selection.
834 template<> struct WriterFactory<FileFormat::VTKHDFTransient> {
835 2 static auto make(const FileFormat::VTKHDFTransient& format,
836 const Concepts::Grid auto& grid,
837 const std::string& base_filename) {
838
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 return _make(format.from(grid), grid, base_filename);
839 }
840 4 static auto make(const FileFormat::VTKHDFTransient& format,
841 const Concepts::Grid auto& grid,
842 const Concepts::Communicator auto& comm,
843 const std::string& base_filename) {
844
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 return _make(format.from(grid), grid, comm, base_filename);
845 }
846 private:
847 template<typename F, typename... Args>
848 6 static auto _make(F&& format, Args&&... args) {
849 6 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
850 }
851 };
852
853 //! Specialization of the ReaderFactory for the transient vtk-hdf file format with automatic flavour selection
854 template<>
855 struct ReaderFactory<FileFormat::VTKHDFTransient>
856 : APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFTransient, VTKHDFReader<>, VTKHDFReader>
857 {};
858
859 //! Specialization of the WriterFactory for the .pvd time series format.
860 template<typename F>
861 struct WriterFactory<FileFormat::PVD<F>> {
862 14 static auto make(const FileFormat::PVD<F>& format,
863 const Concepts::Grid auto& grid,
864 const std::string& base_filename) {
865
3/6
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
14 return PVDWriter{WriterFactory<F>::make(format.piece_format, grid), base_filename};
866 }
867 32 static auto make(const FileFormat::PVD<F>& format,
868 const Concepts::Grid auto& grid,
869 const Concepts::Communicator auto& comm,
870 const std::string& base_filename) {
871
3/6
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
32 return PVDWriter{WriterFactory<F>::make(format.piece_format, grid, comm), base_filename};
872 }
873 };
874
875 //! Specialization of the ReaderFactory for the .pvd time series file format.
876 template<typename PieceFormat>
877 struct ReaderFactory<FileFormat::PVD<PieceFormat>>
878 : APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVD<PieceFormat>, PVDReader<>, PVDReader>
879 {};
880
881 //! Specialization of the ReaderFactory for the .pvd time series closure type.
882 template<>
883 struct ReaderFactory<FileFormat::PVDClosure>
884 : APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVDClosure, PVDReader<>, PVDReader>
885 {};
886
887
888 //! Specialization of the WriterFactory for the any format selector.
889 template<> struct WriterFactory<FileFormat::Any> {
890 private:
891 template<typename G>
892 static constexpr bool is_converter_grid = std::same_as<G, ConverterDetail::ConverterGrid>;
893
894 template<typename F, typename... Args>
895 12 static auto _make(F&& format, Args&&... args) {
896 12 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
897 }
898
899 public:
900 template<Concepts::Grid G>
901 14 static constexpr auto default_format_for() {
902 if constexpr (Concepts::ImageGrid<G> && !is_converter_grid<G>)
903 14 return FileFormat::VTI{};
904 else if constexpr (Concepts::RectilinearGrid<G> && !is_converter_grid<G>)
905 return FileFormat::VTR{};
906 else if constexpr (Concepts::StructuredGrid<G> && !is_converter_grid<G>)
907 return FileFormat::VTS{};
908 else if constexpr (Concepts::UnstructuredGrid<G>)
909 return FileFormat::VTU{};
910 else
911 static_assert(APIDetail::always_false<G>, "Cannot deduce a default format for the given grid");
912 }
913
914 template<Concepts::Grid G>
915 4 static auto make(const FileFormat::Any&, const G& grid) {
916
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
4 return _make(default_format_for<G>(), grid);
917 }
918
919 template<Concepts::Grid G, Concepts::Communicator C>
920 8 static auto make(const FileFormat::Any&, const G& grid, const C& comm) {
921
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
8 return _make(default_format_for<G>(), grid, comm);
922 }
923 };
924
925 //! Specialization of the WriterFactory for the time series variant of the any format selector.
926 template<> struct WriterFactory<FileFormat::AnyTimeSeries> {
927 1 static auto make(const FileFormat::AnyTimeSeries&,
928 const Concepts::Grid auto& grid,
929 const std::string& base_filename) {
930 1 return _make(grid, base_filename);
931 }
932
933 2 static auto make(const FileFormat::AnyTimeSeries&,
934 const Concepts::Grid auto& grid,
935 const Concepts::Communicator auto& comm,
936 const std::string& base_filename) {
937 2 return _make(grid, comm, base_filename);
938 }
939
940 private:
941 template<typename Grid, typename... Args>
942 3 static auto _make(const Grid& grid, Args&&... args) {
943 3 auto fmt = WriterFactory<FileFormat::Any>::template default_format_for<Grid>();
944 3 auto ts_fmt = FileFormat::TimeSeriesClosure{}(fmt);
945
2/3
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
6 return WriterFactory<decltype(ts_fmt)>::make(ts_fmt, grid, std::forward<Args>(args)...);
946 }
947 };
948
949 #ifndef DOXYGEN
950 namespace APIDetail {
951 27 bool has_hdf_file_extension(const std::string& filename) {
952 27 return filename.ends_with(".hdf")
953 || filename.ends_with(".hdf5")
954 || filename.ends_with(".he5")
955
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
27 || filename.ends_with(".h5");
956 }
957
958 template<std::derived_from<GridReader> Reader, typename Communicator>
959 586 std::unique_ptr<Reader> make_reader(const Communicator& c) {
960 if constexpr (std::is_same_v<Communicator, NullCommunicator> ||
961 !std::is_constructible_v<Reader, const Communicator&>)
962 482 return std::make_unique<Reader>();
963 else
964 104 return std::make_unique<Reader>(c);
965 }
966
967 template<Concepts::Communicator C>
968 487 std::unique_ptr<GridReader> make_reader_for(const std::string& filename, const C& c) {
969
3/4
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 248 times.
✓ Branch 4 taken 45 times.
✗ Branch 5 not taken.
487 if (filename.ends_with(".vtu")) return make_reader<VTUReader>(c);
970
3/4
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 205 times.
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
412 else if (filename.ends_with(".vtp")) return make_reader<VTPReader>(c);
971
3/4
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 161 times.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
341 else if (filename.ends_with(".vti")) return make_reader<VTIReader>(c);
972
3/4
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 118 times.
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
269 else if (filename.ends_with(".vtr")) return make_reader<VTRReader>(c);
973
3/4
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 76 times.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
198 else if (filename.ends_with(".vts")) return make_reader<VTSReader>(c);
974
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 74 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
128 else if (filename.ends_with(".pvtu")) return make_reader<PVTUReader>(c);
975
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 72 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
124 else if (filename.ends_with(".pvtp")) return make_reader<PVTPReader>(c);
976
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 70 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
120 else if (filename.ends_with(".pvti")) return make_reader<PVTIReader>(c);
977
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 68 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
116 else if (filename.ends_with(".pvtr")) return make_reader<PVTRReader>(c);
978
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 68 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
112 else if (filename.ends_with(".pvts")) return make_reader<PVTSReader>(c);
979
3/4
✓ Branch 1 taken 41 times.
✓ Branch 2 taken 27 times.
✓ Branch 4 taken 41 times.
✗ Branch 5 not taken.
112 else if (filename.ends_with(".pvd")) return make_reader<PVDReader<C>>(c);
980 #if GRIDFORMAT_HAVE_HIGH_FIVE
981
2/4
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
45 else if (has_hdf_file_extension(filename)) return make_reader<VTKHDFReader<C>>(c);
982 #endif
983 throw IOError("Could not deduce an available file format for '" + filename + "'");
984 }
985
986 } // namespace APIDetail
987 #endif // DOXYGEN
988
989 // Implementation of the AnyReaderFactory function
990 template<Concepts::Communicator C>
991 311 std::unique_ptr<GridReader> AnyReaderFactory<C>::make_for(const std::string& filename) const {
992 311 return APIDetail::make_reader_for(filename, _comm);
993 }
994
995 //! Options for format conversions
996 template<typename OutFormat, typename InFormat = FileFormat::Any>
997 struct ConversionOptions {
998 OutFormat out_format = {};
999 InFormat in_format = {};
1000 int verbosity = 0;
1001 };
1002
1003 /*!
1004 * \ingroup API
1005 * \brief Convert between parallel grid file formats.
1006 * \param in The input filename.
1007 * \param out The output filename.
1008 * \param opts Conversion options.
1009 * \param communicator The communicator (for parallel I/O).
1010 * \note Converting into .vtp file format does not work yet.
1011 */
1012 template<typename OutFormat,
1013 typename InFormat,
1014 typename Communicator = None>
1015 52 std::string convert(const std::string& in,
1016 const std::string& out,
1017 const ConversionOptions<OutFormat, InFormat>& opts,
1018 const Communicator& communicator = {}) {
1019 static constexpr bool use_communicator = !std::same_as<Communicator, None>;
1020 static_assert(
1021 !use_communicator || Concepts::Communicator<Communicator>,
1022 "Given communicator does not satisfy the communicator concepts."
1023 );
1024
1025 using WriterDetail::has_parallel_factory;
1026 using WriterDetail::has_sequential_factory;
1027 using WriterDetail::has_parallel_time_series_factory;
1028 using WriterDetail::has_sequential_time_series_factory;
1029 using CG = ConverterDetail::ConverterGrid;
1030
1031 static constexpr bool is_single_file_out_format = [&] () {
1032 if constexpr (use_communicator) return has_parallel_factory<OutFormat, CG, Communicator>;
1033 else return has_sequential_factory<OutFormat, CG>;
1034 } ();
1035
1036 static constexpr bool is_time_series_out_format = [&] () {
1037 if constexpr (use_communicator) return has_parallel_time_series_factory<OutFormat, CG, Communicator>;
1038 else return has_sequential_time_series_factory<OutFormat, CG>;
1039 } ();
1040
1041
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
52 if (opts.verbosity > 0)
1042 std::cout << "Opening '" << in << "'" << std::endl;
1043
1044
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
78 auto reader = [&] () {
1045 18 if constexpr (use_communicator) return Reader{opts.in_format, communicator};
1046
8/16
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 17 taken 5 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 5 times.
✗ Branch 21 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
8 else return Reader{opts.in_format};
1047 } ();
1048
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
52 reader.open(in);
1049 if constexpr (use_communicator)
1050
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 if (reader.number_of_pieces() > 1
1051
6/10
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 16 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 18 times.
36 && reader.number_of_pieces() != static_cast<unsigned>(Parallel::size(communicator)))
1052 throw IOError(
1053 "Can only convert parallel files if the number of processes matches "
1054 "the number of processes that were used to write the original file "
1055 "(" + std::to_string(reader.number_of_pieces()) + ")"
1056 );
1057
1058
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
52 const bool print_progress_output = opts.verbosity > 1 && [&] () {
1059 if constexpr (use_communicator) return GridFormat::Parallel::rank(communicator) == 0;
1060 else return true;
1061 } ();
1062
1063 142 const auto step_call_back = [&] (std::size_t step_idx, const std::string& filename) {
1064
3/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
45 if (print_progress_output)
1065 std::cout << "Wrote step " << step_idx << " to '" << filename << "'" << std::endl;
1066 };
1067
1068 78 const auto invoke_factory = [&] <typename Fmt, typename... T> (const Fmt& fmt, const auto& grid, T&&... args) {
1069 if constexpr (use_communicator)
1070 18 return WriterFactory<Fmt>::make(fmt, grid, communicator, std::forward<T>(args)...);
1071 else
1072 8 return WriterFactory<Fmt>::make(fmt, grid, std::forward<T>(args)...);
1073 };
1074
1075 if constexpr (is_single_file_out_format) {
1076
3/4
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 17 times.
46 if (reader.is_sequence())
1077 18 return convert(reader, [&] (const auto& grid) {
1078
2/6
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
12 return invoke_factory(FileFormat::TimeSeriesClosure{}(opts.out_format), grid, out);
1079
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 }, step_call_back);
1080
1081
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
51 const auto filename = convert(reader, out, [&] (const auto& grid) {
1082 17 return invoke_factory(opts.out_format, grid);
1083 });
1084
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
34 if (print_progress_output)
1085 std::cout << "Wrote '" << filename << "'" << std::endl;
1086
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
34 return filename;
1087 34 } else if constexpr (is_time_series_out_format) {
1088 3 return convert(reader, [&] (const auto& grid) {
1089 3 return invoke_factory(opts.out_format, grid, out);
1090
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
12 }, step_call_back);
1091 } else {
1092 static_assert(
1093 APIDetail::always_false<OutFormat>,
1094 "No viable factory found for the requested format"
1095 );
1096 }
1097 52 }
1098
1099
1100 // We place the format instances in a namespace different from FileFormats, in which
1101 // the format types are defined above. Further below, we make these instances available
1102 // in the GridFormat namespace directly. Having a separate namespace allows downstream ยด
1103 // projects to expose the format instances in their own namespace without having to expose
1104 // all of GridFormat. Also, separating the format types from the instances further allows
1105 // "hiding" the former and only expose the latter.
1106 namespace Formats {
1107
1108 //! \addtogroup API
1109 //! \{
1110 //! \addtogroup FormatSelectors
1111 //! \{
1112 //! \name File Format Selectors
1113 //! \{
1114
1115 inline constexpr FileFormat::Any any;
1116 inline constexpr FileFormat::VTI vti;
1117 inline constexpr FileFormat::VTR vtr;
1118 inline constexpr FileFormat::VTS vts;
1119 inline constexpr FileFormat::VTP vtp;
1120 inline constexpr FileFormat::VTU vtu;
1121 inline constexpr FileFormat::PVD pvd;
1122 inline constexpr FileFormat::PVDClosure pvd_with;
1123 inline constexpr FileFormat::TimeSeriesClosure time_series;
1124 inline constexpr FileFormat::VTKHDF vtk_hdf;
1125 inline constexpr FileFormat::VTKHDFTransient vtk_hdf_transient;
1126
1127 //! \} name File Format Selectors
1128 //! \} group FormatSelectors
1129 //! \} group API
1130
1131 /*!
1132 * \ingroup API
1133 * \brief Selects a default format suitable to write the given grid
1134 * \tparam G The grid type for which to select a file format.
1135 */
1136 template<Concepts::Grid G>
1137 2 constexpr auto default_for() { return WriterFactory<FileFormat::Any>::template default_format_for<G>(); }
1138
1139 /*!
1140 * \ingroup API
1141 * \brief Selects a default format suitable to write the given grid
1142 * \tparam G The grid type for which to select a file format.
1143 */
1144 template<Concepts::Grid G>
1145 2 constexpr auto default_for(const G&) { return default_for<G>(); }
1146
1147 } // namespace Formats
1148
1149 // expose format instances
1150 using namespace Formats;
1151
1152 // bring the format instances into the FileFormat namespace
1153 namespace FileFormat { using namespace Formats; }
1154
1155 } // namespace GridFormat
1156
1157 #endif // GRIDFORMAT_GRIDFORMAT_HPP_
1158