8#ifndef GRIDFORMAT_GRID_WRITER_HPP_
9#define GRIDFORMAT_GRID_WRITER_HPP_
19#include <gridformat/parallel/communication.hpp>
20#include <gridformat/common/type_traits.hpp>
21#include <gridformat/common/precision.hpp>
22#include <gridformat/common/concepts.hpp>
23#include <gridformat/common/field_storage.hpp>
24#include <gridformat/common/range_field.hpp>
25#include <gridformat/common/scalar_field.hpp>
26#include <gridformat/common/logging.hpp>
28#include <gridformat/grid/grid.hpp>
29#include <gridformat/grid/_detail.hpp>
30#include <gridformat/grid/entity_fields.hpp>
39template<
typename Writer>
41 static constexpr auto get(
const Writer&) {
return NullCommunicator{}; }
45template<
typename Writer>
46 requires(
requires(
const Writer& w) { { w.communicator() }; } )
48 static constexpr Concepts::Communicator
decltype(
auto) get(
const Writer& w) {
49 return w.communicator();
74 using Field =
typename FieldStorage::Field;
75 using FieldPtr =
typename FieldStorage::FieldPtr;
77 explicit GridWriterBase(
const Grid& grid, std::optional<WriterOptions> opts)
79 , _opts{std::move(opts)}
82 template<std::ranges::range R>
83 void set_meta_data(
const std::string& name, R&& range) {
84 _meta_data.set(name, RangeField{std::forward<R>(range)});
87 void set_meta_data(
const std::string& name, std::string text) {
88 if (_opts && _opts.value().append_null_terminator_to_strings)
90 _meta_data.set(name, RangeField{std::move(text)});
93 template<Concepts::Scalar T>
94 void set_meta_data(
const std::string& name, T value) {
95 _meta_data.set(name, ScalarField{value});
98 template<std::derived_from<Field> F>
99 void set_meta_data(
const std::string& name, F&& field) {
100 static_assert(!std::is_lvalue_reference_v<F>,
"Cannot take metadata fields by reference, please move");
104 void set_meta_data(
const std::string& name, FieldPtr ptr) {
105 _meta_data.set(name, ptr);
108 FieldPtr remove_meta_data(
const std::string& name) {
109 return _meta_data.pop(name);
112 template<Concepts::Po
intFunction<Gr
id> F, Concepts::Scalar T = Gr
idDetail::Po
intFunctionScalarType<Gr
id, F>>
113 void set_point_field(
const std::string& name, F&& point_function,
const Precision<T>& prec = {}) {
114 static_assert(!std::is_lvalue_reference_v<F>,
"Cannot take functions by reference, please move");
115 set_point_field(name, _make_point_field(std::move(point_function), prec));
118 template<std::derived_from<Field> F>
119 void set_point_field(
const std::string& name, F&& field) {
120 static_assert(!std::is_lvalue_reference_v<F>,
"Cannot take fields by reference, please move");
124 void set_point_field(
const std::string& name, FieldPtr field_ptr) {
125 _point_fields.set(name, std::move(field_ptr));
128 FieldPtr remove_point_field(
const std::string& name) {
129 return _point_fields.pop(name);
132 template<Concepts::CellFunction<Gr
id> F, Concepts::Scalar T = Gr
idDetail::CellFunctionScalarType<Gr
id, F>>
133 void set_cell_field(
const std::string& name, F&& cell_function,
const Precision<T>& prec = {}) {
134 static_assert(!std::is_lvalue_reference_v<F>,
"Cannot take functions by reference, please move");
135 set_cell_field(name, _make_cell_field(std::move(cell_function), prec));
138 template<std::derived_from<Field> F>
139 void set_cell_field(
const std::string& name, F&& field) {
140 static_assert(!std::is_lvalue_reference_v<F>,
"Cannot take fields by reference, please move");
144 void set_cell_field(
const std::string& name, FieldPtr field_ptr) {
145 _cell_fields.set(name, field_ptr);
148 FieldPtr remove_cell_field(
const std::string& name) {
149 return _cell_fields.pop(name);
154 _point_fields.clear();
155 _cell_fields.clear();
158 void set_ignore_warnings(
bool value) {
159 _ignore_warnings = value;
162 const Grid& grid()
const {
166 const std::optional<WriterOptions>& writer_options()
const {
170 template<
typename Writer>
171 void copy_fields(
Writer& w)
const {
173 throw TypeError(
"Cannot copy fields into writers with different options");
174 if (_opts.has_value() && writer_options().value() != w.
writer_options().value())
175 throw TypeError(
"Cannot copy fields into writers with different options");
177 for (
const auto& [name, field_ptr] : meta_data_fields(*
this))
179 for (
const auto& [name, field_ptr] : point_fields(*
this))
181 for (
const auto& [name, field_ptr] : cell_fields(*
this))
186 friend Concepts::RangeOf<std::pair<std::string, FieldPtr>>
auto
188 return writer._point_field_names()
189 | std::views::filter([&, r=rank] (
const std::string& n) {
190 return writer._get_point_field(n).layout().dimension() - 1 == r;
192 | std::views::transform([&] (std::string n) {
193 auto field_ptr = writer._get_point_field_ptr(n);
194 return std::make_pair(std::move(n), std::move(field_ptr));
199 friend Concepts::RangeOf<std::pair<std::string, FieldPtr>>
auto
201 return writer._cell_field_names()
202 | std::views::filter([&, r=rank] (
const std::string& n) {
203 return writer._get_cell_field(n).layout().dimension() - 1 == r;
205 | std::views::transform([&] (std::string n) {
206 auto field_ptr = writer._get_cell_field_ptr(n);
207 return std::make_pair(std::move(n), std::move(field_ptr));
211 friend Concepts::RangeOf<std::pair<std::string, FieldPtr>>
auto point_fields(
const GridWriterBase& writer) {
212 return writer._point_field_names() | std::views::transform([&] (std::string n) {
213 auto field_ptr = writer._get_point_field_ptr(n);
214 return std::make_pair(std::move(n), std::move(field_ptr));
218 friend Concepts::RangeOf<std::pair<std::string, FieldPtr>>
auto cell_fields(
const GridWriterBase& writer) {
219 return writer._cell_field_names() | std::views::transform([&] (std::string n) {
220 auto field_ptr = writer._get_cell_field_ptr(n);
221 return std::make_pair(std::move(n), std::move(field_ptr));
225 friend Concepts::RangeOf<std::pair<std::string, FieldPtr>>
auto meta_data_fields(
const GridWriterBase& writer) {
226 return writer._meta_data_field_names() | std::views::transform([&] (std::string n) {
227 auto field_ptr = writer._get_meta_data_field_ptr(n);
228 return std::make_pair(std::move(n), std::move(field_ptr));
233 void _log_warning(std::string_view warning)
const {
234 if (!_ignore_warnings)
237 + (warning.ends_with(
"\n") ?
"" :
"\n")
238 +
"To deactivate this warning, call set_ignore_warnings(true);"
242 template<
typename EntityFunction, Concepts::Scalar T>
243 auto _make_point_field(EntityFunction&& f,
const Precision<T>& prec)
const {
244 if (_opts.has_value())
245 return PointField{_grid, std::move(f), _opts.value().use_structured_grid_ordering, prec};
246 return PointField{_grid, std::move(f),
false, prec};
249 template<
typename EntityFunction, Concepts::Scalar T>
250 auto _make_cell_field(EntityFunction&& f,
const Precision<T>& prec)
const {
251 if (_opts.has_value())
252 return CellField{_grid, std::move(f), _opts.value().use_structured_grid_ordering, prec};
253 return CellField{_grid, std::move(f),
false, prec};
256 std::ranges::range
auto _point_field_names()
const {
257 return _point_fields.field_names();
260 std::ranges::range
auto _cell_field_names()
const {
261 return _cell_fields.field_names();
264 const Field& _get_point_field(
const std::string& name)
const {
265 return _point_fields.get(name);
268 FieldPtr _get_point_field_ptr(
const std::string& name)
const {
269 return _point_fields.get_ptr(name);
272 const Field& _get_cell_field(
const std::string& name)
const {
273 return _cell_fields.get(name);
276 FieldPtr _get_cell_field_ptr(
const std::string& name)
const {
277 return _cell_fields.get_ptr(name);
280 std::ranges::range
auto _meta_data_field_names()
const {
281 return _meta_data.field_names();
284 const Field& _get_meta_data_field(
const std::string& name)
const {
285 return _meta_data.get(name);
288 FieldPtr _get_meta_data_field_ptr(
const std::string& name)
const {
289 return _meta_data.get_ptr(name);
294 FieldStorage _point_fields;
295 FieldStorage _cell_fields;
296 FieldStorage _meta_data;
297 std::optional<WriterOptions> _opts;
298 bool _ignore_warnings =
false;
302template<
typename Gr
id>
312 explicit GridWriter(
const Grid& grid, std::string extension, std::optional<WriterOptions> opts)
314 , _extension(std::move(extension))
317 std::string write(
const std::string& filename)
const {
318 std::string filename_with_ext = filename + _extension;
319 _write(filename_with_ext);
320 return filename_with_ext;
323 void write(std::ostream& s)
const {
327 const std::string& extension()
const {
332 std::string _extension;
334 virtual void _write(
const std::string& filename_with_ext)
const {
335 std::ofstream result_file(filename_with_ext, std::ios::out);
339 virtual void _write(std::ostream&)
const = 0;
343template<
typename Gr
id>
357 std::string write(
double t) {
358 std::string filename = _write(t);
364 unsigned _step_count = 0;
367 virtual std::string _write(
double) = 0;
371namespace GridDetail {
373 template<
bool is_transient,
typename G>
376 struct WriterBase<true, G> : std::type_identity<TimeSeriesGridWriter<G>> {};
378 struct WriterBase<false, G> : std::type_identity<GridWriter<G>> {};
FieldPtr make_field_ptr(F &&f)
Factory function for field pointers.
Definition: field.hpp:192