// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /***************************************************************************** * See the file COPYING for full copying permissions. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * *****************************************************************************/ /*! * \file * \ingroup InputOutput * \brief A VTK output module to simplify writing dumux simulation data to VTK format. Specialization for staggered grids with dofs on faces. */ #ifndef DUMUX_STAGGERED_VTK_OUTPUT_MODULE_HH #define DUMUX_STAGGERED_VTK_OUTPUT_MODULE_HH #include #include #include #include namespace Dumux { template class PointCloudVtkWriter; /*! * \ingroup InputOutput * \brief A VTK output module to simplify writing dumux simulation data to VTK format * Specialization for staggered grids with dofs on faces. */ template class StaggeredVtkOutputModule : public VtkOutputModule { friend class VtkOutputModule; using ParentType = VtkOutputModule; using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry); using GridVariables = typename GET_PROP_TYPE(TypeTag, GridVariables); using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector); using FaceVariables = typename GET_PROP_TYPE(TypeTag, FaceVariables); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); enum { dim = GridView::dimension }; enum { dimWorld = GridView::dimensionworld }; using GlobalPosition = Dune::FieldVector; using DofTypeIndices = typename GET_PROP(TypeTag, DofTypeIndices); typename DofTypeIndices::CellCenterIdx cellCenterIdx; typename DofTypeIndices::FaceIdx faceIdx; struct FaceVarScalarDataInfo { std::function get; std::string name; }; struct FaceVarVectorDataInfo { std::function get; std::string name; }; struct FaceFieldScalarDataInfo { FaceFieldScalarDataInfo(const std::vector& f, const std::string& n) : data(f), name(n) {} const std::vector& data; const std::string name; }; struct FaceFieldVectorDataInfo { FaceFieldVectorDataInfo(const std::vector& f, const std::string& n) : data(f), name(n) {} const std::vector& data; const std::string name; }; public: StaggeredVtkOutputModule(const Problem& problem, const FVGridGeometry& fvGridGeometry, const GridVariables& gridVariables, const SolutionVector& sol, const std::string& name, bool verbose = true, Dune::VTK::DataMode dm = Dune::VTK::conforming) : ParentType(problem, fvGridGeometry, gridVariables, sol, name, verbose, dm) , problem_(problem) , gridGeom_(fvGridGeometry) , gridVariables_(gridVariables) , sol_(sol) , faceWriter_(std::make_shared>(coordinates_)) , sequenceWriter_(faceWriter_, problem.name() + "-face", "","", fvGridGeometry.gridView().comm().rank(), fvGridGeometry.gridView().comm().size() ) { writeFaceVars_ = getParamFromGroup(GET_PROP_VALUE(TypeTag, ModelParameterGroup), "Vtk.WriteFaceData", false); coordinatesInitialized_ = false; } ////////////////////////////////////////////////////////////////////////////////////////////// //! Methods to conveniently add face variables //! Do not call these methods after initialization ////////////////////////////////////////////////////////////////////////////////////////////// //! Add a scalar valued field //! \param v The field to be added //! \param name The name of the vtk field void addFaceField(const std::vector& v, const std::string& name) { if (v.size() == this->gridGeom_.gridView().size(1)) faceFieldScalarDataInfo_.emplace_back(v, name); else DUNE_THROW(Dune::RangeError, "Size mismatch of added field!"); } //! Add a vector valued field //! \param v The field to be added //! \param name The name of the vtk field void addFaceField(const std::vector& v, const std::string& name) { if (v.size() == this->gridGeom_.gridView().size(1)) faceFieldVectorDataInfo_.emplace_back(v, name); else DUNE_THROW(Dune::RangeError, "Size mismatch of added field!"); } //! Add a scalar-valued faceVarible //! \param f A function taking a FaceVariables object and returning the desired scalar //! \param name The name of the vtk field void addFaceVariable(std::function&& f, const std::string& name) { faceVarScalarDataInfo_.push_back(FaceVarScalarDataInfo{f, name}); } //! Add a vector-valued faceVarible //! \param f A function taking a SubControlVolumeFace and FaceVariables object and returning the desired vector //! \param name The name of the vtk field void addFaceVariable(std::function&& f, const std::string& name) { faceVarVectorDataInfo_.push_back(FaceVarVectorDataInfo{f, name}); } //! Write the values to vtp files //! \param time The current time //! \param type The output type void write(double time, Dune::VTK::OutputType type = Dune::VTK::ascii) { ParentType::write(time, type); if(writeFaceVars_) getFaceDataAndWrite_(time); } private: //! Update the coordinates (the face centers) void updateCoordinates_() { coordinates_.resize(gridGeom_.numFaceDofs()); for(auto&& facet : facets(gridGeom_.gridView())) { const int dofIdxGlobal = gridGeom_.gridView().indexSet().index(facet); coordinates_[dofIdxGlobal] = facet.geometry().center(); } coordinatesInitialized_ = true; } //! Gathers all face-related data and invokes the face vtk-writer using these data. //! \param time The current time void getFaceDataAndWrite_(const Scalar time) { const auto numPoints = gridGeom_.numFaceDofs(); // make sure not to iterate over the same dofs twice std::vector dofVisited(numPoints, false); // get fields for all primary coordinates and variables if(!coordinatesInitialized_) updateCoordinates_(); // prepare some containers to store the relevant data std::vector> faceVarScalarData; std::vector> faceVarVectorData; if(!faceVarScalarDataInfo_.empty()) faceVarScalarData.resize(faceVarScalarDataInfo_.size(), std::vector(numPoints)); if(!faceVarVectorDataInfo_.empty()) faceVarVectorData.resize(faceVarVectorDataInfo_.size(), std::vector(numPoints)); for (const auto& element : elements(gridGeom_.gridView(), Dune::Partitions::interior)) { auto fvGeometry = localView(gridGeom_); auto elemFaceVars = localView(gridVariables_.curGridFaceVars()); if (!faceVarScalarDataInfo_.empty() || !faceVarVectorDataInfo_.empty()) { fvGeometry.bind(element); elemFaceVars.bindElement(element, fvGeometry, sol_); for (auto&& scvf : scvfs(fvGeometry)) { const auto dofIdxGlobal = scvf.dofIndex(); if(dofVisited[dofIdxGlobal]) continue; dofVisited[dofIdxGlobal] = true; const auto& faceVars = elemFaceVars[scvf]; // get the scalar-valued data for (std::size_t i = 0; i < faceVarScalarDataInfo_.size(); ++i) faceVarScalarData[i][dofIdxGlobal] = faceVarScalarDataInfo_[i].get(faceVars); // get the vector-valued data for (std::size_t i = 0; i < faceVarVectorDataInfo_.size(); ++i) faceVarVectorData[i][dofIdxGlobal] = faceVarVectorDataInfo_[i].get(scvf, faceVars); } } } // transfer the data to the point writer if(!faceVarScalarDataInfo_.empty()) for (std::size_t i = 0; i < faceVarScalarDataInfo_.size(); ++i) faceWriter_->addPointData(faceVarScalarData[i], faceVarScalarDataInfo_[i].name); if(!faceVarVectorDataInfo_.empty()) for (std::size_t i = 0; i < faceVarVectorDataInfo_.size(); ++i) faceWriter_->addPointData(faceVarVectorData[i], faceVarVectorDataInfo_[i].name); // account for the custom fields for(const auto& field: faceFieldScalarDataInfo_) faceWriter_->addPointData(field.data, field.name); for(const auto& field: faceFieldVectorDataInfo_) faceWriter_->addPointData(field.data, field.name); // write for the current time step sequenceWriter_.write(time); // clear coordinates to save some memory coordinates_.clear(); coordinates_.shrink_to_fit(); coordinatesInitialized_ = false; } const Problem& problem_; const FVGridGeometry& gridGeom_; const GridVariables& gridVariables_; const SolutionVector& sol_; std::shared_ptr> faceWriter_; VTKSequenceWriter> sequenceWriter_; bool writeFaceVars_; std::vector coordinates_; bool coordinatesInitialized_; std::vector faceVarScalarDataInfo_; std::vector faceVarVectorDataInfo_; std::vector faceFieldScalarDataInfo_; std::vector faceFieldVectorDataInfo_; }; } // end namespace Dumux #endif