8#ifndef GRIDFORMAT_GRID_CONVERTER_HPP_
9#define GRIDFORMAT_GRID_CONVERTER_HPP_
21#include <gridformat/common/exceptions.hpp>
23#include <gridformat/grid/cell_type.hpp>
30namespace ConverterDetail {
32 struct ConverterGrid {
33 const GridReader& reader;
34 std::vector<std::array<double, 3>> points;
35 std::vector<std::pair<CellType, std::vector<std::size_t>>> cells;
37 explicit ConverterGrid(
const GridReader& r) : reader{r} {}
48 const auto in_points = reader.points();
49 const auto in_layout = in_points->layout();
50 const auto in_np = in_layout.extent(0);
51 const auto in_dim = in_layout.dimension() > 1 ? in_layout.extent(1) : 0;
52 if (in_np != reader.number_of_points())
53 throw SizeError(
"Mismatch between stored and defined number of points.");
55 points.reserve(in_np);
56 in_points->visit_field_values([&] <
typename T> (std::span<const T> values) {
57 std::ranges::for_each(std::views::iota(std::size_t{0}, in_np), [&] (
auto p_idx) {
59 std::ranges::for_each(std::views::iota(std::size_t{0}, in_dim), [&] (
auto dim) {
60 points.back().at(dim) =
static_cast<double>(values[p_idx*in_dim + dim]);
67 cells.reserve(reader.number_of_cells());
68 reader.visit_cells([&] (CellType ct, std::vector<std::size_t> corners) {
69 cells.emplace_back(std::pair{std::move(ct), std::move(corners)});
71 if (cells.size() != reader.number_of_cells())
72 throw SizeError(
"Mismatch between stored and defined number of cells.");
78 =
requires {
typename std::remove_cvref_t<T>::Grid; }
79 and std::derived_from<std::remove_cvref_t<T>, GridWriterBase<typename T::Grid>>;
82 concept PieceWriter = Writer<T> and std::derived_from<std::remove_cvref_t<T>, GridWriter<typename T::Grid>>;
85 concept TimeSeriesWriter = Writer<T> and std::derived_from<std::remove_cvref_t<T>, TimeSeriesGridWriter<typename T::Grid>>;
88 concept PieceWriterFactory =
requires (
const T& factory,
const ConverterGrid& grid) {
89 { factory(grid) } -> PieceWriter;
93 concept TimeSeriesWriterFactory =
requires (
const T& factory,
const ConverterGrid& grid,
const std::string& filename) {
94 { factory(grid) } -> TimeSeriesWriter;
98 concept WriterFactory = PieceWriterFactory<T> or TimeSeriesWriterFactory<T>;
100 template<
typename Reader, Writer Writer>
101 void add_piece_fields(
const Reader& reader, Writer& writer) {
103 for (
auto [name, field_ptr] : cell_fields(reader))
104 writer.set_cell_field(std::move(name), std::move(field_ptr));
105 for (
auto [name, field_ptr] : point_fields(reader))
106 writer.set_point_field(std::move(name), std::move(field_ptr));
107 for (
auto [name, field_ptr] : meta_data_fields(reader))
108 writer.set_meta_data(std::move(name), std::move(field_ptr));
111 template<
typename Reader, PieceWriter Writer>
112 std::string write_piece(
const Reader& reader, Writer& writer,
const std::string& filename) {
113 add_piece_fields(reader, writer);
114 return writer.write(filename);
117 template<
typename Reader, TimeSeriesWriter Writer>
118 std::string write_piece(
const Reader& reader, Writer& writer,
double time_step) {
119 add_piece_fields(reader, writer);
120 return writer.write(time_step);
133template<std::derived_from<Gr
idReader> Reader, ConverterDetail::WriterFactory Factory>
134std::string
convert(
const Reader& reader,
const std::string& filename,
const Factory& factory) {
135 ConverterDetail::ConverterGrid grid{reader};
136 auto writer = factory(grid);
137 if (reader.
filename() == filename + writer.extension())
138 throw GridFormat::IOError(
"Cannot read/write from/to the same file");
141 return ConverterDetail::write_piece(reader, writer, filename);
151template<std::derived_from<Gr
idReader> Reader,
152 ConverterDetail::TimeSeriesWriterFactory Factory,
153 std::invocable<std::
size_t, const std::
string&> StepCallBack = decltype([] (std::
size_t, const std::
string&) {})>
155 const Factory& factory,
156 const StepCallBack& call_back = {}) {
158 throw ValueError(
"Cannot convert data from reader to a sequence as the file read is no sequence.");
160 ConverterDetail::ConverterGrid grid{reader};
161 auto writer = factory(grid);
162 std::string filename;
165 if constexpr (Traits::WritesConnectivity<std::remove_cvref_t<
decltype(writer)>>::value)
167 filename = ConverterDetail::write_piece(reader, writer, reader.
time_at_step(step));
168 call_back(step, filename);
178struct Points<ConverterDetail::ConverterGrid> {
179 static std::ranges::range
auto get(
const ConverterDetail::ConverterGrid& grid) {
180 return std::views::iota(std::size_t{0}, grid.reader.number_of_points());
185struct Cells<ConverterDetail::ConverterGrid> {
186 static std::ranges::range
auto get(
const ConverterDetail::ConverterGrid& grid) {
187 const auto max =
static_cast<std::int64_t
>(grid.reader.number_of_cells());
189 throw TypeError(
"Integer overflow. Too many grid cells.");
190 return std::views::iota(std::int64_t{0}, max);
195struct NumberOfPoints<ConverterDetail::ConverterGrid> {
196 static std::size_t get(
const ConverterDetail::ConverterGrid& grid) {
197 return grid.reader.number_of_points();
202struct NumberOfCells<ConverterDetail::ConverterGrid> {
203 static std::size_t get(
const ConverterDetail::ConverterGrid& grid) {
204 return grid.reader.number_of_cells();
209struct CellPoints<ConverterDetail::ConverterGrid, std::int64_t> {
210 static std::ranges::range
auto get(
const ConverterDetail::ConverterGrid& grid,
const std::int64_t i) {
211 return grid.cells.at(i).second | std::views::all;
216struct CellType<ConverterDetail::ConverterGrid, std::int64_t> {
217 static GridFormat::CellType get(
const ConverterDetail::ConverterGrid& grid,
const std::int64_t i) {
218 return grid.cells.at(i).first;
223struct PointCoordinates<ConverterDetail::ConverterGrid, std::size_t> {
224 static std::array<double, 3> get(
const ConverterDetail::ConverterGrid& grid,
const std::size_t i) {
225 return grid.points.at(i);
230struct PointId<ConverterDetail::ConverterGrid, std::size_t> {
231 static std::size_t get(
const ConverterDetail::ConverterGrid&,
const std::size_t i) {
237struct NumberOfCellPoints<ConverterDetail::ConverterGrid, std::int64_t> {
238 static std::size_t get(
const ConverterDetail::ConverterGrid& grid,
const std::int64_t i) {
239 return grid.cells.at(i).second.size();
244struct Origin<ConverterDetail::ConverterGrid> {
245 static std::array<double, 3> get(
const ConverterDetail::ConverterGrid& grid) {
246 return grid.reader.origin();
251struct Spacing<ConverterDetail::ConverterGrid> {
252 static std::array<double, 3> get(
const ConverterDetail::ConverterGrid& grid) {
253 return grid.reader.spacing();
258struct Basis<ConverterDetail::ConverterGrid> {
259 static std::array<std::array<double, 3>, 3> get(
const ConverterDetail::ConverterGrid& grid) {
260 std::array<std::array<double, 3>, 3> result;
261 for (
unsigned int i = 0; i < 3; ++i)
262 result[i] = grid.reader.basis_vector(i);
268struct Extents<ConverterDetail::ConverterGrid> {
269 static std::array<std::size_t, 3> get(
const ConverterDetail::ConverterGrid& grid) {
270 return grid.reader.extents();
275struct Ordinates<ConverterDetail::ConverterGrid> {
276 static std::vector<double> get(
const ConverterDetail::ConverterGrid& grid,
unsigned int i) {
277 return grid.reader.ordinates(i);
281template<
typename Entity>
282struct Location<ConverterDetail::ConverterGrid, Entity> {
283 static std::array<std::size_t, 3> get(
const ConverterDetail::ConverterGrid& grid,
const std::size_t point) {
284 return _get(Ranges::incremented(Extents<ConverterDetail::ConverterGrid>::get(grid), 1), point);
287 static std::array<std::size_t, 3> get(
const ConverterDetail::ConverterGrid& grid,
const std::int64_t cell) {
288 return _get(Extents<ConverterDetail::ConverterGrid>::get(grid), cell);
292 static std::array<std::size_t, 3> _get(std::ranges::range
auto extents, std::integral
auto index) {
294 std::ranges::for_each(extents, [] <std::integral T> (T& e) { e = std::max(e, T{1}); });
295 const auto accumulate_until = [&] (
int dim) {
296 auto range = extents | std::views::take(dim);
297 return std::accumulate(
298 std::ranges::begin(range),
299 std::ranges::end(range),
305 const auto divisor1 = accumulate_until(1);
306 const auto divisor2 = accumulate_until(2);
308 index%divisor2%divisor1,
309 index%divisor2/divisor1,
Base class for grid data readers.
Base classes for grid data writers.
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