24#ifndef DUMUX_IO_VTK_VTKREADER_HH
25#define DUMUX_IO_VTK_VTKREADER_HH
32#include <unordered_map>
35#include <dune/common/parallel/mpihelper.hh>
36#include <dune/common/exceptions.hh>
37#include <dune/grid/common/capabilities.hh>
38#include <dune/grid/io/file/vtk/common.hh>
39#include <dumux/io/xml/tinyxml2.h>
40#include <dune/grid/common/gridfactory.hh>
57 using Data = std::unordered_map<std::string, std::vector<double>>;
64 fileName_ = Dune::MPIHelper::getCollectiveCommunication().size() > 1 ?
65 getProcessFileName_(fileName) : fileName;
67 const auto eResult = doc_.LoadFile(fileName_.c_str());
68 if (eResult != tinyxml2::XML_SUCCESS)
69 DUNE_THROW(Dune::IOError,
"Couldn't open XML file " << fileName_ <<
".");
78 template<
class Container>
81 using namespace tinyxml2;
83 const XMLElement* pieceNode = getPieceNode_();
84 if (pieceNode ==
nullptr)
85 DUNE_THROW(Dune::IOError,
"Couldn't get 'Piece' node in " << fileName_ <<
".");
87 const XMLElement* dataNode = getDataNode_(pieceNode, type);
88 if (dataNode ==
nullptr)
89 DUNE_THROW(Dune::IOError,
"Couldn't get 'PointData' or 'CellData' node in " << fileName_ <<
".");
91 const XMLElement* dataArray = findDataArray_(dataNode, name);
92 if (dataArray ==
nullptr)
93 DUNE_THROW(Dune::IOError,
"Couldn't find the data array " << name <<
".");
95 return parseDataArray_<Container>(dataArray);
103 std::unique_ptr<Grid>
readGrid(
bool verbose =
false)
const
105 static_assert(!Dune::Capabilities::isCartesian<Grid>::v,
"Grid reader only supports unstructured grid implementations");
107 if (verbose) std::cout <<
"Reading " << Grid::dimension <<
"d grid from vtk file " << fileName_ <<
"." << std::endl;
110 Dune::GridFactory<Grid> factory;
112 readGrid_(factory, verbose);
114 return std::unique_ptr<Grid>(factory.createGrid());
124 std::unique_ptr<Grid>
readGrid(Dune::GridFactory<Grid>& factory,
bool verbose =
false)
const
126 static_assert(!Dune::Capabilities::isCartesian<Grid>::v,
"Grid reader only supports unstructured grid implementations");
128 if (verbose) std::cout <<
"Reading " << Grid::dimension <<
"d grid from vtk file " << fileName_ <<
"." << std::endl;
130 readGrid_(factory, verbose);
132 return std::unique_ptr<Grid>(factory.createGrid());
144 std::unique_ptr<Grid>
readGrid(Dune::GridFactory<Grid>& factory,
Data& cellData,
Data& pointData,
bool verbose =
false)
const
146 static_assert(!Dune::Capabilities::isCartesian<Grid>::v,
"Grid reader only supports unstructured grid implementations");
148 if (verbose) std::cout <<
"Reading " << Grid::dimension <<
"d grid from vtk file " << fileName_ <<
"." << std::endl;
150 readGrid_(factory, verbose);
151 readGridData_(cellData, pointData, verbose);
153 return std::unique_ptr<Grid>(factory.createGrid());
160 std::string getProcessFileName_(
const std::string& pvtkFileName)
162 using namespace tinyxml2;
165 const auto eResult = pDoc.LoadFile(pvtkFileName.c_str());
166 if (eResult != XML_SUCCESS)
167 DUNE_THROW(Dune::IOError,
"Couldn't open XML file " << pvtkFileName <<
".");
170 const XMLElement* pieceNode = getPieceNode_(pDoc, pvtkFileName);
171 if (pieceNode ==
nullptr)
172 DUNE_THROW(Dune::IOError,
"Couldn't get 'Piece' node in " << pvtkFileName <<
".");
174 const auto myrank = Dune::MPIHelper::getCollectiveCommunication().rank();
175 for (
int rank = 0; rank < myrank; ++rank)
177 pieceNode = pieceNode->NextSiblingElement(
"Piece");
178 if (pieceNode ==
nullptr)
179 DUNE_THROW(Dune::IOError,
"Couldn't find 'Piece' node for rank "
180 << rank <<
" in " << pvtkFileName <<
".");
183 const char *vtkFileName = pieceNode->Attribute(
"Source");
184 if (vtkFileName ==
nullptr)
185 DUNE_THROW(Dune::IOError,
"Couldn't get 'Source' attribute of 'Piece' node no. " << myrank <<
" in " << pvtkFileName);
196 void readGrid_(Dune::GridFactory<Grid>& factory,
bool verbose =
false)
const
198 using namespace tinyxml2;
200 const XMLElement* pieceNode = getPieceNode_();
201 if (pieceNode ==
nullptr)
202 DUNE_THROW(Dune::IOError,
"Couldn't get 'Piece' node in " << fileName_ <<
".");
204 const XMLElement* pointsNode = pieceNode->FirstChildElement(
"Points")->FirstChildElement(
"DataArray");
205 if (pointsNode ==
nullptr)
206 DUNE_THROW(Dune::IOError,
"Couldn't get data array of points in " << fileName_ <<
".");
208 using Point3D = Dune::FieldVector<double, 3>;
209 std::vector<Point3D> points3D;
210 std::stringstream dataStream(pointsNode->GetText());
211 std::istream_iterator<Point3D> it(dataStream);
212 std::copy(it, std::istream_iterator<Point3D>(), std::back_inserter(points3D));
215 auto points = adaptPointDimension_<Grid::dimensionworld>(std::move(points3D));
217 if (verbose) std::cout <<
"Found " << points.size() <<
" vertices." << std::endl;
220 for (
auto&& point : points)
221 factory.insertVertex(std::move(point));
223 const XMLElement* cellsNode = pieceNode->FirstChildElement(
"Cells");
224 const XMLElement* linesNode = pieceNode->FirstChildElement(
"Lines");
227 const XMLElement* connectivityNode = findDataArray_(cellsNode,
"connectivity");
228 const XMLElement* offsetsNode = findDataArray_(cellsNode,
"offsets");
229 const XMLElement* typesNode = findDataArray_(cellsNode,
"types");
231 const auto connectivity = parseDataArray_<std::vector<unsigned int>>(connectivityNode);
232 const auto offsets = parseDataArray_<std::vector<unsigned int>>(offsetsNode);
233 const auto types = parseDataArray_<std::vector<unsigned int>>(typesNode);
235 if (verbose) std::cout <<
"Found " << offsets.size() <<
" element." << std::endl;
237 unsigned int lastOffset = 0;
238 for (
unsigned int i = 0; i < offsets.size(); ++i)
240 const auto geomType = vtkToDuneGeomType_(types[i]);
241 unsigned int offset = offsets[i];
242 std::vector<unsigned int> corners; corners.resize(offset-lastOffset);
243 for (
unsigned int j = 0; j < offset-lastOffset; ++j)
244 corners[Dune::VTK::renumber(geomType, j)] = connectivity[lastOffset+j];
245 factory.insertElement(geomType, std::move(corners));
253 if (Grid::dimension != 1)
254 DUNE_THROW(Dune::IOError,
"Grid expects dimension " << Grid::dimension
255 <<
" but " << fileName_ <<
" contains a 1D grid.");
257 const XMLElement* connectivityNode = findDataArray_(linesNode,
"connectivity");
258 const XMLElement* offsetsNode = findDataArray_(linesNode,
"offsets");
260 const auto connectivity = parseDataArray_<std::vector<unsigned int>>(connectivityNode);
261 const auto offsets = parseDataArray_<std::vector<unsigned int>>(offsetsNode);
263 if (verbose) std::cout <<
"Found " << offsets.size() <<
" polylines." << std::endl;
265 unsigned int lastOffset = 0;
266 for (
unsigned int i = 0; i < offsets.size(); ++i)
270 unsigned int offset = offsets[i];
271 for (
unsigned int j = 0; j < offset-lastOffset-1; ++j)
272 factory.insertElement(Dune::GeometryTypes::line,
273 std::vector<unsigned int>({ connectivity[lastOffset+j], connectivity[lastOffset+j+1] }));
278 DUNE_THROW(Dune::IOError,
"No Cells or Lines element found in " << fileName_);
287 void readGridData_(Data& cellData, Data& pointData,
bool verbose =
false)
const
289 using namespace tinyxml2;
291 const XMLElement* pieceNode = getPieceNode_();
292 if (pieceNode ==
nullptr)
293 DUNE_THROW(Dune::IOError,
"Couldn't get 'Piece' node in " << fileName_ <<
".");
295 const XMLElement* cellDataNode = getDataNode_(pieceNode, DataType::cellData);
296 if (cellDataNode !=
nullptr)
298 const XMLElement* cellsNode = pieceNode->FirstChildElement(
"Cells");
299 const XMLElement* linesNode = pieceNode->FirstChildElement(
"Lines");
303 const XMLElement* dataArray = cellDataNode->FirstChildElement(
"DataArray");
304 for (; dataArray !=
nullptr; dataArray = dataArray->NextSiblingElement(
"DataArray"))
306 const char *attributeText = dataArray->Attribute(
"Name");
308 if (attributeText ==
nullptr)
309 DUNE_THROW(Dune::IOError,
"Couldn't get Name attribute of a cell data array.");
311 cellData[std::string(attributeText)] = parseDataArray_<std::vector<double>>(dataArray);
318 const XMLElement* dataArray = cellDataNode->FirstChildElement(
"DataArray");
321 Data polyLineCellData;
322 for (; dataArray !=
nullptr; dataArray = dataArray->NextSiblingElement(
"DataArray"))
324 const char *attributeText = dataArray->Attribute(
"Name");
326 if (attributeText ==
nullptr)
327 DUNE_THROW(Dune::IOError,
"Couldn't get Name attribute of a cell data array.");
329 polyLineCellData[std::string(attributeText)] = parseDataArray_<std::vector<double>>(dataArray);
335 const XMLElement* offsetsNode = findDataArray_(linesNode,
"offsets");
336 const auto offsets = parseDataArray_<std::vector<unsigned int>>(offsetsNode);
338 if (offsets.size() != polyLineCellData.begin()->second.size())
339 DUNE_THROW(Dune::IOError,
"Expected the same number of cell data entries (is "
340 << polyLineCellData.begin()->second.size()
341 <<
") as polylines (" << offsets.size() <<
")!");
344 unsigned int lastOffset = 0;
345 std::size_t numCells = 0;
346 for (
unsigned int i = 0; i < offsets.size(); ++i)
348 unsigned int offset = offsets[i];
349 for (
unsigned int j = 0; j < offset-lastOffset-1; ++j)
355 for (
const auto& dArray : polyLineCellData)
357 cellData[dArray.first] = std::vector<double>(numCells);
358 auto& cd = cellData[dArray.first];
359 const auto& pd = dArray.second;
362 std::size_t cellIdx = 0;
363 for (
unsigned int i = 0; i < offsets.size(); ++i)
365 unsigned int offset = offsets[i];
366 for (
unsigned int j = 0; j < offset-lastOffset-1; ++j)
367 cd[cellIdx++] = pd[i];
374 DUNE_THROW(Dune::IOError,
"No Cells or Lines element found in " << fileName_);
377 const XMLElement* pointDataNode = getDataNode_(pieceNode, DataType::pointData);
378 if (pointDataNode !=
nullptr)
380 const XMLElement* dataArray = pointDataNode->FirstChildElement(
"DataArray");
381 for (; dataArray !=
nullptr; dataArray = dataArray->NextSiblingElement(
"DataArray"))
383 const char *attributeText = dataArray->Attribute(
"Name");
385 if (attributeText ==
nullptr)
386 DUNE_THROW(Dune::IOError,
"Couldn't get Name attribute of a point data array.");
388 pointData[std::string(attributeText)] = parseDataArray_<std::vector<double>>(dataArray);
397 const tinyxml2::XMLElement* getPieceNode_()
const
398 {
return getPieceNode_(doc_, fileName_); }
406 const tinyxml2::XMLElement* getPieceNode_(
const tinyxml2::XMLDocument& doc,
const std::string& fileName)
const
408 using namespace tinyxml2;
410 const XMLElement* pieceNode = doc.FirstChildElement(
"VTKFile");
411 if (pieceNode ==
nullptr)
412 DUNE_THROW(Dune::IOError,
"Couldn't get 'VTKFile' node in " << fileName <<
".");
414 pieceNode = pieceNode->FirstChildElement(
"UnstructuredGrid");
415 if (pieceNode ==
nullptr)
416 pieceNode = doc.FirstChildElement(
"VTKFile")->FirstChildElement(
"PolyData");
417 if (pieceNode ==
nullptr)
418 pieceNode = doc.FirstChildElement(
"VTKFile")->FirstChildElement(
"PUnstructuredGrid");
419 if (pieceNode ==
nullptr)
420 pieceNode = doc.FirstChildElement(
"VTKFile")->FirstChildElement(
"PPolyData");
421 if (pieceNode ==
nullptr)
422 DUNE_THROW(Dune::IOError,
"Couldn't get 'UnstructuredGrid', 'PUnstructuredGrid', 'PolyData', or 'PPolyData' node in " << fileName <<
".");
424 return pieceNode->FirstChildElement(
"Piece");
433 const tinyxml2::XMLElement* getDataNode_(
const tinyxml2::XMLElement* pieceNode,
const DataType& type)
const
435 using namespace tinyxml2;
437 const XMLElement* dataNode =
nullptr;
438 if (type == DataType::pointData)
439 dataNode = pieceNode->FirstChildElement(
"PointData");
440 else if (type == DataType::cellData)
441 dataNode = pieceNode->FirstChildElement(
"CellData");
443 DUNE_THROW(Dune::IOError,
"Only cell and point data are supported.");
454 const tinyxml2::XMLElement* findDataArray_(
const tinyxml2::XMLElement* dataNode,
const std::string& name)
const
456 using namespace tinyxml2;
459 const XMLElement* dataArray = dataNode->FirstChildElement(
"DataArray");
460 for (; dataArray !=
nullptr; dataArray = dataArray->NextSiblingElement(
"DataArray"))
462 const char *attributeText = dataArray->Attribute(
"Name");
464 if (attributeText ==
nullptr)
465 DUNE_THROW(Dune::IOError,
"Couldn't get Name attribute of a data array.");
467 if (attributeText == name)
479 template<
class Container>
480 Container parseDataArray_(
const tinyxml2::XMLElement* dataArray)
const
483 std::stringstream dataStream(dataArray->GetText());
484 std::istream_iterator<typename Container::value_type> it(dataStream);
485 std::copy(it, std::istream_iterator<typename Container::value_type>(), std::back_inserter(data));
493 Dune::GeometryType vtkToDuneGeomType_(
unsigned int vtkCellType)
const
497 case Dune::VTK::GeometryType::vertex:
return Dune::GeometryTypes::vertex;
498 case Dune::VTK::GeometryType::line:
return Dune::GeometryTypes::line;
499 case Dune::VTK::GeometryType::triangle:
return Dune::GeometryTypes::triangle;
500 case Dune::VTK::GeometryType::quadrilateral:
return Dune::GeometryTypes::quadrilateral;
501 case Dune::VTK::GeometryType::hexahedron:
return Dune::GeometryTypes::hexahedron;
502 case Dune::VTK::GeometryType::prism:
return Dune::GeometryTypes::prism;
503 case Dune::VTK::GeometryType::pyramid:
return Dune::GeometryTypes::pyramid;
504 default: DUNE_THROW(Dune::NotImplemented,
"VTK cell type " << vtkCellType);
508 template<
int dim, std::enable_if_t<(dim < 3),
int> = 0>
509 std::vector<Dune::FieldVector<
double, dim>>
510 adaptPo
intDimension_(std::vector<Dune::FieldVector<
double, 3>>&& po
ints3D) const
512 std::vector<Dune::FieldVector<
double, dim>> po
ints(po
ints3D.size());
513 for (std::
size_t i = 0; i < po
ints.size(); ++i)
514 for (
int j = 0; j < dim; ++j)
515 po
ints[i][j] = po
ints3D[i][j];
519 template<
int dim, std::enable_if_t<(dim == 3),
int> = 0>
520 std::vector<Dune::FieldVector<double, dim>>
521 adaptPointDimension_(std::vector<Dune::FieldVector<double, 3>>&& points3D)
const
522 {
return std::move(points3D); }
524 std::string fileName_;
525 tinyxml2::XMLDocument doc_;
A vtk file reader using tinyxml2 as xml backend.
Definition: vtkreader.hh:49
std::unique_ptr< Grid > readGrid(Dune::GridFactory< Grid > &factory, Data &cellData, Data &pointData, bool verbose=false) const
Read a grid from a vtk/vtu/vtp file, reading all cell and point data.
Definition: vtkreader.hh:144
Container readData(const std::string &name, const DataType &type) const
read data from the vtk file to a container, e.g. std::vector<double>
Definition: vtkreader.hh:79
VTKReader(const std::string &fileName)
The contructor creates a tinyxml2::XMLDocument from file.
Definition: vtkreader.hh:62
std::unique_ptr< Grid > readGrid(Dune::GridFactory< Grid > &factory, bool verbose=false) const
Read a grid from a vtk/vtu/vtp file, ignoring cell and point data.
Definition: vtkreader.hh:124
std::unique_ptr< Grid > readGrid(bool verbose=false) const
Read a grid from a vtk/vtu/vtp file, ignoring cell and point data.
Definition: vtkreader.hh:103
DataType
The data array types.
Definition: vtkreader.hh:54
std::unordered_map< std::string, std::vector< double > > Data
the cell / point data type for point data read from a grid file
Definition: vtkreader.hh:57