KASKADE 7 development version
vtkreader.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2014-2021 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef VTKREADER_HH
14#define VTKREADER_HH
15
16
17#include <vector>
18#include <map>
19#include <string>
20#include <memory>
21#include <iostream>
22#include <algorithm>
23#include <sstream>
24#include <cassert>
25
26#include <boost/fusion/container/vector.hpp>
27#include <boost/fusion/include/zip_view.hpp>
28
29#include <dune/grid/config.h>
30#include <dune/grid/common/gridfactory.hh>
31
32#include <fem/functionspace.hh>
33#include <fem/lagrangespace.hh>
35
36namespace Kaskade
37{
39 namespace VTKReaderDetail
40 {
41 enum CoefficientDataType
42 {
43 pointData,
44 cellData
45 };
46
47 struct CoefficientData
48 {
49 CoefficientDataType type;
50 std::size_t numComponents = 0;
51 std::vector<double> data;
52 };
53
54 struct VTKData
55 {
56 bool reverseByteOrder = false; // if loading binary
57 std::string headerType = "UInt32"; // data type for binary data size header
58 std::string compressor; // compression method for binary data (not yet supported)
59 std::string filename;
60 std::size_t dimVertex = 0, numPoints = 0, numCells = 0;
61 std::vector<double> coordinates;
62 std::vector<std::size_t> connectivity, offsets, types;
63 std::map<std::string, CoefficientData> coefficientData; // this includes PointData and CellData
64 };
65
66 struct VTKCell
67 {
68 int vtkGeomType;
69 std::vector<std::size_t> corners, edges;
70 };
71
72 } // namespace VTKReaderDetail
74
94 {
95 public:
99 enum Flags
100 {
105
107 };
108
113 {
114 bool dataProvided = false;
115 bool continuous = false;
116 int order = 0;
118 };
119
123 VTKReader() = default;
124
129 VTKReader(std::string const& filename);
130
135 void load(std::string const& filename);
136
142 void loadOnlyData(std::string const& filename);
143
152 template<class Grid>
153 std::unique_ptr<Grid> createGrid();
154
155 template<class Grid, class Deformation>
156 std::unique_ptr<Grid> createGrid(Deformation const& deformation);
157
174 template<class VariableSet>
175 void getCoefficients(VariableSet& varSet, int interpolationFlags = noInterpolation) const;
176
181 template<class FSE>
182 void getCoefficients(std::string const& functionName, FSE& fse, int interpolationFlags = noInterpolation) const;
183
192 std::vector<std::string> functionNames() const;
193
200 FunctionInfo getFunctionInfo(std::string const& functionName) const;
201
206 private:
207
208 enum LoadOption
209 {
210 loadOptionEverything,
211 loadOptionOnlyData
212 };
213
214 enum CoefficientMapping
215 {
216 continuous,
217 discontinuous
218 };
219
220 template<class VariableSet, class FSEVarDescPair>
221 void copyCoefficientsByName(VariableSet const& varSet, FSEVarDescPair& pair, int interpolationFlags) const;
222
223 template<class FSE>
224 void copyCoefficients(std::string const& functionName, VTKReaderDetail::CoefficientData const& coefficientData, FSE& fse, int interpolationFlags) const;
225
226 template<class FSE>
227 void copyCoefficientsInterpolated(std::string const& functionName,
228 VTKReaderDetail::CoefficientData const& coefficientData,
229 FSE& fse) const;
230
231 template<class FSE>
232 void copyCoefficientsDirectly(std::string const& functionName,
233 VTKReaderDetail::CoefficientData const& coefficientData,
234 FSE& fse) const;
235
236 void loadVTKInternal(std::string const& filename, LoadOption option);
237 void prepareGridCreation(std::vector<VTKReaderDetail::VTKCell>& vtkCells, std::vector<char>& isCorner);
238 void reset();
239 void clearCoefficientData();
240
241
242 VTKReaderDetail::VTKData vtk; // stores global information about the VTK file
243
244 bool gridWasLoaded = false,
245 gridWasCreated = false;
246
247 // coefficientMapping and polynomialOrder refer only to PointData. CellData is handled separately.
248 CoefficientMapping coefficientMapping = continuous;
249 int polynomialOrder = 0;
250
251 // index mapping: for a coefficient-index i, dataIndices[i] is the corresponding vtk-index
252 std::vector<std::size_t> pointDataIndices, cellDataIndices;
253 };
254
255
256 std::ostream& operator<<(std::ostream& stream, VTKReader::FunctionInfo const& info);
257
258 // ----------------------------------------------------------------------------------------------
259 // ----------------------------------------------------------------------------------------------
260
262 namespace VTKReaderDetail
263 {
264 // used to find duplicate points
265 struct IndexedPoint
266 {
267 std::size_t vtkIdx = 0, numComponents = 0;
268 std::vector<double>::const_iterator coordinates;
269
270 bool operator<(IndexedPoint const& other) const;
271 bool operator==(IndexedPoint const& other) const; // for std::adjacent_find
272 };
273
274 // used to keep track of indices during grid creation
275 template<class Grid>
276 class VTKFactoryHelper
277 {
278 public:
279 template<class Deformation> void insertVertices(std::vector<char> const& isCorner, VTKData const& vtk, Deformation const& deformation);
280 void insertVertices(std::vector<char> const& isCorner, VTKData const& vtk);
281 void insertCells(std::vector<VTKCell> const& vtkCells);
282 std::unique_ptr<Grid> createGrid();
283 void setIndicesForDuplicatePoints(std::vector<IndexedPoint> const& indexedPoints, std::vector<std::size_t> const& vertexVTKToMerged);
284 void getDataIndicesContinuous(typename Grid::LeafGridView const& leafView, std::vector<VTKCell> const& vtkCells, std::vector<std::size_t>& dataIndicesOut) const;
285 void getDataIndicesDiscontinuous(typename Grid::LeafGridView const& leafView, std::vector<VTKCell> const& vtkCells, std::vector<std::size_t>& dataIndicesOut) const;
286 void getCellDataIndices(typename Grid::LeafGridView const& leafView, std::vector<std::size_t>& dataIndicesOut) const;
287
288 private:
289
290 template<class ElementEntity>
291 void getIndicesLocalToVTK(VTKCell const& vtkCell, ElementEntity const& element, std::vector<std::size_t>& vertexLocalToVTK, std::vector<std::size_t>& edgeLocalToVTK) const;
292
293 Dune::GridFactory<Grid> factory;
294 std::vector<std::size_t> vertexVTKToInsertion, vertexInsertionToVTK;
295 std::size_t totalCorners = 0, totalEdges = 0;
296 };
297
298 std::string formatWarning(std::string const& filename, std::string const& message);
299
300 Dune::GeometryType getDuneGeomType(int vtkGeomType);
301 std::size_t getDuneCorner(int vtkGeomType, std::size_t corner);
302 void countCornersAndEdges(int vtkGeomType, std::size_t& numCorners, std::size_t& numEdges);
303 int countCellDim(int vtkGeomType);
304 // compare index-pairs as sets
305 struct CompareTwoSet
306 {
307 bool operator()(std::pair<std::size_t, std::size_t> const& p1, std::pair<std::size_t, std::size_t> const& p2) const;
308 };
309 using EdgeTable = std::map<std::pair<std::size_t, std::size_t>, std::size_t, CompareTwoSet>;
310
311 std::size_t findEdgeIndex(EdgeTable const& edgeTable, std::size_t a, std::size_t b);
312 std::pair<std::size_t, std::size_t> getVTKLocalCorners(int vtkGeomType, std::size_t edge);
313 std::vector<std::size_t> getIndicesPerCell(std::vector<std::size_t> const& corners, std::vector<std::size_t> const& edges, int vtkGeomType);
314
315 template<class ElementEntity, class IndexSet>
316 EdgeTable createEdgeTable(ElementEntity const& element, IndexSet const& indexSet, std::vector<std::size_t> const& vertexGridToVTK)
317 {
318 // for an element, create a map {c0, c1} -> e.
319 // {c0, c1} and e define the same edge. {c0, c1} are the vtk-indices of its corners and e is the grid-index of the edge-entity.
320
321 constexpr int dim = IndexSet::dimension;
322 constexpr int codimEdge = dim - 1, codimVertex = dim;
323 EdgeTable edgeTable;
324 auto refElement = Dune::ReferenceElements<double, dim>::general(element.type());
325
326 unsigned numEdges = refElement.size(codimEdge);
327 for(unsigned i = 0; i < numEdges; ++i)
328 {
329 // get local corner indices for local edge i
330 std::size_t c0 = refElement.subEntity(i, codimEdge, 0, codimVertex);
331 std::size_t c1 = refElement.subEntity(i, codimEdge, 1, codimVertex);
332
333 // transform {c0, c1} and i to grid
334 c0 = indexSet.subIndex(element, c0, codimVertex);
335 c1 = indexSet.subIndex(element, c1, codimVertex);
336 std::size_t e = indexSet.subIndex(element, i, codimEdge);
337
338 // transform {c0, c1} to vtk
339 c0 = vertexGridToVTK[c0];
340 c1 = vertexGridToVTK[c1];
341
342 // insert into edgeTable
343 edgeTable[std::make_pair(c0, c1)] = e;
344 }
345 return edgeTable;
346 }
347
348 // match FSEs with their names
349 template<class DataSequence, class VariableDescriptionSequence>
350 boost::fusion::zip_view<boost::fusion::vector<DataSequence&, VariableDescriptionSequence const&>>
351 makeZipView(DataSequence& data, VariableDescriptionSequence const& descriptions)
352 {
353 using Sequences = boost::fusion::vector<DataSequence&, VariableDescriptionSequence const&>;
354 return boost::fusion::zip_view<Sequences>(Sequences(data, descriptions));
355 }
356
357 // VTKFactoryHelper
358
359 template<class Grid>
360 template<class Deformation>
361 void VTKFactoryHelper<Grid>::insertVertices(std::vector<char> const& isCorner, VTKData const& vtk, Deformation const& deformation)
362 {
363 // Insert vertices from VTK's coordinate vector into grid and keep track of indices.
364 // If too many or too few coordinates are provided, excess values are ignored or set to 0 respectively.
365 constexpr int dim = Grid::dimension;
366 using Vertex = Dune::FieldVector<double, dim>;
367 std::size_t numComponentsToRead = std::min((std::size_t)dim, vtk.dimVertex);
368 vertexVTKToInsertion.resize(vtk.numPoints, 0);
369 std::size_t countInsertion = 0;
370
371 for(std::size_t i = 0; i < vtk.numPoints; ++i)
372 {
373 // only insert marked corners
374 if(isCorner[i])
375 {
376 std::size_t offs = i * vtk.dimVertex;
377 Vertex vertex(0);
378 auto it = vtk.coordinates.begin() + offs;
379 std::copy(it, it + numComponentsToRead, vertex.begin());
380 factory.insertVertex(deformation(vertex));
381
382 vertexInsertionToVTK.push_back(i);
383 vertexVTKToInsertion[i] = countInsertion;
384 ++countInsertion;
385 }
386 }
387 totalCorners = countInsertion;
388 // totalEdges is used only for continuous coefficient mapping
389 // otherwise the number is wrong due to duplicate points
390 totalEdges = vtk.numPoints - totalCorners;
391 }
392
393 template<class Grid>
394 void VTKFactoryHelper<Grid>::insertVertices(std::vector<char> const& isCorner, VTKData const& vtk)
395 {
396 auto identity = [] (auto x) {return x;};
397 insertVertices(isCorner, vtk, identity);
398 }
399
400 template<class Grid>
401 void VTKFactoryHelper<Grid>::insertCells(std::vector<VTKCell> const& vtkCells)
402 {
403 int dim = Grid::dimension;
404 // insert cells using the insertion-indices of their corners
405 for(VTKCell const& vtkCell : vtkCells)
406 {
407 int geoType = vtkCell.vtkGeomType;
408 int cellDim = countCellDim(geoType);
409
410 if(dim !=cellDim){
411 continue;
412 }
413
414 std::vector<unsigned int> corners(vtkCell.corners.size());
415 for(std::size_t k = 0; k < corners.size(); ++k)
416 {
417 std::size_t corner = getDuneCorner(vtkCell.vtkGeomType, k);
418 std::size_t vtkCornerIdx = vtkCell.corners[corner];
419 corners[k] = (unsigned int) vertexVTKToInsertion[vtkCornerIdx];
420 }
421 factory.insertElement(getDuneGeomType(vtkCell.vtkGeomType), corners);
422 }
423 }
424
425 template<class Grid>
426 std::unique_ptr<Grid> VTKFactoryHelper<Grid>::createGrid()
427 {
428 return std::unique_ptr<Grid>(factory.createGrid());
429 }
430
431 template<class Grid>
432 void VTKFactoryHelper<Grid>::setIndicesForDuplicatePoints(std::vector<IndexedPoint> const& indexedPoints, std::vector<std::size_t> const& vertexVTKToMerged)
433 {
434 // duplicate points get the insertion index of their representative
435 for(IndexedPoint const& p : indexedPoints)
436 {
437 std::size_t mergedIdx = vertexVTKToMerged[p.vtkIdx];
438 std::size_t insertionIdx = vertexVTKToInsertion[mergedIdx];
439 vertexVTKToInsertion[p.vtkIdx] = insertionIdx;
440 }
441 }
442
443 template<class Grid>
444 void VTKFactoryHelper<Grid>::getDataIndicesContinuous(typename Grid::LeafGridView const& leafView, std::vector<VTKCell> const& vtkCells, std::vector<std::size_t>& dataIndicesOut) const
445 {
446 std::vector<std::size_t> vertexGridToVTK(totalCorners), edgeGridToVTK(totalEdges);
447
448 // vertices
449 auto const& indexSet = leafView.indexSet();
450 for(auto const& vertexEntity : vertices(leafView))
451 {
452 std::size_t insertionIdx = factory.insertionIndex(vertexEntity);
453 std::size_t gridIdx = indexSet.index(vertexEntity);
454
455 if(insertionIdx >= vertexInsertionToVTK.size() || gridIdx >= vertexGridToVTK.size())
456 {
457 // Grid returned invalid index?
458 throw Kaskade::GridException("Vertex index is out of bounds.", __FILE__, __LINE__);
459 }
460
461 std::size_t vtkIdx = vertexInsertionToVTK[insertionIdx];
462 vertexGridToVTK[gridIdx] = vtkIdx;
463 }
464
465 // edges
466 for(auto const& elementEntity : elements(leafView))
467 {
468 // get the vtk-definition used to create this cell
469 std::size_t insertionIdx = factory.insertionIndex(elementEntity);
470 // out of bounds check
471 if(insertionIdx >= vtkCells.size())
472 {
473 // Grid returned invalid index?
474 throw Kaskade::GridException("Cell insertion index is out of bounds.", __FILE__, __LINE__);
475 }
476
477 VTKCell const& vtkCell = vtkCells[insertionIdx];
478
479 // the EdgeTable for this cell maps {c0, c1} -> e,
480 // where c0, c1 are the vtk-indices of two of its corners and e is the grid-index of the edge between c0 and c1
481 EdgeTable edgeTable = createEdgeTable(elementEntity, indexSet, vertexGridToVTK);
482 for(std::size_t i = 0; i < vtkCell.edges.size(); ++i)
483 {
484 // get the vtk-index of an edge
485 std::size_t vtkIdx = vtkCell.edges[i];
486
487 // get vtk's local indices of the corresponding corners
488 std::pair<int, int> vtkLocalCorners = getVTKLocalCorners(vtkCell.vtkGeomType, i);
489
490 // use the local indices to look up the vtk-indices of these corners
491 // finally find the grid-index of the edge via the EdgeTable
492 std::size_t gridIdx = findEdgeIndex(edgeTable, vtkCell.corners[vtkLocalCorners.first], vtkCell.corners[vtkLocalCorners.second]);
493
494 if(gridIdx >= edgeGridToVTK.size())
495 {
496 // Grid returned invalid index?
497 throw Kaskade::GridException("Edge index is out of bounds.", __FILE__, __LINE__);
498 }
499 edgeGridToVTK[gridIdx]= vtkIdx;
500 }
501 }
502
503 dataIndicesOut.resize(totalCorners + totalEdges);
504 std::copy(edgeGridToVTK.begin(), edgeGridToVTK.end(), dataIndicesOut.begin());
505 std::copy(vertexGridToVTK.begin(), vertexGridToVTK.end(), dataIndicesOut.begin() + totalEdges);
506 }
507
508 template<class Grid>
509 void VTKFactoryHelper<Grid>::getDataIndicesDiscontinuous(typename Grid::LeafGridView const& leafView, std::vector<VTKCell> const& vtkCells, std::vector<std::size_t>& dataIndicesOut) const
510 {
511 // per cell indices are first stored as blocks
512 std::vector<std::vector<std::size_t>> dataIndicesPerCell(vtkCells.size());
513
514 for(auto const& elementEntity : elements(leafView))
515 {
516 // get the corresponding vtk-cell
517 std::size_t insertionIdx = factory.insertionIndex(elementEntity);
518 if(insertionIdx >= vtkCells.size())
519 {
520 // Grid returned invalid index?
521 throw Kaskade::GridException("Cell insertion index is out of bounds.", __FILE__, __LINE__);
522 }
523 VTKCell const& vtkCell = vtkCells[insertionIdx];
524
525 // get the data-indices for this cell in Kaskade discontinuous order
526 std::vector<std::size_t> vertexLocalToVTK, edgeLocalToVTK;
527 getIndicesLocalToVTK(vtkCell, elementEntity, vertexLocalToVTK, edgeLocalToVTK);
528 std::vector<std::size_t> cellIndices = getIndicesPerCell(vertexLocalToVTK, edgeLocalToVTK, vtkCell.vtkGeomType);
529
530 // insert in the right place
531 std::size_t gridIdx = leafView.indexSet().index(elementEntity);
532 // out of bounds check
533 if(gridIdx >= dataIndicesPerCell.size())
534 {
535 // Grid returned invalid index?
536 throw Kaskade::GridException("Cell index is out of bounds.", __FILE__, __LINE__);
537 }
538 dataIndicesPerCell[gridIdx] = cellIndices;
539 }
540
541 // make a sequence out of the blocks
542 for(std::vector<std::size_t> const& cellIndices : dataIndicesPerCell)
543 {
544 for(std::size_t idx : cellIndices)
545 {
546 dataIndicesOut.push_back(idx);
547 }
548 }
549 }
550
551 template<class Grid>
552 void VTKFactoryHelper<Grid>::getCellDataIndices(typename Grid::LeafGridView const& leafView, std::vector<std::size_t>& dataIndicesOut) const
553 {
554 std::size_t numCells = leafView.size(0);
555 dataIndicesOut.resize(numCells);
556
557 for(auto const& elementEntity : elements(leafView))
558 {
559 // cells were inserted in vtk order, so vtk-index == insertion-index
560 std::size_t vtkIdx = factory.insertionIndex(elementEntity);
561 std::size_t gridIdx = leafView.indexSet().index(elementEntity);
562 if(gridIdx >= dataIndicesOut.size())
563 {
564 // Grid returned invalid index?
565 throw Kaskade::GridException("Cell index is out of bounds.", __FILE__, __LINE__);
566 }
567 dataIndicesOut[gridIdx] = vtkIdx;
568 }
569 }
570
571 template<class Grid>
572 template<class ElementEntity>
573 void VTKFactoryHelper<Grid>::getIndicesLocalToVTK(VTKCell const& vtkCell, ElementEntity const& element, std::vector<std::size_t>& vertexLocalToVTK, std::vector<std::size_t>& edgeLocalToVTK) const
574 {
575 // this function takes one grid-element and maps its local indices (corners and edges) to the right vtk data indices
576 // edges are identified via the insertion-indices of their corners
577 // vtkCell and element must define the same cell for this to work
578
579 using IndexPair = std::pair<std::size_t, std::size_t>;
580
581 // abusing std::map, the desired mapping will be in the values
582 std::map<std::size_t, IndexPair> cornerLookup; // c(ins) ---> (c(grid_local), c(vtk-data))
583 std::map<IndexPair, IndexPair, CompareTwoSet> edgeLookup; // {a, b}(ins) ---> (e(grid_local), e(vtk-data))
584
585 std::size_t numCorners = vtkCell.corners.size(), numEdges = vtkCell.edges.size();
586 constexpr int dim = Grid::dimension;
587 constexpr int codimVertex = dim, codimEdge = dim - 1;
588
589 assert(element.subEntities(codimVertex) == numCorners);
590 assert(numEdges == 0 || element.subEntities(codimEdge) == numEdges);
591
592 // corners
593 std::vector<std::size_t> vertexLocalToInsertion(numCorners);
594
595 for(std::size_t i = 0; i < numCorners; ++i)
596 {
597 // grid
598 auto vertexEntity = element.template subEntity<codimVertex>(i);
599 std::size_t insertionIndex = factory.insertionIndex(vertexEntity);
600 cornerLookup[insertionIndex].first = i;
601 vertexLocalToInsertion[i] = insertionIndex;
602
603 // vtk
604 std::size_t vtkIndex = vtkCell.corners[i];
605 insertionIndex = vertexVTKToInsertion[vtkIndex];
606 cornerLookup[insertionIndex].second = vtkIndex;
607 }
608
609 // edges
610 auto refElement = Dune::ReferenceElements<double, dim>::general(element.type());
611
612 for(std::size_t i = 0; i < numEdges; ++i)
613 {
614 // grid
615 std::size_t c0 = refElement.subEntity(i, codimEdge, 0, codimVertex); // local
616 std::size_t c1 = refElement.subEntity(i, codimEdge, 1, codimVertex); // local
617 c0 = vertexLocalToInsertion[c0]; // insertion
618 c1 = vertexLocalToInsertion[c1]; // insertion
619 edgeLookup[std::make_pair(c0, c1)].first = i; // local
620
621 // vtk
622 IndexPair p = getVTKLocalCorners(vtkCell.vtkGeomType, i); // local
623 c0 = vtkCell.corners[p.first]; // vtk
624 c1 = vtkCell.corners[p.second]; // vtk
625 c0 = vertexVTKToInsertion[c0]; // insertion
626 c1 = vertexVTKToInsertion[c1]; // insertion
627 std::size_t edgeDataIdx = vtkCell.edges[i]; // vtk
628 edgeLookup[std::make_pair(c0, c1)].second = edgeDataIdx;
629 }
630
631 assert(cornerLookup.size() == numCorners);
632 assert(edgeLookup.size() == numEdges);
633
634 // fill vectors to return
635 vertexLocalToVTK.resize(numCorners);
636
637 for(auto const& p : cornerLookup)
638 {
639 IndexPair const& ip = p.second;
640 vertexLocalToVTK[ip.first] = ip.second;
641 }
642
643 edgeLocalToVTK.resize(numEdges);
644
645 for(auto const& p : edgeLookup)
646 {
647 IndexPair const& ip = p.second;
648 edgeLocalToVTK[ip.first] = ip.second;
649 }
650 }
651
652 } // namespace VTKReaderDetail
654
655 // VTKReader
656
657
658 template<class Grid>
659 std::unique_ptr<Grid> VTKReader::createGrid()
660 {
661 // identity means grid vertices are not transformed
662 auto identity = [] (auto x) {return x;};
663 return createGrid<Grid>(identity);
664 }
665
666 template<class Grid, class Deformation>
667 std::unique_ptr<Grid> VTKReader::createGrid(Deformation const& deformation)
668 {
669 using namespace VTKReaderDetail;
670
671 if(!gridWasLoaded)
672 {
673 throw Kaskade::FileIOException("No grid data has been loaded.", vtk.filename, __FILE__, __LINE__);
674 }
675
676 std::vector<char> isCorner(vtk.numPoints, 0);
677 std::vector<VTKCell> vtkCells(vtk.numCells);
678
679 // reset indices, group cells, mark corners, set polynomialOrder
680 prepareGridCreation(vtkCells, isCorner);
681
682 std::vector<IndexedPoint> indexedPoints;
683 std::vector<std::size_t> vertexVTKToMerged;
684
685 // collect non-edge points
686 for(std::size_t i = 0; i < vtk.numPoints; ++i)
687 {
688 if(isCorner[i])
689 {
690 std::size_t offs = i * vtk.dimVertex;
691 IndexedPoint p;
692 p.vtkIdx = i;
693 p.numComponents = vtk.dimVertex;
694 p.coordinates = vtk.coordinates.begin() + offs;
695 indexedPoints.push_back(p);
696 }
697 }
698
699 std::sort(indexedPoints.begin(), indexedPoints.end());
700
701 // detect duplicates and set coefficientMapping.
702 // coefficientMapping is set to discontinuous if there is at least one duplicate point.
703 bool hasDuplicatePoints = std::adjacent_find(indexedPoints.begin(), indexedPoints.end()) != indexedPoints.end();
704 coefficientMapping = hasDuplicatePoints? discontinuous : continuous;
705
706 if(hasDuplicatePoints)
707 {
708 // The isCorner vector will be used to prevent insertion of duplicate points.
709 vertexVTKToMerged.resize(vtk.numPoints, 0);
710 // unmark all corners
711 std::fill(isCorner.begin(), isCorner.end(), 0);
712
713 auto P = indexedPoints.begin();
714 while(P != indexedPoints.end())
715 {
716 // mark P as corner
717 isCorner[P->vtkIdx] = 1;
718 // map duplicates' vtk-indices to P's vtk-index
719 std::size_t currentRepresentativeIdx = P->vtkIdx;
720 auto range = std::equal_range(P, indexedPoints.end(), *P);
721 for(auto it = range.first; it != range.second; ++it)
722 {
723 vertexVTKToMerged[it->vtkIdx] = currentRepresentativeIdx;
724 }
725 P = range.second;
726 }
727 }
728
729 VTKFactoryHelper<Grid> factoryHelper;
730 std::unique_ptr<Grid> grid;
731
732 // create the grid
733 try
734 {
735 factoryHelper.insertVertices(isCorner, vtk, deformation);
736
737 // If points have been merged, map vtk-indices of duplicate points to the same insertion index.
738 if (coefficientMapping == discontinuous)
739 {
740 factoryHelper.setIndicesForDuplicatePoints(indexedPoints, vertexVTKToMerged);
741 }
742
743 factoryHelper.insertCells(vtkCells);
744 grid = factoryHelper.createGrid();
745 }
746 catch(Dune::GridError const& e)
747 {
748 throw Kaskade::FileIOException(e.what(), vtk.filename, __FILE__, __LINE__);
749 }
750
751 // Get the indices. We always obtain index-mappings for PointData and CellData.
752 auto leafView = grid->leafGridView();
753
754 if (coefficientMapping == continuous)
755 {
756 factoryHelper.getDataIndicesContinuous(leafView, vtkCells, pointDataIndices);
757 }
758 else // discontinuous
759 {
760 factoryHelper.getDataIndicesDiscontinuous(leafView, vtkCells, pointDataIndices);
761 }
762
763 factoryHelper.getCellDataIndices(leafView, cellDataIndices);
764
765 gridWasCreated = true;
766 return grid;
767 }
768
769 template<class VariableSet>
770 void VTKReader::getCoefficients(VariableSet& varSet, int interpolationFlags) const
771 {
772 using namespace VTKReaderDetail;
773
774 if (!gridWasCreated)
775 {
776 throw Kaskade::FileIOException("Grid must be created before accessing data.", vtk.filename, __FILE__, __LINE__);
777 }
778
779 // Loop through FSEs and their descriptions simultaneously to match input data by name.
780 auto functions = makeZipView(varSet.data, typename VariableSet::Descriptions::Variables());
781 boost::fusion::for_each(functions, [&](auto const& f){this->copyCoefficientsByName(varSet, f, interpolationFlags);});
782 }
783
784 template<class FSE>
785 void VTKReader::getCoefficients(std::string const& functionName, FSE& fse, int interpolationFlags) const
786 {
787 using namespace VTKReaderDetail;
788
789 if(!gridWasCreated)
790 {
791 throw Kaskade::FileIOException("Grid must be created before accessing data.", vtk.filename, __FILE__, __LINE__);
792 }
793
794 auto it = vtk.coefficientData.find(functionName);
795 if(it != vtk.coefficientData.end())
796 copyCoefficients(functionName, it->second, fse, interpolationFlags);
797 else
798 {
799 // warning
800 std::ostringstream out;
801 out << "No coefficient data provided for " << functionName << ".";
802 std::cout << formatWarning(vtk.filename, out.str()) << std::endl;
803 }
804 }
805
806 template<class VariableSet, class FSEVarDescPair>
807 void VTKReader::copyCoefficientsByName(VariableSet const& varSet, FSEVarDescPair& pair, int interpolationFlags) const
808 {
809 using namespace boost::fusion;
810 using namespace VTKReaderDetail;
811
812 auto& fse = at_c<0>(pair);
813 auto const& desc = at_c<1>(pair);
814 std::string functionName = varSet.descriptions.names[desc.id];
815
816 // find data-values associated with fse's name
817 auto it = vtk.coefficientData.find(functionName);
818 if(it != vtk.coefficientData.end())
819 {
820 copyCoefficients(functionName, it->second, fse, interpolationFlags);
821 }
822 else
823 {
824 // warning
825 std::ostringstream out;
826 out << "No data provided for " << functionName << ".";
827 std::cout << formatWarning(vtk.filename, out.str()) << std::endl;
828 }
829 }
830
831 template<class FSE>
832 void VTKReader::copyCoefficients(std::string const& functionName,
833 VTKReaderDetail::CoefficientData const& coefficientData,
834 FSE& fse,
835 int interpolationFlags) const
836 {
837 using namespace VTKReaderDetail;
838
839 constexpr int fseCoefficientDim = FSE::StorageValueType::dimension;
840 int fseMaxOrder = fse.space().mapper().maxOrder(), fseContinuity = FSE::Space::continuity;
841
842 bool interpolationNeeded = false;
843
844 if ((std::size_t)fseCoefficientDim != coefficientData.numComponents)
845 {
846 if((interpolationFlags & allowCoefficientDimensionMismatch) == 0)
847 {
848 std::ostringstream out;
849 out << "\"" << functionName << "\": Coefficient dimension mismatch.\nfunction info: "
850 << getFunctionInfo(functionName);
851 throw Kaskade::FileIOException(out.str(), vtk.filename, __FILE__, __LINE__);
852 }
853 }
854
855 // order is always 0 for CellData
856 int order = coefficientData.type==cellData? 0: polynomialOrder;
857
858 if (fseMaxOrder != order)
859 {
860 if (interpolationFlags & allowOrderMismatch)
861 interpolationNeeded = true;
862 else
863 {
864 std::ostringstream out;
865 out << "\"" << functionName << "\": Order mismatch.\nfunction info: "
866 << getFunctionInfo(functionName);
867 throw Kaskade::FileIOException(out.str(), vtk.filename, __FILE__, __LINE__);
868 }
869 }
870
871 // continuity is always discontinuous for CellData
872 CoefficientMapping continuity = coefficientData.type==cellData? discontinuous: coefficientMapping;
873
874 if ( (fseContinuity < 0 && continuity == continuous)
875 || (fseContinuity >= 0 && continuity == discontinuous))
876 {
877 if (interpolationFlags & allowContinuityMismatch)
878 interpolationNeeded = true;
879 else
880 {
881 std::ostringstream out;
882 out << "\"" << functionName << "\": Continuity mismatch.\nfunction info: "
883 << getFunctionInfo(functionName);
884 throw Kaskade::FileIOException(out.str(), vtk.filename, __FILE__, __LINE__);
885 }
886 }
887
888 if (interpolationNeeded)
889 copyCoefficientsInterpolated(functionName, coefficientData, fse);
890 else
891 copyCoefficientsDirectly(functionName, coefficientData, fse);
892 }
893
894 template<class FSE>
895 void VTKReader::copyCoefficientsInterpolated(std::string const& functionName,
896 VTKReaderDetail::CoefficientData const& coefficientData,
897 FSE& fse) const
898 {
899 using namespace Kaskade;
900 using namespace VTKReaderDetail;
901
902 using Mapper = typename FSE::Space::Mapper;
903 using Scalar = typename FSE::Space::Scalar;
904 using LeafView = typename Mapper::Grid::LeafGridView;
905 constexpr int fseCoefficientDim = FSE::StorageValueType::dimension;
906
907 // If interpolation is necessary, we create a function space matching the
908 // data format, load the data into such a function, and then use the
909 // FE function interpolated assignment functionality.
910
911 if (coefficientData.type == pointData)
912 {
913 if (coefficientMapping == continuous)
914 {
916
917 Space space(fse.space().gridManager(), fse.space().grid().leafGridView(), polynomialOrder);
918 auto otherFSE = space.template element<fseCoefficientDim>();
919 copyCoefficientsDirectly(functionName, coefficientData, otherFSE);
920 fse = otherFSE;
921 }
922 else // discontinuous
923 {
925
926 Space space(fse.space().gridManager(), fse.space().grid().leafGridView(), polynomialOrder);
927 auto otherFSE = space.template element<fseCoefficientDim>();
928 copyCoefficientsDirectly(functionName, coefficientData, otherFSE);
929 fse = otherFSE;
930 }
931 }
932 else if (coefficientData.type == cellData)
933 {
934 // CellData means discontinuous, order 0
936
937 Space space(fse.space().gridManager(), fse.space().grid().leafGridView(), 0);
938 auto otherFSE = space.template element<fseCoefficientDim>();
939 copyCoefficientsDirectly(functionName, coefficientData, otherFSE);
940 fse = otherFSE;
941 }
942 }
943
944 template<class FSE>
945 void VTKReader::copyCoefficientsDirectly(std::string const& functionName,
946 VTKReaderDetail::CoefficientData const& coefficientData,
947 FSE& fse) const
948 {
949 using namespace VTKReaderDetail;
950
951 constexpr int fseCoefficientDim = FSE::StorageValueType::dimension;
952 std::size_t numComponentsToCopy = std::min(std::size_t(fseCoefficientDim), coefficientData.numComponents);
953 std::vector<std::size_t> const& indices = coefficientData.type == pointData? pointDataIndices : cellDataIndices;
954
955 if(indices.size() != fse.coefficients().size())
956 {
957 std::ostringstream out;
958 out << "\"" << functionName << "\": Number of coefficients doesn't match number of data points.\nfunction info: " << getFunctionInfo(functionName);
959 throw Kaskade::FileIOException(out.str(), vtk.filename, __FILE__, __LINE__);
960 }
961 for(std::size_t i = 0; i < indices.size(); ++i)
962 {
963 std::size_t dataIdx = indices[i];
964 auto& block = fse.coefficients()[i];
965 auto itData = coefficientData.data.begin() + dataIdx * coefficientData.numComponents;
966 std::copy(itData, itData + numComponentsToCopy, block.begin());
967 }
968 }
969} // namespace Kaskade
970
971#endif
A representation of a finite element function space defined over a domain covered by a grid.
An exception class for file IO errors.
An exception class for grid related errors.
A class to create a grid and load coefficients from a VTK file.
Definition: vtkreader.hh:94
FunctionInfo getFunctionInfo(std::string const &functionName) const
Information about the expected type of function. Meet these criteria to copy values into your variabl...
std::unique_ptr< Grid > createGrid()
Create a grid from a previously loaded VTK file.
Definition: vtkreader.hh:659
VTKReader()=default
Default constructor.
Flags
Options for getCoefficients().
Definition: vtkreader.hh:100
@ allowCoefficientDimensionMismatch
Definition: vtkreader.hh:104
VTKReader(std::string const &filename)
Constructor that loads a VTK file.
void loadOnlyData(std::string const &filename)
Loads only coefficient data, omitting the grid. This can be used for time series.
void getCoefficients(VariableSet &varSet, int interpolationFlags=noInterpolation) const
Copy the data from the current VTK file into the coefficients of your FEFunctions.
Definition: vtkreader.hh:770
std::vector< std::string > functionNames() const
Lists the functions stored in the file by their name.
void load(std::string const &filename)
Loads a VTK file.
A class for storing a heterogeneous collection of FunctionSpaceElement s.
Definition: variables.hh:341
Descriptions const & descriptions
Descriptions of variable set, of type VariableSetDescription (lots of useful infos)
Definition: variables.hh:510
FEFunctionSpace and FunctionSpaceElement and the like.
std::unique_ptr< Grid > createGrid(std::vector< Type > const &cubes)
Extract simplicial grid from list of cubes.
Dune::FieldVector< T, n > min(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise minimum.
Definition: fixdune.hh:122
Lagrange Finite Elements.
std::ostream & operator<<(std::ostream &s, std::vector< Scalar > const &vec)
Definition: dune_bridge.hh:47
Information about a data set loaded from a file.
Definition: vtkreader.hh:113