14#ifndef GRIDFORMAT_GRIDFORMAT_HPP_
15#define GRIDFORMAT_GRIDFORMAT_HPP_
27#include <gridformat/common/exceptions.hpp>
28#include <gridformat/parallel/communication.hpp>
56namespace GridFormat::APIDetail {
58 template<
typename... T>
59 inline constexpr bool always_false =
false;
61 template<
typename... T>
62 struct DefaultAsserter {
63 static constexpr bool do_assert() {
66 "Requested reader/writer is unavailable due to missing dependency"
73 template<
template<
typename...>
typename Asserter = DefaultAsserter>
74 class UnavailableWriter :
public GridWriter<ImageGrid<2, double>> {
76 template<
typename... Args>
77 UnavailableWriter(Args&&...) {
static_assert(Asserter<Args...>::do_assert()); }
79 void _throw()
const {
throw GridFormat::NotImplemented(
"Writer unavailable"); }
80 void _write(std::ostream&)
const { _throw(); }
84 template<
template<
typename...>
typename Asserter = DefaultAsserter>
85 class UnavailableTimeSeriesWriter :
public TimeSeriesGridWriter<ImageGrid<2, double>> {
87 template<
typename... Args>
88 UnavailableTimeSeriesWriter(Args&&...) {
static_assert(Asserter<Args...>::do_assert()); }
90 void _throw()
const {
throw GridFormat::NotImplemented(
"Writer unavailable"); }
91 std::string _write(
double)
override { _throw();
return ""; }
95 template<
template<
typename...>
typename Asserter = DefaultAsserter>
96 class UnavailableReader :
public GridReader {
98 template<
typename... Args>
99 UnavailableReader(Args&&...) {
static_assert(Asserter<Args...>::do_assert()); }
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; }
115#if GRIDFORMAT_HAVE_HIGH_FIVE
118inline constexpr bool _gfmt_api_have_high_five =
true;
121inline constexpr bool _gfmt_api_have_high_five =
false;
122namespace GridFormat {
124template<
typename... T>
125struct VTKHDFAsserter {
126 static constexpr bool do_assert() {
128 APIDetail::always_false<T...>,
129 "VTKHDF reader/writers require HighFive"
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>;
142using VTKHDFImageGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
143template<
typename T =
void>
using VTKHDFUnstructuredGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
144template<
typename T =
void>
using VTKHDFReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
151namespace GridFormat {
162namespace FileFormat {
165template<
typename Format,
typename Opts>
167 using Options = Opts;
168 std::optional<Options> opts = {};
172 return with(std::move(_opts));
176 constexpr Format
with(Options _opts)
const {
178 f.opts = std::move(_opts);
184template<
typename VTKFormat>
189 Variant::unwrap_to(cur_opts.encoder, e);
190 return this->
with(std::move(cur_opts));
196 Variant::unwrap_to(cur_opts.data_format, f);
197 return this->
with(std::move(cur_opts));
203 Variant::unwrap_to(cur_opts.compressor, c);
204 return this->
with(std::move(cur_opts));
291template<
typename VTX>
349 template<
typename Gr
id>
350 constexpr auto from(
const Grid&)
const {
367 template<
typename Gr
id>
368 static constexpr auto from(
const Grid&) {
375 return {std::move(opts)};
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 {};
400template<
typename PieceFormat = Any>
402 PieceFormat piece_format;
411 template<
typename Format>
412 constexpr auto operator()(
const Format& f)
const {
414 Detail::IsVTKXMLFormat<Format>::value,
415 "The PVD format is only available with vtk-xml file formats"
427 template<
typename Format>
428 constexpr auto operator()(
const Format& f)
const {
429 if constexpr (Detail::IsVTKXMLFormat<Format>::value)
431 else if constexpr (std::same_as<VTKHDFImage, Format>)
433 else if constexpr (std::same_as<VTKHDFUnstructured, Format>)
435 else if constexpr (std::same_as<VTKHDF, Format>)
437 else if constexpr (std::same_as<Any, Format>)
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."
456 template<
typename SeqReader,
typename ParReader>
457 class SequentialOrParallelReader :
public GridReader {
459 template<
typename R>
using Communicator =
decltype(CommunicatorAccess<R>::get(std::declval<const R&>()));
460 using ParCommunicator = Communicator<ParReader>;
461 using SeqCommunicator = Communicator<SeqReader>;
464 SequentialOrParallelReader(SeqReader&& seq, ParReader&& par)
465 : _seq_reader{std::move(seq)}
466 , _par_reader{std::move(par)}
469 ParCommunicator communicator()
const {
470 const bool is_parallel = !_use_sequential.value_or(
true);
472 if constexpr (!std::is_same_v<ParCommunicator, SeqCommunicator>)
473 throw InvalidState(
"Cannot access communicator for sequential variant of the reader");
475 return CommunicatorAccess<SeqReader>::get(_seq_reader);
477 return CommunicatorAccess<ParReader>::get(_par_reader);
481 SeqReader _seq_reader;
482 ParReader _par_reader;
483 std::optional<bool> _use_sequential = {};
485 std::string _name()
const override {
486 return _is_set() ? _access().name() : std::string{
"undefined"};
489 void _open(
const std::string& filename,
typename GridReader::FieldNames& names)
override {
491 std::string seq_error;
493 _seq_reader.open(filename);
494 _use_sequential =
true;
495 }
catch (
const std::exception& e) {
496 seq_error = e.what();
497 _use_sequential.reset();
500 _par_reader.open(filename);
501 _use_sequential =
false;
502 }
catch (
const std::exception& par_err) {
503 _use_sequential.reset();
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()
513 ReaderDetail::copy_field_names(_access(), names);
516 void _close()
override {
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(); }
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); }
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); }
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); }
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);
544 ReaderDetail::copy_field_names(_access(), names);
547 bool _is_set()
const {
return _use_sequential.has_value(); }
548 void _throw_if_not_set()
const {
550 throw IOError(
"No data has been read");
553 GridReader& _access() {
555 return _use_sequential.value()
556 ?
static_cast<GridReader&
>(_seq_reader)
557 :
static_cast<GridReader&
>(_par_reader);
560 const GridReader& _access()
const {
562 return _use_sequential.value()
563 ?
static_cast<const GridReader&
>(_seq_reader)
564 :
static_cast<const GridReader&
>(_par_reader);
568 template<
typename S,
typename P>
569 SequentialOrParallelReader(S&&, P&&) -> SequentialOrParallelReader<std::remove_cvref_t<S>, std::remove_cvref_t<P>>;
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}};
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}; }
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}; }
599template<
typename S,
typename P>
601:
public std::bool_constant<WritesConnectivity<S>::value || WritesConnectivity<P>::value>
615 const Concepts::Communicator
auto& comm) {
622struct ReaderFactory<FileFormat::VTI> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTI, VTIReader, PVTIReader> {};
632 const Concepts::Communicator
auto& comm) {
639struct ReaderFactory<FileFormat::VTR> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTR, VTRReader, PVTRReader> {};
649 const Concepts::Communicator
auto& comm) {
656struct ReaderFactory<FileFormat::VTS> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTS, VTSReader, PVTSReader> {};
666 const Concepts::Communicator
auto& comm) {
673struct ReaderFactory<FileFormat::VTP> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTP, VTPReader, PVTPReader> {};
683 const Concepts::Communicator
auto& comm) {
690struct ReaderFactory<FileFormat::VTU> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTU, VTUReader, PVTUReader> {};
696 const std::string& base_filename) {
704 const Concepts::Communicator
auto& comm,
705 const std::string& base_filename) {
721 const Concepts::Communicator
auto& comm) {
729: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImage,
730 VTKHDFImageGridReader,
731 VTKHDFImageGridReader>
738 const std::string& base_filename) {
739 if (f.opts.has_value())
745 const Concepts::Communicator
auto& comm,
746 const std::string& base_filename) {
747 if (f.opts.has_value())
756: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImageTransient,
757 VTKHDFImageGridReader,
758 VTKHDFImageGridReader>
769 const Concepts::Communicator
auto& comm) {
777: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructured,
778 VTKHDFUnstructuredGridReader<>,
779 VTKHDFUnstructuredGridReader>
786 const std::string& base_filename) {
787 if (f.opts.has_value())
793 const Concepts::Communicator
auto& comm,
794 const std::string& base_filename) {
795 if (f.opts.has_value())
804: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructuredTransient,
805 VTKHDFUnstructuredGridReader<>,
806 VTKHDFUnstructuredGridReader>
813 return _make(format.from(grid), grid);
817 const Concepts::Communicator
auto& comm) {
818 return _make(format.from(grid), grid, comm);
821 template<
typename F,
typename... Args>
822 static auto _make(F&& format, Args&&... args) {
830: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDF, VTKHDFReader<>, VTKHDFReader>
837 const std::string& base_filename) {
838 return _make(format.from(grid), grid, base_filename);
842 const Concepts::Communicator
auto& comm,
843 const std::string& base_filename) {
844 return _make(format.from(grid), grid, comm, base_filename);
847 template<
typename F,
typename... Args>
848 static auto _make(F&& format, Args&&... args) {
856: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFTransient, VTKHDFReader<>, VTKHDFReader>
864 const std::string& base_filename) {
869 const Concepts::Communicator
auto& comm,
870 const std::string& base_filename) {
876template<
typename PieceFormat>
878: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVD<PieceFormat>, PVDReader<>, PVDReader>
884: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVDClosure, PVDReader<>, PVDReader>
892 static constexpr bool is_converter_grid = std::same_as<G, ConverterDetail::ConverterGrid>;
894 template<
typename F,
typename... Args>
895 static auto _make(F&& format, Args&&... args) {
900 template<Concepts::Gr
id G>
901 static constexpr auto default_format_for() {
911 static_assert(APIDetail::always_false<G>,
"Cannot deduce a default format for the given grid");
914 template<Concepts::Gr
id G>
916 return _make(default_format_for<G>(), grid);
919 template<Concepts::Gr
id 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);
929 const std::string& base_filename) {
930 return _make(grid, base_filename);
935 const Concepts::Communicator
auto& comm,
936 const std::string& base_filename) {
937 return _make(grid, comm, base_filename);
941 template<
typename Grid,
typename... Args>
942 static auto _make(
const Grid& grid, Args&&... args) {
945 return WriterFactory<
decltype(ts_fmt)>::make(ts_fmt, grid, std::forward<Args>(args)...);
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");
958 template<std::derived_from<Gr
idReader> 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>();
964 return std::make_unique<Reader>(c);
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);
983 throw IOError(
"Could not deduce an available file format for '" + filename +
"'");
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);
996template<
typename OutFormat,
typename InFormat = FileFormat::Any>
998 OutFormat out_format = {};
999 InFormat in_format = {};
1012template<
typename OutFormat,
1014 typename Communicator = None>
1016 const std::string& out,
1018 const Communicator& communicator = {}) {
1019 static constexpr bool use_communicator = !std::same_as<Communicator, None>;
1021 !use_communicator || Concepts::Communicator<Communicator>,
1022 "Given communicator does not satisfy the communicator concepts."
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;
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>;
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>;
1041 if (opts.verbosity > 0)
1042 std::cout <<
"Opening '" << in <<
"'" << std::endl;
1044 auto reader = [&] () {
1045 if constexpr (use_communicator)
return Reader{opts.in_format, communicator};
1046 else return Reader{opts.in_format};
1049 if constexpr (use_communicator)
1050 if (reader.number_of_pieces() > 1
1051 && reader.number_of_pieces() !=
static_cast<unsigned>(Parallel::size(communicator)))
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()) +
")"
1058 const bool print_progress_output = opts.verbosity > 1 && [&] () {
1059 if constexpr (use_communicator)
return GridFormat::Parallel::rank(communicator) == 0;
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;
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)...);
1072 return WriterFactory<Fmt>::make(fmt, grid, std::forward<T>(args)...);
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);
1081 const auto filename =
convert(reader, out, [&] (
const auto& grid) {
1082 return invoke_factory(opts.out_format, grid);
1084 if (print_progress_output)
1085 std::cout <<
"Wrote '" << filename <<
"'" << std::endl;
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);
1093 APIDetail::always_false<OutFormat>,
1094 "No viable factory found for the requested format"
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;
1136template<Concepts::Gr
id G>
1144template<Concepts::Gr
id G>
1150using namespace Formats;
1153namespace 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: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.
A generic writer providing access to the writers for all supported formats.