OGS
transformData.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "transformData.h"
5
6#include <algorithm>
7#include <array>
8#include <optional>
9#include <range/v3/action/push_back.hpp>
10#include <range/v3/view/transform.hpp>
11#include <string>
12
13#include "BaseLib/cpp23.h"
14#if defined(USE_PETSC)
15#include "BaseLib/MPI.h"
16#endif
17#include "InfoLib/GitInfo.h"
19#include "MeshLib/Mesh.h"
20#include "MeshLib/MeshEnums.h"
21#include "MeshLib/Node.h"
23#include "partition.h"
24
25using namespace BaseLib;
26namespace MeshLib::IO
27{
29{
30 // https://xdmf.org/index.php/XDMF_Model_and_Format#Topology, Section
31 // Arbitrary
33 unsigned int number_of_nodes;
34};
35
36static constexpr auto elemOGSTypeToXDMFType()
37{
39 elem_type{};
67 ParentDataType::WEDGE, 6}; // parallel triangle wedge
76 return elem_type;
77}
78
80
81constexpr auto cellTypeOGS2XDMF(MeshLib::CellType const& cell_type)
82{
83 return elem_type_ogs2xdmf[to_underlying(cell_type)];
84}
85
86std::optional<XdmfHdfData> transformAttribute(
87 std::pair<std::string, PropertyVectorBase*> const& property_pair,
88 unsigned int const n_files, unsigned int const chunk_size_bytes)
89{
90 // 3 data that will be captured and written by lambda f below
92 std::size_t num_of_tuples = 0;
93 void const* data_ptr = 0;
94
95 // lambda f : Collects properties from the PropertyVectorBase. It captures
96 // (and overwrites) data that can only be collected via the typed property.
97 // It has boolean return type to allow kind of pipe using || operator.
98 auto f = [&data_type, &num_of_tuples, &data_ptr,
99 &property_pair](auto basic_type) -> bool
100 {
101 auto const property_base = property_pair.second;
102 auto const typed_property =
103 dynamic_cast<PropertyVector<decltype(basic_type)> const*>(
104 property_base);
105 if (typed_property == nullptr)
106 {
107 return false;
108 }
109 // overwrite captured data
110 num_of_tuples = typed_property->getNumberOfTuples();
111 data_ptr = typed_property->data();
112
113 if constexpr (std::is_same_v<double, decltype(basic_type)>)
114 {
115 // The standard 64-bit IEEE 754 floating-point type
116 // (double-precision) has a 53 bit fractional part (52 bits written,
117 // one implied)
118 static_assert((std::numeric_limits<double>::digits == 53),
119 "Double has 52 bits fractional part");
121 }
122 else if constexpr (std::is_same_v<float, decltype(basic_type)>)
123 {
124 // The standard 32-bit IEEE 754 floating-point type
125 // (single-precision) has a 24 bit fractional part (23 bits written,
126 // one implied)
127 static_assert((std::numeric_limits<float>::digits == 24),
128 "Float has 23 bits fractional part");
130 }
131 else if constexpr (std::is_same_v<int32_t, decltype(basic_type)>)
132 {
133 data_type = MeshPropertyDataType::int32;
134 }
135 else if constexpr (std::is_same_v<uint32_t, decltype(basic_type)>)
136 {
138 }
139 else if constexpr (std::is_same_v<int64_t, decltype(basic_type)>)
140 {
141 data_type = MeshPropertyDataType::int64;
142 }
143 else if constexpr (std::is_same_v<uint64_t, decltype(basic_type)>)
144 {
146 }
147 else if constexpr (std::is_same_v<int8_t, decltype(basic_type)>)
148 {
149 data_type = MeshPropertyDataType::int8;
150 }
151 else if constexpr (std::is_same_v<uint8_t, decltype(basic_type)>)
152 {
153 data_type = MeshPropertyDataType::uint8;
154 }
155 else if constexpr (std::is_same_v<char, decltype(basic_type)>)
156 {
158 }
159 else if constexpr (std::is_same_v<unsigned char, decltype(basic_type)>)
160 {
161 static_assert((std::numeric_limits<unsigned char>::digits == 8),
162 "Unsigned char has 8 bits");
163 data_type = MeshPropertyDataType::uchar;
164 }
165 else if constexpr (std::is_same_v<unsigned long, decltype(basic_type)>)
166 {
167 if (sizeof(unsigned long) == 8 &&
168 std::numeric_limits<unsigned long>::digits == 64)
169 {
171 }
172 else if (sizeof(unsigned long) == 4 &&
173 std::numeric_limits<unsigned long>::digits == 32)
174 {
176 }
177 else
178 {
179 return false;
180 }
181 }
182 else if constexpr (std::is_same_v<std::size_t, decltype(basic_type)>)
183 {
184 if (sizeof(std::size_t) == 8 &&
185 std::numeric_limits<std::size_t>::digits == 64)
186 {
188 }
189 else if (sizeof(std::size_t) == 4 &&
190 std::numeric_limits<std::size_t>::digits == 32)
191 {
193 }
194 else
195 {
196 return false;
197 }
198 }
199 else
200 {
201 return false;
202 }
203 return true;
204 };
205
206 f(double{}) || f(float{}) || f(int{}) || f(long{}) || f(unsigned{}) ||
207 f(long{}) || f(static_cast<unsigned long>(0)) || f(std::size_t{}) ||
208 f(char{}) || f(static_cast<unsigned char>(0));
209
210 if (data_type == MeshPropertyDataType::unknown)
211 {
212 return std::nullopt;
213 }
214
215 auto const& property_base = property_pair.second;
216 auto const& global_components =
217 property_base->getNumberOfGlobalComponents();
218 // TODO (tm) property_pair vector::getNumberOfGlobalComponents should return
219 // unsigned value. Then explicit cast from signed to unsigned int and
220 // assert can be removed here. Implicit cast to long long is fine and
221 // can be kept
222 assert(global_components >= 0);
223 auto const ui_global_components =
224 static_cast<unsigned int>(global_components);
225
226 MeshLib::MeshItemType const mesh_item_type =
227 property_base->getMeshItemType();
228
229 std::string const& name = property_base->getPropertyName();
230
231 HdfData hdf = {data_ptr, num_of_tuples, ui_global_components, name,
232 data_type, n_files, chunk_size_bytes};
233
234 XdmfData xdmf{num_of_tuples, ui_global_components, data_type,
235 name, mesh_item_type, n_files,
236 std::nullopt};
237
238 return XdmfHdfData{std::move(hdf), std::move(xdmf)};
239}
240
241std::vector<XdmfHdfData> transformAttributes(
242 MeshLib::Mesh const& mesh,
243 std::set<std::string> const& output_variable_names,
244 unsigned int const n_files,
245 unsigned int const chunk_size_bytes)
246{
247 MeshLib::Properties const& properties = mesh.getProperties();
248
249 // \TODO (tm) use c++20 ranges
250 // a = p | filter (first!=OGS_VERSION) | filter null_opt | transformAttr |
251 std::vector<XdmfHdfData> attributes;
252 for (auto const& [name, property_base] : properties)
253 {
255 {
256 continue;
257 }
258
259 if (!output_variable_names.contains(name))
260 {
261 continue;
262 }
263
264 if (auto const attribute = transformAttribute(
265
266 std::pair(std::string(name), property_base), n_files,
267 chunk_size_bytes))
268
269 {
270 attributes.push_back(attribute.value());
271 }
272 else
273 {
274 WARN("Could not create attribute meta of {:s}.", name);
275 }
276 }
277 return attributes;
278}
279
280std::vector<double> transformToXDMFGeometry(MeshLib::Mesh const& mesh)
281{
282 std::vector<MeshLib::Node*> const& nodes = mesh.getNodes();
283
284 int const point_size = 3;
285 std::vector<double> values;
286 values.reserve(nodes.size() * point_size);
287 for (auto const& n : nodes)
288 {
289 const double* x = n->data();
290 values.insert(values.cend(), x, x + point_size);
291 }
292
293 return values;
294}
295
296XdmfHdfData transformGeometry(MeshLib::Mesh const& mesh, double const* data_ptr,
297 unsigned int const n_files,
298 unsigned int const chunk_size_bytes)
299{
300 std::string const name = "geometry";
301 std::vector<MeshLib::Node*> const& nodes = mesh.getNodes();
302
303 int const point_size = 3;
304 auto const& partition_dim = nodes.size();
305
306 HdfData const hdf = {data_ptr,
307 partition_dim,
308 point_size,
309 name,
311 n_files,
312 chunk_size_bytes};
313 XdmfData const xdmf = {
314 partition_dim, point_size, MeshPropertyDataType::float64,
315 name, std::nullopt, n_files,
316 std::nullopt};
317
318 return XdmfHdfData{std::move(hdf), std::move(xdmf)};
319}
320
322{
323 auto const& elements = mesh.getElements();
324
325 if (elements.empty())
326 {
328 }
329 auto const ogs_cell_type = elements[0]->getCellType();
330
331 if (std::any_of(elements.begin(), elements.end(), [&](auto const& cell)
332 { return cell->getCellType() != ogs_cell_type; }))
333 {
335 }
336
337 return cellTypeOGS2XDMF(ogs_cell_type).id;
338}
339
340#if !defined(USE_PETSC)
342{
343 return getLocalTopologyType(mesh);
344}
345#else
347{
348 auto const local_topology_type = getLocalTopologyType(mesh);
349 // get the topology_type from other partitions
350 BaseLib::MPI::Mpi const mpi;
351
352 std::vector<int> const topology_types =
353 BaseLib::MPI::allgather(static_cast<int>(local_topology_type), mpi);
354
355 auto const common_topology_type =
356 std::all_of(topology_types.begin(), topology_types.end(),
357 [&local_topology_type](int other)
358 { return other == static_cast<int>(local_topology_type); })
359 ? local_topology_type
361 return common_topology_type;
362}
363#endif // USE_PETSC
364
365std::pair<std::vector<std::size_t>, ParentDataType> transformToXDMFTopology(
366 MeshLib::Mesh const& mesh, std::size_t const offset)
367{
368 std::vector<MeshLib::Element*> const& elements = mesh.getElements();
369 std::vector<std::size_t> values;
370
371 auto const push_cellnode_ids_to_vector =
372 [&values, &offset](auto const& cell)
373 {
374 values |= ranges::actions::push_back(
375 cell->nodes() | MeshLib::views::ids |
376 ranges::views::transform([&offset](auto const node_id)
377 { return node_id + offset; }));
378 };
379
380 auto const topology_type = getTopologyType(mesh);
381 if (topology_type == ParentDataType::MIXED)
382 {
383 values.reserve(elements.size() * 2); // each cell has at least two
384 // numbers
385 for (auto const& cell : elements)
386 {
387 auto const ogs_cell_type = cell->getCellType();
388 auto const xdmf_cell_id = cellTypeOGS2XDMF(ogs_cell_type).id;
389 values.push_back(to_underlying(xdmf_cell_id));
390 if (ogs_cell_type == MeshLib::CellType::LINE2)
391 {
392 values.push_back(2);
393 }
394 push_cellnode_ids_to_vector(cell);
395 }
396 }
397 else
398 {
399 values.reserve(elements.size() * elements[0]->getNumberOfNodes());
400 for (auto const& cell : elements)
401 {
402 push_cellnode_ids_to_vector(cell);
403 }
404 }
405
406 return {values, topology_type};
407}
408
409XdmfHdfData transformTopology(std::vector<std::size_t> const& values,
410 ParentDataType const parent_data_type,
411 unsigned int const n_files,
412 unsigned int const chunk_size_bytes)
413{
414 std::string const name = "topology";
415 auto const tuple_size = ParentDataType2String(parent_data_type).second;
416 HdfData const hdf = {values.data(),
417 values.size() / tuple_size,
418 tuple_size,
419 name,
421 n_files,
422 chunk_size_bytes};
423 XdmfData const xdmf{values.size() / tuple_size,
424 tuple_size,
426 name,
427 std::nullopt,
428 n_files,
429 parent_data_type};
430
431 return XdmfHdfData{std::move(hdf), std::move(xdmf)};
432}
433} // namespace MeshLib::IO
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
std::pair< std::string, std::size_t > ParentDataType2String(ParentDataType p)
MeshPropertyDataType
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition Mesh.h:98
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:101
Properties & getProperties()
Definition Mesh.h:127
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
constexpr std::size_t getNumberOfTuples() const
static std::vector< T > allgather(T const &value, Mpi const &mpi)
Definition MPI.h:87
constexpr auto to_underlying(E e) noexcept
Converts an enumeration to its underlying type.
Definition cpp23.h:22
const std::string OGS_VERSION
Definition GitInfo.cpp:11
ParentDataType getLocalTopologyType(MeshLib::Mesh const &mesh)
constexpr auto cellTypeOGS2XDMF(MeshLib::CellType const &cell_type)
ParentDataType getTopologyType(MeshLib::Mesh const &mesh)
std::optional< XdmfHdfData > transformAttribute(std::pair< std::string, PropertyVectorBase * > const &property_pair, unsigned int const n_files, unsigned int const chunk_size_bytes)
std::pair< std::vector< std::size_t >, ParentDataType > transformToXDMFTopology(MeshLib::Mesh const &mesh, std::size_t const offset)
Copies all cells into a new vector. Contiguous data used for writing. The topology is specific to xdm...
std::vector< double > transformToXDMFGeometry(MeshLib::Mesh const &mesh)
Copies all node points into a new vector. Contiguous data used for writing. Conform with XDMF standar...
XdmfHdfData transformGeometry(MeshLib::Mesh const &mesh, double const *data_ptr, unsigned int const n_files, unsigned int const chunk_size_bytes)
Create meta data for geometry used for hdf5 and xdmf.
static constexpr auto elemOGSTypeToXDMFType()
std::vector< XdmfHdfData > transformAttributes(MeshLib::Mesh const &mesh, std::set< std::string > const &output_variable_names, unsigned int const n_files, unsigned int const chunk_size_bytes)
Create meta data for attributes used for hdf5 and xdmf.
XdmfHdfData transformTopology(std::vector< std::size_t > const &values, ParentDataType const parent_data_type, unsigned int const n_files, unsigned int const chunk_size_bytes)
Create meta data for topology used for HDF5 and XDMF.
constexpr auto elem_type_ogs2xdmf
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
Definition Mesh.h:218
CellType
Types of mesh elements supported by OpenGeoSys.
Definition MeshEnums.h:54