From 8f9bd0d9b08e79fcd329b38f8b47edcce65ddccd Mon Sep 17 00:00:00 2001 From: Kilian Weishaupt <kilian.weishaupt@iws.uni-stuttgart.de> Date: Wed, 8 Feb 2017 16:31:15 +0100 Subject: [PATCH] [staggeredGrid][vtk] Revise staggered vtk writer * Now provides void addPointData() to make usage more similar to existing writer * Will get an interface which allows use with dune sequence writer --- dumux/freeflow/staggered/model.hh | 110 ------- dumux/freeflow/staggered/vtkoutputmodule.hh | 6 +- dumux/io/staggeredvtkoutputmodule.hh | 166 +++++----- dumux/io/staggeredvtkwriter.hh | 301 ++++++++++-------- .../staggered/kovasznaytestproblem.hh | 42 +-- 5 files changed, 279 insertions(+), 346 deletions(-) diff --git a/dumux/freeflow/staggered/model.hh b/dumux/freeflow/staggered/model.hh index 2856c75b03..16dbdaef44 100644 --- a/dumux/freeflow/staggered/model.hh +++ b/dumux/freeflow/staggered/model.hh @@ -93,116 +93,6 @@ public: // NonIsothermalModel::maybeAddTemperature(vtkOutputModule); } - - /*! - * \brief \copybrief Dumux::ImplicitModel::addOutputVtkFields - * - * Specialization for the NavierStokesModel, adding the pressure and - * the process rank to the VTK writer. - */ - template<class MultiWriter> - void addOutputVtkFields(const SolutionVector &sol, - MultiWriter &writer) - { - // TODO: implement vtk output properly, account for 3d - using VectorField = Dune::BlockVector<Dune::FieldVector<double, dimWorld> >; - - // create the required scalar fields - const auto numElements = this->gridView_().size(0); - auto *p = writer.allocateManagedBuffer(numElements); - auto *delP = writer.allocateManagedBuffer(numElements); - - auto *v_x_pos = writer.allocateManagedBuffer(numElements); - auto *v_x_neg = writer.allocateManagedBuffer(numElements); - auto *v_y_pos = writer.allocateManagedBuffer(numElements); - auto *v_y_neg = writer.allocateManagedBuffer(numElements); - - VectorField *velocity = writer.template allocateManagedBuffer<double, dimWorld>(numElements); - - // initialize velocity field - for (unsigned int i = 0; i < numElements; ++i) - { - (*velocity)[i] = Scalar(0); - } - - auto *rank = writer.allocateManagedBuffer(numElements); - - for (const auto& element : elements(this->gridView_(), Dune::Partitions::interior)) - { - auto eIdx = this->elementMapper().index(element); - (*rank)[eIdx] = this->gridView_().comm().rank(); - - // get the local fv geometry - auto fvGeometry = localView(this->globalFvGeometry()); - fvGeometry.bindElement(element); - - auto elemVolVars = localView(this->curGlobalVolVars()); - elemVolVars.bindElement(element, fvGeometry, this->curSol()); - - for (auto&& scv : scvs(fvGeometry)) - { - const auto& volVars = elemVolVars[scv]; - auto dofIdxGlobal = scv.dofIndex(); - - (*p)[dofIdxGlobal] = volVars.pressure(); - (*delP)[dofIdxGlobal] = volVars.pressure() - 1.1e5; - - GlobalPosition velocityVector(0.0); - for (auto&& scvf : scvfs(fvGeometry)) - { - auto& origFaceVars = this->curGlobalFaceVars().faceVars(scvf.dofIndex()); - auto dirIdx = scvf.directionIndex(); - - velocityVector[dirIdx] += 0.5*origFaceVars.velocity(); - - if(scvf.unitOuterNormal()[dirIdx] > 0.0) - { - if(dirIdx == 0) - (*v_x_pos)[dofIdxGlobal] = origFaceVars.velocity(); - if(dirIdx == 1) - (*v_y_pos)[dofIdxGlobal] = origFaceVars.velocity(); - } - else - { - if(dirIdx == 0) - (*v_x_neg)[dofIdxGlobal] = origFaceVars.velocity(); - if(dirIdx == 1) - (*v_y_neg)[dofIdxGlobal] = origFaceVars.velocity(); - } - } - (*velocity)[dofIdxGlobal] = velocityVector; - } - } - writer.attachDofData(*p, "p", isBox); - writer.attachDofData(*delP, "delP", isBox); - writer.attachDofData(*v_x_pos, "v_x_pos", isBox); - writer.attachDofData(*v_x_neg, "v_x_neg", isBox); - writer.attachDofData(*v_y_pos, "v_y_pos", isBox); - writer.attachDofData(*v_y_neg, "v_y_neg", isBox); - writer.attachCellData(*rank, "process rank"); - writer.attachDofData(*velocity, "velocity", isBox, dim); - } - - auto velocity(const Element& element) const - { - GlobalPosition velocityVector(0.0); - - // get the local fv geometry - auto fvGeometry = localView(this->globalFvGeometry()); - fvGeometry.bindElement(element); - for (auto&& scv : scvs(fvGeometry)) - { - for (auto&& scvf : scvfs(fvGeometry)) - { - auto& origFaceVars = this->curGlobalFaceVars().faceVars(scvf.dofIndex()); - auto dirIdx = scvf.directionIndex(); - velocityVector[dirIdx] += 0.5*origFaceVars.velocity(); - } - } - return velocityVector; - } - - }; } diff --git a/dumux/freeflow/staggered/vtkoutputmodule.hh b/dumux/freeflow/staggered/vtkoutputmodule.hh index f3fe5f22d3..3a55f7c828 100644 --- a/dumux/freeflow/staggered/vtkoutputmodule.hh +++ b/dumux/freeflow/staggered/vtkoutputmodule.hh @@ -71,13 +71,13 @@ private: * \param face The face */ template<class Face> - void getVectorData_(Data& priVarVectorData, const Face& face) + void getPrivarVectorData_(Data& priVarVectorData, const Face& face) { const int dofIdxGlobal = face.dofIndex(); const int dirIdx = directionIndex(face.unitOuterNormal()); const Scalar velocity = this->problem().model().curSol()[faceIdx][dofIdxGlobal][0]; - for (int i = 0; i < this->faceData().priVarVectorDataInfo.size(); ++i) - priVarVectorData[i][dofIdxGlobal * this->faceData().priVarVectorDataInfo[i].pvIdx.size() + dirIdx] = velocity; + for (int i = 0; i < this->priVarVectorDataInfo_.size(); ++i) + priVarVectorData[i][dofIdxGlobal * this->priVarVectorDataInfo_[i].pvIdx.size() + dirIdx] = velocity; } }; diff --git a/dumux/io/staggeredvtkoutputmodule.hh b/dumux/io/staggeredvtkoutputmodule.hh index 4a6ab7c82c..acbeb5afe3 100644 --- a/dumux/io/staggeredvtkoutputmodule.hh +++ b/dumux/io/staggeredvtkoutputmodule.hh @@ -55,6 +55,8 @@ class StaggeredVtkOutputModule : public VtkOutputModuleBase<TypeTag> enum { dim = GridView::dimension }; enum { dimWorld = GridView::dimensionworld }; + using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>; + using DofTypeIndices = typename GET_PROP(TypeTag, DofTypeIndices); typename DofTypeIndices::CellCenterIdx cellCenterIdx; typename DofTypeIndices::FaceIdx faceIdx; @@ -65,31 +67,14 @@ class StaggeredVtkOutputModule : public VtkOutputModuleBase<TypeTag> using Positions = std::vector<Scalar>; using Data = std::vector<std::vector<Scalar>>; - // a collection of types and variables to be passed to the staggered vtk writer - struct WriterData - { - using Positions = StaggeredVtkOutputModule::Positions; - using PriVarScalarDataInfo = StaggeredVtkOutputModule::PriVarScalarDataInfo; - using PriVarVectorDataInfo = StaggeredVtkOutputModule::PriVarVectorDataInfo; - using Data = StaggeredVtkOutputModule::Data; - Data priVarScalarData; - Data priVarVectorData; - Data secondVarScalarData; - Data secondVarVectorData; - Positions positions; - std::vector<PriVarScalarDataInfo> priVarScalarDataInfo; - std::vector<PriVarVectorDataInfo> priVarVectorDataInfo; - std::vector<PriVarScalarDataInfo> secondVarScalarDataInfo; - std::vector<PriVarVectorDataInfo> secondVarVectorDataInfo; - }; - public: StaggeredVtkOutputModule(const Problem& problem, - Dune::VTK::DataMode dm = Dune::VTK::conforming) : ParentType(problem, dm), faceWriter_(problem) + Dune::VTK::DataMode dm = Dune::VTK::conforming) : ParentType(problem, dm), faceWriter_(coordinates_) { writeFaceVars_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Vtk, WriteFaceData); + coordinatesInitialized_ = false; } ////////////////////////////////////////////////////////////////////////////////////////////// @@ -97,12 +82,31 @@ public: //! Do not call these methods after initialization ////////////////////////////////////////////////////////////////////////////////////////////// + + //! Output a scalar field + //! \param name The name of the vtk field + //! \returns A reference to the resized scalar field to be filled with the actual data + std::vector<Scalar>& createFaceScalarField(const std::string& name) + { + faceScalarFields_.emplace_back(std::make_pair(std::vector<Scalar>(this->problem().model().numFaceDofs()), name)); + return faceScalarFields_.back().first; + } + + //! Output a vector field + //! \param name The name of the vtk field + //! \returns A reference to the resized vector field to be filled with the actual data + std::vector<GlobalPosition>& createFaceVectorField(const std::string& name) + { + faceVectorFields_.emplace_back(std::make_pair(std::vector<GlobalPosition>(this->problem().model().numFaceDofs()), name)); + return faceVectorFields_.back().first; + } + //! Output a scalar primary variable //! \param name The name of the vtk field //! \param pvIdx The index in the primary variables vector void addFacePrimaryVariable(const std::string& name, unsigned int pvIdx) { - faceData_.priVarScalarDataInfo.push_back(PriVarScalarDataInfo{pvIdx, name}); + priVarScalarDataInfo_.push_back(PriVarScalarDataInfo{pvIdx, name}); } //! Output a vector primary variable @@ -111,7 +115,7 @@ public: void addFacePrimaryVariable(const std::string& name, std::vector<unsigned int> pvIndices) { assert(pvIndices.size() < 4 && "Vtk doesn't support vector dimensions greater than 3!"); - faceData_.priVarVectorDataInfo.push_back(PriVarVectorDataInfo{pvIndices, name}); + priVarVectorDataInfo_.push_back(PriVarVectorDataInfo{pvIndices, name}); } void write(double time, Dune::VTK::OutputType type = Dune::VTK::ascii) @@ -142,16 +146,25 @@ protected: return this->problem().model().curSol()[cellCenterIdx][dofIdxGlobal][pvIdx]; } - /*! - * \brief Returns a reference to the face data - */ - const WriterData& faceData() const - { - return faceData_; - } + std::vector<PriVarScalarDataInfo> priVarScalarDataInfo_; + std::vector<PriVarVectorDataInfo> priVarVectorDataInfo_; + std::vector<PriVarScalarDataInfo> secondVarScalarDataInfo_; + std::vector<PriVarVectorDataInfo> secondVarVectorDataInfo_; private: + void updateCoordinates_() + { + std::cout << "updating coordinates" << std::endl; + coordinates_.resize(this->problem().model().numFaceDofs()); + for(auto&& facet : facets(this->problem().gridView())) + { + const int dofIdxGlobal = this->problem().gridView().indexSet().index(facet); + coordinates_[dofIdxGlobal] = facet.geometry().center(); + } + coordinatesInitialized_ = true; + } + /*! * \brief Gathers all face-related data and invokes the face vtk-writer using these data. */ @@ -163,13 +176,14 @@ private: std::vector<bool> dofVisited(numPoints, false); // get fields for all primary coordinates and variables - Positions positions(numPoints*3); + if(!coordinatesInitialized_) + updateCoordinates_(); - Data priVarScalarData(faceData_.priVarScalarDataInfo.size(), std::vector<Scalar>(numPoints)); + Data priVarScalarData(priVarScalarDataInfo_.size(), std::vector<Scalar>(numPoints)); - Data priVarVectorData(faceData_.priVarVectorDataInfo.size()); - for (std::size_t i = 0; i < faceData_.priVarVectorDataInfo.size(); ++i) - priVarVectorData[i].resize(numPoints*faceData_.priVarVectorDataInfo[i].pvIdx.size()); + Data priVarVectorData(priVarVectorDataInfo_.size()); + for (std::size_t i = 0; i < priVarVectorDataInfo_.size(); ++i) + priVarVectorData[i].resize(numPoints*priVarVectorDataInfo_[i].pvIdx.size()); for(auto&& element : elements(this->problem().gridView())) { @@ -180,54 +194,35 @@ private: if(dofVisited[scvf.dofIndex()]) continue; - asImp_().getPositions_(positions, scvf); - asImp_().getScalarData_(priVarScalarData, scvf); - asImp_().getVectorData_(priVarVectorData, scvf); + asImp_().getPrivarScalarData_(priVarScalarData, scvf); + asImp_().getPrivarVectorData_(priVarVectorData, scvf); + dofVisited[scvf.dofIndex()] = true; } } - faceData_.priVarScalarData = std::move(priVarScalarData); - faceData_.priVarVectorData = std::move(priVarVectorData); - faceData_.positions = std::move(positions); -// results.secondVarScalarData = xxx; //TODO: implemented secondVarData -// results.secondVarScalarData = xxx; + // transfer priVar scalar data to writer + for(int i = 0; i < priVarScalarDataInfo_.size(); ++i) + faceWriter_.addPointData(priVarScalarData[i], priVarScalarDataInfo_[i].name); - faceWriter_.write(faceData_); - } + // transfer priVar vector data to writer + for(int i = 0; i < priVarVectorDataInfo_.size(); ++i) + faceWriter_.addPointData(priVarVectorData[i], priVarVectorDataInfo_[i].name, priVarVectorDataInfo_[i].pvIdx.size()); - /*! - * \brief Retrives the position (center) of the face. - * ParaView expects three-dimensional coordinates, therefore we fill empty entries with zero for dim < 3. - * - * \param positions Container to store the positions - * \param face The face - */ - template<class Face> - void getPositions_(Positions& positions, const Face& face) - { - const int dofIdxGlobal = face.dofIndex(); - auto pos = face.center(); - if(dim == 1) - { - positions[dofIdxGlobal*3] = pos[0]; - positions[dofIdxGlobal*3 + 1] = 0.0; - positions[dofIdxGlobal*3 + 2] = 0.0; - } - else if(dim == 2) - { - positions[dofIdxGlobal*3] = pos[0]; - positions[dofIdxGlobal*3 + 1] = pos[1]; - positions[dofIdxGlobal*3 + 2] = 0.0; - } - else - { - positions[dofIdxGlobal*3] = pos[0]; - positions[dofIdxGlobal*3 + 1] = pos[1] ; - positions[dofIdxGlobal*3 + 2] = pos[2] ; - } + // transfer custom scalar data to writer + for(auto&& scalarField : faceScalarFields_) + faceWriter_.addPointData(scalarField.first, scalarField.second); + + // transfer custom vector data to writer + for(auto&& vectorField : faceVectorFields_) + faceWriter_.addPointData(vectorField.first, vectorField.second, 3); + + faceWriter_.write(); + faceScalarFields_.clear(); + faceVectorFields_.clear(); } + /*! * \brief Retrives scalar-valued data from the face. * @@ -235,13 +230,11 @@ private: * \param face The face */ template<class Face> - void getScalarData_(Data& priVarScalarData, const Face& face) + void getPrivarScalarData_(Data& priVarScalarData, const Face& face) { const int dofIdxGlobal = face.dofIndex(); - for(int pvIdx = 0; pvIdx < faceData_.priVarScalarDataInfo.size(); ++pvIdx) - { + for(int pvIdx = 0; pvIdx < priVarScalarDataInfo_.size(); ++pvIdx) priVarScalarData[pvIdx][dofIdxGlobal] = this->problem().model().curSol()[faceIdx][dofIdxGlobal][pvIdx]; - } } /*! @@ -251,19 +244,24 @@ private: * \param face The face */ template<class Face> - void getVectorData_(Data& priVarVectorData, const Face& face) + void getPrivarVectorData_(Data& priVarVectorData, const Face& face) { const int dofIdxGlobal = face.dofIndex(); - for (int i = 0; i < faceData_.priVarVectorDataInfo.size(); ++i) - for (int j = 0; j < faceData_.priVarVectorDataInfo[i].pvIdx.size(); ++j) - priVarVectorData[i][dofIdxGlobal*faceData_.priVarVectorDataInfo[i].pvIdx.size() + j] - = this->problem().model().curSol()[faceIdx][dofIdxGlobal][faceData_.priVarVectorDataInfo[i].pvIdx[j]]; + for (int i = 0; i < priVarVectorDataInfo_.size(); ++i) + for (int j = 0; j < priVarVectorDataInfo_[i].pvIdx.size(); ++j) + priVarVectorData[i][dofIdxGlobal*priVarVectorDataInfo_[i].pvIdx.size() + j] + = this->problem().model().curSol()[faceIdx][dofIdxGlobal][priVarVectorDataInfo_[i].pvIdx[j]]; } - StaggeredVtkWriter<TypeTag, WriterData> faceWriter_; - WriterData faceData_; + StaggeredVtkWriter<dimWorld> faceWriter_; bool writeFaceVars_; + std::vector<GlobalPosition> coordinates_; + bool coordinatesInitialized_; + + std::list<std::pair<std::vector<Scalar>, std::string>> faceScalarFields_; + std::list<std::pair<std::vector<GlobalPosition>, std::string>> faceVectorFields_; + //! Returns the implementation of the problem (i.e. static polymorphism) Implementation &asImp_() { return *static_cast<Implementation *>(this); } diff --git a/dumux/io/staggeredvtkwriter.hh b/dumux/io/staggeredvtkwriter.hh index 8db5bbbc59..f262bcd59a 100644 --- a/dumux/io/staggeredvtkwriter.hh +++ b/dumux/io/staggeredvtkwriter.hh @@ -27,6 +27,7 @@ #include <dumux/io/vtkoutputmodulebase.hh> #include <dumux/io/staggeredvtkoutputmodule.hh> +#include <dune/grid/io/file/vtk/common.hh> namespace Properties { @@ -46,108 +47,174 @@ namespace Dumux * initialization and/or be turned on/off using the designated properties. Additionally * non-standardized scalar and vector fields can be added to the writer manually. */ -template<class TypeTag, class WriterData> +template<int dim> class StaggeredVtkWriter { - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using DofTypeIndices = typename GET_PROP(TypeTag, DofTypeIndices); - typename DofTypeIndices::CellCenterIdx cellCenterIdx; - typename DofTypeIndices::FaceIdx faceIdx; - - enum { dim = GridView::dimension }; - enum { dimWorld = GridView::dimensionworld }; - using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>; + using Scalar = double; + using GlobalPosition = Dune::FieldVector<Scalar, dim>; static constexpr unsigned int precision = 6; static constexpr unsigned int numBeforeLineBreak = 15; - using ScalarInfo = std::vector<typename WriterData::PriVarScalarDataInfo>; - using VectorInfo = std::vector<typename WriterData::PriVarVectorDataInfo>; - using Positions = typename WriterData::Positions; - using Data = typename WriterData::Data; + template<class ContainerType> + class VTKLocalFunction + { + public: + VTKLocalFunction(const ContainerType& data, const std::string& name, const int numComponents) : data_(data), name_(name), numComponents_(numComponents) + {} + + const std::string& name() const + { + return name_; + } + + int numComponents() const + { + return numComponents_; + } + + auto& operator() (const int dofIdx) const { return data_[dofIdx]; } + + decltype(auto) begin() const + { + return data_.begin(); + } + + decltype(auto) end() const + { + return data_.end(); + } + + int size() const + { + return data_.size(); + } + + private: + const ContainerType& data_; + const std::string name_; + const int numComponents_; + }; + public: - StaggeredVtkWriter(const Problem& problem) : problem_(problem) + using ScalarLocalFunction = VTKLocalFunction<std::vector<Scalar>>; + using VectorLocalFunction = VTKLocalFunction<std::vector<GlobalPosition>>; + + + StaggeredVtkWriter(const std::vector<GlobalPosition>& coordinates) : coordinates_(coordinates) {} - void write(const WriterData& data) + void write(/*const WriterData& data*/) { - if(data.priVarScalarDataInfo.empty() && - data.priVarVectorDataInfo.empty() && - data.secondVarScalarDataInfo.empty() && - data.secondVarVectorDataInfo.empty()) - return; file_.open(fileName_()); - write_(data); + writeHeader_(); + writeCoordinates_(coordinates_); + writeDataInfo_(); + + for(auto&& data : scalarPointData_) + { + writeData_(data); + } + for(auto&& data :vectorPointData_) + { + writeData_(data); + } + + file_ << "</PointData>\n"; + file_ << "</Piece>\n"; + file_ << "</PolyData>\n"; + file_ << "</VTKFile>"; + + clear(); + file_.close(); ++curWriterNum_; } + + std::string write ( const std::string &name, + Dune::VTK::OutputType type = Dune::VTK::ascii ) + { + return "dummy"; + } + + + void addPointData(const std::vector<Scalar>& v, const std::string &name, int ncomps = 1) + { + assert(v.size() == ncomps * coordinates_.size()); + scalarPointData_.push_back(ScalarLocalFunction(v, name, ncomps)); + } + + void addPointData(const std::vector<GlobalPosition>& v, const std::string &name, int ncomps = 1) + { + assert(v.size() == coordinates_.size()); + vectorPointData_.push_back(VectorLocalFunction(v, name, ncomps)); + } + + + void clear() + { + scalarPointData_.clear(); + vectorPointData_.clear(); + } + + private: - void writeHeader_(const int numPoints) + void writeHeader_() { std::string header = "<?xml version=\"1.0\"?>\n"; header += "<VTKFile type=\"PolyData\" version=\"0.1\" byte_order=\"LittleEndian\">\n"; header += "<PolyData>\n"; - header += "<Piece NumberOfLines=\"0\" NumberOfPoints=\"" + std::to_string(numPoints) + "\">\n"; + header += "<Piece NumberOfLines=\"0\" NumberOfPoints=\"" + std::to_string(coordinates_.size()) + "\">\n"; file_ << header; } /*! - * \brief Writes the coordinates and the simulation data to the file - * - * \param priVarScalarData Container to store the scalar-valued data - * \param priVarVectorData Container to store the vector-valued data - * \param scalarInfo Information concerning the data (e.g. names) - * \param vectorInfo Information concerning the data (e.g. names) - * \param positions Container to store the positions + * \brief Writes information about the data to the file */ - void write_(const WriterData& data) + void writeDataInfo_() { - const int numPoints = problem_.model().numFaceDofs(); - writeHeader_(numPoints); - writeCoordinates_(data.positions); - std::string scalarName; std::string vectorName; + bool foundScalar = false; + bool foundVector = false; - bool scalarValuesPresent = false; - bool vectorValuesPresent = false; - - - if(!(data.priVarScalarDataInfo.empty() && data.secondVarScalarDataInfo.empty())) + for(auto&& data : scalarPointData_) { - scalarValuesPresent = true; - scalarName = data.priVarScalarDataInfo.empty() ? data.secondVarScalarDataInfo[0].name : - data.priVarScalarDataInfo[0].name; + if(data.numComponents() == 1 && !foundScalar) + { + scalarName = data.name(); + foundScalar = true; + continue; + } + + if(data.numComponents() > 1 && !foundVector) + { + vectorName = data.name(); + foundVector = true; + } } - if(!(data.priVarVectorDataInfo.empty() && data.secondVarVectorDataInfo.empty())) + + for(auto&& data : vectorPointData_) { - vectorValuesPresent = true; - vectorName = data.priVarVectorDataInfo.empty() ? data.secondVarVectorDataInfo[0].name : - data.priVarVectorDataInfo[0].name; + if(data.numComponents() > 1 && !foundVector) + { + vectorName = data.name(); + foundVector = true; + } } - if(scalarValuesPresent) - if(vectorValuesPresent) - file_ << "<PointData Scalars=\"" << scalarName << "\" Vectors=\"" << vectorName <<"\">"; + if(foundScalar) + if(foundVector) + file_ << "<PointData Scalars=\"" << scalarName << "\" Vectors=\"" << vectorName <<"\">\n"; else - file_ << "<PointData Scalars=\"" << scalarName << "\">"; - else if(vectorValuesPresent) - file_ << "<PointData Vectors=\"" << vectorName << "\">"; + file_ << "<PointData Scalars=\"" << scalarName << "\">\n"; + else if(foundVector) + file_ << "<PointData Vectors=\"" << vectorName << "\">\n"; else return; - - file_ << std::endl; - writeAllData_(data); - - file_ << "</PointData>\n"; - file_ << "</Piece>\n"; - file_ << "</PolyData>\n"; - file_ << "</VTKFile>"; } /*! @@ -155,7 +222,7 @@ private: * * \param positions Container to store the positions */ - void writeCoordinates_(const Positions& positions) + void writeCoordinates_(const std::vector<GlobalPosition>& positions) { // write the positions to the file file_ << "<Points>\n"; @@ -163,7 +230,13 @@ private: int counter = 0; for(auto&& x : positions) { - file_ << x << " "; + file_ << x ; + + if(x.size() == 1) + file_ << " 0 0 "; + if(x.size() == 2) + file_ << " 0 "; + // introduce a line break after a certain time if((++counter) > numBeforeLineBreak) { @@ -175,92 +248,72 @@ private: file_ << "</Points>\n"; } - void writeAllData_(const WriterData& data) - { - // write scalar-valued primary variable data - if(!data.priVarScalarDataInfo.empty()) - writeScalarData_(data.priVarScalarData, data.priVarScalarDataInfo); - - // write vector-valued primary variable data - if(!data.priVarVectorDataInfo.empty()) - writeVectorData_(data.priVarVectorData, data.priVarVectorDataInfo); - - // write scalar-valued secondary variable data - if(!data.secondVarScalarDataInfo.empty()) - writeScalarData_(data.secondVarScalarData, data.secondVarScalarDataInfo); - - // write vector-valued primary variable data - if(!data.secondVarVectorDataInfo.empty()) - writeVectorData_(data.secondVarVectorData, data.secondVarVectorDataInfo); - } - /*! - * \brief Writes scalar-valued data to the file + * \brief Writes data to the file * - * \param priVarScalarData Container to store the data - * \param info Information concerning the data (e.g. names) + * \param data The data container which hold the data itself, as well as the name of the data set and the number of its components */ - void writeScalarData_(const Data& priVarScalarData, const ScalarInfo& info) + template<class T> + void writeData_(const T& data) { - // write the priVars to the file - for(int pvIdx = 0; pvIdx < info.size(); ++pvIdx) + file_ << "<DataArray type=\"Float32\" Name=\"" << data.name() << "\" NumberOfComponents=\"" << data.numComponents() << "\" format=\"ascii\">\n"; + int counter = 0; + for(auto&& value : data) { - file_ << "<DataArray type=\"Float32\" Name=\"" << info[pvIdx].name << "\" NumberOfComponents=\"1\" format=\"ascii\">\n"; - int counter = 0; - for(auto&& x : priVarScalarData[pvIdx]) + // forward to specialized function + writeToFile_(value); + + // introduce a line break after a certain time + if((++counter) > numBeforeLineBreak) { - file_ << x << " " ; - // introduce a line break after a certain time - if((++counter) > numBeforeLineBreak) - { - file_ << std::endl; - counter = 0; - } + file_ << std::endl; + counter = 0; } - file_ << "\n</DataArray>\n"; } + file_ << "\n</DataArray>\n"; } /*! - * \brief Writes vector-valued data to the file + * \brief Writes a scalar to the file * - * \param priVarVectorData Container to store the data - * \param info Information concerning the data (e.g. names) + * \param s The scalar */ - void writeVectorData_(const Data& priVarVectorData, const VectorInfo& info) + void writeToFile_(const Scalar& s) { - // write the priVars to the file - for(int i = 0; i < info.size(); ++i) - { - file_ << "<DataArray type=\"Float32\" Name=\"" << info[i].name << "\" NumberOfComponents=\"" << info[i].pvIdx.size() << "\" format=\"ascii\">\n"; - int counter = 0; - for(auto&& x : priVarVectorData[i]) - { - file_ << x << " " ; - // introduce a line break after a certain time - if((++counter) > numBeforeLineBreak) - { - file_ << std::endl; - counter = 0; - } - } - file_ << "\n</DataArray>\n"; - } + file_ << s << " "; + } + + /*! + * \brief Writes a vector to the file + * + * \param g The vector + */ + void writeToFile_(const GlobalPosition& g) + { + assert(g.size() > 1 && g.size() < 4); + if(g.size() < 3) + file_ << g << " 0 "; + else + file_ << g; } + /*! * \brief Returns the file name for each timestep */ std::string fileName_() const { std::ostringstream oss; - oss << problem_.name() << "-face-" << std::setw(5) << std::setfill('0') << curWriterNum_ << ".vtp"; + oss << /*problem_.name() <<*/ "face-" << std::setw(5) << std::setfill('0') << curWriterNum_ << ".vtp"; return oss.str(); } - const Problem& problem_; + const std::vector<GlobalPosition>& coordinates_; std::ofstream file_; int curWriterNum_{0}; + + std::list<ScalarLocalFunction> scalarPointData_; + std::list<VectorLocalFunction> vectorPointData_; }; } // end namespace Dumux diff --git a/test/freeflow/staggered/kovasznaytestproblem.hh b/test/freeflow/staggered/kovasznaytestproblem.hh index c274b3a1c2..75c07c4961 100644 --- a/test/freeflow/staggered/kovasznaytestproblem.hh +++ b/test/freeflow/staggered/kovasznaytestproblem.hh @@ -299,52 +299,44 @@ public: return values; } + /*! - * \brief Append all quantities of interest which can be derived - * from the solution of the current time step to the VTK - * writer. + * \brief Adds additional VTK output data to the VTKWriter. Function is called by the output module on every write. */ - void addOutputVtkFields() + template<class VtkOutputModule> + void addVtkOutputFields(VtkOutputModule& outputModule) const { - //Here we calculate the analytical solution - const auto numElements = this->gridView().size(0); - auto& pExact = *(this->resultWriter().allocateManagedBuffer(numElements)); - auto& velocityExact = *(this->resultWriter()).template allocateManagedBuffer<double, dimWorld>(numElements); - - using DofTypeIndices = typename GET_PROP(TypeTag, DofTypeIndices); - typename DofTypeIndices::FaceIdx faceIdx; - - const auto someElement = *(elements(this->gridView()).begin()); - - auto someFvGeometry = localView(this->model().globalFvGeometry()); - someFvGeometry.bindElement(someElement); - const auto someScv = *(scvs(someFvGeometry).begin()); + auto& pressureExact = outputModule.createScalarField("pressureExact", 0); + auto& velocityExact = outputModule.createVectorField("velocityExact", dim); - Scalar time = std::max(this->timeManager().time() + this->timeManager().timeStepSize(), 1e-10); + auto& scalarFaceVelocityExact = outputModule.createFaceScalarField("scalarFaceVelocityExact"); + auto& vectorFaceVelocityExact = outputModule.createFaceVectorField("vectorFaceVelocityExact"); for (const auto& element : elements(this->gridView())) { auto fvGeometry = localView(this->model().globalFvGeometry()); fvGeometry.bindElement(element); - for (auto&& scv : scvs(fvGeometry)) { auto dofIdxGlobal = scv.dofIndex(); - const auto& globalPos = scv.dofPosition(); - - pExact[dofIdxGlobal] = dirichletAtPos(globalPos)[pressureIdx]; + auto dofPosition = scv.dofPosition(); + pressureExact[dofIdxGlobal] = dirichletAtPos(dofPosition)[pressureIdx]; GlobalPosition velocityVector(0.0); for (auto&& scvf : scvfs(fvGeometry)) { auto dirIdx = scvf.directionIndex(); - velocityVector[dirIdx] += 0.5*dirichletAtPos(globalPos)[faceIdx][dirIdx]; + auto analyticalSolution = dirichletAtPos(dofPosition)[faceIdx][dirIdx]; + velocityVector[dirIdx] += 0.5*analyticalSolution; + scalarFaceVelocityExact[dofIdxGlobal] = analyticalSolution; + + GlobalPosition tmp(0.0); + tmp[dirIdx] = analyticalSolution; + vectorFaceVelocityExact[dofIdxGlobal] = std::move(tmp); } velocityExact[dofIdxGlobal] = velocityVector; } } - this->resultWriter().attachDofData(pExact, "p_exact", false); - this->resultWriter().attachDofData(velocityExact, "velocity_exact", false, dim); } /*! -- GitLab