OGS
VtkMeshConverter.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 "VtkMeshConverter.h"
5
6#include <cstdint>
7
9#include "MeshLib/Mesh.h"
10#include "MeshLib/Node.h"
11
12// Conversion from Image to QuadMesh
13#include <vtkBitArray.h>
14#include <vtkCharArray.h>
15#include <vtkDoubleArray.h>
16#include <vtkFloatArray.h>
17#include <vtkIdTypeArray.h>
18#include <vtkImageData.h>
19#include <vtkIntArray.h>
20#include <vtkLongArray.h>
21#include <vtkLongLongArray.h>
22#include <vtkPointData.h>
23#include <vtkShortArray.h>
24#include <vtkSignedCharArray.h>
25#include <vtkSmartPointer.h>
26#include <vtkUnsignedCharArray.h>
27#include <vtkUnsignedLongArray.h>
28#include <vtkUnsignedLongLongArray.h>
29#include <vtkUnsignedShortArray.h>
30
31// Conversion from vtkUnstructuredGrid
32#include <vtkCell.h>
33#include <vtkCellData.h>
34#include <vtkUnsignedIntArray.h>
35#include <vtkUnstructuredGrid.h>
36
37namespace MeshLib
38{
39namespace detail
40{
41template <class T_ELEMENT>
43 const std::vector<MeshLib::Node*>& nodes, vtkIdList* const node_ids,
44 std::size_t const element_id)
45{
46 auto** ele_nodes = new MeshLib::Node*[T_ELEMENT::n_all_nodes];
47 for (unsigned k(0); k < T_ELEMENT::n_all_nodes; k++)
48 {
49 ele_nodes[k] = nodes[node_ids->GetId(k)];
50 }
51 return new T_ELEMENT(ele_nodes, element_id);
52}
53} // namespace detail
54
56 vtkUnstructuredGrid* grid, bool const compute_element_neighbors,
57 std::string const& mesh_name)
58{
59 if (!grid)
60 {
61 return nullptr;
62 }
63
64 // set mesh nodes
65 const std::size_t nNodes = grid->GetPoints()->GetNumberOfPoints();
66 std::vector<MeshLib::Node*> nodes(nNodes);
67 double* coords = nullptr;
68 for (std::size_t i = 0; i < nNodes; i++)
69 {
70 coords = grid->GetPoints()->GetPoint(i);
71 nodes[i] = new MeshLib::Node(coords[0], coords[1], coords[2], i);
72 }
73
74 // set mesh elements
75 const std::size_t nElems = grid->GetNumberOfCells();
76 std::vector<MeshLib::Element*> elements;
77 elements.reserve(nElems);
78 auto node_ids = vtkSmartPointer<vtkIdList>::New();
79 for (std::size_t i = 0; i < nElems; i++)
80 {
81 MeshLib::Element* elem;
82 grid->GetCellPoints(i, node_ids);
83
84 int cell_type = grid->GetCellType(i);
85 switch (cell_type)
86 {
87 case VTK_VERTEX:
88 {
90 nodes, node_ids, i);
91 break;
92 }
93 case VTK_LINE:
94 {
96 nodes, node_ids, i);
97 break;
98 }
99 case VTK_TRIANGLE:
100 {
102 nodes, node_ids, i);
103 break;
104 }
105 case VTK_QUAD:
106 {
108 nodes, node_ids, i);
109 break;
110 }
111 case VTK_PIXEL:
112 {
113 auto** quad_nodes = new MeshLib::Node*[4];
114 quad_nodes[0] = nodes[node_ids->GetId(0)];
115 quad_nodes[1] = nodes[node_ids->GetId(1)];
116 quad_nodes[2] = nodes[node_ids->GetId(3)];
117 quad_nodes[3] = nodes[node_ids->GetId(2)];
118 elem = new MeshLib::Quad(quad_nodes, i);
119 break;
120 }
121 case VTK_TETRA:
122 {
124 nodes, node_ids, i);
125 break;
126 }
127 case VTK_HEXAHEDRON:
128 {
130 nodes, node_ids, i);
131 break;
132 }
133 case VTK_VOXEL:
134 {
135 auto** voxel_nodes = new MeshLib::Node*[8];
136 voxel_nodes[0] = nodes[node_ids->GetId(0)];
137 voxel_nodes[1] = nodes[node_ids->GetId(1)];
138 voxel_nodes[2] = nodes[node_ids->GetId(3)];
139 voxel_nodes[3] = nodes[node_ids->GetId(2)];
140 voxel_nodes[4] = nodes[node_ids->GetId(4)];
141 voxel_nodes[5] = nodes[node_ids->GetId(5)];
142 voxel_nodes[6] = nodes[node_ids->GetId(7)];
143 voxel_nodes[7] = nodes[node_ids->GetId(6)];
144 elem = new MeshLib::Hex(voxel_nodes, i);
145 break;
146 }
147 case VTK_PYRAMID:
148 {
150 nodes, node_ids, i);
151 break;
152 }
153 case VTK_WEDGE:
154 {
155 auto** prism_nodes = new MeshLib::Node*[6];
156 for (unsigned j = 0; j < 3; ++j)
157 {
158 prism_nodes[j] = nodes[node_ids->GetId(j + 3)];
159 prism_nodes[j + 3] = nodes[node_ids->GetId(j)];
160 }
161 elem = new MeshLib::Prism(prism_nodes, i);
162 break;
163 }
164 case VTK_QUADRATIC_EDGE:
165 {
167 nodes, node_ids, i);
168 break;
169 }
170 case VTK_QUADRATIC_TRIANGLE:
171 {
173 nodes, node_ids, i);
174 break;
175 }
176 case VTK_QUADRATIC_QUAD:
177 {
179 nodes, node_ids, i);
180 break;
181 }
182 case VTK_BIQUADRATIC_QUAD:
183 {
185 nodes, node_ids, i);
186 break;
187 }
188 case VTK_QUADRATIC_TETRA:
189 {
191 nodes, node_ids, i);
192 break;
193 }
194 case VTK_QUADRATIC_HEXAHEDRON:
195 {
197 nodes, node_ids, i);
198 break;
199 }
200 case VTK_QUADRATIC_PYRAMID:
201 {
202 elem =
204 nodes, node_ids, i);
205 break;
206 }
207 case VTK_QUADRATIC_WEDGE:
208 {
210 nodes, node_ids, i);
211
212 break;
213 }
214 default:
215 ERR("VtkMeshConverter::convertUnstructuredGrid(): Unknown mesh "
216 "element type '{:d}'.",
217 cell_type);
218 return nullptr;
219 }
220
221 elements.push_back(elem);
222 }
223
224 MeshLib::Mesh* mesh = new MeshLib::Mesh(mesh_name, nodes, elements,
225 compute_element_neighbors);
226 convertScalarArrays(*grid, *mesh);
227
228 return mesh;
229}
230
231void VtkMeshConverter::convertScalarArrays(vtkUnstructuredGrid& grid,
232 MeshLib::Mesh& mesh)
233{
234 vtkPointData* point_data = grid.GetPointData();
235 auto const n_point_arrays =
236 static_cast<unsigned>(point_data->GetNumberOfArrays());
237 for (unsigned i = 0; i < n_point_arrays; ++i)
238 {
239 convertArray(*point_data->GetArray(i),
240 mesh.getProperties(),
242 }
243
244 vtkCellData* cell_data = grid.GetCellData();
245 auto const n_cell_arrays =
246 static_cast<unsigned>(cell_data->GetNumberOfArrays());
247 for (unsigned i = 0; i < n_cell_arrays; ++i)
248 {
249 convertArray(*cell_data->GetArray(i),
250 mesh.getProperties(),
252 }
253
254 vtkFieldData* field_data = grid.GetFieldData();
255 auto const n_field_arrays =
256 static_cast<unsigned>(field_data->GetNumberOfArrays());
257 for (unsigned i = 0; i < n_field_arrays; ++i)
258 {
260 *vtkDataArray::SafeDownCast(field_data->GetAbstractArray(i)),
261 mesh.getProperties(),
263 }
264}
265
266void VtkMeshConverter::convertArray(vtkDataArray& array,
267 MeshLib::Properties& properties,
269{
270 if (vtkDoubleArray::SafeDownCast(&array))
271 {
272 VtkMeshConverter::convertTypedArray<double>(array, properties, type);
273 return;
274 }
275
276 if (vtkFloatArray::SafeDownCast(&array))
277 {
278 VtkMeshConverter::convertTypedArray<float>(array, properties, type);
279 return;
280 }
281
282 if (vtkBitArray::SafeDownCast(&array))
283 {
284 VtkMeshConverter::convertTypedArray<bool>(array, properties, type);
285 return;
286 }
287
288 // This also covers the vtkTypeInt8Array type, which is derived from the
289 // vtkCharArray type.
290 if (vtkCharArray::SafeDownCast(&array) ||
291 vtkSignedCharArray::SafeDownCast(&array))
292 {
293 if constexpr (sizeof(std::int8_t) != sizeof(char))
294 {
295 OGS_FATAL(
296 "Array '{:s}' in VTU file uses unsupported data type '{:s}' "
297 "not convertible to char.",
298 array.GetName(), array.GetDataTypeAsString());
299 }
300 VtkMeshConverter::convertTypedArray<char>(array, properties, type);
301 return;
302 }
303
304 // This also covers the vtkTypeInt16Array type, which is derived from the
305 // vtkShortArray type.
306 if (vtkShortArray::SafeDownCast(&array))
307 {
308 if constexpr (sizeof(std::int16_t) != sizeof(short))
309 {
310 OGS_FATAL(
311 "Array '{:s}' in VTU file uses unsupported data type '{:s}' "
312 "not convertible to short.",
313 array.GetName(), array.GetDataTypeAsString());
314 }
315 VtkMeshConverter::convertTypedArray<short>(array, properties, type);
316 return;
317 }
318
319 // This also covers the vtkTypeInt32Array type, which is derived from the
320 // vtkIntArray type.
321 if (vtkIntArray::SafeDownCast(&array))
322 {
323 if constexpr (sizeof(std::int32_t) != sizeof(int))
324 {
325 OGS_FATAL(
326 "Array '{:s}' in VTU file uses unsupported data type '{:s}' "
327 "not convertible to int.",
328 array.GetName(), array.GetDataTypeAsString());
329 }
330 VtkMeshConverter::convertTypedArray<int>(array, properties, type);
331 return;
332 }
333
334 // This is not a unique conversion depending on the sizes of int, long, and
335 // long long. Converting to the apparently smaller type.
336 if (vtkLongArray::SafeDownCast(&array))
337 {
338 if constexpr (sizeof(long) == sizeof(int))
339 {
340 VtkMeshConverter::convertTypedArray<int>(array, properties, type);
341 return;
342 }
343 if constexpr (sizeof(long long) == sizeof(long))
344 {
345 VtkMeshConverter::convertTypedArray<long>(array, properties, type);
346 return;
347 }
348
349 OGS_FATAL(
350 "Array '{:s}' in VTU file uses unsupported data type '{:s}' ({:d}) "
351 "not convertible to int ({:d}), or long ({:d}) types.",
352 array.GetName(), array.GetDataTypeAsString(),
353 array.GetDataTypeSize(), sizeof(int), sizeof(long));
354 }
355
356 // Ensure, vtkTypeInt64Array and vtkLongLongArray are using the same type.
357 static_assert(sizeof(std::int64_t) == sizeof(long long));
358
359 // This also covers the vtkTypeInt64Array type, which is derived from the
360 // vtkLongLongArray type.
361 // Converting to the apparently smaller type.
362 if (vtkLongLongArray::SafeDownCast(&array))
363 {
364 if constexpr (sizeof(long long) == sizeof(long))
365 {
366 VtkMeshConverter::convertTypedArray<long>(array, properties, type);
367 return;
368 }
369 else // ll > l. Other cases are not possible because ll >= l in c++.
370 {
372 type);
373 return;
374 }
375 }
376
377 // This also covers the vtkTypeUInt8Array type, which is derived from the
378 // vtkUnsignedCharArray type.
379 if (vtkUnsignedCharArray::SafeDownCast(&array))
380 {
381 if constexpr (sizeof(std::uint8_t) != sizeof(unsigned char))
382 {
383 OGS_FATAL(
384 "Array '{:s}' in VTU file uses unsupported data type '{:s}' "
385 "not convertible to unsigned char.",
386 array.GetName(), array.GetDataTypeAsString());
387 }
389 type);
390 return;
391 }
392
393 // This also covers the vtkTypeUInt16Array type, which is derived from the
394 // vtkUnsignedShortArray type.
395 if (vtkUnsignedShortArray::SafeDownCast(&array))
396 {
397 if constexpr (sizeof(std::uint16_t) != sizeof(unsigned short))
398 {
399 OGS_FATAL(
400 "Array '{:s}' in VTU file uses unsupported data type '{:s}' "
401 "not convertible to unsigned short.",
402 array.GetName(), array.GetDataTypeAsString());
403 }
405 type);
406 return;
407 }
408
409 // This also covers the vtkTypeUInt32Array type, which is derived from the
410 // vtkUnsignedIntArray type.
411 if (vtkUnsignedIntArray::SafeDownCast(&array))
412 {
413 if constexpr (sizeof(std::uint32_t) != sizeof(unsigned))
414 {
415 OGS_FATAL(
416 "Array '{:s}' in VTU file uses unsupported data type '{:s}' "
417 "not convertible to unsigned.",
418 array.GetName(), array.GetDataTypeAsString());
419 }
420
421 // MaterialIDs are assumed to be integers
422 if (std::strncmp(array.GetName(), "MaterialIDs", 11) == 0)
423 {
424 VtkMeshConverter::convertTypedArray<int>(array, properties, type);
425 }
426 else
427 {
429 type);
430 }
431
432 return;
433 }
434
435 // This is not a unique conversion depending on the sizes of unsigned,
436 // unsigned long, and unsigned long long. Converting to the apparently
437 // smaller type.
438 if (vtkUnsignedLongArray::SafeDownCast(&array))
439 {
440 if constexpr (sizeof(unsigned long) == sizeof(unsigned))
441 {
443 type);
444 return;
445 }
446 if constexpr (sizeof(unsigned long long) == sizeof(unsigned long))
447 {
449 array, properties, type);
450 return;
451 }
452
453 OGS_FATAL(
454 "Array '{:s}' in VTU file uses unsupported data type '{:s}' ({:d}) "
455 "not convertible to unsigned ({:d}), or unsigned long ({:d}) "
456 "types.",
457 array.GetName(), array.GetDataTypeAsString(),
458 array.GetDataTypeSize(), sizeof(unsigned), sizeof(unsigned long));
459 }
460
461 // Ensure, vtkTypeUInt64Array and vtkUnsignedLongLongArray are using the
462 // same type.
463 static_assert(sizeof(std::uint64_t) == sizeof(unsigned long long));
464
465 // This also covers the vtkTypeUInt64Array type, which is derived from the
466 // vtkUnsignedLongLongArray type.
467 // Converting to the apparently smaller type.
468 if (vtkUnsignedLongLongArray::SafeDownCast(&array))
469 {
470 if constexpr (sizeof(unsigned long long) == sizeof(unsigned long))
471 {
473 array, properties, type);
474 return;
475 }
476 else // ull > ul. Other cases are not possible because ull >= ul in
477 // c++.
478 {
480 array, properties, type);
481 return;
482 }
483 }
484
485 if (vtkIdTypeArray::SafeDownCast(&array))
486 {
487 // Bulk node ids and bulk element ids are std::size_t in OGS but
488 // sometimes vtkIdType is used in the input (e.g. as result of a vtk
489 // filter).
490 using namespace std::literals;
491 if (array.GetName() == "bulk_element_ids"sv ||
492 array.GetName() == "bulk_node_ids"sv)
493 {
495 type);
496 }
497 else
498 {
500 type);
501 }
502 return;
503 }
504
505 WARN(
506 "Array '{:s}' in VTU file uses unsupported data type '{:s}' of size "
507 "{:d}. The data array will not be available.",
508 array.GetName(), array.GetDataTypeAsString(), array.GetDataTypeSize());
509}
510
511} // end namespace MeshLib
#define OGS_FATAL(...)
Definition Error.h:19
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
Properties & getProperties()
Definition Mesh.h:125
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
static void convertTypedArray(vtkDataArray &array, MeshLib::Properties &properties, MeshLib::MeshItemType type)
static void convertScalarArrays(vtkUnstructuredGrid &grid, MeshLib::Mesh &mesh)
static MeshLib::Mesh * convertUnstructuredGrid(vtkUnstructuredGrid *grid, bool const compute_element_neighbors=false, std::string const &mesh_name="vtkUnstructuredGrid")
Converts a vtkUnstructuredGrid object to a Mesh.
static void convertArray(vtkDataArray &array, MeshLib::Properties &properties, MeshLib::MeshItemType type)
MeshLib::Element * createElementWithSameNodeOrder(const std::vector< MeshLib::Node * > &nodes, vtkIdList *const node_ids, std::size_t const element_id)
TemplateElement< MeshLib::QuadRule4 > Quad
Definition Quad.h:17
TemplateElement< MeshLib::PrismRule6 > Prism
Definition Prism.h:14
TemplateElement< MeshLib::HexRule8 > Hex
Definition Hex.h:14