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 UnavailableReader :
public GridReader {
87 template<
typename... Args>
88 UnavailableReader(Args&&...) {
static_assert(Asserter<Args...>::do_assert()); }
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; }
104#if GRIDFORMAT_HAVE_HIGH_FIVE
107inline constexpr bool _gfmt_api_have_high_five =
true;
110inline constexpr bool _gfmt_api_have_high_five =
false;
111namespace GridFormat {
113template<
typename... T>
114struct VTKHDFAsserter {
115 static constexpr bool do_assert() {
117 APIDetail::always_false<T...>,
118 "VTKHDF reader/writers require HighFive"
124using VTKHDFWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
125using VTKHDFTimeSeriesWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
126using VTKHDFImageGridWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
127using VTKHDFUnstructuredGridWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
128using VTKHDFImageGridTimeSeriesWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
129using VTKHDFUnstructuredTimeSeriesWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
131using VTKHDFImageGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
132template<
typename T =
void>
using VTKHDFUnstructuredGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
133template<
typename T =
void>
using VTKHDFReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
140namespace GridFormat {
151namespace FileFormat {
154template<
typename Format,
typename Opts>
156 using Options = Opts;
157 std::optional<Options> opts = {};
161 return with(std::move(_opts));
165 constexpr Format
with(Options _opts)
const {
167 f.opts = std::move(_opts);
173template<
typename VTKFormat>
178 Variant::unwrap_to(cur_opts.encoder, e);
179 return this->
with(std::move(cur_opts));
185 Variant::unwrap_to(cur_opts.data_format, f);
186 return this->
with(std::move(cur_opts));
192 Variant::unwrap_to(cur_opts.compressor, c);
193 return this->
with(std::move(cur_opts));
280template<
typename VTX>
338 template<
typename Gr
id>
339 constexpr auto from(
const Grid&)
const {
356 template<
typename Gr
id>
357 static constexpr auto from(
const Grid&) {
364 return {std::move(opts)};
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 {};
389template<
typename PieceFormat = Any>
391 PieceFormat piece_format;
400 template<
typename Format>
401 constexpr auto operator()(
const Format& f)
const {
403 Detail::IsVTKXMLFormat<Format>::value,
404 "The PVD format is only available with vtk-xml file formats"
416 template<
typename Format>
417 constexpr auto operator()(
const Format& f)
const {
418 if constexpr (Detail::IsVTKXMLFormat<Format>::value)
420 else if constexpr (std::same_as<VTKHDFImage, Format>)
422 else if constexpr (std::same_as<VTKHDFUnstructured, Format>)
424 else if constexpr (std::same_as<VTKHDF, Format>)
426 else if constexpr (std::same_as<Any, Format>)
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."
445 template<
typename SeqReader,
typename ParReader>
446 class SequentialOrParallelReader :
public GridReader {
448 template<
typename R>
using Communicator =
decltype(CommunicatorAccess<R>::get(std::declval<const R&>()));
449 using ParCommunicator = Communicator<ParReader>;
450 using SeqCommunicator = Communicator<SeqReader>;
453 SequentialOrParallelReader(SeqReader&& seq, ParReader&& par)
454 : _seq_reader{std::move(seq)}
455 , _par_reader{std::move(par)}
458 ParCommunicator communicator()
const {
459 const bool is_parallel = !_use_sequential.value_or(
true);
461 if constexpr (!std::is_same_v<ParCommunicator, SeqCommunicator>)
462 throw InvalidState(
"Cannot access communicator for sequential variant of the reader");
464 return CommunicatorAccess<SeqReader>::get(_seq_reader);
466 return CommunicatorAccess<ParReader>::get(_par_reader);
470 SeqReader _seq_reader;
471 ParReader _par_reader;
472 std::optional<bool> _use_sequential = {};
474 std::string _name()
const override {
475 return _is_set() ? _access().name() : std::string{
"undefined"};
478 void _open(
const std::string& filename,
typename GridReader::FieldNames& names)
override {
480 std::string seq_error;
482 _seq_reader.open(filename);
483 _use_sequential =
true;
484 }
catch (
const std::exception& e) {
485 seq_error = e.what();
486 _use_sequential.reset();
489 _par_reader.open(filename);
490 _use_sequential =
false;
491 }
catch (
const std::exception& par_err) {
492 _use_sequential.reset();
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()
502 ReaderDetail::copy_field_names(_access(), names);
505 void _close()
override {
510 std::size_t _number_of_cells()
const override {
return _access().number_of_cells(); }
511 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(); }
514 FieldPtr _cell_field(std::string_view n)
const override {
return _access().cell_field(n); }
515 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); }
518 FieldPtr _points()
const override {
return _access().points(); }
519 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); }
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); }
527 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);
533 ReaderDetail::copy_field_names(_access(), names);
536 bool _is_set()
const {
return _use_sequential.has_value(); }
537 void _throw_if_not_set()
const {
539 throw IOError(
"No data has been read");
542 GridReader& _access() {
544 return _use_sequential.value()
545 ?
static_cast<GridReader&
>(_seq_reader)
546 :
static_cast<GridReader&
>(_par_reader);
549 const GridReader& _access()
const {
551 return _use_sequential.value()
552 ?
static_cast<const GridReader&
>(_seq_reader)
553 :
static_cast<const GridReader&
>(_par_reader);
557 template<
typename S,
typename P>
558 SequentialOrParallelReader(S&&, P&&) -> SequentialOrParallelReader<std::remove_cvref_t<S>, std::remove_cvref_t<P>>;
560 template<
typename Format,
typename SeqReader,
typename ParReader>
561 struct SequentialOrParallelReaderFactory {
562 template<Concepts::Communicator C = NullCommunicator>
563 static auto make(
const Format&,
const C& comm = null_communicator) {
564 return SequentialOrParallelReader{SeqReader{}, ParReader{comm}};
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}; }
575 template<
typename F,
typename S,
template<
typename>
typename P>
576 struct DefaultTemplatedReaderFactory {
577 static auto make(
const F&) {
return S{}; }
578 template<Concepts::Communicator Communicator>
579 static auto make(
const F&,
const Communicator& comm) {
return P<Communicator>{comm}; }
588template<
typename S,
typename P>
590:
public std::bool_constant<WritesConnectivity<S>::value || WritesConnectivity<P>::value>
604 const Concepts::Communicator
auto& comm) {
611struct ReaderFactory<FileFormat::VTI> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTI, VTIReader, PVTIReader> {};
621 const Concepts::Communicator
auto& comm) {
628struct ReaderFactory<FileFormat::VTR> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTR, VTRReader, PVTRReader> {};
638 const Concepts::Communicator
auto& comm) {
645struct ReaderFactory<FileFormat::VTS> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTS, VTSReader, PVTSReader> {};
655 const Concepts::Communicator
auto& comm) {
662struct ReaderFactory<FileFormat::VTP> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTP, VTPReader, PVTPReader> {};
672 const Concepts::Communicator
auto& comm) {
679struct ReaderFactory<FileFormat::VTU> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTU, VTUReader, PVTUReader> {};
685 const std::string& base_filename) {
693 const Concepts::Communicator
auto& comm,
694 const std::string& base_filename) {
710 const Concepts::Communicator
auto& comm) {
718: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImage,
719 VTKHDFImageGridReader,
720 VTKHDFImageGridReader>
727 const std::string& base_filename) {
728 if (f.opts.has_value())
734 const Concepts::Communicator
auto& comm,
735 const std::string& base_filename) {
736 if (f.opts.has_value())
745: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImageTransient,
746 VTKHDFImageGridReader,
747 VTKHDFImageGridReader>
758 const Concepts::Communicator
auto& comm) {
766: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructured,
767 VTKHDFUnstructuredGridReader<>,
768 VTKHDFUnstructuredGridReader>
775 const std::string& base_filename) {
776 if (f.opts.has_value())
782 const Concepts::Communicator
auto& comm,
783 const std::string& base_filename) {
784 if (f.opts.has_value())
793: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructuredTransient,
794 VTKHDFUnstructuredGridReader<>,
795 VTKHDFUnstructuredGridReader>
802 return _make(format.from(grid), grid);
806 const Concepts::Communicator
auto& comm) {
807 return _make(format.from(grid), grid, comm);
810 template<
typename F,
typename... Args>
811 static auto _make(F&& format, Args&&... args) {
819: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDF, VTKHDFReader<>, VTKHDFReader>
826 const std::string& base_filename) {
827 return _make(format.from(grid), grid, base_filename);
831 const Concepts::Communicator
auto& comm,
832 const std::string& base_filename) {
833 return _make(format.from(grid), grid, comm, base_filename);
836 template<
typename F,
typename... Args>
837 static auto _make(F&& format, Args&&... args) {
845: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFTransient, VTKHDFReader<>, VTKHDFReader>
853 const std::string& base_filename) {
858 const Concepts::Communicator
auto& comm,
859 const std::string& base_filename) {
865template<
typename PieceFormat>
867: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVD<PieceFormat>, PVDReader<>, PVDReader>
873: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVDClosure, PVDReader<>, PVDReader>
881 static constexpr bool is_converter_grid = std::same_as<G, ConverterDetail::ConverterGrid>;
883 template<
typename F,
typename... Args>
884 static auto _make(F&& format, Args&&... args) {
889 template<Concepts::Gr
id G>
890 static constexpr auto default_format_for() {
900 static_assert(APIDetail::always_false<G>,
"Cannot deduce a default format for the given grid");
903 template<Concepts::Gr
id G>
905 return _make(default_format_for<G>(), grid);
908 template<Concepts::Gr
id G, Concepts::Communicator C>
909 static auto make(
const FileFormat::Any&,
const G& grid,
const C& comm) {
910 return _make(default_format_for<G>(), grid, comm);
918 const std::string& base_filename) {
919 return _make(grid, base_filename);
924 const Concepts::Communicator
auto& comm,
925 const std::string& base_filename) {
926 return _make(grid, comm, base_filename);
930 template<
typename Grid,
typename... Args>
931 static auto _make(
const Grid& grid, Args&&... args) {
934 return WriterFactory<
decltype(ts_fmt)>::make(ts_fmt, grid, std::forward<Args>(args)...);
940 bool has_hdf_file_extension(
const std::string& filename) {
941 return filename.ends_with(
".hdf")
942 || filename.ends_with(
".hdf5")
943 || filename.ends_with(
".he5")
944 || filename.ends_with(
".h5");
947 template<std::derived_from<Gr
idReader> Reader,
typename Communicator>
948 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 return std::make_unique<Reader>();
953 return std::make_unique<Reader>(c);
956 template<Concepts::Communicator C>
957 std::unique_ptr<GridReader> make_reader_for(
const std::string& filename,
const C& c) {
958 if (filename.ends_with(
".vtu"))
return make_reader<VTUReader>(c);
959 else if (filename.ends_with(
".vtp"))
return make_reader<VTPReader>(c);
960 else if (filename.ends_with(
".vti"))
return make_reader<VTIReader>(c);
961 else if (filename.ends_with(
".vtr"))
return make_reader<VTRReader>(c);
962 else if (filename.ends_with(
".vts"))
return make_reader<VTSReader>(c);
963 else if (filename.ends_with(
".pvtu"))
return make_reader<PVTUReader>(c);
964 else if (filename.ends_with(
".pvtp"))
return make_reader<PVTPReader>(c);
965 else if (filename.ends_with(
".pvti"))
return make_reader<PVTIReader>(c);
966 else if (filename.ends_with(
".pvtr"))
return make_reader<PVTRReader>(c);
967 else if (filename.ends_with(
".pvts"))
return make_reader<PVTSReader>(c);
968 else if (filename.ends_with(
".pvd"))
return make_reader<PVDReader<C>>(c);
969#if GRIDFORMAT_HAVE_HIGH_FIVE
970 else if (has_hdf_file_extension(filename))
return make_reader<VTKHDFReader<C>>(c);
972 throw IOError(
"Could not deduce an available file format for '" + filename +
"'");
979template<Concepts::Communicator C>
980std::unique_ptr<GridReader> AnyReaderFactory<C>::make_for(
const std::string& filename)
const {
981 return APIDetail::make_reader_for(filename, _comm);
985template<
typename OutFormat,
typename InFormat = FileFormat::Any>
987 OutFormat out_format = {};
988 InFormat in_format = {};
1001template<
typename OutFormat,
1003 typename Communicator = None>
1005 const std::string& out,
1007 const Communicator& communicator = {}) {
1008 static constexpr bool use_communicator = !std::same_as<Communicator, None>;
1010 !use_communicator || Concepts::Communicator<Communicator>,
1011 "Given communicator does not satisfy the communicator concepts."
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;
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>;
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>;
1030 if (opts.verbosity > 0)
1031 std::cout <<
"Opening '" << in <<
"'" << std::endl;
1033 auto reader = [&] () {
1034 if constexpr (use_communicator)
return Reader{opts.in_format, communicator};
1035 else return Reader{opts.in_format};
1038 if constexpr (use_communicator)
1039 if (reader.number_of_pieces() > 1
1040 && reader.number_of_pieces() !=
static_cast<unsigned>(Parallel::size(communicator)))
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()) +
")"
1047 const bool print_progress_output = opts.verbosity > 1 && [&] () {
1048 if constexpr (use_communicator)
return GridFormat::Parallel::rank(communicator) == 0;
1052 const auto step_call_back = [&] (std::size_t step_idx,
const std::string& filename) {
1053 if (print_progress_output)
1054 std::cout <<
"Wrote step " << step_idx <<
" to '" << filename <<
"'" << std::endl;
1057 const auto invoke_factory = [&] <
typename Fmt,
typename... T> (
const Fmt& fmt,
const auto& grid, T&&... args) {
1058 if constexpr (use_communicator)
1059 return WriterFactory<Fmt>::make(fmt, grid, communicator, std::forward<T>(args)...);
1061 return WriterFactory<Fmt>::make(fmt, grid, std::forward<T>(args)...);
1064 if constexpr (is_single_file_out_format) {
1065 if (reader.is_sequence())
1066 return convert(reader, [&] (
const auto& grid) {
1067 return invoke_factory(FileFormat::TimeSeriesClosure{}(opts.out_format), grid, out);
1070 const auto filename =
convert(reader, out, [&] (
const auto& grid) {
1071 return invoke_factory(opts.out_format, grid);
1073 if (print_progress_output)
1074 std::cout <<
"Wrote '" << filename <<
"'" << std::endl;
1076 }
else if constexpr (is_time_series_out_format) {
1077 return convert(reader, [&] (
const auto& grid) {
1078 return invoke_factory(opts.out_format, grid, out);
1082 APIDetail::always_false<OutFormat>,
1083 "No viable factory found for the requested format"
1104inline constexpr FileFormat::Any any;
1105inline constexpr FileFormat::VTI vti;
1106inline constexpr FileFormat::VTR vtr;
1107inline constexpr FileFormat::VTS vts;
1108inline constexpr FileFormat::VTP vtp;
1109inline constexpr FileFormat::VTU vtu;
1110inline constexpr FileFormat::PVD pvd;
1111inline constexpr FileFormat::PVDClosure pvd_with;
1112inline constexpr FileFormat::TimeSeriesClosure time_series;
1113inline constexpr FileFormat::VTKHDF vtk_hdf;
1114inline constexpr FileFormat::VTKHDFTransient vtk_hdf_transient;
1125template<Concepts::Gr
id G>
1133template<Concepts::Gr
id G>
1139using namespace Formats;
1142namespace 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:1126
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:1004
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.