GCC Code Coverage Report


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