GridFormat 0.6.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#include <concepts>
21
22#include <gridformat/reader.hpp>
23#include <gridformat/writer.hpp>
24
27
28#include <gridformat/common/exceptions.hpp>
29#include <gridformat/common/multi_string.hpp>
30#include <gridformat/parallel/communication.hpp>
31
35
39
43
47
51
54
56
57#ifndef DOXYGEN
58namespace GridFormat::APIDetail {
59
60 template<typename... T>
61 inline constexpr bool always_false = false;
62
63 // The converter grid satisfies all grid concepts, but its actual type is only known at runtime
64 template<typename G>
65 inline constexpr bool is_converter_grid = std::same_as<G, ConverterDetail::ConverterGrid>;
66
67 template<typename... T>
68 struct DefaultAsserter {
69 static constexpr bool do_assert() {
70 static_assert(
71 always_false<T...>,
72 "Requested reader/writer is unavailable due to missing dependency"
73 );
74 return false;
75 }
76 };
77
78 // Derive from GridWriter to make this a "valid" writer (and abuse some valid grid impl for that)
79 template<template<typename...> typename Asserter = DefaultAsserter>
80 class UnavailableWriter : public GridWriter<ImageGrid<2, double>> {
81 public:
82 template<typename... Args>
83 UnavailableWriter(Args&&...) { static_assert(Asserter<Args...>::do_assert()); }
84 private:
85 void _throw() const { throw GridFormat::NotImplemented("Writer unavailable"); }
86 void _write(std::ostream&) const { _throw(); }
87 };
88
89 // Derive from TimeSeriesGridWriter to make this a "valid" writer (and abuse some valid grid impl for that)
90 template<template<typename...> typename Asserter = DefaultAsserter>
91 class UnavailableTimeSeriesWriter : public TimeSeriesGridWriter<ImageGrid<2, double>> {
92 public:
93 template<typename... Args>
94 UnavailableTimeSeriesWriter(Args&&...) { static_assert(Asserter<Args...>::do_assert()); }
95 private:
96 void _throw() const { throw GridFormat::NotImplemented("Writer unavailable"); }
97 std::string _write(double) override { _throw(); return ""; }
98 };
99
100 // Derive from Reader to make this a "valid" reader
101 template<template<typename...> typename Asserter = DefaultAsserter>
102 class UnavailableReader : public GridReader {
103 public:
104 template<typename... Args>
105 UnavailableReader(Args&&...) { static_assert(Asserter<Args...>::do_assert()); }
106 private:
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; }
117 };
118
119} // namespace GridFormat::APIDetail
120
121#if GRIDFORMAT_HAVE_HIGH_FIVE
124inline constexpr bool _gfmt_api_have_high_five = true;
125#else
127inline constexpr bool _gfmt_api_have_high_five = false;
128namespace GridFormat {
129
130template<typename... T>
131struct VTKHDFAsserter {
132 static constexpr bool do_assert() {
133 static_assert(
134 APIDetail::always_false<T...>,
135 "VTKHDF reader/writers require HighFive"
136 );
137 return false;
138 }
139};
140
141using VTKHDFWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
142using VTKHDFTimeSeriesWriter = APIDetail::UnavailableTimeSeriesWriter<VTKHDFAsserter>;
143using VTKHDFImageGridWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
144using VTKHDFUnstructuredGridWriter = APIDetail::UnavailableWriter<VTKHDFAsserter>;
145using VTKHDFImageGridTimeSeriesWriter = APIDetail::UnavailableTimeSeriesWriter<VTKHDFAsserter>;
146using VTKHDFUnstructuredTimeSeriesWriter = APIDetail::UnavailableTimeSeriesWriter<VTKHDFAsserter>;
147
148using VTKHDFImageGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
149template<typename T = void> using VTKHDFUnstructuredGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
150template<typename T = void> using VTKHDFReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
151
152} // namespace GridFormat
153#endif // GRIDFORMAT_HAVE_HIGH_FIVE
154#endif // DOXYGEN
155
156
157namespace GridFormat {
158
160inline constexpr GridFormat::NullCommunicator null_communicator;
161
163template<typename FileFormat> struct WriterFactory;
164
166template<typename FileFormat> struct ReaderFactory;
167
168namespace FileFormat {
169
171template<typename Format, typename Opts>
173 using Options = Opts;
174 std::optional<Options> opts = {};
175
177 constexpr Format operator()(Options _opts) const {
178 return with(std::move(_opts));
179 }
180
182 constexpr Format with(Options _opts) const {
183 Format f;
184 f.opts = std::move(_opts);
185 return f;
186 }
187};
188
190template<typename VTKFormat>
191struct VTKXMLFormatBase : public FormatWithOptions<VTKFormat, VTK::XMLOptions> {
193 constexpr auto with_encoding(VTK::XML::Encoder e) const {
194 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
195 Variant::unwrap_to(cur_opts.encoder, e);
196 return this->with(std::move(cur_opts));
197 }
198
200 constexpr auto with_data_format(VTK::XML::DataFormat f) const {
201 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
202 Variant::unwrap_to(cur_opts.data_format, f);
203 return this->with(std::move(cur_opts));
204 }
205
207 constexpr auto with_compression(VTK::XML::Compressor c) const {
208 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
209 Variant::unwrap_to(cur_opts.compressor, c);
210 return this->with(std::move(cur_opts));
211 }
212};
213
214
221struct Any {};
222
223
230
231
242struct VTI : VTKXMLFormatBase<VTI> {};
243
254struct VTR : VTKXMLFormatBase<VTR> {};
255
266struct VTS : VTKXMLFormatBase<VTS> {};
267
278struct VTP : VTKXMLFormatBase<VTP> {};
279
290struct VTU : VTKXMLFormatBase<VTU> {};
291
297template<typename VTX>
298struct VTKXMLTimeSeries : VTKXMLFormatBase<VTKXMLTimeSeries<VTX>> {};
299
300
317struct VTKHDFImage {};
318
325: FormatWithOptions<VTKHDFImageTransient, VTK::HDFTransientOptions> {};
326
338
345: FormatWithOptions<VTKHDFUnstructuredTransient, VTK::HDFTransientOptions> {};
346
357struct VTKHDFTransient : FormatWithOptions<VTKHDFTransient, VTK::HDFTransientOptions> {
358 template<typename Grid>
359 constexpr auto from(const Grid&) const {
360 if constexpr (Concepts::ImageGrid<Grid> && !APIDetail::is_converter_grid<Grid>)
361 return VTKHDFImageTransient{this->opts};
362 else
363 return VTKHDFUnstructuredTransient{this->opts};
364 }
365};
366
377struct VTKHDF {
378 template<typename Grid>
379 static constexpr auto from(const Grid&) {
380 if constexpr (Concepts::ImageGrid<Grid> && !APIDetail::is_converter_grid<Grid>)
381 return VTKHDFImage{};
382 else
383 return VTKHDFUnstructured{};
384 }
385
388 return {std::move(opts)};
389 }
390};
391
392#ifndef DOXYGEN
393namespace Detail {
394
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 {};
401
402} // namespace Detail
403#endif // DOXYGEN
404
413template<typename PieceFormat = Any>
414struct PVD {
415 PieceFormat piece_format;
416};
417
424 template<typename Format>
425 constexpr auto operator()(const Format& f) const {
426 static_assert(
427 Detail::IsVTKXMLFormat<Format>::value,
428 "The PVD format is only available with vtk-xml file formats"
429 );
430 return PVD<Format>{f};
431 }
432};
433
440 template<typename Format>
441 constexpr auto operator()(const Format& f) const {
442 if constexpr (Detail::IsVTKXMLFormat<Format>::value)
443 return VTKXMLTimeSeries<Format>{f.opts};
444 else if constexpr (std::same_as<VTKHDFImage, Format>)
445 return VTKHDFImageTransient{};
446 else if constexpr (std::same_as<VTKHDFUnstructured, Format>)
448 else if constexpr (std::same_as<VTKHDF, Format>)
449 return VTKHDFTransient{};
450 else if constexpr (std::same_as<Any, Format>)
451 return AnyTimeSeries{};
452 else {
453 static_assert(
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."
457 );
458 }
459 }
460};
461
462} // namespace FileFormat
463
464
465#ifndef DOXYGEN
466namespace APIDetail {
467
468 // Meta-Reader for file formats that have different format flavours in parallel/sequential
469 template<typename SeqReader, typename ParReader>
470 class SequentialOrParallelReader : public GridReader {
471 template<typename R> using CommunicatorAccess = Traits::CommunicatorAccess<R>;
472 template<typename R> using Communicator = decltype(CommunicatorAccess<R>::get(std::declval<const R&>()));
473 using ParCommunicator = Communicator<ParReader>;
474 using SeqCommunicator = Communicator<SeqReader>;
475
476 public:
477 SequentialOrParallelReader(SeqReader&& seq, ParReader&& par)
478 : _seq_reader{std::move(seq)}
479 , _par_reader{std::move(par)}
480 {}
481
482 ParCommunicator communicator() const {
483 const bool is_parallel = !_use_sequential.value_or(true);
484 if (!is_parallel) {
485 if constexpr (!std::is_same_v<ParCommunicator, SeqCommunicator>)
486 throw InvalidState("Cannot access communicator for sequential variant of the reader");
487 else
488 return CommunicatorAccess<SeqReader>::get(_seq_reader);
489 }
490 return CommunicatorAccess<ParReader>::get(_par_reader);
491 }
492
493 private:
494 SeqReader _seq_reader;
495 ParReader _par_reader;
496 std::optional<bool> _use_sequential = {};
497
498 std::string _name() const override {
499 return _is_set() ? _access().name() : std::string{"undefined"};
500 }
501
502 void _open(const std::string& filename, typename GridReader::FieldNames& names) override {
503 _close();
504 std::string seq_error;
505 try {
506 _seq_reader.open(filename);
507 _use_sequential = true;
508 } catch (const std::exception& e) {
509 seq_error = e.what();
510 _use_sequential.reset();
511 _seq_reader.close();
512 try {
513 _par_reader.open(filename);
514 _use_sequential = false;
515 } catch (const std::exception& par_err) {
516 _use_sequential.reset();
517 _par_reader.close();
518 throw IOError(
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()
522 );
523 }
524 }
525
526 ReaderDetail::copy_field_names(_access(), names);
527 }
528
529 void _close() override {
530 if (_is_set())
531 _access().close();
532 }
533
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(); }
537
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); }
541
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); }
545
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); }
550
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);
556 names.clear();
557 ReaderDetail::copy_field_names(_access(), names);
558 }
559
560 bool _is_set() const { return _use_sequential.has_value(); }
561 void _throw_if_not_set() const {
562 if (!_is_set())
563 throw IOError("No data has been read");
564 }
565
566 GridReader& _access() {
567 _throw_if_not_set();
568 return _use_sequential.value()
569 ? static_cast<GridReader&>(_seq_reader)
570 : static_cast<GridReader&>(_par_reader);
571 }
572
573 const GridReader& _access() const {
574 _throw_if_not_set();
575 return _use_sequential.value()
576 ? static_cast<const GridReader&>(_seq_reader)
577 : static_cast<const GridReader&>(_par_reader);
578 }
579 };
580
581 template<typename S, typename P>
582 SequentialOrParallelReader(S&&, P&&) -> SequentialOrParallelReader<std::remove_cvref_t<S>, std::remove_cvref_t<P>>;
583
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}};
589 }
590 };
591
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}; }
596 };
597
598 // Specialization for cases where the parallel reader is templated on the communicator
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}; }
604 };
605
606} // namespace APIDetail
607#endif // DOXYGEN
608
609// Traits specializations for SequentialOrParallelReader
610namespace Traits {
611
612template<typename S, typename P>
613struct WritesConnectivity<APIDetail::SequentialOrParallelReader<S, P>>
614: public std::bool_constant<WritesConnectivity<S>::value || WritesConnectivity<P>::value>
615{};
616
617} // namespace Traits
618
620template<> struct WriterFactory<FileFormat::VTI> {
621 static auto make(const FileFormat::VTI& format,
622 const Concepts::ImageGrid auto& grid) {
623 return VTIWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
624 }
625
626 static auto make(const FileFormat::VTI& format,
627 const Concepts::ImageGrid auto& grid,
628 const Concepts::Communicator auto& comm) {
629 return PVTIWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
630 }
631};
632
634template<>
635struct ReaderFactory<FileFormat::VTI> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTI, VTIReader, PVTIReader> {};
636
638template<> struct WriterFactory<FileFormat::VTR> {
639 static auto make(const FileFormat::VTR& format,
640 const Concepts::RectilinearGrid auto& grid) {
641 return VTRWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
642 }
643 static auto make(const FileFormat::VTR& format,
644 const Concepts::RectilinearGrid auto& grid,
645 const Concepts::Communicator auto& comm) {
646 return PVTRWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
647 }
648};
649
651template<>
652struct ReaderFactory<FileFormat::VTR> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTR, VTRReader, PVTRReader> {};
653
655template<> struct WriterFactory<FileFormat::VTS> {
656 static auto make(const FileFormat::VTS& format,
657 const Concepts::StructuredGrid auto& grid) {
658 return VTSWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
659 }
660 static auto make(const FileFormat::VTS& format,
661 const Concepts::StructuredGrid auto& grid,
662 const Concepts::Communicator auto& comm) {
663 return PVTSWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
664 }
665};
666
668template<>
669struct ReaderFactory<FileFormat::VTS> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTS, VTSReader, PVTSReader> {};
670
672template<> struct WriterFactory<FileFormat::VTP> {
673 static auto make(const FileFormat::VTP& format,
674 const Concepts::UnstructuredGrid auto& grid) {
675 return VTPWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
676 }
677 static auto make(const FileFormat::VTP& format,
678 const Concepts::UnstructuredGrid auto& grid,
679 const Concepts::Communicator auto& comm) {
680 return PVTPWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
681 }
682};
683
685template<>
686struct ReaderFactory<FileFormat::VTP> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTP, VTPReader, PVTPReader> {};
687
689template<> struct WriterFactory<FileFormat::VTU> {
690 static auto make(const FileFormat::VTU& format,
691 const Concepts::UnstructuredGrid auto& grid) {
692 return VTUWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
693 }
694 static auto make(const FileFormat::VTU& format,
695 const Concepts::UnstructuredGrid auto& grid,
696 const Concepts::Communicator auto& comm) {
697 return PVTUWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
698 }
699};
700
702template<>
703struct ReaderFactory<FileFormat::VTU> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTU, VTUReader, PVTUReader> {};
704
706template<typename F> struct WriterFactory<FileFormat::VTKXMLTimeSeries<F>> {
707 static auto make(const FileFormat::VTKXMLTimeSeries<F>& format,
708 const Concepts::UnstructuredGrid auto& grid,
709 const std::string& base_filename) {
711 WriterFactory<F>::make(F{format.opts.value_or(VTK::XMLOptions{})}, grid),
712 base_filename
713 };
714 }
715 static auto make(const FileFormat::VTKXMLTimeSeries<F>& format,
716 const Concepts::UnstructuredGrid auto& grid,
717 const Concepts::Communicator auto& comm,
718 const std::string& base_filename) {
720 WriterFactory<F>::make(F{format.opts.value_or(VTK::XMLOptions{})}, grid, comm),
721 base_filename
722 };
723 }
724};
725
727template<> struct WriterFactory<FileFormat::VTKHDFImage> {
728 static auto make(const FileFormat::VTKHDFImage&,
729 const Concepts::ImageGrid auto& grid) {
730 return VTKHDFImageGridWriter{grid};
731 }
732 static auto make(const FileFormat::VTKHDFImage&,
733 const Concepts::ImageGrid auto& grid,
734 const Concepts::Communicator auto& comm) {
735 return VTKHDFImageGridWriter{grid, comm};
736 }
737};
738
740template<>
741struct ReaderFactory<FileFormat::VTKHDFImage>
742: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImage,
743 VTKHDFImageGridReader,
744 VTKHDFImageGridReader>
745{};
746
748template<> struct WriterFactory<FileFormat::VTKHDFImageTransient> {
749 static auto make(const FileFormat::VTKHDFImageTransient& f,
750 const Concepts::ImageGrid auto& grid,
751 const std::string& base_filename) {
752 if (f.opts.has_value())
753 return VTKHDFImageGridTimeSeriesWriter{grid, base_filename, f.opts.value()};
754 return VTKHDFImageGridTimeSeriesWriter{grid, base_filename};
755 }
756 static auto make(const FileFormat::VTKHDFImageTransient& f,
757 const Concepts::ImageGrid auto& grid,
758 const Concepts::Communicator auto& comm,
759 const std::string& base_filename) {
760 if (f.opts.has_value())
761 return VTKHDFImageGridTimeSeriesWriter{grid, comm, base_filename, f.opts.value()};
762 return VTKHDFImageGridTimeSeriesWriter{grid, comm, base_filename};
763 }
764};
765
767template<>
768struct ReaderFactory<FileFormat::VTKHDFImageTransient>
769: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImageTransient,
770 VTKHDFImageGridReader,
771 VTKHDFImageGridReader>
772{};
773
775template<> struct WriterFactory<FileFormat::VTKHDFUnstructured> {
776 static auto make(const FileFormat::VTKHDFUnstructured&,
777 const Concepts::UnstructuredGrid auto& grid) {
778 return VTKHDFUnstructuredGridWriter{grid};
779 }
780 static auto make(const FileFormat::VTKHDFUnstructured&,
781 const Concepts::UnstructuredGrid auto& grid,
782 const Concepts::Communicator auto& comm) {
783 return VTKHDFUnstructuredGridWriter{grid, comm};
784 }
785};
786
788template<>
789struct ReaderFactory<FileFormat::VTKHDFUnstructured>
790: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructured,
791 VTKHDFUnstructuredGridReader<>,
792 VTKHDFUnstructuredGridReader>
793{};
794
796template<> struct WriterFactory<FileFormat::VTKHDFUnstructuredTransient> {
797 static auto make(const FileFormat::VTKHDFUnstructuredTransient& f,
798 const Concepts::UnstructuredGrid auto& grid,
799 const std::string& base_filename) {
800 if (f.opts.has_value())
801 return VTKHDFUnstructuredTimeSeriesWriter{grid, base_filename, f.opts.value()};
802 return VTKHDFUnstructuredTimeSeriesWriter{grid, base_filename};
803 }
804 static auto make(const FileFormat::VTKHDFUnstructuredTransient& f,
805 const Concepts::UnstructuredGrid auto& grid,
806 const Concepts::Communicator auto& comm,
807 const std::string& base_filename) {
808 if (f.opts.has_value())
809 return VTKHDFUnstructuredTimeSeriesWriter{grid, comm, base_filename, f.opts.value()};
810 return VTKHDFUnstructuredTimeSeriesWriter{grid, comm, base_filename};
811 }
812};
813
815template<>
816struct ReaderFactory<FileFormat::VTKHDFUnstructuredTransient>
817: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructuredTransient,
818 VTKHDFUnstructuredGridReader<>,
819 VTKHDFUnstructuredGridReader>
820{};
821
823template<> struct WriterFactory<FileFormat::VTKHDF> {
824 static auto make(const FileFormat::VTKHDF& format,
825 const Concepts::Grid auto& grid) {
826 return _make(format.from(grid), grid);
827 }
828 static auto make(const FileFormat::VTKHDF& format,
829 const Concepts::Grid auto& grid,
830 const Concepts::Communicator auto& comm) {
831 return _make(format.from(grid), grid, comm);
832 }
833 private:
834 template<typename F, typename... Args>
835 static auto _make(F&& format, Args&&... args) {
836 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
837 }
838};
839
841template<>
842struct ReaderFactory<FileFormat::VTKHDF>
843: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDF, VTKHDFReader<>, VTKHDFReader>
844{};
845
847template<> struct WriterFactory<FileFormat::VTKHDFTransient> {
848 static auto make(const FileFormat::VTKHDFTransient& format,
849 const Concepts::Grid auto& grid,
850 const std::string& base_filename) {
851 return _make(format.from(grid), grid, base_filename);
852 }
853 static auto make(const FileFormat::VTKHDFTransient& format,
854 const Concepts::Grid auto& grid,
855 const Concepts::Communicator auto& comm,
856 const std::string& base_filename) {
857 return _make(format.from(grid), grid, comm, base_filename);
858 }
859 private:
860 template<typename F, typename... Args>
861 static auto _make(F&& format, Args&&... args) {
862 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
863 }
864};
865
867template<>
868struct ReaderFactory<FileFormat::VTKHDFTransient>
869: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFTransient, VTKHDFReader<>, VTKHDFReader>
870{};
871
873template<typename F>
874struct WriterFactory<FileFormat::PVD<F>> {
875 static auto make(const FileFormat::PVD<F>& format,
876 const Concepts::Grid auto& grid,
877 const std::string& base_filename) {
878 return PVDWriter{WriterFactory<F>::make(format.piece_format, grid), base_filename};
879 }
880 static auto make(const FileFormat::PVD<F>& format,
881 const Concepts::Grid auto& grid,
882 const Concepts::Communicator auto& comm,
883 const std::string& base_filename) {
884 return PVDWriter{WriterFactory<F>::make(format.piece_format, grid, comm), base_filename};
885 }
886};
887
889template<typename PieceFormat>
890struct ReaderFactory<FileFormat::PVD<PieceFormat>>
891: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVD<PieceFormat>, PVDReader<>, PVDReader>
892{};
893
895template<>
896struct ReaderFactory<FileFormat::PVDClosure>
897: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVDClosure, PVDReader<>, PVDReader>
898{};
899
900
902template<> struct WriterFactory<FileFormat::Any> {
903 private:
904 template<typename F, typename... Args>
905 static auto _make(F&& format, Args&&... args) {
906 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
907 }
908
909 public:
910 template<Concepts::Grid G>
911 static constexpr auto default_format_for() {
912 if constexpr (Concepts::ImageGrid<G> && !APIDetail::is_converter_grid<G>)
913 return FileFormat::VTI{};
914 else if constexpr (Concepts::RectilinearGrid<G> && !APIDetail::is_converter_grid<G>)
915 return FileFormat::VTR{};
916 else if constexpr (Concepts::StructuredGrid<G> && !APIDetail::is_converter_grid<G>)
917 return FileFormat::VTS{};
918 else if constexpr (Concepts::UnstructuredGrid<G>)
919 return FileFormat::VTU{};
920 else
921 static_assert(APIDetail::always_false<G>, "Cannot deduce a default format for the given grid");
922 }
923
924 template<Concepts::Grid G>
925 static auto make(const FileFormat::Any&, const G& grid) {
926 return _make(default_format_for<G>(), grid);
927 }
928
929 template<Concepts::Grid 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);
932 }
933};
934
936template<> struct WriterFactory<FileFormat::AnyTimeSeries> {
937 static auto make(const FileFormat::AnyTimeSeries&,
938 const Concepts::Grid auto& grid,
939 const std::string& base_filename) {
940 return _make(grid, base_filename);
941 }
942
943 static auto make(const FileFormat::AnyTimeSeries&,
944 const Concepts::Grid auto& grid,
945 const Concepts::Communicator auto& comm,
946 const std::string& base_filename) {
947 return _make(grid, comm, base_filename);
948 }
949
950 private:
951 template<typename Grid, typename... Args>
952 static auto _make(const Grid& grid, Args&&... args) {
953 auto fmt = WriterFactory<FileFormat::Any>::template default_format_for<Grid>();
954 auto ts_fmt = FileFormat::TimeSeriesClosure{}(fmt);
955 return WriterFactory<decltype(ts_fmt)>::make(ts_fmt, grid, std::forward<Args>(args)...);
956 }
957};
958
959#ifndef DOXYGEN
960namespace APIDetail {
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");
966 }
967
968 template<std::derived_from<GridReader> 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>();
973 else
974 return std::make_unique<Reader>(c);
975 }
976
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);
992#endif
993 throw IOError("Could not deduce an available file format for '" + filename + "'");
994 }
995
996} // namespace APIDetail
997#endif // DOXYGEN
998
999// Implementation of the AnyReaderFactory function
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);
1003}
1004
1006template<typename OutFormat, typename InFormat = FileFormat::Any>
1008 OutFormat out_format = {};
1009 InFormat in_format = {};
1010 int verbosity = 0;
1011};
1012
1022template<typename OutFormat,
1023 typename InFormat,
1024 typename Communicator = None>
1025std::string convert(const std::string& in,
1026 const std::string& out,
1028 const Communicator& communicator = {}) {
1029 static constexpr bool use_communicator = !std::same_as<Communicator, None>;
1030 static_assert(
1031 !use_communicator || Concepts::Communicator<Communicator>,
1032 "Given communicator does not satisfy the communicator concepts."
1033 );
1034
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;
1040
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>;
1044 } ();
1045
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>;
1049 } ();
1050
1051 if (opts.verbosity > 0)
1052 std::cout << "Opening '" << in << "'" << std::endl;
1053
1054 auto reader = [&] () {
1055 if constexpr (use_communicator) return Reader{opts.in_format, communicator};
1056 else return Reader{opts.in_format};
1057 } ();
1058 reader.open(in);
1059 if constexpr (use_communicator)
1060 if (reader.number_of_pieces() > 1
1061 && reader.number_of_pieces() != static_cast<unsigned>(Parallel::size(communicator)))
1062 throw IOError(
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()) + ")"
1066 );
1067
1068 const bool print_progress_output = opts.verbosity > 1 && [&] () {
1069 if constexpr (use_communicator) return GridFormat::Parallel::rank(communicator) == 0;
1070 else return true;
1071 } ();
1072
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;
1076 };
1077
1078 const auto invoke_factory = [&] <typename Fmt, typename... T> (const Fmt& fmt, const auto& grid, T&&... args) {
1079 if constexpr (use_communicator)
1080 return WriterFactory<Fmt>::make(fmt, grid, communicator, std::forward<T>(args)...);
1081 else
1082 return WriterFactory<Fmt>::make(fmt, grid, std::forward<T>(args)...);
1083 };
1084
1085 if constexpr (is_single_file_out_format) {
1086 if (reader.is_sequence())
1087 return convert(reader, [&] (const auto& grid) {
1088 return invoke_factory(FileFormat::TimeSeriesClosure{}(opts.out_format), grid, out);
1089 }, step_call_back);
1090
1091 const auto filename = convert(reader, out, [&] (const auto& grid) {
1092 return invoke_factory(opts.out_format, grid);
1093 });
1094 if (print_progress_output)
1095 std::cout << "Wrote '" << filename << "'" << std::endl;
1096 return filename;
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);
1100 }, step_call_back);
1101 } else {
1102 static_assert(
1103 APIDetail::always_false<OutFormat>,
1104 "No viable factory found for the requested format"
1105 );
1106 }
1107}
1108
1109
1110// We place the format instances in a namespace different from FileFormats, in which
1111// the format types are defined above. Further below, we make these instances available
1112// in the GridFormat namespace directly. Having a separate namespace allows downstream ´
1113// projects to expose the format instances in their own namespace without having to expose
1114// all of GridFormat. Also, separating the format types from the instances further allows
1115// "hiding" the former and only expose the latter.
1116namespace Formats {
1117
1124
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;
1136
1140
1146template<Concepts::Grid G>
1147constexpr auto default_for() { return WriterFactory<FileFormat::Any>::template default_format_for<G>(); }
1148
1154template<Concepts::Grid G>
1155constexpr auto default_for(const G&) { return default_for<G>(); }
1156
1157} // namespace Formats
1158
1159// expose format instances
1160using namespace Formats;
1161
1162// bring the format instances into the FileFormat namespace
1163namespace FileFormat { using namespace Formats; }
1164
1165} // namespace GridFormat
1166
1167#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:53
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
Interface to the readers for all supported file formats.
Definition reader.hpp:94
Writer for .vti file format.
Definition vti_writer.hpp:33
Reader for the VTK-HDF file format for image grids.
Definition hdf_image_grid_reader.hpp:39
Writer for the transient VTK HDF file format for image grids.
Definition hdf_image_grid_writer.hpp:397
Writer for the VTK HDF file format for image grids.
Definition hdf_image_grid_writer.hpp:386
Convenience reader for the vtk-hdf file format that supports both the image & unstructured grid file ...
Definition hdf_reader.hpp:31
Convenience writer for the vtk-hdf file format, automatically selecting the image or unstructured gri...
Definition hdf_writer.hpp:75
Reader for the VTK-HDF file format for unstructured grids.
Definition hdf_unstructured_grid_reader.hpp:38
Writer for the VTK HDF file format for unstructured grids.
Definition hdf_unstructured_grid_writer.hpp:397
Writer for the transient VTK HDF file format for unstructured grids.
Definition hdf_unstructured_grid_writer.hpp:408
Convenience writer for the vtk-hdf file format, automatically selecting the image or unstructured gri...
Definition hdf_writer.hpp:55
Writer for time series of a VTK-XML file format. Populates the "TimeValue" metadata field supported b...
Definition xml_time_series_writer.hpp:27
Writer for .vtu file format.
Definition vtp_writer.hpp:57
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:160
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.
Options for format conversions.
Definition gridformat.hpp:1007
Time series variant of the Any format selector.
Definition gridformat.hpp:229
Selector for an unspecified file format. When using this format, GridFormat will automatically select...
Definition gridformat.hpp:221
Base class for formats taking options.
Definition gridformat.hpp:172
constexpr Format with(Options _opts) const
Construct a new instance of this format with the given options.
Definition gridformat.hpp:182
constexpr Format operator()(Options _opts) const
Construct a new instance of this format with the given options.
Definition gridformat.hpp:177
Closure for selecting the .pvd file format. Takes a VTK-XML format and returns an instance of PVD.
Definition gridformat.hpp:423
Selector for the .pvd file format for a time series. For more information, see here.
Definition gridformat.hpp:414
Closure for time series format selection. Takes a sequential format and returns a time series variant...
Definition gridformat.hpp:439
Selector for the .vti/.pvti image grid file format to be passed to the Writer.
Definition gridformat.hpp:242
Transient variant of the vtk-hdf image data format.
Definition gridformat.hpp:325
Selector for the vtk-hdf file format for image grids. For more information, see here.
Definition gridformat.hpp:317
Selector for the transient vtk-hdf file format with automatic deduction of the flavour....
Definition gridformat.hpp:357
Transient variant of the vtk-hdf unstructured grid format.
Definition gridformat.hpp:345
Selector for the vtk-hdf file format for unstructured grids. For more information,...
Definition gridformat.hpp:337
Selector for the vtk-hdf file format with automatic deduction of the flavour. If the grid for which a...
Definition gridformat.hpp:377
constexpr VTKHDFTransient with(VTK::HDFTransientOptions opts) const
Return the transient variant of this format with the given options.
Definition gridformat.hpp:387
Base class for VTK-XML formats.
Definition gridformat.hpp:191
constexpr auto with_compression(VTK::XML::Compressor c) const
Construct a new instance of this format with modified compression option.
Definition gridformat.hpp:207
constexpr auto with_encoding(VTK::XML::Encoder e) const
Construct a new instance of this format with modified encoding option.
Definition gridformat.hpp:193
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:200
Selector for a time series of any VTK-XML format.
Definition gridformat.hpp:298
Selector for the .vtp/.pvtp file format for two-dimensional unstructured grids.
Definition gridformat.hpp:278
Selector for the .vtr/.pvtr rectilinear grid file format to be passed to the Writer.
Definition gridformat.hpp:254
Selector for the .vts/.pvts structured grid file format to be passed to the Writer.
Definition gridformat.hpp:266
Selector for the .vtu/.pvtu file format for general unstructured grids.
Definition gridformat.hpp:290
Factory class to create a reader for the given file format.
Definition gridformat.hpp:166
Can be specialized by parallel writers to expose their underlying communicator.
Definition writer.hpp:41
Can be specialized by writers in case the file format does not contain connectivity information.
Definition writer.hpp:37
Options for transient vtk-hdf file formats.
Definition hdf_common.hpp:37
Options for VTK-XML files for setting the desired encoding, data format and compression.
Definition xml.hpp:100
Factory class to create a writer for the given file format.
Definition gridformat.hpp:163
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...