dune-vtk  0.2
vtkreader.impl.hh
Go to the documentation of this file.
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>
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>
43 void VtkReader<Grid,Creator,Field>::readSerialFileFromStream (std::ifstream& input, bool fillCreator)
44 {
45  clear();
46  compressor_ = Vtk::CompressorTypes::NONE;
48  std::string data_id = "";
49  std::string data_format = "";
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") {
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>
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
315 template <class IStream, class T, class Sections>
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>
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
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>
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
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>
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
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>
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
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>
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::INT64)
520  readAppended(input, vec_offsets, HeaderType(offsets_data.offset));
521  else if (offsets_data.type == Vtk::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::INT64)
531  readAppended(input, vec_connectivity, HeaderType(connectivity_data.offset));
532  else if (connectivity_data.type == Vtk::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 
560 template <class T, class IStream>
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>
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>
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>
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_) {
660  read_compressed_zlib(values.data() + i*num_values, buffer_in.data(), bs, cbs[i], input);
661  break;
663  read_compressed_lz4(values.data() + i*num_values, buffer_in.data(), bs, cbs[i], input);
664  break;
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>
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>
698 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>
730 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>
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>
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
Macro for wrapping error checks and throwing exceptions.
#define VTK_ASSERT_MSG(cond, text)
check if condition cond holds; otherwise, throw a VtkError with a message.
Definition: errors.hh:19
#define VTK_ASSERT(cond)
check if condition cond holds; otherwise, throw a VtkError.
Definition: errors.hh:29
Definition: datacollectorinterface.hh:9
Sections skipRestOfDataArray(IStream &input, Sections section, Sections parent_section)
Definition: vtkreader.impl.hh:342
Sections readDataArray(IStream &input, std::vector< T > &values, std::size_t max_size, Sections section, Sections parent_section)
Definition: vtkreader.impl.hh:316
Vtk::DataTypes dataTypeOf(Dune::VTK::Precision p)
Definition: types.cc:98
@ BINARY
Definition: types.hh:23
@ COMPRESSED
Definition: types.hh:24
@ ASCII
Definition: types.hh:22
@ NONE
Definition: types.hh:140
@ ZLIB
Definition: types.hh:141
@ LZ4
Definition: types.hh:142
@ LZMA
Definition: types.hh:143
std::string & trim(std::string &str)
trim a string from both sides
Definition: string.hh:52
std::string to_lower(std::string input)
convert all characters in a string to upper case
Definition: string.hh:22
std::string & ltrim(std::string &str)
trim a string from the left
Definition: string.hh:30
DataTypes
Definition: types.hh:50
@ UINT64
Definition: types.hh:55
@ UINT8
Definition: types.hh:52
@ INT32
Definition: types.hh:54
@ INT64
Definition: types.hh:55
@ UINT32
Definition: types.hh:54
@ UNKNOWN
Definition: types.hh:51
bool exists(Path const &p)
Test whether the path is a valid (existing and accessible) file / directory.
Definition: filesystem.cc:134
Definition: errors.hh:12
Definition: filesystem.hh:15
Path extension() const
Returns the file extension path component.
Definition: filesystem.cc:77
std::string string() const
Return the path as string.
Definition: filesystem.cc:27
File-Reader for Vtk unstructured .vtu files.
Definition: vtkreader.hh:37
void read(std::string const &filename, bool fillCreator=true)
Read the grid from file with filename into the GridCreator.
Definition: vtkreader.impl.hh:20
void readParallelFileFromStream(std::ifstream &input, int rank, int size, bool create=true)
Read the grid from and input stream, referring to a .pvtu file, into the GridFactory factory_.
Definition: vtkreader.impl.hh:249
void fillGridCreator(bool insertPieces=true)
Definition: vtkreader.impl.hh:681
void readSerialFileFromStream(std::ifstream &input, bool create=true)
Read the grid from an input stream, referring to a .vtu file, into the GridFactory factory_.
Definition: vtkreader.impl.hh:43