GridFormat 0.4.0
I/O-Library for grid-like data structures
Loading...
Searching...
No Matches
gridformat.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2// SPDX-License-Identifier: MIT
14#ifndef GRIDFORMAT_GRIDFORMAT_HPP_
15#define GRIDFORMAT_GRIDFORMAT_HPP_
16
17#include <memory>
18#include <optional>
19#include <type_traits>
20
21#include <gridformat/reader.hpp>
22#include <gridformat/writer.hpp>
23
26
27#include <gridformat/common/exceptions.hpp>
28#include <gridformat/parallel/communication.hpp>
29
33
37
41
45
49
52
54
55#ifndef DOXYGEN
56namespace GridFormat::APIDetail {
57
58 template<typename... T>
59 inline constexpr bool always_false = false;
60
61 template<typename... T>
62 struct DefaultAsserter {
63 static constexpr bool do_assert() {
64 static_assert(
65 always_false<T...>,
66 "Requested reader/writer is unavailable due to missing dependency"
67 );
68 return false;
69 }
70 };
71
72 // Derive from GridWriter to make this a "valid" writer (and abuse some valid grid impl for that)
73 template<template<typename...> typename Asserter = DefaultAsserter>
74 class UnavailableWriter : public GridWriter<ImageGrid<2, double>> {
75 public:
76 template<typename... Args>
77 UnavailableWriter(Args&&...) { static_assert(Asserter<Args...>::do_assert()); }
78 private:
79 void _throw() const { throw GridFormat::NotImplemented("Writer unavailable"); }
80 void _write(std::ostream&) const { _throw(); }
81 };
82
83 // Derive from Reader to make this a "valid" reader
84 template<template<typename...> typename Asserter = DefaultAsserter>
85 class UnavailableReader : public GridReader {
86 public:
87 template<typename... Args>
88 UnavailableReader(Args&&...) { static_assert(Asserter<Args...>::do_assert()); }
89 private:
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; }
100 };
101
102} // namespace GridFormat::APIDetail
103
104#if GRIDFORMAT_HAVE_HIGH_FIVE
107inline constexpr bool _gfmt_api_have_high_five = true;
108#else
110inline constexpr bool _gfmt_api_have_high_five = false;
111namespace GridFormat {
112
113template<typename... T>
114struct VTKHDFAsserter {
115 static constexpr bool do_assert() {
116 static_assert(
117 APIDetail::always_false<T...>,
118 "VTKHDF reader/writers require HighFive"
119 );
120 return false;
121 }
122};
123
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>;
130
131using VTKHDFImageGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
132template<typename T = void> using VTKHDFUnstructuredGridReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
133template<typename T = void> using VTKHDFReader = APIDetail::UnavailableReader<VTKHDFAsserter>;
134
135} // namespace GridFormat
136#endif // GRIDFORMAT_HAVE_HIGH_FIVE
137#endif // DOXYGEN
138
139
140namespace GridFormat {
141
143inline constexpr GridFormat::NullCommunicator null_communicator;
144
146template<typename FileFormat> struct WriterFactory;
147
149template<typename FileFormat> struct ReaderFactory;
150
151namespace FileFormat {
152
154template<typename Format, typename Opts>
156 using Options = Opts;
157 std::optional<Options> opts = {};
158
160 constexpr Format operator()(Options _opts) const {
161 return with(std::move(_opts));
162 }
163
165 constexpr Format with(Options _opts) const {
166 Format f;
167 f.opts = std::move(_opts);
168 return f;
169 }
170};
171
173template<typename VTKFormat>
174struct VTKXMLFormatBase : public FormatWithOptions<VTKFormat, VTK::XMLOptions> {
176 constexpr auto with_encoding(VTK::XML::Encoder e) const {
177 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
178 Variant::unwrap_to(cur_opts.encoder, e);
179 return this->with(std::move(cur_opts));
180 }
181
183 constexpr auto with_data_format(VTK::XML::DataFormat f) const {
184 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
185 Variant::unwrap_to(cur_opts.data_format, f);
186 return this->with(std::move(cur_opts));
187 }
188
190 constexpr auto with_compression(VTK::XML::Compressor c) const {
191 auto cur_opts = this->opts.value_or(VTK::XMLOptions{});
192 Variant::unwrap_to(cur_opts.compressor, c);
193 return this->with(std::move(cur_opts));
194 }
195};
196
197
204struct Any {};
205
206
213
214
225struct VTI : VTKXMLFormatBase<VTI> {};
226
237struct VTR : VTKXMLFormatBase<VTR> {};
238
249struct VTS : VTKXMLFormatBase<VTS> {};
250
261struct VTP : VTKXMLFormatBase<VTP> {};
262
273struct VTU : VTKXMLFormatBase<VTU> {};
274
280template<typename VTX>
281struct VTKXMLTimeSeries : VTKXMLFormatBase<VTKXMLTimeSeries<VTX>> {};
282
283
297struct VTKHDFImage {};
298
305: FormatWithOptions<VTKHDFImageTransient, VTK::HDFTransientOptions> {};
306
318
325: FormatWithOptions<VTKHDFUnstructuredTransient, VTK::HDFTransientOptions> {};
326
337struct VTKHDFTransient : FormatWithOptions<VTKHDFTransient, VTK::HDFTransientOptions> {
338 template<typename Grid>
339 constexpr auto from(const Grid&) const {
340 // TODO: Once the VTKHDFImageGridReader is stable, use image format for image grids
341 return VTKHDFUnstructuredTransient{this->opts};
342 }
343};
344
355struct VTKHDF {
356 template<typename Grid>
357 static constexpr auto from(const Grid&) {
358 // TODO: Once the VTKHDFImageGridReader is stable, use image format for image grids
359 return VTKHDFUnstructured{};
360 }
361
364 return {std::move(opts)};
365 }
366};
367
368#ifndef DOXYGEN
369namespace Detail {
370
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 {};
377
378} // namespace Detail
379#endif // DOXYGEN
380
389template<typename PieceFormat = Any>
390struct PVD {
391 PieceFormat piece_format;
392};
393
400 template<typename Format>
401 constexpr auto operator()(const Format& f) const {
402 static_assert(
403 Detail::IsVTKXMLFormat<Format>::value,
404 "The PVD format is only available with vtk-xml file formats"
405 );
406 return PVD<Format>{f};
407 }
408};
409
416 template<typename Format>
417 constexpr auto operator()(const Format& f) const {
418 if constexpr (Detail::IsVTKXMLFormat<Format>::value)
419 return VTKXMLTimeSeries<Format>{f.opts};
420 else if constexpr (std::same_as<VTKHDFImage, Format>)
421 return VTKHDFImageTransient{};
422 else if constexpr (std::same_as<VTKHDFUnstructured, Format>)
424 else if constexpr (std::same_as<VTKHDF, Format>)
425 return VTKHDFTransient{};
426 else if constexpr (std::same_as<Any, Format>)
427 return AnyTimeSeries{};
428 else {
429 static_assert(
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."
433 );
434 }
435 }
436};
437
438} // namespace FileFormat
439
440
441#ifndef DOXYGEN
442namespace APIDetail {
443
444 // Meta-Reader for file formats that have different format flavours in parallel/sequential
445 template<typename SeqReader, typename ParReader>
446 class SequentialOrParallelReader : public GridReader {
447 template<typename R> using CommunicatorAccess = Traits::CommunicatorAccess<R>;
448 template<typename R> using Communicator = decltype(CommunicatorAccess<R>::get(std::declval<const R&>()));
449 using ParCommunicator = Communicator<ParReader>;
450 using SeqCommunicator = Communicator<SeqReader>;
451
452 public:
453 SequentialOrParallelReader(SeqReader&& seq, ParReader&& par)
454 : _seq_reader{std::move(seq)}
455 , _par_reader{std::move(par)}
456 {}
457
458 ParCommunicator communicator() const {
459 const bool is_parallel = !_use_sequential.value_or(true);
460 if (!is_parallel) {
461 if constexpr (!std::is_same_v<ParCommunicator, SeqCommunicator>)
462 throw InvalidState("Cannot access communicator for sequential variant of the reader");
463 else
464 return CommunicatorAccess<SeqReader>::get(_seq_reader);
465 }
466 return CommunicatorAccess<ParReader>::get(_par_reader);
467 }
468
469 private:
470 SeqReader _seq_reader;
471 ParReader _par_reader;
472 std::optional<bool> _use_sequential = {};
473
474 std::string _name() const override {
475 return _is_set() ? _access().name() : std::string{"undefined"};
476 }
477
478 void _open(const std::string& filename, typename GridReader::FieldNames& names) override {
479 _close();
480 std::string seq_error;
481 try {
482 _seq_reader.open(filename);
483 _use_sequential = true;
484 } catch (const std::exception& e) {
485 seq_error = e.what();
486 _use_sequential.reset();
487 _seq_reader.close();
488 try {
489 _par_reader.open(filename);
490 _use_sequential = false;
491 } catch (const std::exception& par_err) {
492 _use_sequential.reset();
493 _par_reader.close();
494 throw IOError(
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()
498 );
499 }
500 }
501
502 ReaderDetail::copy_field_names(_access(), names);
503 }
504
505 void _close() override {
506 if (_is_set())
507 _access().close();
508 }
509
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(); }
513
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); }
517
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); }
521
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); }
526
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);
532 names.clear();
533 ReaderDetail::copy_field_names(_access(), names);
534 }
535
536 bool _is_set() const { return _use_sequential.has_value(); }
537 void _throw_if_not_set() const {
538 if (!_is_set())
539 throw IOError("No data has been read");
540 }
541
542 GridReader& _access() {
543 _throw_if_not_set();
544 return _use_sequential.value()
545 ? static_cast<GridReader&>(_seq_reader)
546 : static_cast<GridReader&>(_par_reader);
547 }
548
549 const GridReader& _access() const {
550 _throw_if_not_set();
551 return _use_sequential.value()
552 ? static_cast<const GridReader&>(_seq_reader)
553 : static_cast<const GridReader&>(_par_reader);
554 }
555 };
556
557 template<typename S, typename P>
558 SequentialOrParallelReader(S&&, P&&) -> SequentialOrParallelReader<std::remove_cvref_t<S>, std::remove_cvref_t<P>>;
559
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}};
565 }
566 };
567
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}; }
572 };
573
574 // Specialization for cases where the parallel reader is templated on the communicator
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}; }
580 };
581
582} // namespace APIDetail
583#endif // DOXYGEN
584
585// Traits specializations for SequentialOrParallelReader
586namespace Traits {
587
588template<typename S, typename P>
589struct WritesConnectivity<APIDetail::SequentialOrParallelReader<S, P>>
590: public std::bool_constant<WritesConnectivity<S>::value || WritesConnectivity<P>::value>
591{};
592
593} // namespace Traits
594
596template<> struct WriterFactory<FileFormat::VTI> {
597 static auto make(const FileFormat::VTI& format,
598 const Concepts::ImageGrid auto& grid) {
599 return VTIWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
600 }
601
602 static auto make(const FileFormat::VTI& format,
603 const Concepts::ImageGrid auto& grid,
604 const Concepts::Communicator auto& comm) {
605 return PVTIWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
606 }
607};
608
610template<>
611struct ReaderFactory<FileFormat::VTI> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTI, VTIReader, PVTIReader> {};
612
614template<> struct WriterFactory<FileFormat::VTR> {
615 static auto make(const FileFormat::VTR& format,
616 const Concepts::RectilinearGrid auto& grid) {
617 return VTRWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
618 }
619 static auto make(const FileFormat::VTR& format,
620 const Concepts::RectilinearGrid auto& grid,
621 const Concepts::Communicator auto& comm) {
622 return PVTRWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
623 }
624};
625
627template<>
628struct ReaderFactory<FileFormat::VTR> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTR, VTRReader, PVTRReader> {};
629
631template<> struct WriterFactory<FileFormat::VTS> {
632 static auto make(const FileFormat::VTS& format,
633 const Concepts::StructuredGrid auto& grid) {
634 return VTSWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
635 }
636 static auto make(const FileFormat::VTS& format,
637 const Concepts::StructuredGrid auto& grid,
638 const Concepts::Communicator auto& comm) {
639 return PVTSWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
640 }
641};
642
644template<>
645struct ReaderFactory<FileFormat::VTS> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTS, VTSReader, PVTSReader> {};
646
648template<> struct WriterFactory<FileFormat::VTP> {
649 static auto make(const FileFormat::VTP& format,
650 const Concepts::UnstructuredGrid auto& grid) {
651 return VTPWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
652 }
653 static auto make(const FileFormat::VTP& format,
654 const Concepts::UnstructuredGrid auto& grid,
655 const Concepts::Communicator auto& comm) {
656 return PVTPWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
657 }
658};
659
661template<>
662struct ReaderFactory<FileFormat::VTP> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTP, VTPReader, PVTPReader> {};
663
665template<> struct WriterFactory<FileFormat::VTU> {
666 static auto make(const FileFormat::VTU& format,
667 const Concepts::UnstructuredGrid auto& grid) {
668 return VTUWriter{grid, format.opts.value_or(VTK::XMLOptions{})};
669 }
670 static auto make(const FileFormat::VTU& format,
671 const Concepts::UnstructuredGrid auto& grid,
672 const Concepts::Communicator auto& comm) {
673 return PVTUWriter{grid, comm, format.opts.value_or(VTK::XMLOptions{})};
674 }
675};
676
678template<>
679struct ReaderFactory<FileFormat::VTU> : APIDetail::SequentialOrParallelReaderFactory<FileFormat::VTU, VTUReader, PVTUReader> {};
680
682template<typename F> struct WriterFactory<FileFormat::VTKXMLTimeSeries<F>> {
683 static auto make(const FileFormat::VTKXMLTimeSeries<F>& format,
684 const Concepts::UnstructuredGrid auto& grid,
685 const std::string& base_filename) {
687 WriterFactory<F>::make(F{format.opts.value_or(VTK::XMLOptions{})}, grid),
688 base_filename
689 };
690 }
691 static auto make(const FileFormat::VTKXMLTimeSeries<F>& format,
692 const Concepts::UnstructuredGrid auto& grid,
693 const Concepts::Communicator auto& comm,
694 const std::string& base_filename) {
696 WriterFactory<F>::make(F{format.opts.value_or(VTK::XMLOptions{})}, grid, comm),
697 base_filename
698 };
699 }
700};
701
703template<> struct WriterFactory<FileFormat::VTKHDFImage> {
704 static auto make(const FileFormat::VTKHDFImage&,
705 const Concepts::ImageGrid auto& grid) {
706 return VTKHDFImageGridWriter{grid};
707 }
708 static auto make(const FileFormat::VTKHDFImage&,
709 const Concepts::ImageGrid auto& grid,
710 const Concepts::Communicator auto& comm) {
711 return VTKHDFImageGridWriter{grid, comm};
712 }
713};
714
716template<>
717struct ReaderFactory<FileFormat::VTKHDFImage>
718: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImage,
719 VTKHDFImageGridReader,
720 VTKHDFImageGridReader>
721{};
722
724template<> struct WriterFactory<FileFormat::VTKHDFImageTransient> {
725 static auto make(const FileFormat::VTKHDFImageTransient& f,
726 const Concepts::ImageGrid auto& grid,
727 const std::string& base_filename) {
728 if (f.opts.has_value())
729 return VTKHDFImageGridTimeSeriesWriter{grid, base_filename, f.opts.value()};
730 return VTKHDFImageGridTimeSeriesWriter{grid, base_filename};
731 }
732 static auto make(const FileFormat::VTKHDFImageTransient& f,
733 const Concepts::ImageGrid auto& grid,
734 const Concepts::Communicator auto& comm,
735 const std::string& base_filename) {
736 if (f.opts.has_value())
737 return VTKHDFImageGridTimeSeriesWriter{grid, comm, base_filename, f.opts.value()};
738 return VTKHDFImageGridTimeSeriesWriter{grid, comm, base_filename};
739 }
740};
741
743template<>
744struct ReaderFactory<FileFormat::VTKHDFImageTransient>
745: APIDetail::DefaultReaderFactory<FileFormat::VTKHDFImageTransient,
746 VTKHDFImageGridReader,
747 VTKHDFImageGridReader>
748{};
749
751template<> struct WriterFactory<FileFormat::VTKHDFUnstructured> {
752 static auto make(const FileFormat::VTKHDFUnstructured&,
753 const Concepts::UnstructuredGrid auto& grid) {
754 return VTKHDFUnstructuredGridWriter{grid};
755 }
756 static auto make(const FileFormat::VTKHDFUnstructured&,
757 const Concepts::UnstructuredGrid auto& grid,
758 const Concepts::Communicator auto& comm) {
759 return VTKHDFUnstructuredGridWriter{grid, comm};
760 }
761};
762
764template<>
765struct ReaderFactory<FileFormat::VTKHDFUnstructured>
766: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructured,
767 VTKHDFUnstructuredGridReader<>,
768 VTKHDFUnstructuredGridReader>
769{};
770
772template<> struct WriterFactory<FileFormat::VTKHDFUnstructuredTransient> {
773 static auto make(const FileFormat::VTKHDFUnstructuredTransient& f,
774 const Concepts::ImageGrid auto& grid,
775 const std::string& base_filename) {
776 if (f.opts.has_value())
777 return VTKHDFUnstructuredTimeSeriesWriter{grid, base_filename, f.opts.value()};
778 return VTKHDFUnstructuredTimeSeriesWriter{grid, base_filename};
779 }
780 static auto make(const FileFormat::VTKHDFUnstructuredTransient& f,
781 const Concepts::ImageGrid auto& grid,
782 const Concepts::Communicator auto& comm,
783 const std::string& base_filename) {
784 if (f.opts.has_value())
785 return VTKHDFUnstructuredTimeSeriesWriter{grid, comm, base_filename, f.opts.value()};
786 return VTKHDFUnstructuredTimeSeriesWriter{grid, comm, base_filename};
787 }
788};
789
791template<>
792struct ReaderFactory<FileFormat::VTKHDFUnstructuredTransient>
793: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFUnstructuredTransient,
794 VTKHDFUnstructuredGridReader<>,
795 VTKHDFUnstructuredGridReader>
796{};
797
799template<> struct WriterFactory<FileFormat::VTKHDF> {
800 static auto make(const FileFormat::VTKHDF& format,
801 const Concepts::Grid auto& grid) {
802 return _make(format.from(grid), grid);
803 }
804 static auto make(const FileFormat::VTKHDF& format,
805 const Concepts::Grid auto& grid,
806 const Concepts::Communicator auto& comm) {
807 return _make(format.from(grid), grid, comm);
808 }
809 private:
810 template<typename F, typename... Args>
811 static auto _make(F&& format, Args&&... args) {
812 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
813 }
814};
815
817template<>
818struct ReaderFactory<FileFormat::VTKHDF>
819: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDF, VTKHDFReader<>, VTKHDFReader>
820{};
821
823template<> struct WriterFactory<FileFormat::VTKHDFTransient> {
824 static auto make(const FileFormat::VTKHDFTransient& format,
825 const Concepts::Grid auto& grid,
826 const std::string& base_filename) {
827 return _make(format.from(grid), grid, base_filename);
828 }
829 static auto make(const FileFormat::VTKHDFTransient& format,
830 const Concepts::Grid auto& grid,
831 const Concepts::Communicator auto& comm,
832 const std::string& base_filename) {
833 return _make(format.from(grid), grid, comm, base_filename);
834 }
835 private:
836 template<typename F, typename... Args>
837 static auto _make(F&& format, Args&&... args) {
838 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
839 }
840};
841
843template<>
844struct ReaderFactory<FileFormat::VTKHDFTransient>
845: APIDetail::DefaultTemplatedReaderFactory<FileFormat::VTKHDFTransient, VTKHDFReader<>, VTKHDFReader>
846{};
847
849template<typename F>
850struct WriterFactory<FileFormat::PVD<F>> {
851 static auto make(const FileFormat::PVD<F>& format,
852 const Concepts::Grid auto& grid,
853 const std::string& base_filename) {
854 return PVDWriter{WriterFactory<F>::make(format.piece_format, grid), base_filename};
855 }
856 static auto make(const FileFormat::PVD<F>& format,
857 const Concepts::Grid auto& grid,
858 const Concepts::Communicator auto& comm,
859 const std::string& base_filename) {
860 return PVDWriter{WriterFactory<F>::make(format.piece_format, grid, comm), base_filename};
861 }
862};
863
865template<typename PieceFormat>
866struct ReaderFactory<FileFormat::PVD<PieceFormat>>
867: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVD<PieceFormat>, PVDReader<>, PVDReader>
868{};
869
871template<>
872struct ReaderFactory<FileFormat::PVDClosure>
873: APIDetail::DefaultTemplatedReaderFactory<FileFormat::PVDClosure, PVDReader<>, PVDReader>
874{};
875
876
878template<> struct WriterFactory<FileFormat::Any> {
879 private:
880 template<typename G>
881 static constexpr bool is_converter_grid = std::same_as<G, ConverterDetail::ConverterGrid>;
882
883 template<typename F, typename... Args>
884 static auto _make(F&& format, Args&&... args) {
885 return WriterFactory<F>::make(format, std::forward<Args>(args)...);
886 }
887
888 public:
889 template<Concepts::Grid G>
890 static constexpr auto default_format_for() {
891 if constexpr (Concepts::ImageGrid<G> && !is_converter_grid<G>)
892 return FileFormat::VTI{};
893 else if constexpr (Concepts::RectilinearGrid<G> && !is_converter_grid<G>)
894 return FileFormat::VTR{};
895 else if constexpr (Concepts::StructuredGrid<G> && !is_converter_grid<G>)
896 return FileFormat::VTS{};
897 else if constexpr (Concepts::UnstructuredGrid<G>)
898 return FileFormat::VTU{};
899 else
900 static_assert(APIDetail::always_false<G>, "Cannot deduce a default format for the given grid");
901 }
902
903 template<Concepts::Grid G>
904 static auto make(const FileFormat::Any&, const G& grid) {
905 return _make(default_format_for<G>(), grid);
906 }
907
908 template<Concepts::Grid 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);
911 }
912};
913
915template<> struct WriterFactory<FileFormat::AnyTimeSeries> {
916 static auto make(const FileFormat::AnyTimeSeries&,
917 const Concepts::Grid auto& grid,
918 const std::string& base_filename) {
919 return _make(grid, base_filename);
920 }
921
922 static auto make(const FileFormat::AnyTimeSeries&,
923 const Concepts::Grid auto& grid,
924 const Concepts::Communicator auto& comm,
925 const std::string& base_filename) {
926 return _make(grid, comm, base_filename);
927 }
928
929 private:
930 template<typename Grid, typename... Args>
931 static auto _make(const Grid& grid, Args&&... args) {
932 auto fmt = WriterFactory<FileFormat::Any>::template default_format_for<Grid>();
933 auto ts_fmt = FileFormat::TimeSeriesClosure{}(fmt);
934 return WriterFactory<decltype(ts_fmt)>::make(ts_fmt, grid, std::forward<Args>(args)...);
935 }
936};
937
938#ifndef DOXYGEN
939namespace APIDetail {
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");
945 }
946
947 template<std::derived_from<GridReader> 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>();
952 else
953 return std::make_unique<Reader>(c);
954 }
955
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);
971#endif
972 throw IOError("Could not deduce an available file format for '" + filename + "'");
973 }
974
975} // namespace APIDetail
976#endif // DOXYGEN
977
978// Implementation of the AnyReaderFactory function
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);
982}
983
985template<typename OutFormat, typename InFormat = FileFormat::Any>
987 OutFormat out_format = {};
988 InFormat in_format = {};
989 int verbosity = 0;
990};
991
1001template<typename OutFormat,
1002 typename InFormat,
1003 typename Communicator = None>
1004std::string convert(const std::string& in,
1005 const std::string& out,
1007 const Communicator& communicator = {}) {
1008 static constexpr bool use_communicator = !std::same_as<Communicator, None>;
1009 static_assert(
1010 !use_communicator || Concepts::Communicator<Communicator>,
1011 "Given communicator does not satisfy the communicator concepts."
1012 );
1013
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;
1019
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>;
1023 } ();
1024
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>;
1028 } ();
1029
1030 if (opts.verbosity > 0)
1031 std::cout << "Opening '" << in << "'" << std::endl;
1032
1033 auto reader = [&] () {
1034 if constexpr (use_communicator) return Reader{opts.in_format, communicator};
1035 else return Reader{opts.in_format};
1036 } ();
1037 reader.open(in);
1038 if constexpr (use_communicator)
1039 if (reader.number_of_pieces() > 1
1040 && reader.number_of_pieces() != static_cast<unsigned>(Parallel::size(communicator)))
1041 throw IOError(
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()) + ")"
1045 );
1046
1047 const bool print_progress_output = opts.verbosity > 1 && [&] () {
1048 if constexpr (use_communicator) return GridFormat::Parallel::rank(communicator) == 0;
1049 else return true;
1050 } ();
1051
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;
1055 };
1056
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)...);
1060 else
1061 return WriterFactory<Fmt>::make(fmt, grid, std::forward<T>(args)...);
1062 };
1063
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);
1068 }, step_call_back);
1069
1070 const auto filename = convert(reader, out, [&] (const auto& grid) {
1071 return invoke_factory(opts.out_format, grid);
1072 });
1073 if (print_progress_output)
1074 std::cout << "Wrote '" << filename << "'" << std::endl;
1075 return filename;
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);
1079 }, step_call_back);
1080 } else {
1081 static_assert(
1082 APIDetail::always_false<OutFormat>,
1083 "No viable factory found for the requested format"
1084 );
1085 }
1086}
1087
1088
1089// We place the format instances in a namespace different from FileFormats, in which
1090// the format types are defined above. Further below, we make these instances available
1091// in the GridFormat namespace directly. Having a separate namespace allows downstream ´
1092// projects to expose the format instances in their own namespace without having to expose
1093// all of GridFormat. Also, separating the format types from the instances further allows
1094// "hiding" the former and only expose the latter.
1095namespace Formats {
1096
1103
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;
1115
1119
1125template<Concepts::Grid G>
1126constexpr auto default_for() { return WriterFactory<FileFormat::Any>::template default_format_for<G>(); }
1127
1133template<Concepts::Grid G>
1134constexpr auto default_for(const G&) { return default_for<G>(); }
1135
1136} // namespace Formats
1137
1138// expose format instances
1139using namespace Formats;
1140
1141// bring the format instances into the FileFormat namespace
1142namespace FileFormat { using namespace Formats; }
1143
1144} // namespace GridFormat
1145
1146#endif // GRIDFORMAT_GRIDFORMAT_HPP_
Abstract base class for all readers, defines the common interface.
Definition: reader.hpp:51
Writer for .pvd time-series file format.
Definition: pvd_writer.hpp:52
Writer for parallel .pvti files.
Definition: pvti_writer.hpp:41
Writer for parallel .pvtu files.
Definition: pvtp_writer.hpp:34
Writer for parallel .pvtr files.
Definition: pvtr_writer.hpp:40
Writer for parallel .pvts files.
Definition: pvts_writer.hpp:41
Writer for parallel .pvtu files.
Definition: pvtu_writer.hpp:34
Writer for .vti file format.
Definition: vti_writer.hpp:33
Writer for the transient VTK HDF file format for image grids.
Definition: hdf_image_grid_writer.hpp:396
Writer for the VTK HDF file format for image grids.
Definition: hdf_image_grid_writer.hpp:385
Writer for the VTK HDF file format for unstructured grids.
Definition: hdf_unstructured_grid_writer.hpp:386
Writer for the transient VTK HDF file format for unstructured grids.
Definition: hdf_unstructured_grid_writer.hpp:397
Writer for time series of a VTK-XML file format. Populates the "TimeValue" metadata field supported b...
Definition: xml_time_series_writer.hpp:25
Writer for .vtu file format.
Definition: vtp_writer.hpp:56
Writer for .vtr file format.
Definition: vtr_writer.hpp:35
Writer for .vts file format.
Definition: vts_writer.hpp:35
Writer for .vtu file format.
Definition: vtu_writer.hpp:30
Concept a type that fulfills any of the grid interfaces.
Definition: concepts.hpp:93
Concept for grids to be used as image grids.
Definition: concepts.hpp:53
Concept for grids to be used as rectilinear grids.
Definition: concepts.hpp:66
Concept for grids to be used as structured grids.
Definition: concepts.hpp:74
Concept for grids to be used as unstructured grids.
Definition: concepts.hpp:82
Converter between grid formats.
constexpr GridFormat::NullCommunicator null_communicator
Null communicator that can be used e.g. to read parallel file formats sequentially.
Definition: gridformat.hpp:143
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.
Options for format conversions.
Definition: gridformat.hpp:986
Time series variant of the Any format selector.
Definition: gridformat.hpp:212
Selector for an unspecified file format. When using this format, GridFormat will automatically select...
Definition: gridformat.hpp:204
Base class for formats taking options.
Definition: gridformat.hpp:155
constexpr Format with(Options _opts) const
Construct a new instance of this format with the given options.
Definition: gridformat.hpp:165
constexpr Format operator()(Options _opts) const
Construct a new instance of this format with the given options.
Definition: gridformat.hpp:160
Closure for selecting the .pvd file format. Takes a VTK-XML format and returns an instance of PVD.
Definition: gridformat.hpp:399
Selector for the .pvd file format for a time series. For more information, see here.
Definition: gridformat.hpp:390
Closure for time series format selection. Takes a sequential format and returns a time series variant...
Definition: gridformat.hpp:415
Selector for the .vti/.pvti image grid file format to be passed to the Writer.
Definition: gridformat.hpp:225
Transient variant of the vtk-hdf image data format.
Definition: gridformat.hpp:305
Selector for the vtk-hdf file format for image grids. For more information, see here.
Definition: gridformat.hpp:297
Selector for the transient vtk-hdf file format with automatic deduction of the flavour....
Definition: gridformat.hpp:337
Transient variant of the vtk-hdf unstructured grid format.
Definition: gridformat.hpp:325
Selector for the vtk-hdf file format for unstructured grids. For more information,...
Definition: gridformat.hpp:317
Selector for the vtk-hdf file format with automatic deduction of the flavour. If the grid for which a...
Definition: gridformat.hpp:355
constexpr VTKHDFTransient with(VTK::HDFTransientOptions opts)
Return the transient variant of this format with the given options.
Definition: gridformat.hpp:363
Base class for VTK-XML formats.
Definition: gridformat.hpp:174
constexpr auto with_compression(VTK::XML::Compressor c) const
Construct a new instance of this format with modified compression option.
Definition: gridformat.hpp:190
constexpr auto with_encoding(VTK::XML::Encoder e) const
Construct a new instance of this format with modified encoding option.
Definition: gridformat.hpp:176
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:183
Selector for a time series of any VTK-XML format.
Definition: gridformat.hpp:281
Selector for the .vtp/.pvtp file format for two-dimensional unstructured grids.
Definition: gridformat.hpp:261
Selector for the .vtr/.pvtr rectilinear grid file format to be passed to the Writer.
Definition: gridformat.hpp:237
Selector for the .vts/.pvts structured grid file format to be passed to the Writer.
Definition: gridformat.hpp:249
Selector for the .vtu/.pvtu file format for general unstructured grids.
Definition: gridformat.hpp:273
Factory class to create a reader for the given file format.
Definition: gridformat.hpp:149
Can be specialized by parallel writers to expose their underlying communicator.
Definition: writer.hpp:40
Can be specialized by writers in case the file format does not contain connectivity information.
Definition: writer.hpp:36
Options for transient vtk-hdf file formats.
Definition: hdf_common.hpp:26
Options for VTK-XML files for setting the desired encoding, data format and compression.
Definition: xml.hpp:99
Factory class to create a writer for the given file format.
Definition: gridformat.hpp:146
A generic writer providing access to the writers for all supported formats.