27#include <boost/fusion/include/zip.hpp>
28#include <boost/range/iterator_range.hpp>
30#include <dune/grid/common/grid.hh>
31#include <dune/geometry/quadraturerules.hh>
32#include <dune/geometry/referenceelements.hh>
50 namespace FunctionSpace_Detail {
52 template <
class>
class ToDomainRepresentation;
55 namespace VTKWriterDetail
58 std::string vtkEndianness();
74 vtkquadQuadrilateral = 23,
75 vtkquadTetrahedron = 24,
76 vtkquadHexahedron = 25,
77 vtkLagrangeTriangle = 69,
78 vtkLagrangeQuadrilateral = 70,
79 vtkLagrangeTetrahedron = 71,
80 vtkLagrangeHexahedron = 72
84 VTKGeometryType vtkType(Dune::GeometryType
const& t,
int order);
93 std::pair<int,int> vtkPointToDune(Dune::GeometryType
const& type,
int vtkPoint);
102 class VTKDataArrayWriter
115 std::string
const& name,
int ncomps,
116 size_t entries,
int indentCount,
int precision);
130 ~VTKDataArrayWriter();
140 std::unique_ptr<Base64Writer>
base64;
146 void indent(std::ostream& s,
int indentCount);
154 template <
class ct,
int dim>
158 CornerQuadratureRule(Dune::GeometryType gt,
int order)
159 :
Dune::QuadratureRule<ct,dim>(gt,order)
161 assert(1<=order && order<=2);
163 auto refCell = Dune::referenceElement<ct,dim>(gt);
166 int const n = refCell.size(dim) + (order==2 ? refCell.size(dim-1) : 0);
172 for (
int i=0; i<n; ++i)
174 auto [k,codim] = vtkPointToDune(gt,i);
175 this->push_back(Dune::QuadraturePoint<ct,dim>(refCell.position(k,codim),w));
183 template <
class Gr
idView>
186 using Cell =
typename GridView::template Codim<0>::Entity;
187 using IndexSet =
typename GridView::IndexSet;
188 using CellIterator =
typename GridView::template Codim<0>::Iterator;
190 static int constexpr dim = GridView::dimension;
193 VTKGridInfo(GridView
const& gridView_, IoOptions
const& options_)
194 : gridView(gridView_),
195 cells(gridView.template begin<0>(),gridView.template end<0>()),
196 ncells(gridView.size(0)),
203 for (
auto const& cell: cells)
205 ncorners += cell.subEntities(dim);
206 if (options.order==2)
207 ncorners += cell.subEntities(dim-1);
214 npoints = gridView.size(dim);
215 if (options.order==2)
216 npoints += gridView.size(dim-1);
224 template <
class Cell>
225 auto center(
Cell const& cell,
int subindex,
int codim)
const
227 return Dune::ReferenceElements<typename GridView::ctype,dim>::general(cell.type()).position(subindex,codim);
232 template <
class Cell>
233 int conformingIndex(
Cell const& cell,
int subindex,
int codim)
const
237 return gridView.indexSet().subIndex(cell,subindex,codim);
239 return gridView.size(dim) + gridView.indexSet().subIndex(cell,subindex,codim);
243 template <
class Scalar=
typename Gr
idView::ctype>
244 void writeGridPoints (
int indentCount, std::ostream& s)
const
246 VTKDataArrayWriter<Scalar> p(s, options.outputType,
"Coordinates", 3,
247 npoints, indentCount, options.precision);
256 std::vector<Vector> xs(npoints);
257 for (
auto const& cell: cells)
260 for (
int corner=0; corner<cell.subEntities(dim); ++corner)
261 xs[conformingIndex(cell,corner,dim)] = cell.geometry().corner(corner);
264 if (options.order == 2)
265 for (
int edge=0; edge<cell.subEntities(dim-1); ++edge)
266 xs[conformingIndex(cell,edge,dim-1)] = cell.geometry().global(center(cell,edge,dim-1));
271 if (options.order > 2)
273 assert(
"VTK output of order > 2 not yet implemented\n"==0);
277 for (
auto const& x: xs)
283 for (
auto const& cell: cells)
286 for (
int corner=0; corner<cell.subEntities(dim); ++corner)
287 p.write(
static_cast<Vector>(cell.geometry().corner(corner)));
290 if (options.order == 2)
291 for (
int edge=0; edge<cell.subEntities(dim-1); ++edge)
292 p.write(
static_cast<Vector>(cell.geometry().global(center(cell,edge,dim-1))));
297 if (options.order == 3)
299 assert(
"VTK output of order > 2 not yet implemented\n"==0);
305 void writeGridCells (
int indentCount, std::ostream& s)
const
308 auto p1 = std::make_unique<VTKDataArrayWriter<int>>(s, options.outputType,
"connectivity", 1,
309 ncorners, indentCount, options.precision);
312 std::vector<int> offsets; offsets.reserve(ncells);
313 for (
auto const& cell: cells)
315 int const numCorners = cell.subEntities(dim);
316 int const numEdges = cell.subEntities(dim-1);
317 int const numPoints = numCorners + (options.order==2? numEdges: 0);
319 for (
int vtkPoint=0; vtkPoint<numPoints; ++vtkPoint)
321 auto subentity = vtkPointToDune(cell.type(),vtkPoint);
323 conformingIndex(cell,subentity.first,subentity.second):
324 offset + (subentity.second==dim? 0: numCorners) + subentity.first );
327 offsets.push_back(offset);
332 auto p2 = std::make_unique<VTKDataArrayWriter<int>>(s, options.outputType,
"offsets", 1,
333 ncells, indentCount, options.precision);
334 for (
int off: offsets)
341 VTKDataArrayWriter<unsigned char> p(s, options.outputType,
"types", 1,
342 ncells, indentCount, options.precision);
343 for (
auto const& cell: cells)
344 p.write(
static_cast<unsigned char>(vtkType(cell.type(),options.order)));
349 GridView
const& gridView;
350 boost::iterator_range<CellIterator> cells;
354 IoOptions
const& options;
377 template <
class Gr
idView,
class Function,
class Names>
378 void writeCellData (VTKGridInfo<GridView>
const& gridInfo,
Function const& pair, Names
const& names,
int indentCount, std::ostream& s)
380 using Scalar =
typename std::remove_reference_t<typename boost::fusion::result_of::value_at_c<Function,0>::type>::Scalar;
382 auto const& f = boost::fusion::at_c<0>(pair);
385 if (f.space().mapper().maxOrder() > 0)
388 auto varDesc = boost::fusion::at_c<1>(pair);
389 VTKDataArrayWriter<Scalar> p(s, gridInfo.options.outputType, names[varDesc.id], varDesc.m, gridInfo.ncells, indentCount, gridInfo.options.precision);
390 for (
auto const& cell: gridInfo.cells)
391 p.write(f.value(cell,gridInfo.center(cell,0,0)));
396 template <
class Gr
idView,
class Function,
class Names>
397 void writeVertexData (VTKGridInfo<GridView>
const& gridInfo,
Function const& pair,
398 Names
const& names,
int indentCount, std::ostream& s, Timings& timer)
400 using ValueType =
typename std::remove_reference_t<typename boost::fusion::result_of::value_at_c<Function,0>::type>::ValueType;
401 using Grid =
typename GridView::Grid;
402 using Scalar =
typename ValueType::field_type;
403 constexpr int dim = GridView::dimension;
405 auto const& f = boost::fusion::at_c<0>(pair);
406 auto varDesc = boost::fusion::at_c<1>(pair);
409 if (f.space().mapper().maxOrder() == 0)
414 std::string
const& name = names[varDesc.id].empty() ?
"var"+
paddedString(varDesc.id,2)
416 VTKDataArrayWriter<Scalar> p(s, gridInfo.options.outputType, name,
417 varDesc.m, gridInfo.npoints, indentCount,
418 gridInfo.options.precision);
423 std::vector<ValueType> fs(gridInfo.npoints,ValueType(0.0));
424 std::vector<short>
count(gridInfo.npoints,0);
429 FunctionSpace_Detail::ToDomainRepresentation<std::remove_const_t<std::remove_reference_t<typename boost::fusion::result_of::value_at_c<Function,0>::type>>> tdr(f);
430 auto const& df = tdr.get();
435 ShapeFunctionCache<Grid,Scalar> sfCache;
436 auto evaluator = f.space().evaluator(&sfCache,0);
437 CornerQuadratureRule<typename Grid::ctype,dim> qr(gridInfo.cells.begin()->type(),
438 gridInfo.options.order);
440 timer.start(
"eval at vertices");
441 for (
auto const& cell: gridInfo.cells)
443 evaluator.moveTo(cell);
444 assert(cell.type()==qr.type());
445 for (
int point=0; point<qr.size(); ++point)
447 auto [k,codim] = vtkPointToDune(cell.type(),point);
448 int idx = gridInfo.conformingIndex(cell,k,codim);
452 evaluator.evaluateAt(qp.position(),qr,point,0);
453 fs[idx] += df.value(evaluator);
456 timer.stop(
"eval at vertices");
458 timer.start(
"write out");
459 for (
int i=0; i<gridInfo.npoints; ++i)
460 p.write(fs[i]/
static_cast<typename ValueType::field_type
>(
count[i]));
461 timer.stop(
"write out");
465 for (
auto const& cell: gridInfo.cells)
468 for (
int corner=0; corner<cell.subEntities(dim); ++corner)
469 p.write(f.value(cell,gridInfo.center(cell,corner,dim)));
472 if (gridInfo.options.order == 2)
473 for (
int edge=0; edge<cell.subEntities(dim-1); ++edge)
474 p.write(f.value(cell,gridInfo.center(cell,edge,dim-1)));
481 if (gridInfo.options.order > 2)
491 template <
class Functions,
class Names>
492 std::string guessActiveFields(Functions
const& functions, Names
const& names,
bool cellData)
494 std::string scalar =
"";
495 std::string vector =
"";
497 boost::fusion::for_each(functions,[&](
auto const& pair)
499 auto const& f = boost::fusion::at_c<0>(pair);
500 auto varDesc = boost::fusion::at_c<1>(pair);
503 if ( (f.space().mapper().maxOrder()==0 && cellData)
504 || (f.space().mapper().maxOrder()>0 && !cellData) )
506 if (f.components>1 && vector.empty())
507 vector =
" Vectors=\"" + names[varDesc.id] +
"\"";
508 if (f.components==1 && scalar.empty())
509 scalar =
" Scalars=\"" + names[varDesc.id] +
"\"" ;
512 return scalar+vector;
529 template <
class VariableSet>
532 using namespace VTKWriterDetail;
536 timer.start(
"VTK output");
548 constexpr int dim = VariableSet::Descriptions::Grid::dimension;
550 timer.start(
"grid info");
551 VTKGridInfo<typename VariableSet::Descriptions::GridView> gridInfo(vars.
descriptions.gridView,options);
552 timer.stop(
"grid info");
555 s <<
"<?xml version=\"1.0\"?>" << std::endl;
558 std::string
const gridTag = dim>1?
"UnstructuredGrid":
"PolyData";
559 s <<
"<VTKFile type=\"" << gridTag <<
"\" version=\"0.1\" byte_order=\"" << vtkEndianness() <<
"\">\n";
563 indent(s,indentCount);
564 s <<
"<" << gridTag <<
">" << std::endl;
568 indent(s,indentCount);
570 s <<
"<Piece NumberOfPoints=\"" << gridInfo.npoints <<
"\" NumberOfCells=\"" << gridInfo.ncells <<
"\">\n";
572 s <<
"<Piece NumberOfPoints=\"" << gridInfo.npoints <<
"\" NumberOfVerts=\"0\" NumberOfLines=\"" << gridInfo.ncells <<
"\" NumberOfPolys=\"0\">\n";
576 timer.start(
"write vertices");
577 indent(s,indentCount); s <<
"<Points>" << std::endl;
579 gridInfo.template writeGridPoints<float>(indentCount+1,s);
581 gridInfo.template writeGridPoints<double>(indentCount+1,s);
582 indent(s,indentCount); s <<
"</Points>" << std::endl;
583 timer.stop(
"write vertices");
586 timer.start(
"write cells");
587 std::string
const cellTagName = dim>1?
"Cells":
"Lines";
588 indent(s,indentCount); s <<
'<' << cellTagName <<
">\n";
589 gridInfo.writeGridCells(indentCount+1,s);
590 indent(s,indentCount); s <<
"</" << cellTagName <<
">\n";
591 timer.stop(
"write cells");
594 auto varDesc =
typename VariableSet::Descriptions::Variables();
595 auto functions = boost::fusion::zip(vars.
data,varDesc);
599 timer.start(
"write cell data");
600 indent(s,indentCount); s <<
"<CellData"
601 << guessActiveFields(functions,vars.
descriptions.names,
true) <<
">\n";
602 boost::fusion::for_each(functions,[&](
auto const& f)
604 writeCellData(gridInfo,f,vars.
descriptions.names,indentCount+1,s);
606 indent(s,indentCount); s <<
"</CellData>" << std::endl;
607 timer.stop(
"write cell data");
611 timer.start(
"write point data");
612 indent(s,indentCount); s <<
"<PointData"
613 << guessActiveFields(functions,vars.
descriptions.names,
false) <<
">\n";
614 boost::fusion::for_each(functions,[&](
auto const& f)
616 writeVertexData(gridInfo,f,vars.
descriptions.names,indentCount+1,s,timer);
618 indent(s,indentCount); s <<
"</PointData>\n";
619 timer.stop(
"write point data");
623 indent(s,indentCount); s <<
"</Piece>\n";
627 indent(s,indentCount); s <<
"</" << gridTag <<
">\n";
630 s <<
"</VTKFile>" << std::endl;
632 timer.stop(
"VTK output");
649 template <
class VariableSet>
653 fname += (VariableSet::Descriptions::GridView::dimension>1?
".vtu" :
".vtp");
656 std::ofstream file(fname);
Function is the interface for evaluatable functions .
An exception class for file IO errors.
static Timings & instance()
Returns a reference to a single default instance.
A class for storing a heterogeneous collection of FunctionSpaceElement s.
Descriptions const & descriptions
Descriptions of variable set, of type VariableSetDescription (lots of useful infos)
int count(Cell const &cell, int codim)
Computes the number of subentities of codimension c of a given entity.
std::string paddedString(int n, int places=3)
creates a zero-padded string representation of the given number
void writeVTK(Function const &f, std::string const &filename, IoOptions options, std::string fname)
Writes a single finite element function to a VTK file.
typename GridView::template Codim< 0 >::Entity Cell
The type of cells (entities of codimension 0) in the grid view.
Dune::FieldVector< T, n > max(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise maximum.
Dune::FieldVector< T, n > min(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise minimum.
Output of mesh and solution for visualization software.
Dune::FieldVector< Scalar, dim > Vector
options for VTK/AMIRA output
OutputType
Determines text or binary output format. Currently this is only used by VTK output.