26#include <boost/fusion/container/vector.hpp>
27#include <boost/fusion/include/zip_view.hpp>
29#include <dune/grid/config.h>
30#include <dune/grid/common/gridfactory.hh>
39 namespace VTKReaderDetail
41 enum CoefficientDataType
47 struct CoefficientData
49 CoefficientDataType type;
50 std::size_t numComponents = 0;
51 std::vector<double> data;
56 bool reverseByteOrder =
false;
57 std::string headerType =
"UInt32";
58 std::string compressor;
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;
69 std::vector<std::size_t> corners, edges;
135 void load(std::string
const& filename);
155 template<
class Gr
id,
class Deformation>
156 std::unique_ptr<Grid>
createGrid(Deformation
const& deformation);
174 template<
class VariableSet>
210 loadOptionEverything,
214 enum CoefficientMapping
220 template<
class VariableSet,
class FSEVarDescPair>
221 void copyCoefficientsByName(VariableSet
const& varSet, FSEVarDescPair& pair,
int interpolationFlags)
const;
224 void copyCoefficients(std::string
const& functionName, VTKReaderDetail::CoefficientData
const& coefficientData, FSE& fse,
int interpolationFlags)
const;
227 void copyCoefficientsInterpolated(std::string
const& functionName,
228 VTKReaderDetail::CoefficientData
const& coefficientData,
232 void copyCoefficientsDirectly(std::string
const& functionName,
233 VTKReaderDetail::CoefficientData
const& coefficientData,
236 void loadVTKInternal(std::string
const& filename, LoadOption option);
237 void prepareGridCreation(std::vector<VTKReaderDetail::VTKCell>& vtkCells, std::vector<char>& isCorner);
239 void clearCoefficientData();
242 VTKReaderDetail::VTKData vtk;
244 bool gridWasLoaded =
false,
245 gridWasCreated =
false;
248 CoefficientMapping coefficientMapping = continuous;
249 int polynomialOrder = 0;
252 std::vector<std::size_t> pointDataIndices, cellDataIndices;
262 namespace VTKReaderDetail
267 std::size_t vtkIdx = 0, numComponents = 0;
268 std::vector<double>::const_iterator coordinates;
270 bool operator<(IndexedPoint
const& other)
const;
271 bool operator==(IndexedPoint
const& other)
const;
276 class VTKFactoryHelper
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);
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;
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;
293 Dune::GridFactory<Grid> factory;
294 std::vector<std::size_t> vertexVTKToInsertion, vertexInsertionToVTK;
295 std::size_t totalCorners = 0, totalEdges = 0;
298 std::string formatWarning(std::string
const& filename, std::string
const& message);
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);
307 bool operator()(std::pair<std::size_t, std::size_t>
const& p1, std::pair<std::size_t, std::size_t>
const& p2)
const;
309 using EdgeTable = std::map<std::pair<std::size_t, std::size_t>, std::size_t, CompareTwoSet>;
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);
315 template<
class ElementEntity,
class IndexSet>
316 EdgeTable createEdgeTable(ElementEntity
const& element, IndexSet
const& indexSet, std::vector<std::size_t>
const& vertexGridToVTK)
321 constexpr int dim = IndexSet::dimension;
322 constexpr int codimEdge = dim - 1, codimVertex = dim;
324 auto refElement = Dune::ReferenceElements<double, dim>::general(element.type());
326 unsigned numEdges = refElement.size(codimEdge);
327 for(
unsigned i = 0; i < numEdges; ++i)
330 std::size_t c0 = refElement.subEntity(i, codimEdge, 0, codimVertex);
331 std::size_t c1 = refElement.subEntity(i, codimEdge, 1, codimVertex);
334 c0 = indexSet.subIndex(element, c0, codimVertex);
335 c1 = indexSet.subIndex(element, c1, codimVertex);
336 std::size_t e = indexSet.subIndex(element, i, codimEdge);
339 c0 = vertexGridToVTK[c0];
340 c1 = vertexGridToVTK[c1];
343 edgeTable[std::make_pair(c0, c1)] = e;
349 template<
class DataSequence,
class VariableDescriptionSequence>
350 boost::fusion::zip_view<boost::fusion::vector<DataSequence&, VariableDescriptionSequence const&>>
351 makeZipView(DataSequence& data, VariableDescriptionSequence
const& descriptions)
353 using Sequences = boost::fusion::vector<DataSequence&, VariableDescriptionSequence const&>;
354 return boost::fusion::zip_view<Sequences>(Sequences(data, descriptions));
360 template<
class Deformation>
361 void VTKFactoryHelper<Grid>::insertVertices(std::vector<char>
const& isCorner, VTKData
const& vtk, Deformation
const& deformation)
365 constexpr int dim = Grid::dimension;
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;
371 for(std::size_t i = 0; i < vtk.numPoints; ++i)
376 std::size_t offs = i * vtk.dimVertex;
378 auto it = vtk.coordinates.begin() + offs;
379 std::copy(it, it + numComponentsToRead, vertex.begin());
380 factory.insertVertex(deformation(vertex));
382 vertexInsertionToVTK.push_back(i);
383 vertexVTKToInsertion[i] = countInsertion;
387 totalCorners = countInsertion;
390 totalEdges = vtk.numPoints - totalCorners;
394 void VTKFactoryHelper<Grid>::insertVertices(std::vector<char>
const& isCorner, VTKData
const& vtk)
396 auto identity = [] (
auto x) {
return x;};
397 insertVertices(isCorner, vtk, identity);
401 void VTKFactoryHelper<Grid>::insertCells(std::vector<VTKCell>
const& vtkCells)
403 int dim = Grid::dimension;
405 for(VTKCell
const& vtkCell : vtkCells)
407 int geoType = vtkCell.vtkGeomType;
408 int cellDim = countCellDim(geoType);
414 std::vector<unsigned int> corners(vtkCell.corners.size());
415 for(std::size_t k = 0; k < corners.size(); ++k)
417 std::size_t corner = getDuneCorner(vtkCell.vtkGeomType, k);
418 std::size_t vtkCornerIdx = vtkCell.corners[corner];
419 corners[k] = (
unsigned int) vertexVTKToInsertion[vtkCornerIdx];
421 factory.insertElement(getDuneGeomType(vtkCell.vtkGeomType), corners);
428 return std::unique_ptr<Grid>(factory.createGrid());
432 void VTKFactoryHelper<Grid>::setIndicesForDuplicatePoints(std::vector<IndexedPoint>
const& indexedPoints, std::vector<std::size_t>
const& vertexVTKToMerged)
435 for(IndexedPoint
const& p : indexedPoints)
437 std::size_t mergedIdx = vertexVTKToMerged[p.vtkIdx];
438 std::size_t insertionIdx = vertexVTKToInsertion[mergedIdx];
439 vertexVTKToInsertion[p.vtkIdx] = insertionIdx;
444 void VTKFactoryHelper<Grid>::getDataIndicesContinuous(
typename Grid::LeafGridView
const& leafView, std::vector<VTKCell>
const& vtkCells, std::vector<std::size_t>& dataIndicesOut)
const
446 std::vector<std::size_t> vertexGridToVTK(totalCorners), edgeGridToVTK(totalEdges);
449 auto const& indexSet = leafView.indexSet();
450 for(
auto const& vertexEntity : vertices(leafView))
452 std::size_t insertionIdx = factory.insertionIndex(vertexEntity);
453 std::size_t gridIdx = indexSet.index(vertexEntity);
455 if(insertionIdx >= vertexInsertionToVTK.size() || gridIdx >= vertexGridToVTK.size())
461 std::size_t vtkIdx = vertexInsertionToVTK[insertionIdx];
462 vertexGridToVTK[gridIdx] = vtkIdx;
466 for(
auto const& elementEntity : elements(leafView))
469 std::size_t insertionIdx = factory.insertionIndex(elementEntity);
471 if(insertionIdx >= vtkCells.size())
477 VTKCell
const& vtkCell = vtkCells[insertionIdx];
481 EdgeTable edgeTable = createEdgeTable(elementEntity, indexSet, vertexGridToVTK);
482 for(std::size_t i = 0; i < vtkCell.edges.size(); ++i)
485 std::size_t vtkIdx = vtkCell.edges[i];
488 std::pair<int, int> vtkLocalCorners = getVTKLocalCorners(vtkCell.vtkGeomType, i);
492 std::size_t gridIdx = findEdgeIndex(edgeTable, vtkCell.corners[vtkLocalCorners.first], vtkCell.corners[vtkLocalCorners.second]);
494 if(gridIdx >= edgeGridToVTK.size())
499 edgeGridToVTK[gridIdx]= vtkIdx;
503 dataIndicesOut.resize(totalCorners + totalEdges);
504 std::copy(edgeGridToVTK.begin(), edgeGridToVTK.end(), dataIndicesOut.begin());
505 std::copy(vertexGridToVTK.begin(), vertexGridToVTK.end(), dataIndicesOut.begin() + totalEdges);
509 void VTKFactoryHelper<Grid>::getDataIndicesDiscontinuous(
typename Grid::LeafGridView
const& leafView, std::vector<VTKCell>
const& vtkCells, std::vector<std::size_t>& dataIndicesOut)
const
512 std::vector<std::vector<std::size_t>> dataIndicesPerCell(vtkCells.size());
514 for(
auto const& elementEntity : elements(leafView))
517 std::size_t insertionIdx = factory.insertionIndex(elementEntity);
518 if(insertionIdx >= vtkCells.size())
523 VTKCell
const& vtkCell = vtkCells[insertionIdx];
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);
531 std::size_t gridIdx = leafView.indexSet().index(elementEntity);
533 if(gridIdx >= dataIndicesPerCell.size())
538 dataIndicesPerCell[gridIdx] = cellIndices;
542 for(std::vector<std::size_t>
const& cellIndices : dataIndicesPerCell)
544 for(std::size_t idx : cellIndices)
546 dataIndicesOut.push_back(idx);
552 void VTKFactoryHelper<Grid>::getCellDataIndices(
typename Grid::LeafGridView
const& leafView, std::vector<std::size_t>& dataIndicesOut)
const
554 std::size_t numCells = leafView.size(0);
555 dataIndicesOut.resize(numCells);
557 for(
auto const& elementEntity : elements(leafView))
560 std::size_t vtkIdx = factory.insertionIndex(elementEntity);
561 std::size_t gridIdx = leafView.indexSet().index(elementEntity);
562 if(gridIdx >= dataIndicesOut.size())
567 dataIndicesOut[gridIdx] = vtkIdx;
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
579 using IndexPair = std::pair<std::size_t, std::size_t>;
582 std::map<std::size_t, IndexPair> cornerLookup;
583 std::map<IndexPair, IndexPair, CompareTwoSet> edgeLookup;
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;
589 assert(element.subEntities(codimVertex) == numCorners);
590 assert(numEdges == 0 || element.subEntities(codimEdge) == numEdges);
593 std::vector<std::size_t> vertexLocalToInsertion(numCorners);
595 for(std::size_t i = 0; i < numCorners; ++i)
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;
604 std::size_t vtkIndex = vtkCell.corners[i];
605 insertionIndex = vertexVTKToInsertion[vtkIndex];
606 cornerLookup[insertionIndex].second = vtkIndex;
610 auto refElement = Dune::ReferenceElements<double, dim>::general(element.type());
612 for(std::size_t i = 0; i < numEdges; ++i)
615 std::size_t c0 = refElement.subEntity(i, codimEdge, 0, codimVertex);
616 std::size_t c1 = refElement.subEntity(i, codimEdge, 1, codimVertex);
617 c0 = vertexLocalToInsertion[c0];
618 c1 = vertexLocalToInsertion[c1];
619 edgeLookup[std::make_pair(c0, c1)].first = i;
622 IndexPair p = getVTKLocalCorners(vtkCell.vtkGeomType, i);
623 c0 = vtkCell.corners[p.first];
624 c1 = vtkCell.corners[p.second];
625 c0 = vertexVTKToInsertion[c0];
626 c1 = vertexVTKToInsertion[c1];
627 std::size_t edgeDataIdx = vtkCell.edges[i];
628 edgeLookup[std::make_pair(c0, c1)].second = edgeDataIdx;
631 assert(cornerLookup.size() == numCorners);
632 assert(edgeLookup.size() == numEdges);
635 vertexLocalToVTK.resize(numCorners);
637 for(
auto const& p : cornerLookup)
639 IndexPair
const& ip = p.second;
640 vertexLocalToVTK[ip.first] = ip.second;
643 edgeLocalToVTK.resize(numEdges);
645 for(
auto const& p : edgeLookup)
647 IndexPair
const& ip = p.second;
648 edgeLocalToVTK[ip.first] = ip.second;
662 auto identity = [] (
auto x) {
return x;};
663 return createGrid<Grid>(identity);
666 template<
class Gr
id,
class Deformation>
669 using namespace VTKReaderDetail;
676 std::vector<char> isCorner(vtk.numPoints, 0);
677 std::vector<VTKCell> vtkCells(vtk.numCells);
680 prepareGridCreation(vtkCells, isCorner);
682 std::vector<IndexedPoint> indexedPoints;
683 std::vector<std::size_t> vertexVTKToMerged;
686 for(std::size_t i = 0; i < vtk.numPoints; ++i)
690 std::size_t offs = i * vtk.dimVertex;
693 p.numComponents = vtk.dimVertex;
694 p.coordinates = vtk.coordinates.begin() + offs;
695 indexedPoints.push_back(p);
699 std::sort(indexedPoints.begin(), indexedPoints.end());
703 bool hasDuplicatePoints = std::adjacent_find(indexedPoints.begin(), indexedPoints.end()) != indexedPoints.end();
704 coefficientMapping = hasDuplicatePoints? discontinuous : continuous;
706 if(hasDuplicatePoints)
709 vertexVTKToMerged.resize(vtk.numPoints, 0);
711 std::fill(isCorner.begin(), isCorner.end(), 0);
713 auto P = indexedPoints.begin();
714 while(P != indexedPoints.end())
717 isCorner[P->vtkIdx] = 1;
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)
723 vertexVTKToMerged[it->vtkIdx] = currentRepresentativeIdx;
729 VTKFactoryHelper<Grid> factoryHelper;
730 std::unique_ptr<Grid> grid;
735 factoryHelper.insertVertices(isCorner, vtk, deformation);
738 if (coefficientMapping == discontinuous)
740 factoryHelper.setIndicesForDuplicatePoints(indexedPoints, vertexVTKToMerged);
743 factoryHelper.insertCells(vtkCells);
744 grid = factoryHelper.createGrid();
746 catch(Dune::GridError
const& e)
752 auto leafView = grid->leafGridView();
754 if (coefficientMapping == continuous)
756 factoryHelper.getDataIndicesContinuous(leafView, vtkCells, pointDataIndices);
760 factoryHelper.getDataIndicesDiscontinuous(leafView, vtkCells, pointDataIndices);
763 factoryHelper.getCellDataIndices(leafView, cellDataIndices);
765 gridWasCreated =
true;
769 template<
class VariableSet>
772 using namespace VTKReaderDetail;
780 auto functions = makeZipView(varSet.
data,
typename VariableSet::Descriptions::Variables());
781 boost::fusion::for_each(functions, [&](
auto const& f){this->copyCoefficientsByName(varSet, f, interpolationFlags);});
787 using namespace VTKReaderDetail;
794 auto it = vtk.coefficientData.find(functionName);
795 if(it != vtk.coefficientData.end())
796 copyCoefficients(functionName, it->second, fse, interpolationFlags);
800 std::ostringstream out;
801 out <<
"No coefficient data provided for " << functionName <<
".";
802 std::cout << formatWarning(vtk.filename, out.str()) << std::endl;
806 template<
class VariableSet,
class FSEVarDescPair>
807 void VTKReader::copyCoefficientsByName(
VariableSet const& varSet, FSEVarDescPair& pair,
int interpolationFlags)
const
810 using namespace VTKReaderDetail;
812 auto& fse = at_c<0>(pair);
813 auto const& desc = at_c<1>(pair);
814 std::string functionName = varSet.
descriptions.names[desc.id];
817 auto it = vtk.coefficientData.find(functionName);
818 if(it != vtk.coefficientData.end())
820 copyCoefficients(functionName, it->second, fse, interpolationFlags);
825 std::ostringstream out;
826 out <<
"No data provided for " << functionName <<
".";
827 std::cout << formatWarning(vtk.filename, out.str()) << std::endl;
832 void VTKReader::copyCoefficients(std::string
const& functionName,
833 VTKReaderDetail::CoefficientData
const& coefficientData,
835 int interpolationFlags)
const
837 using namespace VTKReaderDetail;
839 constexpr int fseCoefficientDim = FSE::StorageValueType::dimension;
840 int fseMaxOrder = fse.space().mapper().maxOrder(), fseContinuity = FSE::Space::continuity;
842 bool interpolationNeeded =
false;
844 if ((std::size_t)fseCoefficientDim != coefficientData.numComponents)
848 std::ostringstream out;
849 out <<
"\"" << functionName <<
"\": Coefficient dimension mismatch.\nfunction info: "
856 int order = coefficientData.type==cellData? 0: polynomialOrder;
858 if (fseMaxOrder != order)
861 interpolationNeeded =
true;
864 std::ostringstream out;
865 out <<
"\"" << functionName <<
"\": Order mismatch.\nfunction info: "
872 CoefficientMapping continuity = coefficientData.type==cellData? discontinuous: coefficientMapping;
874 if ( (fseContinuity < 0 && continuity == continuous)
875 || (fseContinuity >= 0 && continuity == discontinuous))
878 interpolationNeeded =
true;
881 std::ostringstream out;
882 out <<
"\"" << functionName <<
"\": Continuity mismatch.\nfunction info: "
888 if (interpolationNeeded)
889 copyCoefficientsInterpolated(functionName, coefficientData, fse);
891 copyCoefficientsDirectly(functionName, coefficientData, fse);
895 void VTKReader::copyCoefficientsInterpolated(std::string
const& functionName,
896 VTKReaderDetail::CoefficientData
const& coefficientData,
900 using namespace VTKReaderDetail;
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;
911 if (coefficientData.type == pointData)
913 if (coefficientMapping == continuous)
917 Space space(fse.space().gridManager(), fse.space().grid().leafGridView(), polynomialOrder);
918 auto otherFSE = space.template element<fseCoefficientDim>();
919 copyCoefficientsDirectly(functionName, coefficientData, otherFSE);
926 Space space(fse.space().gridManager(), fse.space().grid().leafGridView(), polynomialOrder);
927 auto otherFSE = space.template element<fseCoefficientDim>();
928 copyCoefficientsDirectly(functionName, coefficientData, otherFSE);
932 else if (coefficientData.type == cellData)
937 Space space(fse.space().gridManager(), fse.space().grid().leafGridView(), 0);
938 auto otherFSE = space.template element<fseCoefficientDim>();
939 copyCoefficientsDirectly(functionName, coefficientData, otherFSE);
945 void VTKReader::copyCoefficientsDirectly(std::string
const& functionName,
946 VTKReaderDetail::CoefficientData
const& coefficientData,
949 using namespace VTKReaderDetail;
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;
955 if(indices.size() != fse.coefficients().size())
957 std::ostringstream out;
958 out <<
"\"" << functionName <<
"\": Number of coefficients doesn't match number of data points.\nfunction info: " <<
getFunctionInfo(functionName);
961 for(std::size_t i = 0; i < indices.size(); ++i)
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());
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.
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.
VTKReader()=default
Default constructor.
Flags
Options for getCoefficients().
@ allowCoefficientDimensionMismatch
@ allowContinuityMismatch
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.
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.
Descriptions const & descriptions
Descriptions of variable set, of type VariableSetDescription (lots of useful infos)
FEFunctionSpace and FunctionSpaceElement and the like.
Dune::FieldVector< T, n > min(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise minimum.
Lagrange Finite Elements.
std::ostream & operator<<(std::ostream &s, std::vector< Scalar > const &vec)
Information about a data set loaded from a file.