ViennaLS
Loading...
Searching...
No Matches
lsVTKReader.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <fstream>
4#include <string>
5#include <unordered_map>
6
7#include <lsFileFormats.hpp>
8#include <lsMesh.hpp>
9
10#include <utility>
11#include <vcLogger.hpp>
12#include <vcSmartPointer.hpp>
13
14#ifdef VIENNALS_USE_VTK
15#include <vtkCellData.h>
16#include <vtkIdList.h>
17#include <vtkPointData.h>
18#include <vtkPolyData.h>
19#include <vtkSmartPointer.h>
20#include <vtkUnstructuredGrid.h>
21#include <vtkXMLPolyDataReader.h>
22#include <vtkXMLUnstructuredGridReader.h>
23#endif // VIENNALS_USE_VTK
24
25namespace viennals {
26
27using namespace viennacore;
28
30template <class T = double> class VTKReader {
31 SmartPointer<Mesh<T>> mesh = nullptr;
33 std::string fileName;
34 std::unordered_map<std::string, std::vector<T>> metaData;
35
36 unsigned vtk_nodes_for_cell_type[15] = {0, 1, 0, 2, 0, 3, 0, 0,
37 4, 4, 4, 8, 8, 6, 5};
38
39 // accepts either vtkPolyData or vtkUnstructuredGrid
40 void extractFieldData(vtkDataSet *data) {
41 vtkFieldData *fieldData = data->GetFieldData();
42 if (!fieldData)
43 return;
44
45 for (int i = 0; i < fieldData->GetNumberOfArrays(); ++i) {
46 vtkDataArray *array = fieldData->GetArray(i);
47 if (!array)
48 continue;
49
50 const char *name = array->GetName();
51 if (!name)
52 continue;
53
54 int numTuples = array->GetNumberOfTuples();
55 int numComponents = array->GetNumberOfComponents();
56
57 std::vector<T> values;
58 values.reserve(numTuples * numComponents);
59
60 for (int t = 0; t < numTuples; ++t) {
61 T tuple[9]; // safe default (up to 9 components)
62 array->GetTuple(t, tuple);
63 for (int c = 0; c < numComponents; ++c)
64 values.push_back(tuple[c]);
65 }
66
67 metaData[name] = std::move(values);
68 }
69 }
70
71public:
72 VTKReader() = default;
73
74 VTKReader(SmartPointer<Mesh<T>> passedMesh) : mesh(passedMesh) {}
75
76 VTKReader(SmartPointer<Mesh<T>> passedMesh, std::string passedFileName)
77 : mesh(passedMesh), fileName(std::move(passedFileName)) {}
78
79 VTKReader(SmartPointer<Mesh<>> passedMesh, FileFormatEnum passedFormat,
80 std::string passedFileName)
81 : mesh(passedMesh), fileFormat(passedFormat),
82 fileName(std::move(passedFileName)) {}
83
85 void setMesh(SmartPointer<Mesh<>> passedMesh) { mesh = passedMesh; }
86
88 void setFileFormat(FileFormatEnum passedFormat) { fileFormat = passedFormat; }
89
91 void setFileName(std::string passedFileName) {
92 fileName = std::move(passedFileName);
93 }
94
95 auto &getMetaData() { return metaData; }
96
97 void apply() {
98 // check mesh
99 if (mesh == nullptr) {
100 Logger::getInstance()
101 .addError("No mesh was passed to VTKReader.")
102 .print();
103 return;
104 }
105 // check filename
106 if (fileName.empty()) {
107 Logger::getInstance()
108 .addError("No file name specified for VTKReader.")
109 .print();
110 return;
111 }
112
113 if (fileFormat == FileFormatEnum::VTK_AUTO) {
114 auto dotPos = fileName.rfind('.');
115 if (dotPos == std::string::npos) {
116 Logger::getInstance()
117 .addError("No valid file format found based on the file ending "
118 "passed to VTKReader.")
119 .print();
120 return;
121 }
122 auto ending = fileName.substr(dotPos);
123 if (ending == ".vtk") {
124 fileFormat = FileFormatEnum::VTK_LEGACY;
125 } else if (ending == ".vtp") {
126 fileFormat = FileFormatEnum::VTP;
127 } else if (ending == ".vtu") {
128 fileFormat = FileFormatEnum::VTU;
129 } else {
130 Logger::getInstance()
131 .addError("No valid file format found based on the file ending "
132 "passed to VTKReader.")
133 .print();
134 return;
135 }
136 }
137
138 // check file format
139 switch (fileFormat) {
141 readVTKLegacy(fileName);
142 break;
143#ifdef VIENNALS_USE_VTK
145 readVTP(fileName);
146 break;
148 readVTU(fileName);
149 break;
150#else
153 Logger::getInstance()
154 .addError("VTKReader was built without VTK support. Only VTK_LEGACY "
155 "can be used.")
156 .print();
157#endif
158 default:
159 Logger::getInstance()
160 .addError("No valid file format set for VTKReader.")
161 .print();
162 }
163 }
164
165private:
166#ifdef VIENNALS_USE_VTK
167 void readVTP(const std::string &filename) {
168
169 mesh->clear();
170 vtkSmartPointer<vtkXMLPolyDataReader> pReader =
171 vtkSmartPointer<vtkXMLPolyDataReader>::New();
172 pReader->SetFileName(filename.c_str());
173 pReader->Update();
174
175 vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
176 polyData = pReader->GetOutput();
177
178 mesh->nodes.resize(polyData->GetNumberOfPoints());
179 for (unsigned i = 0; i < mesh->nodes.size(); ++i) {
180 std::array<double, 3> coords{};
181 polyData->GetPoint(i, coords.data());
182 mesh->nodes[i] = coords;
183 }
184
185 vtkSmartPointer<vtkCellArray> cellArray =
186 vtkSmartPointer<vtkCellArray>::New();
187 // get vertices
188 {
189 mesh->vertices.reserve(polyData->GetNumberOfVerts());
190 cellArray = polyData->GetVerts();
191 cellArray->InitTraversal();
192 vtkIdList *pointList = vtkIdList::New();
193 while (cellArray->GetNextCell(pointList)) {
194 std::array<unsigned, 1> cell{};
195 cell[0] = pointList->GetId(0);
196 mesh->vertices.push_back(cell);
197 }
198 }
199
200 // get lines
201 {
202 mesh->lines.reserve(polyData->GetNumberOfLines());
203 cellArray = polyData->GetLines();
204 cellArray->InitTraversal();
205 vtkIdList *pointList = vtkIdList::New();
206 while (cellArray->GetNextCell(pointList)) {
207 std::array<unsigned, 2> cell{};
208 for (unsigned i = 0; i < 2; ++i) {
209 cell[i] = pointList->GetId(i);
210 }
211 mesh->lines.push_back(cell);
212 }
213 }
214
215 // get triangles
216 {
217 mesh->triangles.reserve(polyData->GetNumberOfPolys());
218 cellArray = polyData->GetPolys();
219 cellArray->InitTraversal();
220 vtkIdList *pointList = vtkIdList::New();
221 while (cellArray->GetNextCell(pointList)) {
222 std::array<unsigned, 3> cell{};
223 for (unsigned i = 0; i < 3; ++i) {
224 cell[i] = pointList->GetId(i);
225 }
226 mesh->triangles.push_back(cell);
227 }
228 }
229
230 // get point data
231 vtkSmartPointer<vtkPointData> pointData =
232 vtkSmartPointer<vtkPointData>::New();
233 pointData = polyData->GetPointData();
234
235 for (int i = 0; i < static_cast<int>(pointData->GetNumberOfArrays()); ++i) {
236 if (vtkDataArray *dataArray = pointData->GetArray(i);
237 dataArray->GetNumberOfComponents() == 1) {
238 mesh->pointData.insertNextScalarData(
240 std::string(pointData->GetArrayName(i)));
241 auto &scalars = *(mesh->pointData.getScalarData(i));
242 scalars.resize(pointData->GetNumberOfTuples());
243 for (unsigned j = 0; j < dataArray->GetNumberOfTuples(); ++j) {
244 scalars[j] = dataArray->GetTuple1(j);
245 }
246 } else if (dataArray->GetNumberOfComponents() == 3) {
247 mesh->pointData.insertNextVectorData(
249 std::string(pointData->GetArrayName(i)));
250 auto &vectors = *(mesh->pointData.getVectorData(i));
251 vectors.resize(pointData->GetNumberOfTuples());
252 for (unsigned j = 0; j < dataArray->GetNumberOfTuples(); ++j) {
253 std::array<double, 3> vector{};
254 dataArray->GetTuple(j, &(vector[0]));
255 vectors[j] = vector;
256 }
257 }
258 }
259
260 // get cell data
261 vtkSmartPointer<vtkCellData> cellData = vtkSmartPointer<vtkCellData>::New();
262 cellData = polyData->GetCellData();
263
264 for (int i = 0; i < cellData->GetNumberOfArrays(); ++i) {
265 vtkDataArray *dataArray = cellData->GetArray(i);
266 if (cellData->GetNumberOfComponents() == 1) {
267 mesh->cellData.insertNextScalarData(
269 std::string(cellData->GetArrayName(i)));
270 auto &scalars = *(mesh->cellData.getScalarData(i));
271 scalars.resize(cellData->GetNumberOfTuples());
272 for (unsigned j = 0; j < dataArray->GetNumberOfTuples(); ++j) {
273 scalars[j] = dataArray->GetTuple1(j);
274 }
275 } else if (cellData->GetNumberOfComponents() == 3) {
276 mesh->cellData.insertNextVectorData(
278 std::string(cellData->GetArrayName(i)));
279 auto &vectors = *(mesh->cellData.getVectorData(i));
280 vectors.resize(cellData->GetNumberOfTuples());
281 for (unsigned j = 0; j < dataArray->GetNumberOfTuples(); ++j) {
282 std::array<double, 3> vector{};
283 dataArray->GetTuple(j, &(vector[0]));
284 vectors[j] = vector;
285 }
286 }
287 }
288
289 // read meta data
290 extractFieldData(polyData);
291 }
292
293 void readVTU(const std::string &filename) {
294
295 mesh->clear();
296
297 vtkSmartPointer<vtkXMLUnstructuredGridReader> greader =
298 vtkSmartPointer<vtkXMLUnstructuredGridReader>::New();
299 greader->SetFileName(filename.c_str());
300 greader->Update();
301
302 vtkSmartPointer<vtkUnstructuredGrid> ugrid =
303 vtkSmartPointer<vtkUnstructuredGrid>::New();
304 ugrid = greader->GetOutput();
305
306 // get all points
307 mesh->nodes.resize(ugrid->GetNumberOfPoints());
308 for (unsigned i = 0; i < mesh->nodes.size(); ++i) {
309 std::array<double, 3> coords{};
310 ugrid->GetPoint(i, &(coords[0]));
311 mesh->nodes[i] = coords;
312 }
313
314 // get cells
315 for (unsigned i = 0; i < ugrid->GetNumberOfCells(); ++i) {
316 vtkIdList *pointList = vtkIdList::New();
317 ugrid->GetCellPoints(i, pointList);
318
319 switch (ugrid->GetCellType(i)) {
320 case 1: // vert
321 {
322 std::array<unsigned, 1> vert{};
323 vert[0] = pointList->GetId(0);
324 mesh->vertices.push_back(vert);
325 } break;
326 case 3: // line
327 {
328 std::array<unsigned, 2> elements{};
329 for (unsigned j = 0; j < 2; ++j) {
330 elements[j] = pointList->GetId(j);
331 }
332 mesh->lines.push_back(elements);
333 } break;
334 case 5: // triangle
335 {
336 std::array<unsigned, 3> elements{};
337 for (unsigned j = 0; j < 3; ++j) {
338 elements[j] = pointList->GetId(j);
339 }
340 mesh->triangles.push_back(elements);
341 } break;
342 case 10: // tetra
343 {
344 std::array<unsigned, 4> elements{};
345 for (unsigned j = 0; j < 4; ++j) {
346 elements[j] = pointList->GetId(j);
347 }
348 mesh->tetras.push_back(elements);
349 } break;
350 case 12: // hexa
351 {
352 std::array<unsigned, 8> elements{};
353 for (unsigned j = 0; j < 8; ++j) {
354 elements[j] = pointList->GetId(j);
355 }
356 mesh->hexas.push_back(elements);
357 } break;
358 }
359 }
360
361 // get point data
362 vtkSmartPointer<vtkPointData> pointData =
363 vtkSmartPointer<vtkPointData>::New();
364 pointData = ugrid->GetPointData();
365
366 for (int i = 0; i < pointData->GetNumberOfArrays(); ++i) {
367 if (vtkDataArray *dataArray = pointData->GetArray(i);
368 dataArray->GetNumberOfComponents() == 1) {
369 mesh->pointData.insertNextScalarData(
371 std::string(pointData->GetArrayName(i)));
372 auto &scalars = *(mesh->pointData.getScalarData(i));
373 scalars.resize(pointData->GetNumberOfTuples());
374 for (unsigned j = 0; j < dataArray->GetNumberOfTuples(); ++j) {
375 scalars[j] = dataArray->GetTuple1(j);
376 }
377 } else if (dataArray->GetNumberOfComponents() == 3) {
378 mesh->pointData.insertNextVectorData(
380 std::string(pointData->GetArrayName(i)));
381 auto &vectors = *(mesh->pointData.getVectorData(i));
382 vectors.resize(pointData->GetNumberOfTuples());
383 for (unsigned j = 0; j < dataArray->GetNumberOfTuples(); ++j) {
384 std::array<double, 3> vector{};
385 dataArray->GetTuple(j, &(vector[0]));
386 vectors[j] = vector;
387 }
388 }
389 }
390
391 // get cell data
392 vtkSmartPointer<vtkCellData> cellData = vtkSmartPointer<vtkCellData>::New();
393 cellData = ugrid->GetCellData();
394
395 for (int i = 0; i < static_cast<int>(cellData->GetNumberOfArrays()); ++i) {
396 vtkDataArray *dataArray = cellData->GetArray(i);
397 if (cellData->GetNumberOfComponents() == 1) {
398 mesh->cellData.insertNextScalarData(
400 std::string(cellData->GetArrayName(i)));
401 auto &scalars = *(mesh->cellData.getScalarData(i));
402 scalars.resize(cellData->GetNumberOfTuples());
403 for (unsigned j = 0; j < dataArray->GetNumberOfTuples(); ++j) {
404 scalars[j] = dataArray->GetTuple1(j);
405 }
406 } else if (cellData->GetNumberOfComponents() == 3) {
407 mesh->cellData.insertNextVectorData(
409 std::string(cellData->GetArrayName(i)));
410 auto &vectors = *(mesh->cellData.getVectorData(i));
411 vectors.resize(cellData->GetNumberOfTuples());
412 for (unsigned j = 0; j < dataArray->GetNumberOfTuples(); ++j) {
413 std::array<double, 3> vector{};
414 dataArray->GetTuple(j, &(vector[0]));
415 vectors[j] = vector;
416 }
417 }
418 }
419
420 // read meta data
421 extractFieldData(ugrid);
422 }
423
424#endif // VIENNALS_USE_VTK
425
426 void readVTKLegacy(const std::string &filename) {
427
428 mesh->clear();
429 // open geometry file
430 std::ifstream f(filename.c_str());
431 if (!f)
432 Logger::getInstance().addError("Could not open geometry file!");
433 std::string temp;
434
435 // Check if geometry is an unstructured grid as required
436 while (std::getline(f, temp)) {
437 if (temp.find("DATASET") != std::string::npos)
438 break;
439 }
440 if (temp.find("UNSTRUCTURED_GRID") == std::string::npos) {
441 Logger::getInstance().addError("DATASET is not an UNSTRUCTURED_GRID!");
442 }
443
444 // Find POINTS in file to know number of nodes to read in
445 while (std::getline(f, temp)) {
446 if (temp.find("POINTS") != std::string::npos)
447 break;
448 }
449 int num_nodes = atoi(&temp[temp.find(' ') + 1]);
450
451 mesh->nodes.resize(num_nodes);
452
453 for (int i = 0; i < num_nodes; i++) {
454 double coords[3];
455
456 for (double &coord : coords)
457 f >> coord;
458 for (int j = 0; j < 3; j++) {
459 mesh->nodes[i][j] = coords[j];
460 // int shift_size = shift.size();
461 // if (shift_size > j)
462 // mesh->nodes[i][j] += shift[j]; // Assign desired shift
463 // if (InputTransformationSigns[j])
464 // mesh->nodes[i][j] = -mesh->nodes[i][j]; // Assign sign
465 // transformation, if needed
466 // mesh->nodes[i][j] *= scale; // Scale the geometry according to
467 // parameters file
468 }
469 }
470
471 while (std::getline(f, temp)) {
472 if (temp.find("CELLS") == 0)
473 break;
474 }
475
476 int num_elems = atoi(&temp[temp.find(' ') + 1]);
477
478 std::ifstream f_ct(filename.c_str()); // stream to read cell CELL_TYPES
479 std::ifstream f_m(
480 filename.c_str()); // stream for material numbers if they exist
481
482 // advance to cell types and check if there are the right number
483 while (std::getline(f_ct, temp)) {
484 if (temp.find("CELL_TYPES") == 0)
485 break;
486 }
487 int num_cell_types = atoi(&temp[temp.find(' ') + 1]);
488 // need a cell_type for each cell
489 if (num_elems != num_cell_types) {
490 Logger::getInstance().addError(
491 "Corrupt input geometry! Number of CELLS and CELL_TYPES "
492 "is different!");
493 }
494
495 bool is_material = true;
496 // advance to material if it is specified
497 while (std::getline(f_m, temp)) {
498 if (temp.find("CELL_DATA") != std::string::npos) {
499 std::getline(f_m, temp);
500 if ((temp.find("SCALARS material") != std::string::npos) ||
501 (temp.find("SCALARS Material") != std::string::npos)) {
502 std::getline(f_m, temp);
503 break;
504 }
505 }
506 }
507 if (f_m.eof()) {
508 is_material = false;
509 }
510
511 // maximum cell to read in is a tetra with 4 points
512 std::vector<VectorType<unsigned int, 4>> elements;
513 elements.reserve(num_elems);
514
515 std::vector<double> materials;
516
517 unsigned elems_fake;
518 unsigned cell_type;
519 unsigned cell_material;
520 for (int i = 0; i < num_elems; i++) {
521 f >> elems_fake;
522 f_ct >> cell_type;
523 if (is_material)
524 f_m >> cell_material;
525 else
526 cell_material =
527 1; // if there are no materials specified make all the same
528
529 // check if the correct number of nodes for cell_type is given
530 unsigned number_nodes = vtk_nodes_for_cell_type[cell_type];
531 if (number_nodes == elems_fake || number_nodes == 0) {
532 // check for different types to subdivide them into supported types
533 switch (cell_type) {
534 case 1: {
535 std::array<unsigned, 1> elem{};
536 f >> elem[0];
537 mesh->template getElements<1>().push_back(elem);
538 materials.push_back(cell_material);
539 break;
540 }
541 case 3: {
542 std::array<unsigned, 2> elem{};
543 for (unsigned j = 0; j < number_nodes; ++j) {
544 f >> elem[j];
545 }
546 mesh->template getElements<2>().push_back(elem);
547 materials.push_back(cell_material);
548 break;
549 }
550 case 5: // triangle for 2D
551 {
552 std::array<unsigned, 3> elem{};
553 for (unsigned j = 0; j < number_nodes; ++j) {
554 f >> elem[j];
555 }
556 mesh->template getElements<3>().push_back(elem);
557 materials.push_back(cell_material);
558 break;
559 }
560
561 case 10: // tetra for 3D
562 {
563 std::array<unsigned, 4> elem{};
564 for (unsigned j = 0; j < number_nodes; ++j) {
565 f >> elem[j];
566 }
567 mesh->template getElements<4>().push_back(elem);
568 materials.push_back(cell_material);
569 break;
570 }
571
572 case 9: // this is a quad, so just plit it into two triangles
573 {
574 std::array<unsigned, 3> elem{};
575 for (unsigned j = 0; j < 3; ++j) {
576 f >> elem[j];
577 }
578 mesh->template getElements<3>().push_back(
579 elem); // push the first three nodes as a triangle
580 materials.push_back(cell_material);
581
582 f >> elem[1]; // replace middle element to create other triangle
583 mesh->template getElements<3>().push_back(elem);
584 materials.push_back(cell_material);
585 break;
586 }
587
588 default:
589 std::ostringstream oss;
590 oss << "VTK Cell type " << cell_type
591 << " is not supported. Cell ignored..." << std::endl;
592 Logger::getInstance().addWarning(oss.str()).print();
593 }
594 } else {
595 std::ostringstream oss;
596 oss << "INVALID CELL TYPE! Expected number of nodes: " << number_nodes
597 << ", Found number of nodes: " << elems_fake
598 << "; Ignoring element...";
599 Logger::getInstance().addError(oss.str());
600 // ignore rest of lines
601 f.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
602 }
603 }
604
605 mesh->cellData.insertNextScalarData(materials, "Material");
606
607 // Now read Cell Data
608 int num_cell_data = 0;
609 while (std::getline(f, temp)) {
610 if (temp.find("CELL_DATA") != std::string::npos) {
611 num_cell_data = atoi(&temp[temp.find(' ') + 1]);
612 break;
613 }
614 }
615 std::cout << "Read cell data: " << num_cell_data << std::endl;
616
617 while (!f.eof()) {
618 std::cout << "reading scalar data" << std::endl;
619 while (std::getline(f, temp)) {
620 if (temp.find("SCALARS") != std::string::npos)
621 break;
622 }
623 if (f.eof()) {
624 break;
625 }
626
627 std::string scalarDataName;
628 {
629 auto firstS = temp.find(' ') + 1;
630 auto secondS = temp.find(' ', firstS + 1);
631 scalarDataName = temp.substr(firstS, secondS - firstS);
632 }
633 std::vector<double> scalarData;
634
635 // consume one line, which defines the lookup table
636 std::getline(f, temp);
637 if (temp != "LOOKUP_TABLE default") {
638 Logger::getInstance()
639 .addWarning("Wrong lookup table for VTKLegacy: " + temp)
640 .print();
641 }
642
643 // now read scalar values
644 for (int i = 0; i < num_cell_data; ++i) {
645 double data;
646 f >> data;
647 scalarData.push_back(data);
648 }
649
650 mesh->cellData.insertNextScalarData(scalarData, scalarDataName);
651 }
652
653 f_ct.close();
654 f_m.close();
655 f.close();
656 }
657};
658
659} // namespace viennals
double T
Definition Epitaxy.cpp:10
This class holds an explicit mesh, which is always given in 3 dimensions. If it describes a 2D mesh,...
Definition lsMesh.hpp:22
std::vector< Vec3D< T > > VectorDataType
Definition lsPointData.hpp:24
std::vector< T > ScalarDataType
Definition lsPointData.hpp:23
void setFileName(std::string passedFileName)
set file name for file to read
Definition lsVTKReader.hpp:91
void setMesh(SmartPointer< Mesh<> > passedMesh)
set the mesh the file should be read into
Definition lsVTKReader.hpp:85
VTKReader(SmartPointer< Mesh< T > > passedMesh, std::string passedFileName)
Definition lsVTKReader.hpp:76
VTKReader(SmartPointer< Mesh< T > > passedMesh)
Definition lsVTKReader.hpp:74
VTKReader(SmartPointer< Mesh<> > passedMesh, FileFormatEnum passedFormat, std::string passedFileName)
Definition lsVTKReader.hpp:79
void setFileFormat(FileFormatEnum passedFormat)
set file format for file to read. Defaults to VTK_LEGACY.
Definition lsVTKReader.hpp:88
void apply()
Definition lsVTKReader.hpp:97
auto & getMetaData()
Definition lsVTKReader.hpp:95
Definition lsAdvect.hpp:36
FileFormatEnum
Definition lsFileFormats.hpp:4
@ VTK_AUTO
Definition lsFileFormats.hpp:8
@ VTK_LEGACY
Definition lsFileFormats.hpp:5
@ VTP
Definition lsFileFormats.hpp:6
@ VTU
Definition lsFileFormats.hpp:7