GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/io/vtk/vtkreader.hh
Date: 2024-05-04 19:09:25
Exec Total Coverage
Lines: 175 201 87.1%
Functions: 23 26 88.5%
Branches: 231 823 28.1%

Line Branch Exec Source
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 //
4 // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5 // SPDX-License-Identifier: GPL-3.0-or-later
6 //
7 /*!
8 * \file
9 * \ingroup InputOutput
10 * \brief A vtk file reader using tinyxml2 as xml backend
11 */
12 #ifndef DUMUX_IO_VTK_VTKREADER_HH
13 #define DUMUX_IO_VTK_VTKREADER_HH
14
15 #include <iostream>
16 #include <iterator>
17 #include <algorithm>
18 #include <memory>
19 #include <type_traits>
20 #include <unordered_map>
21 #include <utility>
22
23 #include <dune/common/parallel/mpihelper.hh>
24 #include <dune/common/exceptions.hh>
25 #include <dune/grid/common/capabilities.hh>
26 #include <dune/grid/io/file/vtk/common.hh>
27 #include <dune/grid/common/gridfactory.hh>
28
29 #include <dumux/io/container.hh>
30 #include <dumux/io/xml/tinyxml2.h>
31
32 namespace Dumux {
33
34 /*!
35 * \ingroup InputOutput
36 * \brief A vtk file reader using tinyxml2 as xml backend
37 */
38 class VTKReader
39 {
40 public:
41 /*!
42 * \brief The data array types
43 */
44 enum class DataType { cellData, pointData };
45
46 //! the cell / point data type for point data read from a grid file
47 using Data = std::unordered_map<std::string, std::vector<double>>;
48
49 /*!
50 * \brief The constructor creates a tinyxml2::XMLDocument from file
51 */
52 63 explicit VTKReader(const std::string& fileName)
53 126 {
54 63 using namespace tinyxml2;
55
7/12
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 61 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 61 times.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 61 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
63 fileName_ = Dune::MPIHelper::getCommunication().size() > 1 ?
56
3/4
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 61 times.
✓ Branch 4 taken 2 times.
63 getProcessFileName_(fileName) : fileName;
57
58
2/4
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 63 times.
✗ Branch 5 not taken.
126 const auto eResult = doc_.LoadFile(fileName_.c_str());
59
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
63 if (eResult != tinyxml2::XML_SUCCESS)
60 DUNE_THROW(Dune::IOError, "Couldn't open XML file " << fileName_ << ".");
61
62 126 const XMLElement* pieceNode = getPieceNode_();
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
63 if (pieceNode == nullptr)
64 DUNE_THROW(Dune::IOError, "Couldn't get 'Piece' node in " << fileName_ << ".");
65 63 }
66
67 /*!
68 * \brief Reviews data from the vtk file to check if there is a data array with a specified name
69 * \param name the name attribute of the data array to read
70 * \param type the data array type
71 */
72 273 bool hasData(const std::string& name, const DataType& type) const
73 {
74 273 using namespace tinyxml2;
75
76 546 const XMLElement* pieceNode = getPieceNode_();
77 273 const XMLElement* dataNode = getDataNode_(pieceNode, type);
78
1/2
✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
273 if (dataNode == nullptr)
79 return false;
80
81 273 const XMLElement* dataArray = findDataArray_(dataNode, name);
82
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 271 times.
273 if (dataArray == nullptr)
83 2 return false;
84
85 return true;
86 }
87
88 /*!
89 * \brief read data from the vtk file to a container, e.g. std::vector<double>
90 * \tparam Container a container type that has begin(), end(), push_back(), e.g. std::vector<>
91 * \param name the name attribute of the data array to read
92 * \param type the data array type
93 */
94 template<class Container>
95 139 Container readData(const std::string& name, const DataType& type) const
96 {
97 using namespace tinyxml2;
98
99 278 const XMLElement* pieceNode = getPieceNode_();
100 139 const XMLElement* dataNode = getDataNode_(pieceNode, type);
101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 125 times.
139 if (dataNode == nullptr)
102 DUNE_THROW(Dune::IOError, "Couldn't get 'PointData' or 'CellData' node in " << fileName_ << ".");
103
104 139 const XMLElement* dataArray = findDataArray_(dataNode, name);
105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 125 times.
139 if (dataArray == nullptr)
106 DUNE_THROW(Dune::IOError, "Couldn't find the data array " << name << ".");
107
108 139 return parseDataArray_<Container>(dataArray);
109 }
110
111 /*!
112 * \brief Read a grid from a vtk/vtu/vtp file, ignoring cell and point data
113 * \param verbose if the output should be verbose
114 */
115 template<class Grid>
116 std::unique_ptr<Grid> readGrid(bool verbose = false) const
117 {
118 static_assert(!Dune::Capabilities::isCartesian<Grid>::v, "Grid reader only supports unstructured grid implementations");
119
120 if (verbose) std::cout << "Reading " << Grid::dimension << "d grid from vtk file " << fileName_ << "." << std::endl;
121
122 // make a grid factory
123 Dune::GridFactory<Grid> factory;
124
125 readGrid_(factory, verbose);
126
127 return std::unique_ptr<Grid>(factory.createGrid());
128 }
129
130 /*!
131 * \brief Read a grid from a vtk/vtu/vtp file, ignoring cell and point data
132 * \note use this signature if the factory might be needed outside to interpret the data via the factory's insertion indices
133 * \param verbose if the output should be verbose
134 * \param factory the (empty) grid factory
135 */
136 template<class Grid>
137 std::unique_ptr<Grid> readGrid(Dune::GridFactory<Grid>& factory, bool verbose = false) const
138 {
139 static_assert(!Dune::Capabilities::isCartesian<Grid>::v, "Grid reader only supports unstructured grid implementations");
140
141 if (verbose) std::cout << "Reading " << Grid::dimension << "d grid from vtk file " << fileName_ << "." << std::endl;
142
143 readGrid_(factory, verbose);
144
145 return std::unique_ptr<Grid>(factory.createGrid());
146 }
147
148 /*!
149 * \brief Read a grid from a vtk/vtu/vtp file, reading all cell and point data
150 * \note the factory will be needed outside to interpret the data via the factory's insertion indices
151 * \param factory the (empty) grid factory
152 * \param cellData the cell data arrays to be filled
153 * \param pointData the point data arrays to be filled
154 * \param verbose if the output should be verbose
155 */
156 template<class Grid>
157 7 std::unique_ptr<Grid> readGrid(Dune::GridFactory<Grid>& factory, Data& cellData, Data& pointData, bool verbose = false) const
158 {
159 static_assert(!Dune::Capabilities::isCartesian<Grid>::v, "Grid reader only supports unstructured grid implementations");
160
161
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
28 if (verbose) std::cout << "Reading " << Grid::dimension << "d grid from vtk file " << fileName_ << "." << std::endl;
162
163 7 readGrid_(factory, verbose);
164 7 readGridData_(cellData, pointData, verbose);
165
166 7 return std::unique_ptr<Grid>(factory.createGrid());
167 }
168
169 private:
170 /*!
171 * \brief get the vtk filename for the current processor
172 */
173 2 std::string getProcessFileName_(const std::string& pvtkFileName)
174 {
175 2 using namespace tinyxml2;
176
177 2 XMLDocument pDoc;
178
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 const auto eResult = pDoc.LoadFile(pvtkFileName.c_str());
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (eResult != XML_SUCCESS)
180 DUNE_THROW(Dune::IOError, "Couldn't open XML file " << pvtkFileName << ".");
181
182 // get the first piece node
183
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 const XMLElement* pieceNode = getPieceNode_(pDoc, pvtkFileName);
184
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 const auto myrank = Dune::MPIHelper::getCommunication().rank();
185
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 for (int rank = 0; rank < myrank; ++rank)
186 {
187 1 pieceNode = pieceNode->NextSiblingElement("Piece");
188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (pieceNode == nullptr)
189 DUNE_THROW(Dune::IOError, "Couldn't find 'Piece' node for rank "
190 << rank << " in " << pvtkFileName << ".");
191 }
192
193 2 const char *vtkFileName = pieceNode->Attribute("Source");
194
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (vtkFileName == nullptr)
195 DUNE_THROW(Dune::IOError, "Couldn't get 'Source' attribute of 'Piece' node no. " << myrank << " in " << pvtkFileName);
196
197
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 return vtkFileName;
198 }
199
200 /*!
201 * \brief Read a grid from a vtk/vtu/vtp file
202 * \param factory the (empty) grid factory
203 * \param verbose if the output should be verbose
204 */
205 template<class Grid>
206 7 void readGrid_(Dune::GridFactory<Grid>& factory, bool verbose = false) const
207 {
208 using namespace tinyxml2;
209
210 14 const XMLElement* pieceNode = getPieceNode_();
211 14 const XMLElement* pointsNode = pieceNode->FirstChildElement("Points")->FirstChildElement("DataArray");
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (pointsNode == nullptr)
213 DUNE_THROW(Dune::IOError, "Couldn't get data array of points in " << fileName_ << ".");
214
215 using Point3D = Dune::FieldVector<double, 3>;
216
1/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
7 std::vector<Point3D> points3D;
217
7/12
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 2 times.
✓ Branch 16 taken 5 times.
28 std::stringstream dataStream(pointsNode->GetText());
218
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 std::istream_iterator<Point3D> it(dataStream);
219
4/8
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
28 std::copy(it, std::istream_iterator<Point3D>(), std::back_inserter(points3D));
220
221 // adapt point dimensions if grid dimension is smaller than 3
222
2/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
12 auto points = adaptPointDimension_<Grid::dimensionworld>(std::move(points3D));
223
224
7/13
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 5 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
28 if (verbose) std::cout << "Found " << points.size() << " vertices." << std::endl;
225
226 // insert vertices to the grid factory
227
4/4
✓ Branch 0 taken 13089 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 13089 times.
✓ Branch 3 taken 7 times.
13105 for (auto&& point : points)
228
1/2
✓ Branch 1 taken 13089 times.
✗ Branch 2 not taken.
13089 factory.insertVertex(std::move(point));
229
230 7 const XMLElement* cellsNode = pieceNode->FirstChildElement("Cells");
231 7 const XMLElement* linesNode = pieceNode->FirstChildElement("Lines");
232
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (cellsNode)
233 {
234
5/12
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
8 const XMLElement* connectivityNode = findDataArray_(cellsNode, "connectivity");
235
5/12
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
8 const XMLElement* offsetsNode = findDataArray_(cellsNode, "offsets");
236
5/12
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
8 const XMLElement* typesNode = findDataArray_(cellsNode, "types");
237
238
2/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
8 const auto connectivity = parseDataArray_<std::vector<unsigned int>>(connectivityNode);
239
2/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
8 const auto offsets = parseDataArray_<std::vector<unsigned int>>(offsetsNode);
240
3/8
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
12 const auto types = parseDataArray_<std::vector<unsigned int>>(typesNode);
241
242
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 4 times.
✗ Branch 12 not taken.
16 if (verbose) std::cout << "Found " << offsets.size() << " element." << std::endl;
243
244 unsigned int lastOffset = 0;
245
4/4
✓ Branch 0 taken 8651 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 8651 times.
✓ Branch 3 taken 4 times.
17310 for (unsigned int i = 0; i < offsets.size(); ++i)
246 {
247
2/4
✓ Branch 1 taken 8651 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8651 times.
✗ Branch 5 not taken.
17302 const auto geomType = vtkToDuneGeomType_(types[i]);
248
1/2
✓ Branch 1 taken 8651 times.
✗ Branch 2 not taken.
8651 unsigned int offset = offsets[i];
249
2/6
✓ Branch 1 taken 8651 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8651 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
25953 std::vector<unsigned int> corners; corners.resize(offset-lastOffset);
250
2/2
✓ Branch 0 taken 46933 times.
✓ Branch 1 taken 8651 times.
55584 for (unsigned int j = 0; j < offset-lastOffset; ++j)
251 140799 corners[Dune::VTK::renumber(geomType, j)] = connectivity[lastOffset+j];
252
1/2
✓ Branch 1 taken 8651 times.
✗ Branch 2 not taken.
8651 factory.insertElement(geomType, std::move(corners));
253
1/2
✓ Branch 0 taken 8651 times.
✗ Branch 1 not taken.
8651 lastOffset = offset;
254 }
255 }
256 // for poly data
257
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 else if (linesNode)
258 {
259 // sanity check
260 if (Grid::dimension != 1)
261 DUNE_THROW(Dune::IOError, "Grid expects dimension " << Grid::dimension
262 << " but " << fileName_ << " contains a 1D grid.");
263
264
5/12
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
6 const XMLElement* connectivityNode = findDataArray_(linesNode, "connectivity");
265
5/12
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
6 const XMLElement* offsetsNode = findDataArray_(linesNode, "offsets");
266
267
1/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 const auto connectivity = parseDataArray_<std::vector<unsigned int>>(connectivityNode);
268
3/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
9 const auto offsets = parseDataArray_<std::vector<unsigned int>>(offsetsNode);
269
270
4/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
12 if (verbose) std::cout << "Found " << offsets.size() << " polylines." << std::endl;
271
272 unsigned int lastOffset = 0;
273
4/4
✓ Branch 0 taken 3477 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3477 times.
✓ Branch 3 taken 3 times.
6960 for (unsigned int i = 0; i < offsets.size(); ++i)
274 {
275 // a polyline can have many points in the VTK format
276 // split the line in segments with two points
277 3477 unsigned int offset = offsets[i];
278
2/2
✓ Branch 0 taken 3496 times.
✓ Branch 1 taken 3477 times.
6973 for (unsigned int j = 0; j < offset-lastOffset-1; ++j)
279
3/10
✓ Branch 1 taken 3496 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3496 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3496 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
10488 factory.insertElement(Dune::GeometryTypes::line,
280
3/6
✓ Branch 1 taken 3496 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3496 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3496 times.
✗ Branch 8 not taken.
10488 std::vector<unsigned int>({ connectivity[lastOffset+j], connectivity[lastOffset+j+1] }));
281 3477 lastOffset = offset;
282 }
283 }
284 else
285 DUNE_THROW(Dune::IOError, "No Cells or Lines element found in " << fileName_);
286 7 }
287
288 /*!
289 * \brief Read a grid data from a vtk/vtu/vtp file
290 * \param cellData the cell data arrays to be filled
291 * \param pointData the point data arrays to be filled
292 * \param verbose if the output should be verbose
293 */
294 7 void readGridData_(Data& cellData, Data& pointData, bool verbose = false) const
295 {
296 7 using namespace tinyxml2;
297
298 14 const XMLElement* pieceNode = getPieceNode_();
299 7 const XMLElement* cellDataNode = getDataNode_(pieceNode, DataType::cellData);
300
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (cellDataNode != nullptr)
301 {
302 7 const XMLElement* cellsNode = pieceNode->FirstChildElement("Cells");
303 7 const XMLElement* linesNode = pieceNode->FirstChildElement("Lines");
304
305
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (cellsNode)
306 {
307 4 const XMLElement* dataArray = cellDataNode->FirstChildElement("DataArray");
308
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
23 for (; dataArray != nullptr; dataArray = dataArray->NextSiblingElement("DataArray"))
309 {
310 19 const char *attributeText = dataArray->Attribute("Name");
311
312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (attributeText == nullptr)
313 DUNE_THROW(Dune::IOError, "Couldn't get Name attribute of a cell data array.");
314
315
6/16
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 19 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 19 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 19 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 19 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 19 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
19 cellData[std::string(attributeText)] = parseDataArray_<std::vector<double>>(dataArray);
316 }
317 }
318 // for poly data
319
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 else if (linesNode)
320 {
321 // first parse all the cell data (each cell in this sense can be a polyline)
322 3 const XMLElement* dataArray = cellDataNode->FirstChildElement("DataArray");
323
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (dataArray)
324 {
325 6 Data polyLineCellData;
326
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
10 for (; dataArray != nullptr; dataArray = dataArray->NextSiblingElement("DataArray"))
327 {
328 7 const char *attributeText = dataArray->Attribute("Name");
329
330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (attributeText == nullptr)
331 DUNE_THROW(Dune::IOError, "Couldn't get Name attribute of a cell data array.");
332
333
7/18
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 7 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 7 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 7 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
7 polyLineCellData[std::string(attributeText)] = parseDataArray_<std::vector<double>>(dataArray);
334 }
335
336 // a polyline can have many points in the VTK format
337 // we split the line in segments with two points
338 // so we also need to duplicate the cell data to fit the increased line number
339
5/12
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
6 const XMLElement* offsetsNode = findDataArray_(linesNode, "offsets");
340
2/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9 const auto offsets = parseDataArray_<std::vector<unsigned int>>(offsetsNode);
341
342
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
15 if (offsets.size() != polyLineCellData.begin()->second.size())
343 DUNE_THROW(Dune::IOError, "Expected the same number of cell data entries (is "
344 << polyLineCellData.begin()->second.size()
345 << ") as polylines (" << offsets.size() << ")!");
346
347 // count the number of Dune cells to be able to resize the data vectors
348 unsigned int lastOffset = 0;
349 std::size_t numCells = 0;
350
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3477 times.
3480 for (unsigned int i = 0; i < offsets.size(); ++i)
351 {
352 3477 unsigned int offset = offsets[i];
353
2/2
✓ Branch 0 taken 3496 times.
✓ Branch 1 taken 3477 times.
6973 for (unsigned int j = 0; j < offset-lastOffset-1; ++j)
354 3496 ++numCells;
355 3477 lastOffset = offset;
356 }
357
358 // create the data arrays
359
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
10 for (const auto& dArray : polyLineCellData)
360 {
361
5/12
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 7 times.
✓ Branch 13 taken 7 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
14 cellData[dArray.first] = std::vector<double>(numCells);
362
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 auto& cd = cellData[dArray.first];
363 const auto& pd = dArray.second;
364
365 lastOffset = 0;
366 std::size_t cellIdx = 0;
367
4/4
✓ Branch 0 taken 8692 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 8692 times.
✓ Branch 3 taken 7 times.
17398 for (unsigned int i = 0; i < offsets.size(); ++i)
368 {
369 8692 unsigned int offset = offsets[i];
370
2/2
✓ Branch 0 taken 8730 times.
✓ Branch 1 taken 8692 times.
17422 for (unsigned int j = 0; j < offset-lastOffset-1; ++j)
371 26190 cd[cellIdx++] = pd[i];
372 8692 lastOffset = offset;
373 }
374 }
375 }
376 }
377 else
378 DUNE_THROW(Dune::IOError, "No Cells or Lines element found in " << fileName_);
379 }
380
381 7 const XMLElement* pointDataNode = getDataNode_(pieceNode, DataType::pointData);
382
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (pointDataNode != nullptr)
383 {
384 3 const XMLElement* dataArray = pointDataNode->FirstChildElement("DataArray");
385
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3 times.
15 for (; dataArray != nullptr; dataArray = dataArray->NextSiblingElement("DataArray"))
386 {
387 12 const char *attributeText = dataArray->Attribute("Name");
388
389
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (attributeText == nullptr)
390 DUNE_THROW(Dune::IOError, "Couldn't get Name attribute of a point data array.");
391
392
6/16
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 12 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 12 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
12 pointData[std::string(attributeText)] = parseDataArray_<std::vector<double>>(dataArray);
393 }
394 }
395 7 }
396
397 /*!
398 * \brief Get the piece node of the XMLDocument
399 * \note Returns nullptr if the piece node wasn't found
400 */
401 const tinyxml2::XMLElement* getPieceNode_() const
402
2/4
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
475 { return getPieceNode_(doc_, fileName_); }
403
404 /*!
405 * \brief Get the piece node an xml document
406 * \note Returns nullptr if the piece node wasn't found
407 * \param doc an xml document
408 * \param fileName a file name the doc was created from
409 */
410 477 const tinyxml2::XMLElement* getPieceNode_(const tinyxml2::XMLDocument& doc, const std::string& fileName) const
411 {
412 477 using namespace tinyxml2;
413
414 477 const XMLElement* pieceNode = doc.FirstChildElement("VTKFile");
415
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 477 times.
477 if (pieceNode == nullptr)
416 DUNE_THROW(Dune::IOError, "Couldn't get 'VTKFile' node in " << fileName << ".");
417
418 477 pieceNode = pieceNode->FirstChildElement("UnstructuredGrid");
419
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 353 times.
477 if (pieceNode == nullptr)
420 248 pieceNode = doc.FirstChildElement("VTKFile")->FirstChildElement("PolyData");
421
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 475 times.
477 if (pieceNode == nullptr)
422 4 pieceNode = doc.FirstChildElement("VTKFile")->FirstChildElement("PUnstructuredGrid");
423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 477 times.
477 if (pieceNode == nullptr)
424 pieceNode = doc.FirstChildElement("VTKFile")->FirstChildElement("PPolyData");
425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 477 times.
477 if (pieceNode == nullptr)
426 DUNE_THROW(Dune::IOError, "Couldn't get 'UnstructuredGrid', 'PUnstructuredGrid', 'PolyData', or 'PPolyData' node in " << fileName << ".");
427
428 954 return pieceNode->FirstChildElement("Piece");
429 }
430
431 /*!
432 * \brief Get the piece node of the XMLDocument
433 * \param pieceNode the pieceNode of the vtk file
434 * \param type the vtk data type (cell data or point data)
435 * \note Returns nullptr if the data node wasn't found
436 */
437 412 const tinyxml2::XMLElement* getDataNode_(const tinyxml2::XMLElement* pieceNode, const DataType& type) const
438 {
439 412 using namespace tinyxml2;
440
441 412 const XMLElement* dataNode = nullptr;
442
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 284 times.
412 if (type == DataType::pointData)
443 128 dataNode = pieceNode->FirstChildElement("PointData");
444
1/2
✓ Branch 0 taken 284 times.
✗ Branch 1 not taken.
284 else if (type == DataType::cellData)
445 284 dataNode = pieceNode->FirstChildElement("CellData");
446 else
447 DUNE_THROW(Dune::IOError, "Only cell and point data are supported.");
448
449 412 return dataNode;
450 }
451
452 /*!
453 * \brief Find a data array with a specific name
454 * \param dataNode a cell or point data node
455 * \param name the name of the data array to be found
456 * \note Returns nullptr if the data array wasn't found
457 */
458 419 const tinyxml2::XMLElement* findDataArray_(const tinyxml2::XMLElement* dataNode, const std::string& name) const
459 {
460 419 using namespace tinyxml2;
461
462 // loop over XML node siblings to find the correct data array
463 419 const XMLElement* dataArray = dataNode->FirstChildElement("DataArray");
464
2/2
✓ Branch 0 taken 2781 times.
✓ Branch 1 taken 2 times.
5147 for (; dataArray != nullptr; dataArray = dataArray->NextSiblingElement("DataArray"))
465 {
466 2781 const char *attributeText = dataArray->Attribute("Name");
467
468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2781 times.
2781 if (attributeText == nullptr)
469 DUNE_THROW(Dune::IOError, "Couldn't get Name attribute of a data array.");
470
471
2/2
✓ Branch 1 taken 2364 times.
✓ Branch 2 taken 417 times.
2781 if (attributeText == name)
472 break;
473 }
474
475 419 return dataArray;
476 }
477
478 /*!
479 * \brief Parses the text of a data array into a container
480 * \tparam Container a container type that has begin(), end(), push_back(), e.g. std::vector<double>
481 * \param dataArray the data array node to be parsed
482 */
483 template<class Container>
484 243 Container parseDataArray_(const tinyxml2::XMLElement* dataArray) const
485 {
486
5/10
✓ Branch 1 taken 170 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 170 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 170 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 170 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 170 times.
✗ Branch 14 not taken.
729 std::stringstream dataStream(dataArray->GetText());
487
1/2
✓ Branch 1 taken 170 times.
✗ Branch 2 not taken.
486 return readStreamToContainer<Container>(dataStream);
488 }
489
490 /*!
491 * \brief Return the Dune::GeometryType for a given VTK geometry type
492 * \param vtkCellType the vtk cell type
493 */
494 8651 Dune::GeometryType vtkToDuneGeomType_(unsigned int vtkCellType) const
495 {
496
3/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 463 times.
✓ Branch 3 taken 4990 times.
✓ Branch 4 taken 3198 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
8651 switch (vtkCellType)
497 {
498 case Dune::VTK::GeometryType::vertex: return Dune::GeometryTypes::vertex;
499 case Dune::VTK::GeometryType::line: return Dune::GeometryTypes::line;
500 463 case Dune::VTK::GeometryType::triangle: return Dune::GeometryTypes::triangle;
501 4990 case Dune::VTK::GeometryType::quadrilateral: return Dune::GeometryTypes::quadrilateral;
502 3198 case Dune::VTK::GeometryType::hexahedron: return Dune::GeometryTypes::hexahedron;
503 case Dune::VTK::GeometryType::prism: return Dune::GeometryTypes::prism;
504 case Dune::VTK::GeometryType::pyramid: return Dune::GeometryTypes::pyramid;
505 default: DUNE_THROW(Dune::NotImplemented, "VTK cell type " << vtkCellType);
506 }
507 }
508
509 template<int dim, std::enable_if_t<(dim < 3), int> = 0>
510 std::vector<Dune::FieldVector<double, dim>>
511 2 adaptPointDimension_(std::vector<Dune::FieldVector<double, 3>>&& points3D) const
512 {
513 6 std::vector<Dune::FieldVector<double, dim>> points(points3D.size());
514
4/4
✓ Branch 0 taken 5190 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5190 times.
✓ Branch 3 taken 2 times.
5192 for (std::size_t i = 0; i < points.size(); ++i)
515
2/2
✓ Branch 0 taken 10380 times.
✓ Branch 1 taken 5190 times.
15570 for (int j = 0; j < dim; ++j)
516 51900 points[i][j] = points3D[i][j];
517 2 return points;
518 }
519
520 template<int dim, std::enable_if_t<(dim == 3), int> = 0>
521 std::vector<Dune::FieldVector<double, dim>>
522 adaptPointDimension_(std::vector<Dune::FieldVector<double, 3>>&& points3D) const
523
2/8
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10 { return std::move(points3D); }
524
525 std::string fileName_; //!< the vtk file name
526 tinyxml2::XMLDocument doc_; //!< the xml document created from file with name fileName_
527 };
528
529 } // end namespace Dumux
530
531 #endif
532