34 using MetaDataType = std::unordered_map<std::string, std::vector<double>>;
36 SmartPointer<Mesh<T>> mesh =
nullptr;
39 MetaDataType metaData;
41#ifdef VIENNALS_USE_VTK
43 vtkSmartPointer<vtkPolyData> cachedPolyData =
nullptr;
44 vtkSmartPointer<vtkUnstructuredGrid> cachedUnstructuredGrid =
nullptr;
46 template <
class In,
class Out>
47 void addDataFromMesh(
const In &inData, Out outData)
const {
49 for (
unsigned i = 0; i < inData.getScalarDataSize(); ++i) {
50 vtkSmartPointer<vtkFloatArray> pointData =
51 vtkSmartPointer<vtkFloatArray>::New();
52 pointData->SetNumberOfComponents(1);
53 pointData->SetName(inData.getScalarDataLabel(i).c_str());
54 auto scalars = *(inData.getScalarData(i));
55 for (
unsigned j = 0; j < inData.getScalarData(i)->size(); ++j) {
56 pointData->InsertNextValue(scalars[j]);
58 outData->AddArray(pointData);
62 for (
unsigned i = 0; i < inData.getVectorDataSize(); ++i) {
63 vtkSmartPointer<vtkFloatArray> vectorData =
64 vtkSmartPointer<vtkFloatArray>::New();
65 vectorData->SetNumberOfComponents(3);
66 vectorData->SetName(inData.getVectorDataLabel(i).c_str());
67 auto vectors = *(inData.getVectorData(i));
68 for (
unsigned j = 0; j < inData.getVectorData(i)->size(); ++j) {
69 vectorData->InsertNextTuple3(vectors[j][0], vectors[j][1],
72 outData->AddArray(vectorData);
76 void addMetaDataToVTK(vtkDataSet *data)
const {
77 if (metaData.empty()) {
82 vtkSmartPointer<vtkFieldData> fieldData = data->GetFieldData();
83 for (
const auto &meta : metaData) {
84 if (meta.second.empty())
87 vtkSmartPointer<vtkFloatArray> metaDataArray =
88 vtkSmartPointer<vtkFloatArray>::New();
89 metaDataArray->SetName(meta.first.c_str());
90 metaDataArray->SetNumberOfValues(meta.second.size());
91 for (
size_t i = 0; i < meta.second.size(); ++i) {
92 metaDataArray->SetValue(i, meta.second[i]);
94 fieldData->AddArray(metaDataArray);
105 : mesh(passedMesh), fileName(std::move(passedFileName)) {}
108 std::string passedFileName)
109 : mesh(passedMesh), fileFormat(passedFormat),
110 fileName(std::move(passedFileName)) {}
119 fileName = std::move(passedFileName);
123 metaData = passedMetaData;
127 metaData[key] = std::vector<double>{value};
130 void addMetaData(
const std::string &key,
const std::vector<double> &values) {
131 metaData[key] = values;
135 for (
const auto &pair : newMetaData) {
136 metaData[pair.first] = pair.second;
140#ifdef VIENNALS_USE_VTK
141 vtkPolyData *getPolyData()
const {
return cachedPolyData; }
143 vtkUnstructuredGrid *getUnstructuredGrid()
const {
144 return cachedUnstructuredGrid;
150 if (mesh ==
nullptr) {
151 Logger::getInstance()
152 .addError(
"No mesh was passed to VTKWriter.")
156 if (mesh->nodes.empty()) {
157 VIENNACORE_LOG_WARNING(
"Writing empty mesh.");
162 if (!fileName.empty()) {
163 auto dotPos = fileName.rfind(
'.');
164 if (dotPos == std::string::npos) {
167 auto ending = fileName.substr(dotPos);
168 if (ending ==
".vtk") {
170 }
else if (ending ==
".vtp") {
172 }
else if (ending ==
".vtu") {
175 Logger::getInstance()
176 .addError(
"No valid file format found based on the file ending "
177 "passed to VTKWriter.")
189 switch (fileFormat) {
191 if (fileName.empty()) {
192 VIENNACORE_LOG_ERROR(
"VTK_LEGACY format requires a filename. Cannot "
193 "use memory-only mode.");
196 writeVTKLegacy(fileName);
198#ifdef VIENNALS_USE_VTK
201 if (!fileName.empty())
206 if (!fileName.empty())
212 VIENNACORE_LOG_WARNING(
213 "VTKWriter was built without VTK support. Falling back "
215 writeVTKLegacy(fileName);
219 VIENNACORE_LOG_ERROR(
"No valid file format set for VTKWriter.");
224#ifdef VIENNALS_USE_VTK
226 cachedPolyData = vtkSmartPointer<vtkPolyData>::New();
228 vtkSmartPointer<vtkPoints> polyPoints = vtkSmartPointer<vtkPoints>::New();
229 for (
auto it = mesh->getNodes().begin(); it != mesh->getNodes().end(); ++it)
230 polyPoints->InsertNextPoint((*it)[0], (*it)[1], (*it)[2]);
231 cachedPolyData->SetPoints(polyPoints);
233 if (mesh->vertices.size() > 0) {
234 vtkSmartPointer<vtkCellArray> polyCells =
235 vtkSmartPointer<vtkCellArray>::New();
236 for (
auto it = mesh->vertices.begin(); it != mesh->vertices.end(); ++it) {
237 polyCells->InsertNextCell(1);
238 polyCells->InsertCellPoint((*it)[0]);
240 cachedPolyData->SetVerts(polyCells);
243 if (mesh->lines.size() > 0) {
244 vtkSmartPointer<vtkCellArray> polyCells =
245 vtkSmartPointer<vtkCellArray>::New();
246 for (
auto it = mesh->lines.begin(); it != mesh->lines.end(); ++it) {
247 polyCells->InsertNextCell(2);
248 for (
unsigned i = 0; i < 2; ++i)
249 polyCells->InsertCellPoint((*it)[i]);
251 cachedPolyData->SetLines(polyCells);
254 if (mesh->triangles.size() > 0) {
255 vtkSmartPointer<vtkCellArray> polyCells =
256 vtkSmartPointer<vtkCellArray>::New();
257 for (
auto it = mesh->triangles.begin(); it != mesh->triangles.end();
259 polyCells->InsertNextCell(3);
260 for (
unsigned i = 0; i < 3; ++i)
261 polyCells->InsertCellPoint((*it)[i]);
263 cachedPolyData->SetPolys(polyCells);
266 addDataFromMesh(mesh->pointData, cachedPolyData->GetPointData());
267 addDataFromMesh(mesh->cellData, cachedPolyData->GetCellData());
268 addMetaDataToVTK(cachedPolyData);
271 void writeVTP(std::string filename)
const {
272 if (cachedPolyData ==
nullptr)
274 if (filename.find(
".vtp") != filename.size() - 4)
276 vtkSmartPointer<vtkXMLPolyDataWriter> pwriter =
277 vtkSmartPointer<vtkXMLPolyDataWriter>::New();
278 pwriter->SetFileName(filename.c_str());
279 pwriter->SetInputData(cachedPolyData);
284 cachedUnstructuredGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
286 vtkSmartPointer<vtkUnstructuredGrid> uGrid = cachedUnstructuredGrid;
289 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
290 for (
auto it = mesh->getNodes().begin(); it != mesh->getNodes().end();
292 points->InsertNextPoint((*it)[0], (*it)[1], (*it)[2]);
294 uGrid->SetPoints(points);
297 vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
298 std::vector<int> cellTypes;
299 cellTypes.reserve(mesh->vertices.size() + mesh->lines.size() +
300 mesh->triangles.size() + mesh->tetras.size() +
304 if (mesh->vertices.size() > 0) {
305 for (
auto it = mesh->vertices.begin(); it != mesh->vertices.end(); ++it) {
306 cells->InsertNextCell(1);
307 cells->InsertCellPoint((*it)[0]);
308 cellTypes.push_back(1);
313 if (mesh->lines.size() > 0) {
314 for (
auto it = mesh->lines.begin(); it != mesh->lines.end(); ++it) {
315 cells->InsertNextCell(2);
316 for (
unsigned i = 0; i < 2; ++i) {
317 cells->InsertCellPoint((*it)[i]);
319 cellTypes.push_back(3);
324 if (mesh->triangles.size() > 0) {
325 for (
auto it = mesh->triangles.begin(); it != mesh->triangles.end();
327 cells->InsertNextCell(3);
328 for (
unsigned i = 0; i < 3; ++i) {
329 cells->InsertCellPoint((*it)[i]);
331 cellTypes.push_back(5);
336 if (mesh->tetras.size() > 0) {
337 for (
auto it = mesh->tetras.begin(); it != mesh->tetras.end(); ++it) {
338 cells->InsertNextCell(4);
339 for (
unsigned i = 0; i < 4; ++i) {
340 cells->InsertCellPoint((*it)[i]);
342 cellTypes.push_back(10);
347 if (mesh->hexas.size() > 0) {
348 for (
auto it = mesh->hexas.begin(); it != mesh->hexas.end(); ++it) {
349 cells->InsertNextCell(8);
350 for (
unsigned i = 0; i < 8; ++i) {
351 cells->InsertCellPoint((*it)[i]);
353 cellTypes.push_back(12);
358 uGrid->SetCells(&(cellTypes[0]), cells);
360 addDataFromMesh(mesh->pointData, uGrid->GetPointData());
361 addDataFromMesh(mesh->cellData, uGrid->GetCellData());
362 addMetaDataToVTK(uGrid);
392 void writeVTU(std::string filename)
const {
393 if (cachedUnstructuredGrid ==
nullptr)
395 if (filename.find(
".vtu") != filename.size() - 4)
397 vtkSmartPointer<vtkXMLUnstructuredGridWriter> owriter =
398 vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
399 owriter->SetFileName(filename.c_str());
400 owriter->SetInputData(cachedUnstructuredGrid);
406 void writeVTKLegacy(
const std::string &filename) {
407 if (mesh ==
nullptr) {
408 Logger::getInstance()
409 .addError(
"No mesh was passed to VTKWriter.")
414 std::ofstream f(filename.c_str());
416 f <<
"# vtk DataFile Version 2.0" << std::endl;
417 f << ((!mesh->lines.empty()) ? 2 : 3) <<
"D Surface" << std::endl;
418 f <<
"ASCII" << std::endl;
419 f <<
"DATASET UNSTRUCTURED_GRID" << std::endl;
420 f <<
"POINTS " << mesh->nodes.size() <<
" float" << std::endl;
423 for (
unsigned int i = 0; i < mesh->nodes.size(); i++) {
424 for (
int j = 0; j < 3; j++)
425 f <<
static_cast<float>(mesh->nodes[i][j]) <<
" ";
429 const unsigned numberOfCells = mesh->vertices.size() + mesh->lines.size() +
430 mesh->triangles.size() +
431 mesh->tetras.size() + mesh->hexas.size();
432 const unsigned cellDataSize =
433 2 * mesh->vertices.size() + 3 * mesh->lines.size() +
434 4 * mesh->triangles.size() + 5 * mesh->tetras.size() +
435 9 * mesh->hexas.size();
437 f <<
"CELLS " << numberOfCells <<
" " << cellDataSize << std::endl;
440 for (
unsigned int i = 0; i < mesh->vertices.size(); i++) {
441 f << 1 <<
" " << mesh->vertices[i][0] << std::endl;
443 for (
unsigned int i = 0; i < mesh->lines.size(); i++) {
445 for (
int j = 0; j < 2; j++)
446 f << mesh->lines[i][j] <<
" ";
450 for (
unsigned int i = 0; i < mesh->triangles.size(); i++) {
452 for (
int j = 0; j < 3; j++)
453 f << mesh->triangles[i][j] <<
" ";
457 for (
unsigned int i = 0; i < mesh->tetras.size(); i++) {
459 for (
int j = 0; j < 4; j++)
460 f << mesh->tetras[i][j] <<
" ";
464 for (
unsigned int i = 0; i < mesh->hexas.size(); i++) {
466 for (
int j = 0; j < 8; j++)
467 f << mesh->hexas[i][j] <<
" ";
471 f <<
"CELL_TYPES " << numberOfCells << std::endl;
472 for (
unsigned i = 0; i < mesh->vertices.size(); ++i)
475 for (
unsigned i = 0; i < mesh->lines.size(); ++i)
478 for (
unsigned i = 0; i < mesh->triangles.size(); ++i)
481 for (
unsigned i = 0; i < mesh->tetras.size(); ++i)
482 f << 10 << std::endl;
484 for (
unsigned i = 0; i < mesh->hexas.size(); ++i)
485 f << 12 << std::endl;
488 if (mesh->pointData.getScalarDataSize() ||
489 mesh->pointData.getVectorDataSize()) {
490 VIENNACORE_LOG_WARNING(
491 "Point data output not supported for legacy VTK output. "
492 "Point data is ignored.");
496 if (mesh->cellData.getScalarDataSize()) {
497 f <<
"CELL_DATA " << mesh->cellData.getScalarData(0)->size() << std::endl;
498 for (
unsigned i = 0; i < mesh->cellData.getScalarDataSize(); ++i) {
499 auto scalars = *(mesh->cellData.getScalarData(i));
500 f <<
"SCALARS " << mesh->cellData.getScalarDataLabel(i) <<
" float"
502 f <<
"LOOKUP_TABLE default" << std::endl;
503 for (
unsigned j = 0; j < scalars.size(); ++j) {
504 f << ((std::abs(scalars[j]) < 1e-6) ? 0.0 : scalars[j]) << std::endl;
510 if (mesh->cellData.getVectorDataSize()) {
511 if (!mesh->cellData.getScalarDataSize())
512 f <<
"CELL_DATA " << mesh->cellData.getVectorData(0)->size()
514 for (
unsigned i = 0; i < mesh->cellData.getVectorDataSize(); ++i) {
515 auto vectors = *(mesh->cellData.getVectorData(i));
516 f <<
"VECTORS " << mesh->cellData.getVectorDataLabel(i) <<
" float"
518 for (
unsigned j = 0; j < vectors.size(); ++j) {
519 for (
unsigned k = 0; k < 3; ++k) {
520 f << vectors[j][k] <<
" ";