GCC Code Coverage Report


Directory: gridformat/
File: gridformat/gridformat.hpp
Date: 2026-10-12 17:50:57
Exec Total Coverage
Lines: 196 234 83.8%
Functions: 214 290 73.8%
Branches: 140 347 40.3%

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