14#ifndef GRIDFORMAT_GRIDFORMAT_HPP_
15#define GRIDFORMAT_GRIDFORMAT_HPP_
28#include <gridformat/common/exceptions.hpp>
29#include <gridformat/common/multi_string.hpp>
30#include <gridformat/parallel/communication.hpp>
58namespace GridFormat::APIDetail {
60 template<
typename... T>
61 inline constexpr bool always_false =
false;
65 inline constexpr bool is_converter_grid = std::same_as<G, ConverterDetail::ConverterGrid>;
67 template<
typename... T>
68 struct DefaultAsserter {
69 static constexpr bool do_assert() {
72 "Requested reader/writer is unavailable due to missing dependency"
79 template<
template<
typename...>
typename Asserter = DefaultAsserter>
80 class UnavailableWriter :
public GridWriter<ImageGrid<2, double>> {
82 template<
typename... Args>
83 UnavailableWriter(Args&&...) {
static_assert(Asserter<Args...>::do_assert()); }
85 void _throw()
const {
throw GridFormat::NotImplemented(
"Writer unavailable"); }
86 void _write(std::ostream&)
const { _throw(); }
90 template<
template<
typename...>
typename Asserter = DefaultAsserter>
91 class UnavailableTimeSeriesWriter :
public TimeSeriesGridWriter<ImageGrid<2, double>> {
93 template<
typename... Args>
94 UnavailableTimeSeriesWriter(Args&&...) {
static_assert(Asserter<Args...>::do_assert()); }
96 void _throw()
const {
throw GridFormat::NotImplemented(
"Writer unavailable"); }
97 std::string _write(
double)
override { _throw();
return ""; }
101 template<
template<
typename...>
typename Asserter = DefaultAsserter>
102 class UnavailableReader :
public GridReader {
104 template<
typename... Args>
105 UnavailableReader(Args&&...) {
static_assert(Asserter<Args...>::do_assert()); }
107 void _throw()
const {
throw GridFormat::NotImplemented(
"Reader unavailable"); }
108 std::string _name()
const override { _throw();
return ""; }
109 void _open(
const std::string&,
typename GridReader::FieldNames&)
override { _throw(); }
110 void _close()
override { _throw(); }
111 std::size_t _number_of_cells()
const override { _throw();
return 0; }
112 std::size_t _number_of_points()
const override { _throw();
return 0; }
113 FieldPtr _cell_field(std::string_view)
const override { _throw();
return nullptr; }
114 FieldPtr _point_field(std::string_view)
const override { _throw();
return nullptr; }
115 FieldPtr _meta_data_field(std::string_view)
const override { _throw();
return nullptr; }
116 bool _is_sequence()
const override { _throw();
return false; }
121#if GRIDFORMAT_HAVE_HIGH_FIVE
124inline constexpr bool _gfmt_api_have_high_five =
true;
127inline constexpr bool _gfmt_api_have_high_five =
false;
128namespace GridFormat {
130template<
typename... T>
131struct VTKHDFAsserter {
132 static constexpr bool do_assert() {
134 APIDetail::always_false<T...>,
135 "VTKHDF reader/writers require HighFive"
141using VTKHDFWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
150template<
typename T =
void>
using VTKHDFReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
157namespace GridFormat {
168namespace FileFormat {
171template<
typename Format,
typename Opts>
173 using Options = Opts;
174 std::optional<Options> opts = {};
178 return with(std::move(_opts));
182 constexpr Format
with(Options _opts)
const {
184 f.opts = std::move(_opts);
190template<
typename VTKFormat>
195 Variant::unwrap_to(cur_opts.encoder, e);
196 return this->
with(std::move(cur_opts));
202 Variant::unwrap_to(cur_opts.data_format, f);
203 return this->
with(std::move(cur_opts));
209 Variant::unwrap_to(cur_opts.compressor, c);
210 return this->
with(std::move(cur_opts));
297template<
typename VTX>
358 template<
typename Gr
id>
359 constexpr auto from(
const Grid&)
const {
378 template<
typename Gr
id>
379 static constexpr auto from(
const Grid&) {
388 return {std::move(opts)};
395 template<
typename F>
struct IsVTKXMLFormat :
public std::false_type {};
396 template<>
struct IsVTKXMLFormat<VTI> :
public std::true_type {};
397 template<>
struct IsVTKXMLFormat<VTR> :
public std::true_type {};
398 template<>
struct IsVTKXMLFormat<VTS> :
public std::true_type {};
399 template<>
struct IsVTKXMLFormat<VTP> :
public std::true_type {};
400 template<>
struct IsVTKXMLFormat<VTU> :
public std::true_type {};
413template<
typename PieceFormat = Any>
415 PieceFormat piece_format;
424 template<
typename Format>
425 constexpr auto operator()(
const Format& f)
const {
427 Detail::IsVTKXMLFormat<Format>::value,
428 "The PVD format is only available with vtk-xml file formats"
440 template<
typename Format>
441 constexpr auto operator()(
const Format& f)
const {
442 if constexpr (Detail::IsVTKXMLFormat<Format>::value)
444 else if constexpr (std::same_as<VTKHDFImage, Format>)
446 else if constexpr (std::same_as<VTKHDFUnstructured, Format>)
448 else if constexpr (std::same_as<VTKHDF, Format>)
450 else if constexpr (std::same_as<Any, Format>)
454 APIDetail::always_false<Format>,
455 "Cannot create a time series variant for the given format. This means the format does not "
456 "define a variant for time series, or, the selected format is already time series format."
469 template<
typename SeqReader,
typename ParReader>
470 class SequentialOrParallelReader :
public GridReader {
472 template<
typename R>
using Communicator =
decltype(CommunicatorAccess<R>::get(std::declval<const R&>()));
473 using ParCommunicator = Communicator<ParReader>;
474 using SeqCommunicator = Communicator<SeqReader>;
477 SequentialOrParallelReader(SeqReader&& seq, ParReader&& par)
478 : _seq_reader{std::move(seq)}
479 , _par_reader{std::move(par)}
482 ParCommunicator communicator()
const {
483 const bool is_parallel = !_use_sequential.value_or(
true);
485 if constexpr (!std::is_same_v<ParCommunicator, SeqCommunicator>)
486 throw InvalidState(
"Cannot access communicator for sequential variant of the reader");
488 return CommunicatorAccess<SeqReader>::get(_seq_reader);
490 return CommunicatorAccess<ParReader>::get(_par_reader);
494 SeqReader _seq_reader;
495 ParReader _par_reader;
496 std::optional<bool> _use_sequential = {};
498 std::string _name()
const override {
499 return _is_set() ? _access().name() : std::string{
"undefined"};
502 void _open(
const std::string& filename,
typename GridReader::FieldNames& names)
override {
504 std::string seq_error;
506 _seq_reader.open(filename);
507 _use_sequential =
true;
508 }
catch (
const std::exception& e) {
509 seq_error = e.what();
510 _use_sequential.reset();
513 _par_reader.open(filename);
514 _use_sequential =
false;
515 }
catch (
const std::exception& par_err) {
516 _use_sequential.reset();
519 "Could not read '" + filename +
"' neither as sequential nor parallel format.\n"
520 "Error with sequential format (" + _seq_reader.name() +
"): " + seq_error +
"\n"
521 "Error with parallel format (" + _par_reader.name() +
"): " + par_err.what()
526 ReaderDetail::copy_field_names(_access(), names);
529 void _close()
override {
534 std::size_t _number_of_cells()
const override {
return _access().number_of_cells(); }
535 std::size_t _number_of_points()
const override {
return _access().number_of_points(); }
536 std::size_t _number_of_pieces()
const override {
return _access().number_of_pieces(); }
538 FieldPtr _cell_field(std::string_view n)
const override {
return _access().cell_field(n); }
539 FieldPtr _point_field(std::string_view n)
const override {
return _access().point_field(n); }
540 FieldPtr _meta_data_field(std::string_view n)
const override {
return _access().meta_data_field(n); }
542 FieldPtr _points()
const override {
return _access().points(); }
543 void _visit_cells(
const typename GridReader::CellVisitor& v)
const override { _access().visit_cells(v); }
544 std::vector<double> _ordinates(
unsigned int i)
const override {
return _access().ordinates(i); }
546 typename GridReader::PieceLocation _location()
const override {
return _access().location(); }
547 typename GridReader::Vector _spacing()
const override {
return _access().spacing(); }
548 typename GridReader::Vector _origin()
const override {
return _access().origin(); }
549 typename GridReader::Vector _basis_vector(
unsigned int i)
const override {
return _access().basis_vector(i); }
551 bool _is_sequence()
const override {
return _access().is_sequence(); }
552 std::size_t _number_of_steps()
const override {
return _access().number_of_steps(); }
553 double _time_at_step(std::size_t i)
const override {
return _access().time_at_step(i); }
554 void _set_step(std::size_t i,
typename GridReader::FieldNames& names)
override {
555 _access().set_step(i);
557 ReaderDetail::copy_field_names(_access(), names);
560 bool _is_set()
const {
return _use_sequential.has_value(); }
561 void _throw_if_not_set()
const {
563 throw IOError(
"No data has been read");
566 GridReader& _access() {
568 return _use_sequential.value()
569 ?
static_cast<GridReader&
>(_seq_reader)
570 : static_cast<GridReader&>(_par_reader);
573 const GridReader& _access()
const {
575 return _use_sequential.value()
576 ?
static_cast<const GridReader&
>(_seq_reader)
577 : static_cast<const GridReader&>(_par_reader);
581 template<
typename S,
typename P>
582 SequentialOrParallelReader(S&&, P&&) -> SequentialOrParallelReader<std::remove_cvref_t<S>, std::remove_cvref_t<P>>;
584 template<
typename Format,
typename SeqReader,
typename ParReader>
585 struct SequentialOrParallelReaderFactory {
586 template<Concepts::Communicator C = NullCommunicator>
587 static auto make(
const Format&,
const C& comm = null_communicator) {
588 return SequentialOrParallelReader{SeqReader{}, ParReader{comm}};
592 template<
typename Format,
typename SequentialReader,
typename ParallelReader>
593 struct DefaultReaderFactory {
594 static auto make(
const Format&) {
return SequentialReader{}; }
595 static auto make(
const Format&,
const Concepts::Communicator
auto& comm) {
return ParallelReader{comm}; }
599 template<
typename F,
typename S,
template<
typename>
typename P>
600 struct DefaultTemplatedReaderFactory {
601 static auto make(
const F&) {
return S{}; }
602 template<Concepts::Communicator Communicator>
603 static auto make(
const F&,
const Communicator& comm) {
return P<Communicator>{comm}; }
612template<
typename S,
typename P>
614:
public std::bool_constant<WritesConnectivity<S>::value || WritesConnectivity<P>::value>
628 const Concepts::Communicator
auto& comm) {
635struct ReaderFactory<FileFormat::VTI> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTI, VTIReader, PVTIReader> {};
645 const Concepts::Communicator
auto& comm) {
652struct ReaderFactory<FileFormat::VTR> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTR, VTRReader, PVTRReader> {};
662 const Concepts::Communicator
auto& comm) {
669struct ReaderFactory<FileFormat::VTS> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTS, VTSReader, PVTSReader> {};
679 const Concepts::Communicator
auto& comm) {
686struct ReaderFactory<FileFormat::VTP> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTP, VTPReader, PVTPReader> {};
696 const Concepts::Communicator
auto& comm) {
703struct ReaderFactory<FileFormat::VTU> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTU, VTUReader, PVTUReader> {};
709 const std::string& base_filename) {
717 const Concepts::Communicator
auto& comm,
718 const std::string& base_filename) {
734 const Concepts::Communicator
auto& comm) {
742: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImage,
743 VTKHDFImageGridReader,
744 VTKHDFImageGridReader>
751 const std::string& base_filename) {
752 if (f.opts.has_value())
758 const Concepts::Communicator
auto& comm,
759 const std::string& base_filename) {
760 if (f.opts.has_value())
769: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImageTransient,
770 VTKHDFImageGridReader,
771 VTKHDFImageGridReader>
782 const Concepts::Communicator
auto& comm) {
790: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructured,
791 VTKHDFUnstructuredGridReader<>,
792 VTKHDFUnstructuredGridReader>
799 const std::string& base_filename) {
800 if (f.opts.has_value())
806 const Concepts::Communicator
auto& comm,
807 const std::string& base_filename) {
808 if (f.opts.has_value())
817: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructuredTransient,
818 VTKHDFUnstructuredGridReader<>,
819 VTKHDFUnstructuredGridReader>
826 return _make(format.from(grid), grid);
830 const Concepts::Communicator
auto& comm) {
831 return _make(format.from(grid), grid, comm);
834 template<
typename F,
typename... Args>
835 static auto _make(F&& format, Args&&... args) {
843: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDF, VTKHDFReader<>, VTKHDFReader>
850 const std::string& base_filename) {
851 return _make(format.from(grid), grid, base_filename);
855 const Concepts::Communicator
auto& comm,
856 const std::string& base_filename) {
857 return _make(format.from(grid), grid, comm, base_filename);
860 template<
typename F,
typename... Args>
861 static auto _make(F&& format, Args&&... args) {
869: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFTransient, VTKHDFReader<>, VTKHDFReader>
877 const std::string& base_filename) {
882 const Concepts::Communicator
auto& comm,
883 const std::string& base_filename) {
889template<
typename PieceFormat>
891: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVD<PieceFormat>, PVDReader<>, PVDReader>
897: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVDClosure, PVDReader<>, PVDReader>
904 template<
typename F,
typename... Args>
905 static auto _make(F&& format, Args&&... args) {
910 template<Concepts::Gr
id G>
911 static constexpr auto default_format_for() {
921 static_assert(APIDetail::always_false<G>,
"Cannot deduce a default format for the given grid");
924 template<Concepts::Gr
id G>
926 return _make(default_format_for<G>(), grid);
929 template<Concepts::Gr
id G, Concepts::Communicator C>
930 static auto make(
const FileFormat::Any&,
const G& grid,
const C& comm) {
931 return _make(default_format_for<G>(), grid, comm);
939 const std::string& base_filename) {
940 return _make(grid, base_filename);
945 const Concepts::Communicator
auto& comm,
946 const std::string& base_filename) {
947 return _make(grid, comm, base_filename);
951 template<
typename Grid,
typename... Args>
952 static auto _make(
const Grid& grid, Args&&... args) {
955 return WriterFactory<
decltype(ts_fmt)>::make(ts_fmt, grid, std::forward<Args>(args)...);
961 inline bool has_hdf_file_extension(
const std::string& filename) {
962 return filename.ends_with(
".hdf")
963 || filename.ends_with(
".hdf5")
964 || filename.ends_with(
".he5")
965 || filename.ends_with(
".h5");
968 template<std::derived_from<Gr
idReader> Reader,
typename Communicator>
969 std::unique_ptr<Reader> make_reader(
const Communicator& c) {
970 if constexpr (std::is_same_v<Communicator, NullCommunicator> ||
971 !std::is_constructible_v<Reader, const Communicator&>)
972 return std::make_unique<Reader>();
974 return std::make_unique<Reader>(c);
977 template<Concepts::Communicator C>
978 std::unique_ptr<GridReader> make_reader_for(
const std::string& filename,
const C& c) {
979 if (filename.ends_with(
".vtu"))
return make_reader<VTUReader>(c);
980 else if (filename.ends_with(
".vtp"))
return make_reader<VTPReader>(c);
981 else if (filename.ends_with(
".vti"))
return make_reader<VTIReader>(c);
982 else if (filename.ends_with(
".vtr"))
return make_reader<VTRReader>(c);
983 else if (filename.ends_with(
".vts"))
return make_reader<VTSReader>(c);
984 else if (filename.ends_with(
".pvtu"))
return make_reader<PVTUReader>(c);
985 else if (filename.ends_with(
".pvtp"))
return make_reader<PVTPReader>(c);
986 else if (filename.ends_with(
".pvti"))
return make_reader<PVTIReader>(c);
987 else if (filename.ends_with(
".pvtr"))
return make_reader<PVTRReader>(c);
988 else if (filename.ends_with(
".pvts"))
return make_reader<PVTSReader>(c);
989 else if (filename.ends_with(
".pvd"))
return make_reader<PVDReader<C>>(c);
990#if GRIDFORMAT_HAVE_HIGH_FIVE
991 else if (has_hdf_file_extension(filename))
return make_reader<VTKHDFReader<C>>(c);
993 throw IOError(
"Could not deduce an available file format for '" + filename +
"'");
1000template<Concepts::Communicator C>
1001std::unique_ptr<GridReader> AnyReaderFactory<C>::make_for(
const std::string& filename)
const {
1002 return APIDetail::make_reader_for(filename, _comm);
1006template<
typename OutFormat,
typename InFormat = FileFormat::Any>
1008 OutFormat out_format = {};
1009 InFormat in_format = {};
1022template<
typename OutFormat,
1024 typename Communicator = None>
1026 const std::string& out,
1028 const Communicator& communicator = {}) {
1029 static constexpr bool use_communicator = !std::same_as<Communicator, None>;
1031 !use_communicator || Concepts::Communicator<Communicator>,
1032 "Given communicator does not satisfy the communicator concepts."
1035 using WriterDetail::has_parallel_factory;
1036 using WriterDetail::has_sequential_factory;
1037 using WriterDetail::has_parallel_time_series_factory;
1038 using WriterDetail::has_sequential_time_series_factory;
1039 using CG = ConverterDetail::ConverterGrid;
1041 static constexpr bool is_single_file_out_format = [&] () {
1042 if constexpr (use_communicator)
return has_parallel_factory<OutFormat, CG, Communicator>;
1043 else return has_sequential_factory<OutFormat, CG>;
1046 static constexpr bool is_time_series_out_format = [&] () {
1047 if constexpr (use_communicator)
return has_parallel_time_series_factory<OutFormat, CG, Communicator>;
1048 else return has_sequential_time_series_factory<OutFormat, CG>;
1051 if (opts.verbosity > 0)
1052 std::cout <<
"Opening '" << in <<
"'" << std::endl;
1054 auto reader = [&] () {
1055 if constexpr (use_communicator)
return Reader{opts.in_format, communicator};
1056 else return Reader{opts.in_format};
1059 if constexpr (use_communicator)
1060 if (reader.number_of_pieces() > 1
1061 && reader.number_of_pieces() !=
static_cast<unsigned>(Parallel::size(communicator)))
1063 "Can only convert parallel files if the number of processes matches "
1064 "the number of processes that were used to write the original file "
1065 "(" + std::to_string(reader.number_of_pieces()) +
")"
1068 const bool print_progress_output = opts.verbosity > 1 && [&] () {
1069 if constexpr (use_communicator)
return GridFormat::Parallel::rank(communicator) == 0;
1073 const auto step_call_back = [&] (std::size_t step_idx,
const std::string& filename) {
1074 if (print_progress_output)
1075 std::cout <<
"Wrote step " << step_idx <<
" to '" << filename <<
"'" << std::endl;
1078 const auto invoke_factory = [&] <
typename Fmt,
typename... T> (
const Fmt& fmt,
const auto& grid, T&&... args) {
1079 if constexpr (use_communicator)
1085 if constexpr (is_single_file_out_format) {
1086 if (reader.is_sequence())
1087 return convert(reader, [&] (
const auto& grid) {
1091 const auto filename =
convert(reader, out, [&] (
const auto& grid) {
1092 return invoke_factory(opts.out_format, grid);
1094 if (print_progress_output)
1095 std::cout <<
"Wrote '" << filename <<
"'" << std::endl;
1097 }
else if constexpr (is_time_series_out_format) {
1098 return convert(reader, [&] (
const auto& grid) {
1099 return invoke_factory(opts.out_format, grid, out);
1103 APIDetail::always_false<OutFormat>,
1104 "No viable factory found for the requested format"
1125inline constexpr FileFormat::Any any;
1126inline constexpr FileFormat::VTI vti;
1127inline constexpr FileFormat::VTR vtr;
1128inline constexpr FileFormat::VTS vts;
1129inline constexpr FileFormat::VTP vtp;
1130inline constexpr FileFormat::VTU vtu;
1131inline constexpr FileFormat::PVD pvd;
1132inline constexpr FileFormat::PVDClosure pvd_with;
1133inline constexpr FileFormat::TimeSeriesClosure time_series;
1134inline constexpr FileFormat::VTKHDF vtk_hdf;
1135inline constexpr FileFormat::VTKHDFTransient vtk_hdf_transient;
1146template<Concepts::Gr
id G>
1154template<Concepts::Gr
id G>
1160using namespace Formats;
1163namespace FileFormat {
using namespace Formats; }
Converter between grid formats.
constexpr auto default_for()
Selects a default format suitable to write the given grid.
Definition gridformat.hpp:1147
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:1025
std::shared_ptr< const Field > FieldPtr
Pointer type used by writers/readers for fields.
Definition field.hpp:205
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.
Reader for .pvd time series file format.
Writer for .pvd time-series file format.
Writer for parallel .pvti files.
Writer for parallel .pvtu files.
Writer for parallel .pvtr files.
Writer for parallel .pvts files.
Writer for parallel .pvtu files.
A generic reader providing access to the readers for all supported formats.
Reader for .vti file format.
Writer for .vti file format.
Reader for .vtp file format.
Writer for .vtu file format.
Reader for .vtr file format.
Writer for .vtr file format.
Reader for .vts file format.
Writer for .vts file format.
Reader for .vtu file format.
Writer for .vtu file format.
A generic writer providing access to the writers for all supported formats.
Writer for time series of a VTK-XML file format. Populates the "TimeValue" metadata field supported b...