1 #include <fstream>
2 #include <iterator>
3 #include <sstream>
4 #include <string>
5
6 #if HAVE_VTK_ZLIB
7 #include <zlib.h>
8 #endif
9
10 #include <dune/common/classname.hh>
11 #include <dune/common/version.hh>
12
13 #include "utility/errors.hh"
14 #include "utility/filesystem.hh"
15 #include "utility/string.hh"
16
17 namespace Dune {
18
19 template <class Grid, class Creator, class Field>
read(std::string const & filename,bool fillCreator)20 void VtkReader<Grid,Creator,Field>::read (std::string const& filename, bool fillCreator)
21 {
22 // check whether file exists!
23 if (!Vtk::exists(filename))
24 DUNE_THROW(IOError, "File " << filename << " does not exist!");
25
26 std::ifstream input(filename, std::ios_base::in | std::ios_base::binary);
27 VTK_ASSERT(input.is_open());
28
29 std::string ext = Vtk::Path(filename).extension().string();
30 if (ext == ".vtu") {
31 readSerialFileFromStream(input, fillCreator);
32 pieces_.push_back(filename);
33 } else if (ext == ".pvtu") {
34 readParallelFileFromStream(input, comm().rank(), comm().size(), fillCreator);
35 } else {
36 DUNE_THROW(Dune::VtkError, "File has unknown file-extension '" << ext << "'. Allowed are only '.vtu' and '.pvtu'.");
37 }
38 read_ = true;
39 }
40
41
42 template <class Grid, class Creator, class Field>
readSerialFileFromStream(std::ifstream & input,bool fillCreator)43 void VtkReader<Grid,Creator,Field>::readSerialFileFromStream (std::ifstream& input, bool fillCreator)
44 {
45 clear();
46 compressor_ = Vtk::CompressorTypes::NONE;
47 Vtk::DataTypes header_type = Vtk::DataTypes::UINT32;
48 std::string data_id = "";
49 std::string data_format = "";
50 Vtk::DataTypes data_type = Vtk::DataTypes::UNKNOWN;
51 unsigned int data_components = 0;
52 std::uint64_t data_offset = 0;
53
54 Sections section = NO_SECTION;
55 for (std::string line; std::getline(input, line); ) {
56 Vtk::ltrim(line);
57
58 if (isSection(line, "VTKFile", section)) {
59 bool closed = false;
60 auto attr = parseXml(line, closed);
61
62 if (!attr["type"].empty())
63 VTK_ASSERT_MSG(attr["type"] == "UnstructuredGrid", "VtkReader supports UnstructuredGrid types");
64 if (!attr["byte_order"].empty())
65 VTK_ASSERT_MSG(attr["byte_order"] == "LittleEndian", "LittleEndian byte order supported");
66
67 if (attr["header_type"] == "UInt32")
68 header_type = Vtk::DataTypes::UINT32;
69 else if (attr["header_type"] == "UInt64")
70 header_type = Vtk::DataTypes::UINT64;
71
72 if (attr["compressor"] == "vtkZLibDataCompressor")
73 compressor_ = Vtk::CompressorTypes::ZLIB;
74 else if (attr["compressor"] == "vtkLZ4DataCompressor")
75 compressor_ = Vtk::CompressorTypes::LZ4;
76 else if (attr["compressor"] == "vtkLZMADataCompressor")
77 compressor_ = Vtk::CompressorTypes::LZMA;
78
79 section = VTK_FILE;
80 }
81 else if (isSection(line, "/VTKFile", section, VTK_FILE)) {
82 section = NO_SECTION;
83 break;
84 }
85 else if (isSection(line, "UnstructuredGrid", section, VTK_FILE))
86 section = UNSTRUCTURED_GRID;
87 else if (isSection(line, "/UnstructuredGrid", section, UNSTRUCTURED_GRID))
88 section = VTK_FILE;
89 else if (isSection(line, "Piece", section, UNSTRUCTURED_GRID)) {
90 bool closed = false;
91 auto attr = parseXml(line, closed);
92
93 VTK_ASSERT_MSG(attr.count("NumberOfPoints") > 0 && attr.count("NumberOfCells") > 0,
94 "Number of points or cells in file must be > 0");
95 numberOfPoints_ = std::stoul(attr["NumberOfPoints"]);
96 numberOfCells_ = std::stoul(attr["NumberOfCells"]);
97 section = PIECE;
98 }
99 else if (isSection(line, "/Piece", section, PIECE))
100 section = UNSTRUCTURED_GRID;
101 else if (isSection(line, "PointData", section, PIECE))
102 section = POINT_DATA;
103 else if (isSection(line, "/PointData", section, POINT_DATA))
104 section = PIECE;
105 else if (isSection(line, "CellData", section, PIECE))
106 section = CELL_DATA;
107 else if (isSection(line, "/CellData", section, CELL_DATA))
108 section = PIECE;
109 else if (isSection(line, "Points", section, PIECE))
110 section = POINTS;
111 else if (isSection(line, "/Points", section, POINTS))
112 section = PIECE;
113 else if (isSection(line, "Cells", section, PIECE))
114 section = CELLS;
115 else if (isSection(line, "/Cells", section, CELLS))
116 section = PIECE;
117 else if (line.substr(1,9) == "DataArray") {
118 bool closed = false;
119 auto attr = parseXml(line, closed);
120
121 data_type = Vtk::dataTypeOf(attr["type"]);
122
123 // Use Section.Name as id
124 data_id = toString(section) + "." + attr["Name"];
125
126 if (section == POINTS)
127 // In the Points section must only be one DataArray with id=Points
128 data_id = "Points";
129
130 data_components = 1;
131 if (!attr["NumberOfComponents"].empty())
132 data_components = std::stoul(attr["NumberOfComponents"]);
133
134 // determine FormatType
135 data_format = Vtk::to_lower(attr["format"]);
136 if (data_format == "appended") {
137 format_ = compressor_ != Vtk::CompressorTypes::NONE ? Vtk::FormatTypes::COMPRESSED : Vtk::FormatTypes::BINARY;
138 } else {
139 format_ = Vtk::FormatTypes::ASCII;
140 }
141
142 // Offset makes sense in appended mode only
143 data_offset = 0;
144 if (!attr["offset"].empty()) {
145 data_offset = std::stoul(attr["offset"]);
146 VTK_ASSERT_MSG(data_format == "appended", "Attribute 'offset' only supported by appended mode");
147 }
148
149 // Store attributes of DataArray
150 dataArray_[data_id] = {attr["Name"], data_type, data_components, data_offset, section};
151
152 // Skip section in appended mode
153 if (data_format == "appended") {
154 if (!closed) {
155 while (std::getline(input, line)) {
156 Vtk::ltrim(line);
157 if (line.substr(1,10) == "/DataArray")
158 break;
159 }
160 }
161 continue;
162 }
163
164 if (section == POINT_DATA)
165 section = PD_DATA_ARRAY;
166 else if (section == POINTS)
167 section = POINTS_DATA_ARRAY;
168 else if (section == CELL_DATA)
169 section = CD_DATA_ARRAY;
170 else if (section == CELLS)
171 section = CELLS_DATA_ARRAY;
172 else
173 DUNE_THROW(Dune::VtkError, "Wrong section for <DataArray>");
174 }
175 else if (line.substr(1,10) == "/DataArray") {
176 if (section == PD_DATA_ARRAY)
177 section = POINT_DATA;
178 else if (section == POINTS_DATA_ARRAY)
179 section = POINTS;
180 else if (section == CD_DATA_ARRAY)
181 section = CELL_DATA;
182 else if (section == CELLS_DATA_ARRAY)
183 section = CELLS;
184 else
185 DUNE_THROW(Dune::VtkError, "Wrong section for </DataArray>");
186 }
187 else if (isSection(line, "AppendedData", section, VTK_FILE)) {
188 bool closed = false;
189 auto attr = parseXml(line, closed);
190 if (!attr["encoding"].empty())
191 VTK_ASSERT_MSG(attr["encoding"] == "raw", "base64 encoding not supported");
192
193 offset0_ = findAppendedDataPosition(input);
194 Vtk::mapDataTypes<std::is_floating_point, std::is_integral>(dataArray_["Points"].type, header_type,
195 [&](auto f, auto h) {
196 this->readPointsAppended(f,h,input);
197 this->readCellsAppended(h,input);
198 });
199
200 // read point and cell data
201 for (auto const& d : dataArray_) {
202 if (d.second.section == POINT_DATA) {
203 Vtk::mapDataTypes<std::is_floating_point, std::is_integral>(d.second.type, header_type,
204 [&](auto f, auto h) {
205 this->readPointDataAppended(f,h,input,d.first);
206 });
207 }
208 else if (d.second.section == CELL_DATA) {
209 Vtk::mapDataTypes<std::is_floating_point, std::is_integral>(d.second.type, header_type,
210 [&](auto f, auto h) {
211 this->readCellDataAppended(f,h,input,d.first);
212 });
213 }
214 }
215
216 section = NO_SECTION; // finish reading after appended section
217 break;
218 }
219 else if (isSection(line, "/AppendedData", section, APPENDED_DATA))
220 section = VTK_FILE;
221
222 switch (section) {
223 case PD_DATA_ARRAY:
224 section = readPointData(input, data_id);
225 break;
226 case POINTS_DATA_ARRAY:
227 section = readPoints(input, data_id);
228 break;
229 case CD_DATA_ARRAY:
230 section = readCellData(input, data_id);
231 break;
232 case CELLS_DATA_ARRAY:
233 section = readCells(input, data_id);
234 break;
235 default:
236 break;
237 }
238 }
239
240 if (section != NO_SECTION)
241 DUNE_THROW(Dune::VtkError, "VTK-File is incomplete. It must end with </VTKFile>!");
242
243 if (fillCreator)
244 fillGridCreator();
245 }
246
247
248 template <class Grid, class Creator, class Field>
readParallelFileFromStream(std::ifstream & input,int,int,bool fillCreator)249 void VtkReader<Grid,Creator,Field>::readParallelFileFromStream (std::ifstream& input, int /* commRank */, int /* commSize */, bool fillCreator)
250 {
251 clear();
252
253 [[maybe_unused]] Vtk::DataTypes header_type = Vtk::DataTypes::UINT32;
254 compressor_ = Vtk::CompressorTypes::NONE;
255
256 Sections section = NO_SECTION;
257 for (std::string line; std::getline(input, line); ) {
258 Vtk::ltrim(line);
259
260 if (isSection(line, "VTKFile", section)) {
261 bool closed = false;
262 auto attr = parseXml(line, closed);
263
264 if (!attr["type"].empty())
265 VTK_ASSERT_MSG(attr["type"] == "PUnstructuredGrid", "VtkReader supports PUnstructuredGrid types");
266 if (!attr["version"].empty())
267 VTK_ASSERT_MSG(std::stod(attr["version"]) == 1.0, "File format must be 1.0");
268 if (!attr["byte_order"].empty())
269 VTK_ASSERT_MSG(attr["byte_order"] == "LittleEndian", "LittleEndian byte order supported");
270
271 if (attr["header_type"] == "UInt32")
272 header_type = Vtk::DataTypes::UINT32;
273 else if (attr["header_type"] == "UInt64")
274 header_type = Vtk::DataTypes::UINT64;
275
276 if (attr["compressor"] == "vtkZLibDataCompressor")
277 compressor_ = Vtk::CompressorTypes::ZLIB;
278 else if (attr["compressor"] == "vtkLZ4DataCompressor")
279 compressor_ = Vtk::CompressorTypes::LZ4;
280 else if (attr["compressor"] == "vtkLZMADataCompressor")
281 compressor_ = Vtk::CompressorTypes::LZMA;
282
283 section = VTK_FILE;
284 }
285 else if (isSection(line, "/VTKFile", section, VTK_FILE)) {
286 section = NO_SECTION;
287 break;
288 } else if (isSection(line, "PUnstructuredGrid", section, VTK_FILE))
289 section = UNSTRUCTURED_GRID;
290 else if (isSection(line, "/PUnstructuredGrid", section, UNSTRUCTURED_GRID))
291 section = VTK_FILE;
292 else if (isSection(line, "Piece", section, UNSTRUCTURED_GRID)) {
293 bool closed = false;
294 auto attr = parseXml(line, closed);
295
296 VTK_ASSERT_MSG(attr.count("Source") > 0, "No source files for partitions provided");
297 pieces_.push_back(attr["Source"]);
298 }
299 }
300
301 VTK_ASSERT_MSG(section == NO_SECTION, "VTK-File is incomplete. It must end with </VTKFile>!");
302
303 if (fillCreator)
304 fillGridCreator();
305 }
306
307
308 // @{ implementation detail
309 /**
310 * Read ASCII data from `input` stream into vector `values`
311 * \param max_size Upper bound for the number of values
312 * \param section Current XML section you are reading in
313 * \param parent_section XML Section to return when current `section` is finished.
314 **/
315 template <class IStream, class T, class Sections>
readDataArray(IStream & input,std::vector<T> & values,std::size_t max_size,Sections section,Sections parent_section)316 Sections readDataArray (IStream& input, std::vector<T>& values, std::size_t max_size,
317 Sections section, Sections parent_section)
318 {
319 values.reserve(max_size < std::size_t(-1) ? max_size : 0);
320 using S = std::conditional_t<(sizeof(T) <= 1), std::uint16_t, T>; // problem when reading chars as ints
321
322 std::size_t idx = 0;
323 for (std::string line; std::getline(input, line);) {
324 Vtk::trim(line);
325 if (line.substr(1,10) == "/DataArray")
326 return parent_section;
327 if (line[0] == '<')
328 break;
329
330 std::istringstream stream(line);
331 S value;
332 for (; stream >> value; idx++)
333 values.push_back(T(value));
334 if (idx >= max_size)
335 break;
336 }
337
338 return section;
339 }
340
341 template <class IStream, class Sections>
skipRestOfDataArray(IStream & input,Sections section,Sections parent_section)342 Sections skipRestOfDataArray (IStream& input, Sections section, Sections parent_section)
343 {
344 for (std::string line; std::getline(input, line);) {
345 Vtk::ltrim(line);
346 if (line.substr(1,10) == "/DataArray")
347 return parent_section;
348 }
349
350 return section;
351 }
352 // @}
353
354
355 // Read values stored on the cells with name `name`
356 template <class Grid, class Creator, class Field>
357 typename VtkReader<Grid,Creator,Field>::Sections
readCellData(std::ifstream & input,std::string id)358 VtkReader<Grid,Creator,Field>::readCellData (std::ifstream& input, std::string id)
359 {
360 VTK_ASSERT(numberOfCells_ > 0);
361 unsigned int components = dataArray_[id].components;
362
363 Sections sec;
364 std::vector<Field>& values = cellData_[id];
365 sec = readDataArray(input, values, components*numberOfCells_, CD_DATA_ARRAY, CELL_DATA);
366 if (sec != CELL_DATA)
367 sec = skipRestOfDataArray(input, CD_DATA_ARRAY, CELL_DATA);
368 VTK_ASSERT(sec == CELL_DATA);
369 VTK_ASSERT(values.size() == components*numberOfCells_);
370
371 return sec;
372 }
373
374
375 template <class Grid, class Creator, class Field>
376 template <class FloatType, class HeaderType>
readCellDataAppended(MetaType<FloatType>,MetaType<HeaderType>,std::ifstream & input,std::string id)377 void VtkReader<Grid,Creator,Field>::readCellDataAppended (MetaType<FloatType>, MetaType<HeaderType>, std::ifstream& input, std::string id)
378 {
379 VTK_ASSERT(numberOfCells_ > 0);
380 unsigned int components = dataArray_[id].components;
381
382 std::vector<FloatType> values;
383 readAppended(input, values, HeaderType(dataArray_[id].offset));
384 VTK_ASSERT(values.size() == components*numberOfCells_);
385
386 cellData_[id].resize(values.size());
387 std::copy(values.begin(), values.end(), cellData_[id].begin());
388 }
389
390
391 template <class Grid, class Creator, class Field>
392 typename VtkReader<Grid,Creator,Field>::Sections
readPointData(std::ifstream & input,std::string id)393 VtkReader<Grid,Creator,Field>::readPointData (std::ifstream& input, std::string id)
394 {
395 VTK_ASSERT(numberOfPoints_ > 0);
396 unsigned int components = dataArray_[id].components;
397
398 Sections sec;
399 std::vector<Field>& values = pointData_[id];
400 sec = readDataArray(input, values, components*numberOfPoints_, PD_DATA_ARRAY, POINT_DATA);
401 if (sec != POINT_DATA)
402 sec = skipRestOfDataArray(input, PD_DATA_ARRAY, POINT_DATA);
403 VTK_ASSERT(sec == POINT_DATA);
404 VTK_ASSERT(values.size() == components*numberOfPoints_);
405
406 return sec;
407 }
408
409
410 template <class Grid, class Creator, class Field>
411 template <class FloatType, class HeaderType>
readPointDataAppended(MetaType<FloatType>,MetaType<HeaderType>,std::ifstream & input,std::string id)412 void VtkReader<Grid,Creator,Field>::readPointDataAppended (MetaType<FloatType>, MetaType<HeaderType>, std::ifstream& input, std::string id)
413 {
414 VTK_ASSERT(numberOfPoints_ > 0);
415 unsigned int components = dataArray_[id].components;
416
417 std::vector<FloatType> values;
418 readAppended(input, values, HeaderType(dataArray_[id].offset));
419 VTK_ASSERT(values.size() == components*numberOfPoints_);
420
421 pointData_[id].resize(values.size());
422 std::copy(values.begin(), values.end(), pointData_[id].begin());
423 }
424
425
426 template <class Grid, class Creator, class Field>
427 typename VtkReader<Grid,Creator,Field>::Sections
readPoints(std::ifstream & input,std::string id)428 VtkReader<Grid,Creator,Field>::readPoints (std::ifstream& input, std::string id)
429 {
430 using T = typename GlobalCoordinate::value_type;
431 VTK_ASSERT(numberOfPoints_ > 0);
432 VTK_ASSERT(id == "Points");
433 VTK_ASSERT(dataArray_["Points"].components == 3u);
434
435 Sections sec;
436
437 std::vector<T> point_values;
438 sec = readDataArray(input, point_values, 3*numberOfPoints_, POINTS_DATA_ARRAY, POINTS);
439 if (sec != POINTS)
440 sec = skipRestOfDataArray(input, POINTS_DATA_ARRAY, POINTS);
441 VTK_ASSERT(sec == POINTS);
442 VTK_ASSERT(point_values.size() == 3*numberOfPoints_);
443
444 // extract points from continuous values
445 GlobalCoordinate p;
446 vec_points.reserve(numberOfPoints_);
447 std::size_t idx = 0;
448 for (std::size_t i = 0; i < numberOfPoints_; ++i) {
449 for (std::size_t j = 0; j < p.size(); ++j)
450 p[j] = point_values[idx++];
451 idx += (3u - p.size());
452 vec_points.push_back(p);
453 }
454
455 return sec;
456 }
457
458
459 template <class Grid, class Creator, class Field>
460 template <class FloatType, class HeaderType>
readPointsAppended(MetaType<FloatType>,MetaType<HeaderType>,std::ifstream & input)461 void VtkReader<Grid,Creator,Field>::readPointsAppended (MetaType<FloatType>, MetaType<HeaderType>, std::ifstream& input)
462 {
463 VTK_ASSERT(numberOfPoints_ > 0);
464 VTK_ASSERT(dataArray_["Points"].components == 3u);
465 std::vector<FloatType> point_values;
466 readAppended(input, point_values, HeaderType(dataArray_["Points"].offset));
467 VTK_ASSERT(point_values.size() == 3*numberOfPoints_);
468
469 // extract points from continuous values
470 GlobalCoordinate p;
471 vec_points.reserve(numberOfPoints_);
472 std::size_t idx = 0;
473 for (std::size_t i = 0; i < numberOfPoints_; ++i) {
474 for (std::size_t j = 0; j < p.size(); ++j)
475 p[j] = FloatType(point_values[idx++]);
476 idx += (3u - p.size());
477 vec_points.push_back(p);
478 }
479 }
480
481
482 template <class Grid, class Creator, class Field>
483 typename VtkReader<Grid,Creator,Field>::Sections
readCells(std::ifstream & input,std::string id)484 VtkReader<Grid,Creator,Field>::readCells (std::ifstream& input, std::string id)
485 {
486 Sections sec = CELLS_DATA_ARRAY;
487
488 VTK_ASSERT(numberOfCells_ > 0);
489 if (id == "Cells.types") {
490 sec = readDataArray(input, vec_types, numberOfCells_, CELLS_DATA_ARRAY, CELLS);
491 VTK_ASSERT(vec_types.size() == numberOfCells_);
492 } else if (id == "Cells.offsets") {
493 sec = readDataArray(input, vec_offsets, numberOfCells_, CELLS_DATA_ARRAY, CELLS);
494 VTK_ASSERT(vec_offsets.size() == numberOfCells_);
495 } else if (id == "Cells.connectivity") {
496 sec = readDataArray(input, vec_connectivity, std::size_t(-1), CELLS_DATA_ARRAY, CELLS);
497 } else if (id == "Cells.global_point_ids") {
498 sec = readDataArray(input, vec_point_ids, numberOfPoints_, CELLS_DATA_ARRAY, CELLS);
499 VTK_ASSERT(vec_point_ids.size() == numberOfPoints_);
500 }
501
502 return sec;
503 }
504
505
506 template <class Grid, class Creator, class Field>
507 template <class HeaderType>
readCellsAppended(MetaType<HeaderType>,std::ifstream & input)508 void VtkReader<Grid,Creator,Field>::readCellsAppended (MetaType<HeaderType>, std::ifstream& input)
509 {
510 VTK_ASSERT(numberOfCells_ > 0);
511 auto types_data = dataArray_["Cells.types"];
512 auto offsets_data = dataArray_["Cells.offsets"];
513 auto connectivity_data = dataArray_["Cells.connectivity"];
514
515 VTK_ASSERT(types_data.type == Vtk::DataTypes::UINT8);
516 readAppended(input, vec_types, HeaderType(types_data.offset));
517 VTK_ASSERT(vec_types.size() == numberOfCells_);
518
519 if (offsets_data.type == Vtk::DataTypes::INT64)
520 readAppended(input, vec_offsets, HeaderType(offsets_data.offset));
521 else if (offsets_data.type == Vtk::DataTypes::INT32) {
522 std::vector<std::int32_t> offsets;
523 readAppended(input, offsets, HeaderType(offsets_data.offset));
524 vec_offsets.resize(offsets.size());
525 std::copy(offsets.begin(), offsets.end(), vec_offsets.begin());
526 }
527 else { DUNE_THROW(Dune::NotImplemented, "Unsupported DataType in Cell offsets."); }
528 VTK_ASSERT(vec_offsets.size() == numberOfCells_);
529
530 if (connectivity_data.type == Vtk::DataTypes::INT64)
531 readAppended(input, vec_connectivity, HeaderType(connectivity_data.offset));
532 else if (connectivity_data.type == Vtk::DataTypes::INT32) {
533 std::vector<std::int32_t> connectivity;
534 readAppended(input, connectivity, HeaderType(connectivity_data.offset));
535 vec_connectivity.resize(connectivity.size());
536 std::copy(connectivity.begin(), connectivity.end(), vec_connectivity.begin());
537 }
538 else { DUNE_THROW(Dune::NotImplemented, "Unsupported DataType in Cell connectivity."); }
539 VTK_ASSERT(vec_connectivity.size() == std::size_t(vec_offsets.back()));
540
541 if (dataArray_.count("Cells.global_point_ids") > 0) {
542 auto point_id_data = dataArray_["Cells.global_point_ids"];
543 VTK_ASSERT(point_id_data.type == Vtk::DataTypes::UINT64);
544 readAppended(input, vec_point_ids, HeaderType(point_id_data.offset));
545 VTK_ASSERT(vec_point_ids.size() == numberOfPoints_);
546 }
547 }
548
549
550 // @{ implementation detail
551 namespace {
552
553 /**
554 * Read compressed data into `buffer_in`, uncompress it and store the result in
555 * the concrete-data-type `buffer`
556 * \param bs Size of the uncompressed data
557 * \param cbs Size of the compressed data
558 * \param input Stream to read from.
559 **/
560 template <class T, class IStream>
read_compressed_zlib(T * buffer,unsigned char * buffer_in,std::uint64_t bs,std::uint64_t cbs,IStream & input)561 void read_compressed_zlib (T* buffer, unsigned char* buffer_in,
562 std::uint64_t bs, std::uint64_t cbs, IStream& input)
563 {
564 #if HAVE_VTK_ZLIB
565 uLongf uncompressed_space = uLongf(bs);
566 uLongf compressed_space = uLongf(cbs);
567
568 Bytef* compressed_buffer = reinterpret_cast<Bytef*>(buffer_in);
569 Bytef* uncompressed_buffer = reinterpret_cast<Bytef*>(buffer);
570
571 input.read((char*)(compressed_buffer), compressed_space);
572 VTK_ASSERT(uLongf(input.gcount()) == compressed_space);
573
574 if (uncompress(uncompressed_buffer, &uncompressed_space, compressed_buffer, compressed_space) != Z_OK) {
575 std::cerr << "Zlib error while uncompressing data.\n";
576 std::abort();
577 }
578 VTK_ASSERT(uLongf(bs) == uncompressed_space);
579 #else
580 std::cerr << "ZLib Compression not supported. Provide the ZLIB package to CMake." << std::endl;
581 std::abort();
582 #endif
583 }
584
585 template <class T, class IStream>
read_compressed_lz4(T *,unsigned char *,std::uint64_t,std::uint64_t,IStream &)586 void read_compressed_lz4 (T* /* buffer */, unsigned char* /* buffer_in */,
587 std::uint64_t /* bs */, std::uint64_t /* cbs */, IStream& /* input */)
588 {
589 #if HAVE_VTK_LZ4
590 std::cerr << "LZ4 Compression not yet implemented" << std::endl;
591 std::abort();
592 #else
593 std::cerr << "LZ4 Compression not supported. Provide the LZ4 package to CMake." << std::endl;
594 std::abort();
595 #endif
596 }
597
598 template <class T, class IStream>
read_compressed_lzma(T *,unsigned char *,std::uint64_t,std::uint64_t,IStream &)599 void read_compressed_lzma (T* /* buffer */, unsigned char* /* buffer_in */,
600 std::uint64_t /* bs */, std::uint64_t /* cbs */, IStream& /* input */)
601 {
602 #if HAVE_VTK_LZMA
603 std::cerr << "LZMA Compression not yet implemented" << std::endl;
604 std::abort();
605 #else
606 std::cerr << "LZMA Compression not supported. Provide the LZMA package to CMake." << std::endl;
607 std::abort();
608 #endif
609 }
610
611 }
612 // @}
613
614
615 template <class Grid, class Creator, class Field>
616 template <class FloatType, class HeaderType>
readAppended(std::ifstream & input,std::vector<FloatType> & values,HeaderType offset)617 void VtkReader<Grid,Creator,Field>::readAppended (std::ifstream& input, std::vector<FloatType>& values, HeaderType offset)
618 {
619 input.seekg(offset0_ + offset);
620
621 HeaderType size = 0;
622
623 HeaderType num_blocks = 0;
624 HeaderType block_size = 0;
625 HeaderType last_block_size = 0;
626 std::vector<HeaderType> cbs; // compressed block sizes
627
628 // read total size / block-size(s)
629 if (compressor_ != Vtk::CompressorTypes::NONE) {
630 input.read((char*)&num_blocks, sizeof(HeaderType));
631 input.read((char*)&block_size, sizeof(HeaderType));
632 input.read((char*)&last_block_size, sizeof(HeaderType));
633
634 VTK_ASSERT(block_size % sizeof(FloatType) == 0);
635
636 // total size of the uncompressed data
637 size = block_size * (num_blocks-1) + last_block_size;
638
639 // size of the compressed blocks
640 cbs.resize(num_blocks);
641 input.read((char*)cbs.data(), num_blocks*sizeof(HeaderType));
642 } else {
643 input.read((char*)&size, sizeof(HeaderType));
644 }
645 VTK_ASSERT(size > 0 && (size % sizeof(FloatType)) == 0);
646 values.resize(size / sizeof(FloatType));
647
648 if (compressor_ != Vtk::CompressorTypes::NONE) {
649 // upper bound for compressed block-size
650 HeaderType compressed_block_size = block_size + (block_size + 999)/1000 + 12;
651 // number of values in the full blocks
652 std::size_t num_values = block_size / sizeof(FloatType);
653
654 std::vector<unsigned char> buffer_in(compressed_block_size);
655 for (std::size_t i = 0; i < std::size_t(num_blocks); ++i) {
656 HeaderType bs = i < std::size_t(num_blocks-1) ? block_size : last_block_size;
657
658 switch (compressor_) {
659 case Vtk::CompressorTypes::ZLIB:
660 read_compressed_zlib(values.data() + i*num_values, buffer_in.data(), bs, cbs[i], input);
661 break;
662 case Vtk::CompressorTypes::LZ4:
663 read_compressed_lz4(values.data() + i*num_values, buffer_in.data(), bs, cbs[i], input);
664 break;
665 case Vtk::CompressorTypes::LZMA:
666 read_compressed_lzma(values.data() + i*num_values, buffer_in.data(), bs, cbs[i], input);
667 break;
668 default:
669 VTK_ASSERT_MSG(false, "Unsupported Compressor type.");
670 break;
671 }
672 }
673 } else {
674 input.read((char*)(values.data()), size);
675 VTK_ASSERT(input.gcount() == std::streamsize(size));
676 }
677 }
678
679
680 template <class Grid, class Creator, class Field>
fillGridCreator(bool insertPieces)681 void VtkReader<Grid,Creator,Field>::fillGridCreator (bool insertPieces)
682 {
683 VTK_ASSERT(vec_points.size() == numberOfPoints_);
684 VTK_ASSERT(vec_types.size() == numberOfCells_);
685 VTK_ASSERT(vec_offsets.size() == numberOfCells_);
686
687 if (!vec_points.empty())
688 creator_->insertVertices(vec_points, vec_point_ids);
689 if (!vec_types.empty())
690 creator_->insertElements(vec_types, vec_offsets, vec_connectivity);
691 if (insertPieces)
692 creator_->insertPieces(pieces_);
693 }
694
695
696 // Convert section into string
697 template <class Grid, class Creator, class Field>
toString(Sections s) const698 std::string VtkReader<Grid,Creator,Field>::toString(Sections s) const
699 {
700 switch (s) {
701 case VTK_FILE:
702 return "VTKFile";
703 case UNSTRUCTURED_GRID:
704 return "UnstructuredGrid";
705 case PIECE:
706 return "Piece";
707 case POINT_DATA:
708 return "PointData";
709 case CELL_DATA:
710 return "CellData";
711 case POINTS:
712 return "Points";
713 case CELLS:
714 return "Cells";
715 case APPENDED_DATA:
716 return "AppendedData";
717 case PD_DATA_ARRAY:
718 case CD_DATA_ARRAY:
719 case POINTS_DATA_ARRAY:
720 case CELLS_DATA_ARRAY:
721 return "DataArray";
722 default:
723 return "Unknown";
724 }
725 }
726
727
728 // Assume input already read the line <AppendedData ...>
729 template <class Grid, class Creator, class Field>
findAppendedDataPosition(std::ifstream & input) const730 std::uint64_t VtkReader<Grid,Creator,Field>::findAppendedDataPosition (std::ifstream& input) const
731 {
732 char c;
733 while (input.get(c) && std::isblank(c)) { /*do nothing*/ }
734
735 std::uint64_t offset = input.tellg();
736 if (c != '_')
737 --offset; // if char is not '_', assume it is part of the data.
738
739 return offset;
740 }
741
742
743 template <class Grid, class Creator, class Field>
parseXml(std::string const & line,bool & closed)744 std::map<std::string, std::string> VtkReader<Grid,Creator,Field>::parseXml (std::string const& line, bool& closed)
745 {
746 closed = false;
747 std::map<std::string, std::string> attr;
748
749 Sections sec = NO_SECTION;
750 bool escape = false;
751
752 std::string name = "";
753 std::string value = "";
754 for (auto c : line) {
755 switch (sec) {
756 case NO_SECTION:
757 if (std::isalpha(c) || c == '_') {
758 name.clear();
759 sec = XML_NAME;
760 name.push_back(c);
761 } else if (c == '/') {
762 closed = true;
763 }
764 break;
765 case XML_NAME:
766 if (std::isalpha(c) || c == '_')
767 name.push_back(c);
768 else
769 sec = (c == '=' ? XML_NAME_ASSIGN : NO_SECTION);
770 break;
771 case XML_NAME_ASSIGN:
772 value.clear();
773 escape = false;
774 VTK_ASSERT_MSG( c == '"', "Format error!" );
775 sec = XML_VALUE;
776 break;
777 case XML_VALUE:
778 if (c == '"' && !escape) {
779 attr[name] = value;
780 sec = NO_SECTION;
781 } else if (c == '\\' && !escape) {
782 escape = true;
783 } else {
784 value.push_back(c);
785 escape = false;
786 }
787 break;
788 default:
789 VTK_ASSERT_MSG(false, "Format error!");
790 }
791 }
792
793 return attr;
794 }
795
796
797 template <class Grid, class Creator, class Field>
clear()798 void VtkReader<Grid,Creator,Field>::clear ()
799 {
800 vec_points.clear();
801 vec_point_ids.clear();
802 vec_types.clear();
803 vec_offsets.clear();
804 vec_connectivity.clear();
805 dataArray_.clear();
806 pieces_.clear();
807
808 numberOfCells_ = 0;
809 numberOfPoints_ = 0;
810 offset0_ = 0;
811 read_ = false;
812 }
813
814 } // end namespace Dune
815