GridFormat 0.4.0
I/O-Library for grid-like data structures
Loading...
Searching...
No Matches
gridformat.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2// SPDX-License-Identifier: MIT
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
26
27#include <gridformat/common/exceptions.hpp>
28#include <gridformat/parallel/communication.hpp>
29
33
37
41
45
49
52
54
55#ifndef DOXYGEN
56namespace GridFormat::APIDetail {
57
58 template<typename... T>
59 inline constexpr bool always_false = false;
60
61 template<typename... T>
62 struct DefaultAsserter {
63 static constexpr bool do_assert() {
64 static_assert(
65 always_false<T...>,
66 "Requested reader/writer is unavailable due to missing dependency"
67 );
68 return false;
69 }
70 };
71
72 // Derive from GridWriter to make this a "valid" writer (and abuse some valid grid impl for that)
73 template<template<typename...> typename Asserter = DefaultAsserter>
74 class UnavailableWriter : public GridWriter<ImageGrid<2, double>> {
75 public:
76 template<typename... Args>
77 UnavailableWriter(Args&&...) { static_assert(Asserter<Args...>::do_assert()); }
78 private:
79 void _throw() const { throw GridFormat::NotImplemented("Writer unavailable"); }
80 void _write(std::ostream&) const { _throw(); }
81 };
82
83 // Derive from TimeSeriesGridWriter to make this a "valid" writer (and abuse some valid grid impl for that)
84 template<template<typename...> typename Asserter = DefaultAsserter>
85 class UnavailableTimeSeriesWriter : public TimeSeriesGridWriter<ImageGrid<2, double>> {
86 public:
87 template<typename... Args>
88 UnavailableTimeSeriesWriter(Args&&...) { static_assert(Asserter<Args...>::do_assert()); }
89 private:
90 void _throw() const { throw GridFormat::NotImplemented("Writer unavailable"); }
91 std::string _write(double) override { _throw(); return ""; }
92 };
93
94 // Derive from Reader to make this a "valid" reader
95 template<template<typename...> typename Asserter = DefaultAsserter>
96 class UnavailableReader : public GridReader {
97 public:
98 template<typename... Args>
99 UnavailableReader(Args&&...) { static_assert(Asserter<Args...>::do_assert()); }
100 private:
101 void _throw() const { throw GridFormat::NotImplemented("Reader unavailable"); }
102 std::string _name() const override { _throw(); return ""; }
103 void _open(const std::string&, typename GridReader::FieldNames&) override { _throw(); }
104 void _close() override { _throw(); }
105 std::size_t _number_of_cells() const override { _throw(); return 0; }
106 std::size_t _number_of_points() const override { _throw(); return 0; }
107 FieldPtr _cell_field(std::string_view) const override { _throw(); return nullptr; }
108 FieldPtr _point_field(std::string_view) const override { _throw(); return nullptr; }
109 FieldPtr _meta_data_field(std::string_view) const override { _throw(); return nullptr; }
110 bool _is_sequence() const override { _throw(); return false; }
111 };
112
113} // namespace GridFormat::APIDetail
114
115#if GRIDFORMAT_HAVE_HIGH_FIVE
118inline constexpr bool _gfmt_api_have_high_five = true;
119#else
121inline constexpr bool _gfmt_api_have_high_five = false;
122namespace GridFormat {
123
124template<typename... T>
125struct VTKHDFAsserter {
126 static constexpr bool do_assert() {
127 static_assert(
128 APIDetail::always_false<T...>,
129 "VTKHDF reader/writers require HighFive"
130 );
131 return false;
132 }
133};
134
135using VTKHDFWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
136using VTKHDFTimeSeriesWriter = APIDetail::UnavailableTimeSeriesWriter<VTKHDFAsserter>;
137using VTKHDFImageGridWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
138using VTKHDFUnstructuredGridWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
139using VTKHDFImageGridTimeSeriesWriter = APIDetail::UnavailableTimeSeriesWriter<VTKHDFAsserter>;
140using VTKHDFUnstructuredTimeSeriesWriter = APIDetail::UnavailableTimeSeriesWriter<VTKHDFAsserter>;
141
142using VTKHDFImageGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
143template<typename T = void> using VTKHDFUnstructuredGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
144template<typename T = void> using VTKHDFReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
145
146} // namespace GridFormat
147#endif // GRIDFORMAT_HAVE_HIGH_FIVE
148#endif // DOXYGEN
149
150
151namespace GridFormat {
152
154inline constexpr GridFormat::NullCommunicator null_communicator;
155
157template<typename FileFormat> struct WriterFactory;
158
160template<typename FileFormat> struct ReaderFactory;
161
162namespace FileFormat {
163
165template<typename Format, typename Opts>
167 using Options = Opts;
168 std::optional<Options> opts = {};
169
171 constexpr Format operator()(Options _opts) const {
172 return with(std::move(_opts));
173 }
174
176 constexpr Format with(Options _opts) const {
177 Format f;
178 f.opts = std::move(_opts);
179 return f;
180 }
181};
182
184template<typename VTKFormat>
185struct VTKXMLFormatBase : public FormatWithOptions<VTKFormat, VTK::XMLOptions> {
187 constexpr auto with_encoding(VTK::XML::Encoder e) const {
188 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
189 Variant::unwrap_to(cur_opts.encoder, e);
190 return this->with(std::move(cur_opts));
191 }
192
194 constexpr auto with_data_format(VTK::XML::DataFormat f) const {
195 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
196 Variant::unwrap_to(cur_opts.data_format, f);
197 return this->with(std::move(cur_opts));
198 }
199
201 constexpr auto with_compression(VTK::XML::Compressor c) const {
202 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
203 Variant::unwrap_to(cur_opts.compressor, c);
204 return this->with(std::move(cur_opts));
205 }
206};
207
208
215struct Any {};
216
217
224
225
236struct VTI : VTKXMLFormatBase<VTI> {};
237
248struct VTR : VTKXMLFormatBase<VTR> {};
249
260struct VTS : VTKXMLFormatBase<VTS> {};
261
272struct VTP : VTKXMLFormatBase<VTP> {};
273
284struct VTU : VTKXMLFormatBase<VTU> {};
285
291template<typename VTX>
292struct VTKXMLTimeSeries : VTKXMLFormatBase<VTKXMLTimeSeries<VTX>> {};
293
294
308struct VTKHDFImage {};
309
316: FormatWithOptions<VTKHDFImageTransient, VTK::HDFTransientOptions> {};
317
329
336: FormatWithOptions<VTKHDFUnstructuredTransient, VTK::HDFTransientOptions> {};
337
348struct VTKHDFTransient : FormatWithOptions<VTKHDFTransient, VTK::HDFTransientOptions> {
349 template<typename Grid>
350 constexpr auto from(const Grid&) const {
351 // TODO: Once the VTKHDFImageGridReader is stable, use image format for image grids
352 return VTKHDFUnstructuredTransient{this->opts};
353 }
354};
355
366struct VTKHDF {
367 template<typename Grid>
368 static constexpr auto from(const Grid&) {
369 // TODO: Once the VTKHDFImageGridReader is stable, use image format for image grids
370 return VTKHDFUnstructured{};
371 }
372
375 return {std::move(opts)};
376 }
377};
378
379#ifndef DOXYGEN
380namespace Detail {
381
382 template<typename F> struct IsVTKXMLFormat : public std::false_type {};
383 template<> struct IsVTKXMLFormat<VTI> : public std::true_type {};
384 template<> struct IsVTKXMLFormat<VTR> : public std::true_type {};
385 template<> struct IsVTKXMLFormat<VTS> : public std::true_type {};
386 template<> struct IsVTKXMLFormat<VTP> : public std::true_type {};
387 template<> struct IsVTKXMLFormat<VTU> : public std::true_type {};
388
389} // namespace Detail
390#endif // DOXYGEN
391
400template<typename PieceFormat = Any>
401struct PVD {
402 PieceFormat piece_format;
403};
404
411 template<typename Format>
412 constexpr auto operator()(const Format& f) const {
413 static_assert(
414 Detail::IsVTKXMLFormat<Format>::value,
415 "The PVD format is only available with vtk-xml file formats"
416 );
417 return PVD<Format>{f};
418 }
419};
420
427 template<typename Format>
428 constexpr auto operator()(const Format& f) const {
429 if constexpr (Detail::IsVTKXMLFormat<Format>::value)
430 return VTKXMLTimeSeries<Format>{f.opts};
431 else if constexpr (std::same_as<VTKHDFImage, Format>)
432 return VTKHDFImageTransient{};
433 else if constexpr (std::same_as<VTKHDFUnstructured, Format>)
435 else if constexpr (std::same_as<VTKHDF, Format>)
436 return VTKHDFTransient{};
437 else if constexpr (std::same_as<Any, Format>)
438 return AnyTimeSeries{};
439 else {
440 static_assert(
441 APIDetail::always_false<Format>,
442 "Cannot create a time series variant for the given format. This means the format does not "
443 "define a variant for time series, or, the selected format is already time series format."
444 );
445 }
446 }
447};
448
449} // namespace FileFormat
450
451
452#ifndef DOXYGEN
453namespace APIDetail {
454
455 // Meta-Reader for file formats that have different format flavours in parallel/sequential
456 template<typename SeqReader, typename ParReader>
457 class SequentialOrParallelReader : public GridReader {
458 template<typename R> using CommunicatorAccess = Traits::CommunicatorAccess<R>;
459 template<typename R> using Communicator = decltype(CommunicatorAccess<R>::get(std::declval<const R&>()));
460 using ParCommunicator = Communicator<ParReader>;
461 using SeqCommunicator = Communicator<SeqReader>;
462
463 public:
464 SequentialOrParallelReader(SeqReader&& seq, ParReader&& par)
465 : _seq_reader{std::move(seq)}
466 , _par_reader{std::move(par)}
467 {}
468
469 ParCommunicator communicator() const {
470 const bool is_parallel = !_use_sequential.value_or(true);
471 if (!is_parallel) {
472 if constexpr (!std::is_same_v<ParCommunicator, SeqCommunicator>)
473 throw InvalidState("Cannot access communicator for sequential variant of the reader");
474 else
475 return CommunicatorAccess<SeqReader>::get(_seq_reader);
476 }
477 return CommunicatorAccess<ParReader>::get(_par_reader);
478 }
479
480 private:
481 SeqReader _seq_reader;
482 ParReader _par_reader;
483 std::optional<bool> _use_sequential = {};
484
485 std::string _name() const override {
486 return _is_set() ? _access().name() : std::string{"undefined"};
487 }
488
489 void _open(const std::string& filename, typename GridReader::FieldNames& names) override {
490 _close();
491 std::string seq_error;
492 try {
493 _seq_reader.open(filename);
494 _use_sequential = true;
495 } catch (const std::exception& e) {
496 seq_error = e.what();
497 _use_sequential.reset();
498 _seq_reader.close();
499 try {
500 _par_reader.open(filename);
501 _use_sequential = false;
502 } catch (const std::exception& par_err) {
503 _use_sequential.reset();
504 _par_reader.close();
505 throw IOError(
506 "Could not read '" + filename + "' neither as sequential nor parallel format.\n"
507 "Error with sequential format (" + _seq_reader.name() + "): " + seq_error + "\n"
508 "Error with parallel format (" + _par_reader.name() + "): " + par_err.what()
509 );
510 }
511 }
512
513 ReaderDetail::copy_field_names(_access(), names);
514 }
515
516 void _close() override {
517 if (_is_set())
518 _access().close();
519 }
520
521 std::size_t _number_of_cells() const override { return _access().number_of_cells(); }
522 std::size_t _number_of_points() const override { return _access().number_of_points(); }
523 std::size_t _number_of_pieces() const override { return _access().number_of_pieces(); }
524
525 FieldPtr _cell_field(std::string_view n) const override { return _access().cell_field(n); }
526 FieldPtr _point_field(std::string_view n) const override { return _access().point_field(n); }
527 FieldPtr _meta_data_field(std::string_view n) const override { return _access().meta_data_field(n); }
528
529 FieldPtr _points() const override { return _access().points(); }
530 void _visit_cells(const typename GridReader::CellVisitor& v) const override { _access().visit_cells(v); }
531 std::vector<double> _ordinates(unsigned int i) const override { return _access().ordinates(i); }
532
533 typename GridReader::PieceLocation _location() const override { return _access().location(); }
534 typename GridReader::Vector _spacing() const override { return _access().spacing(); }
535 typename GridReader::Vector _origin() const override { return _access().origin(); }
536 typename GridReader::Vector _basis_vector(unsigned int i) const override { return _access().basis_vector(i); }
537
538 bool _is_sequence() const override { return _access().is_sequence(); }
539 std::size_t _number_of_steps() const override { return _access().number_of_steps(); }
540 double _time_at_step(std::size_t i) const override { return _access().time_at_step(i); }
541 void _set_step(std::size_t i, typename GridReader::FieldNames& names) override {
542 _access().set_step(i);
543 names.clear();
544 ReaderDetail::copy_field_names(_access(), names);
545 }
546
547 bool _is_set() const { return _use_sequential.has_value(); }
548 void _throw_if_not_set() const {
549 if (!_is_set())
550 throw IOError("No data has been read");
551 }
552
553 GridReader& _access() {
554 _throw_if_not_set();
555 return _use_sequential.value()
556 ? static_cast<GridReader&>(_seq_reader)
557 : static_cast<GridReader&>(_par_reader);
558 }
559
560 const GridReader& _access() const {
561 _throw_if_not_set();
562 return _use_sequential.value()
563 ? static_cast<const GridReader&>(_seq_reader)
564 : static_cast<const GridReader&>(_par_reader);
565 }
566 };
567
568 template<typename S, typename P>
569 SequentialOrParallelReader(S&&, P&&) -> SequentialOrParallelReader<std::remove_cvref_t<S>, std::remove_cvref_t<P>>;
570
571 template<typename Format, typename SeqReader, typename ParReader>
572 struct SequentialOrParallelReaderFactory {
573 template<Concepts::Communicator C = NullCommunicator>
574 static auto make(const Format&, const C& comm = null_communicator) {
575 return SequentialOrParallelReader{SeqReader{}, ParReader{comm}};
576 }
577 };
578
579 template<typename Format, typename SequentialReader, typename ParallelReader>
580 struct DefaultReaderFactory {
581 static auto make(const Format&) { return SequentialReader{}; }
582 static auto make(const Format&, const Concepts::Communicator auto& comm) { return ParallelReader{comm}; }
583 };
584
585 // Specialization for cases where the parallel reader is templated on the communicator
586 template<typename F, typename S, template<typename> typename P>
587 struct DefaultTemplatedReaderFactory {
588 static auto make(const F&) { return S{}; }
589 template<Concepts::Communicator Communicator>
590 static auto make(const F&, const Communicator& comm) { return P<Communicator>{comm}; }
591 };
592
593} // namespace APIDetail
594#endif // DOXYGEN
595
596// Traits specializations for SequentialOrParallelReader
597namespace Traits {
598
599template<typename S, typename P>
600struct WritesConnectivity<APIDetail::SequentialOrParallelReader<S, P>>
601: public std::bool_constant<WritesConnectivity<S>::value || WritesConnectivity<P>::value>
602{};
603
604} // namespace Traits
605
607template<> struct WriterFactory<FileFormat::VTI> {
608 static auto make(const FileFormat::VTI& format,
609 const Concepts::ImageGrid auto& grid) {
610 return VTIWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
611 }
612
613 static auto make(const FileFormat::VTI& format,
614 const Concepts::ImageGrid auto& grid,
615 const Concepts::Communicator auto& comm) {
616 return PVTIWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
617 }
618};
619
621template<>
622struct ReaderFactory<FileFormat::VTI> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTI, VTIReader, PVTIReader> {};
623
625template<> struct WriterFactory<FileFormat::VTR> {
626 static auto make(const FileFormat::VTR& format,
627 const Concepts::RectilinearGrid auto& grid) {
628 return VTRWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
629 }
630 static auto make(const FileFormat::VTR& format,
631 const Concepts::RectilinearGrid auto& grid,
632 const Concepts::Communicator auto& comm) {
633 return PVTRWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
634 }
635};
636
638template<>
639struct ReaderFactory<FileFormat::VTR> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTR, VTRReader, PVTRReader> {};
640
642template<> struct WriterFactory<FileFormat::VTS> {
643 static auto make(const FileFormat::VTS& format,
644 const Concepts::StructuredGrid auto& grid) {
645 return VTSWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
646 }
647 static auto make(const FileFormat::VTS& format,
648 const Concepts::StructuredGrid auto& grid,
649 const Concepts::Communicator auto& comm) {
650 return PVTSWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
651 }
652};
653
655template<>
656struct ReaderFactory<FileFormat::VTS> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTS, VTSReader, PVTSReader> {};
657
659template<> struct WriterFactory<FileFormat::VTP> {
660 static auto make(const FileFormat::VTP& format,
661 const Concepts::UnstructuredGrid auto& grid) {
662 return VTPWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
663 }
664 static auto make(const FileFormat::VTP& format,
665 const Concepts::UnstructuredGrid auto& grid,
666 const Concepts::Communicator auto& comm) {
667 return PVTPWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
668 }
669};
670
672template<>
673struct ReaderFactory<FileFormat::VTP> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTP, VTPReader, PVTPReader> {};
674
676template<> struct WriterFactory<FileFormat::VTU> {
677 static auto make(const FileFormat::VTU& format,
678 const Concepts::UnstructuredGrid auto& grid) {
679 return VTUWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
680 }
681 static auto make(const FileFormat::VTU& format,
682 const Concepts::UnstructuredGrid auto& grid,
683 const Concepts::Communicator auto& comm) {
684 return PVTUWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
685 }
686};
687
689template<>
690struct ReaderFactory<FileFormat::VTU> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTU, VTUReader, PVTUReader> {};
691
693template<typename F> struct WriterFactory<FileFormat::VTKXMLTimeSeries<F>> {
694 static auto make(const FileFormat::VTKXMLTimeSeries<F>& format,
695 const Concepts::UnstructuredGrid auto& grid,
696 const std::string& base_filename) {
698 WriterFactory<F>::make(F{format.opts.value_or(VTK::XMLOptions{})}, grid),
699 base_filename
700 };
701 }
702 static auto make(const FileFormat::VTKXMLTimeSeries<F>& format,
703 const Concepts::UnstructuredGrid auto& grid,
704 const Concepts::Communicator auto& comm,
705 const std::string& base_filename) {
707 WriterFactory<F>::make(F{format.opts.value_or(VTK::XMLOptions{})}, grid, comm),
708 base_filename
709 };
710 }
711};
712
714template<> struct WriterFactory<FileFormat::VTKHDFImage> {
715 static auto make(const FileFormat::VTKHDFImage&,
716 const Concepts::ImageGrid auto& grid) {
717 return VTKHDFImageGridWriter{grid};
718 }
719 static auto make(const FileFormat::VTKHDFImage&,
720 const Concepts::ImageGrid auto& grid,
721 const Concepts::Communicator auto& comm) {
722 return VTKHDFImageGridWriter{grid, comm};
723 }
724};
725
727template<>
728struct ReaderFactory<FileFormat::VTKHDFImage>
729: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImage,
730 VTKHDFImageGridReader,
731 VTKHDFImageGridReader>
732{};
733
735template<> struct WriterFactory<FileFormat::VTKHDFImageTransient> {
736 static auto make(const FileFormat::VTKHDFImageTransient& f,
737 const Concepts::ImageGrid auto& grid,
738 const std::string& base_filename) {
739 if (f.opts.has_value())
740 return VTKHDFImageGridTimeSeriesWriter{grid, base_filename, f.opts.value()};
741 return VTKHDFImageGridTimeSeriesWriter{grid, base_filename};
742 }
743 static auto make(const FileFormat::VTKHDFImageTransient& f,
744 const Concepts::ImageGrid auto& grid,
745 const Concepts::Communicator auto& comm,
746 const std::string& base_filename) {
747 if (f.opts.has_value())
748 return VTKHDFImageGridTimeSeriesWriter{grid, comm, base_filename, f.opts.value()};
749 return VTKHDFImageGridTimeSeriesWriter{grid, comm, base_filename};
750 }
751};
752
754template<>
755struct ReaderFactory<FileFormat::VTKHDFImageTransient>
756: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImageTransient,
757 VTKHDFImageGridReader,
758 VTKHDFImageGridReader>
759{};
760
762template<> struct WriterFactory<FileFormat::VTKHDFUnstructured> {
763 static auto make(const FileFormat::VTKHDFUnstructured&,
764 const Concepts::UnstructuredGrid auto& grid) {
765 return VTKHDFUnstructuredGridWriter{grid};
766 }
767 static auto make(const FileFormat::VTKHDFUnstructured&,
768 const Concepts::UnstructuredGrid auto& grid,
769 const Concepts::Communicator auto& comm) {
770 return VTKHDFUnstructuredGridWriter{grid, comm};
771 }
772};
773
775template<>
776struct ReaderFactory<FileFormat::VTKHDFUnstructured>
777: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructured,
778 VTKHDFUnstructuredGridReader<>,
779 VTKHDFUnstructuredGridReader>
780{};
781
783template<> struct WriterFactory<FileFormat::VTKHDFUnstructuredTransient> {
784 static auto make(const FileFormat::VTKHDFUnstructuredTransient& f,
785 const Concepts::ImageGrid auto& grid,
786 const std::string& base_filename) {
787 if (f.opts.has_value())
788 return VTKHDFUnstructuredTimeSeriesWriter{grid, base_filename, f.opts.value()};
789 return VTKHDFUnstructuredTimeSeriesWriter{grid, base_filename};
790 }
791 static auto make(const FileFormat::VTKHDFUnstructuredTransient& f,
792 const Concepts::ImageGrid auto& grid,
793 const Concepts::Communicator auto& comm,
794 const std::string& base_filename) {
795 if (f.opts.has_value())
796 return VTKHDFUnstructuredTimeSeriesWriter{grid, comm, base_filename, f.opts.value()};
797 return VTKHDFUnstructuredTimeSeriesWriter{grid, comm, base_filename};
798 }
799};
800
802template<>
803struct ReaderFactory<FileFormat::VTKHDFUnstructuredTransient>
804: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructuredTransient,
805 VTKHDFUnstructuredGridReader<>,
806 VTKHDFUnstructuredGridReader>
807{};
808
810template<> struct WriterFactory<FileFormat::VTKHDF> {
811 static auto make(const FileFormat::VTKHDF& format,
812 const Concepts::Grid auto& grid) {
813 return _make(format.from(grid), grid);
814 }
815 static auto make(const FileFormat::VTKHDF& format,
816 const Concepts::Grid auto& grid,
817 const Concepts::Communicator auto& comm) {
818 return _make(format.from(grid), grid, comm);
819 }
820 private:
821 template<typename F, typename... Args>
822 static auto _make(F&& format, Args&&... args) {
823 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
824 }
825};
826
828template<>
829struct ReaderFactory<FileFormat::VTKHDF>
830: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDF, VTKHDFReader<>, VTKHDFReader>
831{};
832
834template<> struct WriterFactory<FileFormat::VTKHDFTransient> {
835 static auto make(const FileFormat::VTKHDFTransient& format,
836 const Concepts::Grid auto& grid,
837 const std::string& base_filename) {
838 return _make(format.from(grid), grid, base_filename);
839 }
840 static auto make(const FileFormat::VTKHDFTransient& format,
841 const Concepts::Grid auto& grid,
842 const Concepts::Communicator auto& comm,
843 const std::string& base_filename) {
844 return _make(format.from(grid), grid, comm, base_filename);
845 }
846 private:
847 template<typename F, typename... Args>
848 static auto _make(F&& format, Args&&... args) {
849 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
850 }
851};
852
854template<>
855struct ReaderFactory<FileFormat::VTKHDFTransient>
856: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFTransient, VTKHDFReader<>, VTKHDFReader>
857{};
858
860template<typename F>
861struct WriterFactory<FileFormat::PVD<F>> {
862 static auto make(const FileFormat::PVD<F>& format,
863 const Concepts::Grid auto& grid,
864 const std::string& base_filename) {
865 return PVDWriter{WriterFactory<F>::make(format.piece_format, grid), base_filename};
866 }
867 static auto make(const FileFormat::PVD<F>& format,
868 const Concepts::Grid auto& grid,
869 const Concepts::Communicator auto& comm,
870 const std::string& base_filename) {
871 return PVDWriter{WriterFactory<F>::make(format.piece_format, grid, comm), base_filename};
872 }
873};
874
876template<typename PieceFormat>
877struct ReaderFactory<FileFormat::PVD<PieceFormat>>
878: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVD<PieceFormat>, PVDReader<>, PVDReader>
879{};
880
882template<>
883struct ReaderFactory<FileFormat::PVDClosure>
884: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVDClosure, PVDReader<>, PVDReader>
885{};
886
887
889template<> struct WriterFactory<FileFormat::Any> {
890 private:
891 template<typename G>
892 static constexpr bool is_converter_grid = std::same_as<G, ConverterDetail::ConverterGrid>;
893
894 template<typename F, typename... Args>
895 static auto _make(F&& format, Args&&... args) {
896 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
897 }
898
899 public:
900 template<Concepts::Grid G>
901 static constexpr auto default_format_for() {
902 if constexpr (Concepts::ImageGrid<G> && !is_converter_grid<G>)
903 return FileFormat::VTI{};
904 else if constexpr (Concepts::RectilinearGrid<G> && !is_converter_grid<G>)
905 return FileFormat::VTR{};
906 else if constexpr (Concepts::StructuredGrid<G> && !is_converter_grid<G>)
907 return FileFormat::VTS{};
908 else if constexpr (Concepts::UnstructuredGrid<G>)
909 return FileFormat::VTU{};
910 else
911 static_assert(APIDetail::always_false<G>, "Cannot deduce a default format for the given grid");
912 }
913
914 template<Concepts::Grid G>
915 static auto make(const FileFormat::Any&, const G& grid) {
916 return _make(default_format_for<G>(), grid);
917 }
918
919 template<Concepts::Grid G, Concepts::Communicator C>
920 static auto make(const FileFormat::Any&, const G& grid, const C& comm) {
921 return _make(default_format_for<G>(), grid, comm);
922 }
923};
924
926template<> struct WriterFactory<FileFormat::AnyTimeSeries> {
927 static auto make(const FileFormat::AnyTimeSeries&,
928 const Concepts::Grid auto& grid,
929 const std::string& base_filename) {
930 return _make(grid, base_filename);
931 }
932
933 static auto make(const FileFormat::AnyTimeSeries&,
934 const Concepts::Grid auto& grid,
935 const Concepts::Communicator auto& comm,
936 const std::string& base_filename) {
937 return _make(grid, comm, base_filename);
938 }
939
940 private:
941 template<typename Grid, typename... Args>
942 static auto _make(const Grid& grid, Args&&... args) {
943 auto fmt = WriterFactory<FileFormat::Any>::template default_format_for<Grid>();
944 auto ts_fmt = FileFormat::TimeSeriesClosure{}(fmt);
945 return WriterFactory<decltype(ts_fmt)>::make(ts_fmt, grid, std::forward<Args>(args)...);
946 }
947};
948
949#ifndef DOXYGEN
950namespace APIDetail {
951 bool has_hdf_file_extension(const std::string& filename) {
952 return filename.ends_with(".hdf")
953 || filename.ends_with(".hdf5")
954 || filename.ends_with(".he5")
955 || filename.ends_with(".h5");
956 }
957
958 template<std::derived_from<GridReader> Reader, typename Communicator>
959 std::unique_ptr<Reader> make_reader(const Communicator& c) {
960 if constexpr (std::is_same_v<Communicator, NullCommunicator> ||
961 !std::is_constructible_v<Reader, const Communicator&>)
962 return std::make_unique<Reader>();
963 else
964 return std::make_unique<Reader>(c);
965 }
966
967 template<Concepts::Communicator C>
968 std::unique_ptr<GridReader> make_reader_for(const std::string& filename, const C& c) {
969 if (filename.ends_with(".vtu")) return make_reader<VTUReader>(c);
970 else if (filename.ends_with(".vtp")) return make_reader<VTPReader>(c);
971 else if (filename.ends_with(".vti")) return make_reader<VTIReader>(c);
972 else if (filename.ends_with(".vtr")) return make_reader<VTRReader>(c);
973 else if (filename.ends_with(".vts")) return make_reader<VTSReader>(c);
974 else if (filename.ends_with(".pvtu")) return make_reader<PVTUReader>(c);
975 else if (filename.ends_with(".pvtp")) return make_reader<PVTPReader>(c);
976 else if (filename.ends_with(".pvti")) return make_reader<PVTIReader>(c);
977 else if (filename.ends_with(".pvtr")) return make_reader<PVTRReader>(c);
978 else if (filename.ends_with(".pvts")) return make_reader<PVTSReader>(c);
979 else if (filename.ends_with(".pvd")) return make_reader<PVDReader<C>>(c);
980#if GRIDFORMAT_HAVE_HIGH_FIVE
981 else if (has_hdf_file_extension(filename)) return make_reader<VTKHDFReader<C>>(c);
982#endif
983 throw IOError("Could not deduce an available file format for '" + filename + "'");
984 }
985
986} // namespace APIDetail
987#endif // DOXYGEN
988
989// Implementation of the AnyReaderFactory function
990template<Concepts::Communicator C>
991std::unique_ptr<GridReader> AnyReaderFactory<C>::make_for(const std::string& filename) const {
992 return APIDetail::make_reader_for(filename, _comm);
993}
994
996template<typename OutFormat, typename InFormat = FileFormat::Any>
998 OutFormat out_format = {};
999 InFormat in_format = {};
1000 int verbosity = 0;
1001};
1002
1012template<typename OutFormat,
1013 typename InFormat,
1014 typename Communicator = None>
1015std::string convert(const std::string& in,
1016 const std::string& out,
1018 const Communicator& communicator = {}) {
1019 static constexpr bool use_communicator = !std::same_as<Communicator, None>;
1020 static_assert(
1021 !use_communicator || Concepts::Communicator<Communicator>,
1022 "Given communicator does not satisfy the communicator concepts."
1023 );
1024
1025 using WriterDetail::has_parallel_factory;
1026 using WriterDetail::has_sequential_factory;
1027 using WriterDetail::has_parallel_time_series_factory;
1028 using WriterDetail::has_sequential_time_series_factory;
1029 using CG = ConverterDetail::ConverterGrid;
1030
1031 static constexpr bool is_single_file_out_format = [&] () {
1032 if constexpr (use_communicator) return has_parallel_factory<OutFormat, CG, Communicator>;
1033 else return has_sequential_factory<OutFormat, CG>;
1034 } ();
1035
1036 static constexpr bool is_time_series_out_format = [&] () {
1037 if constexpr (use_communicator) return has_parallel_time_series_factory<OutFormat, CG, Communicator>;
1038 else return has_sequential_time_series_factory<OutFormat, CG>;
1039 } ();
1040
1041 if (opts.verbosity > 0)
1042 std::cout << "Opening '" << in << "'" << std::endl;
1043
1044 auto reader = [&] () {
1045 if constexpr (use_communicator) return Reader{opts.in_format, communicator};
1046 else return Reader{opts.in_format};
1047 } ();
1048 reader.open(in);
1049 if constexpr (use_communicator)
1050 if (reader.number_of_pieces() > 1
1051 && reader.number_of_pieces() != static_cast<unsigned>(Parallel::size(communicator)))
1052 throw IOError(
1053 "Can only convert parallel files if the number of processes matches "
1054 "the number of processes that were used to write the original file "
1055 "(" + std::to_string(reader.number_of_pieces()) + ")"
1056 );
1057
1058 const bool print_progress_output = opts.verbosity > 1 && [&] () {
1059 if constexpr (use_communicator) return GridFormat::Parallel::rank(communicator) == 0;
1060 else return true;
1061 } ();
1062
1063 const auto step_call_back = [&] (std::size_t step_idx, const std::string& filename) {
1064 if (print_progress_output)
1065 std::cout << "Wrote step " << step_idx << " to '" << filename << "'" << std::endl;
1066 };
1067
1068 const auto invoke_factory = [&] <typename Fmt, typename... T> (const Fmt& fmt, const auto& grid, T&&... args) {
1069 if constexpr (use_communicator)
1070 return WriterFactory<Fmt>::make(fmt, grid, communicator, std::forward<T>(args)...);
1071 else
1072 return WriterFactory<Fmt>::make(fmt, grid, std::forward<T>(args)...);
1073 };
1074
1075 if constexpr (is_single_file_out_format) {
1076 if (reader.is_sequence())
1077 return convert(reader, [&] (const auto& grid) {
1078 return invoke_factory(FileFormat::TimeSeriesClosure{}(opts.out_format), grid, out);
1079 }, step_call_back);
1080
1081 const auto filename = convert(reader, out, [&] (const auto& grid) {
1082 return invoke_factory(opts.out_format, grid);
1083 });
1084 if (print_progress_output)
1085 std::cout << "Wrote '" << filename << "'" << std::endl;
1086 return filename;
1087 } else if constexpr (is_time_series_out_format) {
1088 return convert(reader, [&] (const auto& grid) {
1089 return invoke_factory(opts.out_format, grid, out);
1090 }, step_call_back);
1091 } else {
1092 static_assert(
1093 APIDetail::always_false<OutFormat>,
1094 "No viable factory found for the requested format"
1095 );
1096 }
1097}
1098
1099
1100// We place the format instances in a namespace different from FileFormats, in which
1101// the format types are defined above. Further below, we make these instances available
1102// in the GridFormat namespace directly. Having a separate namespace allows downstream ´
1103// projects to expose the format instances in their own namespace without having to expose
1104// all of GridFormat. Also, separating the format types from the instances further allows
1105// "hiding" the former and only expose the latter.
1106namespace Formats {
1107
1114
1115inline constexpr FileFormat::Any any;
1116inline constexpr FileFormat::VTI vti;
1117inline constexpr FileFormat::VTR vtr;
1118inline constexpr FileFormat::VTS vts;
1119inline constexpr FileFormat::VTP vtp;
1120inline constexpr FileFormat::VTU vtu;
1121inline constexpr FileFormat::PVD pvd;
1122inline constexpr FileFormat::PVDClosure pvd_with;
1123inline constexpr FileFormat::TimeSeriesClosure time_series;
1124inline constexpr FileFormat::VTKHDF vtk_hdf;
1125inline constexpr FileFormat::VTKHDFTransient vtk_hdf_transient;
1126
1130
1136template<Concepts::Grid G>
1137constexpr auto default_for() { return WriterFactory<FileFormat::Any>::template default_format_for<G>(); }
1138
1144template<Concepts::Grid G>
1145constexpr auto default_for(const G&) { return default_for<G>(); }
1146
1147} // namespace Formats
1148
1149// expose format instances
1150using namespace Formats;
1151
1152// bring the format instances into the FileFormat namespace
1153namespace FileFormat { using namespace Formats; }
1154
1155} // namespace GridFormat
1156
1157#endif // GRIDFORMAT_GRIDFORMAT_HPP_
Abstract base class for all readers, defines the common interface.
Definition: reader.hpp:51
Writer for .pvd time-series file format.
Definition: pvd_writer.hpp:52
Writer for parallel .pvti files.
Definition: pvti_writer.hpp:41
Writer for parallel .pvtu files.
Definition: pvtp_writer.hpp:34
Writer for parallel .pvtr files.
Definition: pvtr_writer.hpp:40
Writer for parallel .pvts files.
Definition: pvts_writer.hpp:41
Writer for parallel .pvtu files.
Definition: pvtu_writer.hpp:34
Writer for .vti file format.
Definition: vti_writer.hpp:33
Writer for the transient VTK HDF file format for image grids.
Definition: hdf_image_grid_writer.hpp:396
Writer for the VTK HDF file format for image grids.
Definition: hdf_image_grid_writer.hpp:385
Writer for the VTK HDF file format for unstructured grids.
Definition: hdf_unstructured_grid_writer.hpp:386
Writer for the transient VTK HDF file format for unstructured grids.
Definition: hdf_unstructured_grid_writer.hpp:397
Writer for time series of a VTK-XML file format. Populates the "TimeValue" metadata field supported b...
Definition: xml_time_series_writer.hpp:25
Writer for .vtu file format.
Definition: vtp_writer.hpp:56
Writer for .vtr file format.
Definition: vtr_writer.hpp:35
Writer for .vts file format.
Definition: vts_writer.hpp:35
Writer for .vtu file format.
Definition: vtu_writer.hpp:30
Concept a type that fulfills any of the grid interfaces.
Definition: concepts.hpp:93
Concept for grids to be used as image grids.
Definition: concepts.hpp:53
Concept for grids to be used as rectilinear grids.
Definition: concepts.hpp:66
Concept for grids to be used as structured grids.
Definition: concepts.hpp:74
Concept for grids to be used as unstructured grids.
Definition: concepts.hpp:82
Converter between grid formats.
constexpr GridFormat::NullCommunicator null_communicator
Null communicator that can be used e.g. to read parallel file formats sequentially.
Definition: gridformat.hpp:154
constexpr auto default_for()
Selects a default format suitable to write the given grid.
Definition: gridformat.hpp:1137
std::string convert(const std::string &in, const std::string &out, const ConversionOptions< OutFormat, InFormat > &opts, const Communicator &communicator={})
Convert between parallel grid file formats.
Definition: gridformat.hpp:1015
std::shared_ptr< const Field > FieldPtr
Pointer type used by writers/readers for fields.
Definition: field.hpp:186
Common functionality for writing VTK HDF files.
Readers for the VTK HDF file formats.
Writers for the VTK HDF file formats.
Predefined image grid implementation.
A generic reader providing access to the readers for all supported formats.
Options for format conversions.
Definition: gridformat.hpp:997
Time series variant of the Any format selector.
Definition: gridformat.hpp:223
Selector for an unspecified file format. When using this format, GridFormat will automatically select...
Definition: gridformat.hpp:215
Base class for formats taking options.
Definition: gridformat.hpp:166
constexpr Format with(Options _opts) const
Construct a new instance of this format with the given options.
Definition: gridformat.hpp:176
constexpr Format operator()(Options _opts) const
Construct a new instance of this format with the given options.
Definition: gridformat.hpp:171
Closure for selecting the .pvd file format. Takes a VTK-XML format and returns an instance of PVD.
Definition: gridformat.hpp:410
Selector for the .pvd file format for a time series. For more information, see here.
Definition: gridformat.hpp:401
Closure for time series format selection. Takes a sequential format and returns a time series variant...
Definition: gridformat.hpp:426
Selector for the .vti/.pvti image grid file format to be passed to the Writer.
Definition: gridformat.hpp:236
Transient variant of the vtk-hdf image data format.
Definition: gridformat.hpp:316
Selector for the vtk-hdf file format for image grids. For more information, see here.
Definition: gridformat.hpp:308
Selector for the transient vtk-hdf file format with automatic deduction of the flavour....
Definition: gridformat.hpp:348
Transient variant of the vtk-hdf unstructured grid format.
Definition: gridformat.hpp:336
Selector for the vtk-hdf file format for unstructured grids. For more information,...
Definition: gridformat.hpp:328
Selector for the vtk-hdf file format with automatic deduction of the flavour. If the grid for which a...
Definition: gridformat.hpp:366
constexpr VTKHDFTransient with(VTK::HDFTransientOptions opts)
Return the transient variant of this format with the given options.
Definition: gridformat.hpp:374
Base class for VTK-XML formats.
Definition: gridformat.hpp:185
constexpr auto with_compression(VTK::XML::Compressor c) const
Construct a new instance of this format with modified compression option.
Definition: gridformat.hpp:201
constexpr auto with_encoding(VTK::XML::Encoder e) const
Construct a new instance of this format with modified encoding option.
Definition: gridformat.hpp:187
constexpr auto with_data_format(VTK::XML::DataFormat f) const
Construct a new instance of this format with modified data format option.
Definition: gridformat.hpp:194
Selector for a time series of any VTK-XML format.
Definition: gridformat.hpp:292
Selector for the .vtp/.pvtp file format for two-dimensional unstructured grids.
Definition: gridformat.hpp:272
Selector for the .vtr/.pvtr rectilinear grid file format to be passed to the Writer.
Definition: gridformat.hpp:248
Selector for the .vts/.pvts structured grid file format to be passed to the Writer.
Definition: gridformat.hpp:260
Selector for the .vtu/.pvtu file format for general unstructured grids.
Definition: gridformat.hpp:284
Factory class to create a reader for the given file format.
Definition: gridformat.hpp:160
Can be specialized by parallel writers to expose their underlying communicator.
Definition: writer.hpp:40
Can be specialized by writers in case the file format does not contain connectivity information.
Definition: writer.hpp:36
Options for transient vtk-hdf file formats.
Definition: hdf_common.hpp:26
Options for VTK-XML files for setting the desired encoding, data format and compression.
Definition: xml.hpp:99
Factory class to create a writer for the given file format.
Definition: gridformat.hpp:157
A generic writer providing access to the writers for all supported formats.