diff --git a/dumux/implicit/box/volumevariablesvector.hh b/dumux/implicit/box/volumevariablesvector.hh new file mode 100644 index 0000000000000000000000000000000000000000..0b97fdd5c6fe8ec86c8733bf31349937154383df --- /dev/null +++ b/dumux/implicit/box/volumevariablesvector.hh @@ -0,0 +1,521 @@ +// -*- 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 <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \brief Base class for the volume variables vector + */ +#ifndef DUMUX_IMPLICIT_BOX_VOLVARSVECTOR_HH +#define DUMUX_IMPLICIT_BOX_VOLVARSVECTOR_HH + +#include <dumux/implicit/properties.hh> + +namespace Dumux +{ + +/*! + * \ingroup ImplicitModel + * \brief Base class for the volume variables vector + */ +template<class TypeTag, bool useOldSol, bool enableVolVarsCache> +class BoxVolumeVariablesVector +{}; + +// specialization in case of storing the volume variables +template<class TypeTag, bool useOldSol> +class BoxVolumeVariablesVector<TypeTag, useOldSol,/*enableVolVarCaching*/true> : public std::vector<typename GET_PROP_TYPE(TypeTag, VolumeVariables)> +{ + friend BoxVolumeVariablesVector<TypeTag, !useOldSol, true>; + friend ImplicitModel<TypeTag>; + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector); + using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using IndexType = typename GridView::IndexSet::IndexType; + + static const int dim = GridView::dimension; + using Element = typename GridView::template Codim<0>::Entity; + using Vertex = typename GridView::template Codim<dim>::Entity; + + enum{ isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + + BoxVolumeVariablesVector<TypeTag, useOldSol, true>& operator= (const BoxVolumeVariablesVector<TypeTag, useOldSol, true>& other) = default; + + BoxVolumeVariablesVector<TypeTag, useOldSol, true>& operator= (const BoxVolumeVariablesVector<TypeTag, !useOldSol, true>& other) + { + // do the copy + numScvs_ = other.numScvs_; + volumeVariables_ = other.volumeVariables_; + + // return the existing object + return *this; + }; + +public: + void update(Problem& problem, const SolutionVector& sol) + { + problemPtr_ = &problem; + + numScvs_ = problem.model().fvGeometries().numScv(); + volumeVariables_.resize(numScvs_); + for (const auto& element : elements(problem.gridView())) + { + problem.model().fvGeometries_().bindElement(element); + const auto& fvGeometry = problem.model().fvGeometries(element); + + for (const auto& scv : fvGeometry.scvs()) + { + (*this)[scv].update(sol[scv.dofIndex()], + problem, + element, + scv); + } + } + } + + const VolumeVariables& operator [](IndexType scvIdx) const + { + const auto& scv = problem_().model().fvGeometries().subControlVolume(scvIdx); + return (*this)[scv]; + } + + VolumeVariables& operator [](IndexType scvIdx) + { + const auto& scv = problem_().model().fvGeometries().subControlVolume(scvIdx); + return (*this)[scv]; + } + + const VolumeVariables& operator [](const SubControlVolume& scv) const + { + return volumeVariables_[scv.index()]; + } + + VolumeVariables& operator [](const SubControlVolume& scv) + { + return volumeVariables_[scv.index()]; + } + + // For compatibility reasons with the case of not storing the vol vars. + // function to be called before assembling an element, preparing the vol vars within the stencil + void bind(const Element& element) {} + // In the box method, the vol vars within the elements adjacent to a vertex need to be bound + void bind(const Vertex& vertex) {} + // function to prepare the vol vars within the element + void bindElement(const Element& element) {} + +private: + const Problem& problem_() const + { return *problemPtr_; } + + const Problem* problemPtr_; + + IndexType eIdxBound_; + IndexType numScvs_; + std::vector<VolumeVariables> volumeVariables_; +}; + + +// Specialization when the current volume variables are not stored +template<class TypeTag> +class BoxVolumeVariablesVector<TypeTag, /*isOldSol*/false, /*enableVolVarCaching*/false> +{ + // prev vol vars have to be a friend class in order for the assignment operator to work + friend BoxVolumeVariablesVector<TypeTag, true, false>; + friend ImplicitModel<TypeTag>; + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector); + using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using IndexType = typename GridView::IndexSet::IndexType; + + static const int dim = GridView::dimension; + using Element = typename GridView::template Codim<0>::Entity; + using Vertex = typename GridView::template Codim<dim>::Entity; + + BoxVolumeVariablesVector& operator= (const BoxVolumeVariablesVector<TypeTag, /*isOldSol*/false, /*enableVolVarCaching*/false>& other) = default; + + // operator curVolVars = prevVolVars + void operator= (const BoxVolumeVariablesVector<TypeTag, /*isOldSol*/true, /*enableVolVarCaching*/false>& other) + { + eIdxBound_ = -1; + } + + BoxVolumeVariablesVector() : problemPtr_(nullptr), eIdxBound_(-1) {} + + +public: + + void update(Problem& problem, const SolutionVector& sol) + { + problemPtr_ = &problem; + } + + + // Binding of an element, prepares the volume variables within the element stencil + // called by the local jacobian to prepare element assembly + // specialization for cc models + template <typename T = TypeTag> + typename std::enable_if<!GET_PROP_VALUE(T, ImplicitIsBox)>::type + bind(const Element& element) + { + const auto eIdx = problem_().elementMapper().index(element); + if (eIdx == eIdxBound_ && volVarIndices_.size() > 1) + return; + + eIdxBound_ = eIdx; + + // make sure the FVElementGeometry is bound to the element + problem_().model().fvGeometries_().bind(element); + const auto& fvGeometry = problem_().model().fvGeometries(eIdx); + + // stencil information + const auto& elementStencil = problem_().model().stencils(element).elementStencil(); + const auto& neighborStencil = problem_().model().stencils(element).neighborStencil(); + + // maximum number of possible vol vars to be created + const auto numDofs = elementStencil.size();;// + fvGeometry.numScvf(); + + // resize local containers to the required size + volumeVariables_.resize(numDofs); + volVarIndices_.resize(numDofs); + int localIdx = 0; + + // update the volume variables of the element at hand + const auto& scvI = problem_().model().fvGeometries().subControlVolume(eIdx); + const auto& solI = problem_().model().curSol()[eIdx]; + // VolumeVariables tmp; + // tmp.update(solI, problem_(), element, scvI); + volumeVariables_[localIdx].update(solI, problem_(), element, scvI); + volVarIndices_[localIdx] = scvI.index(); + // volumeVariables_.push_back(tmp); + // volVarIndices_.push_back(scvI.index()); + localIdx++; + + // Update the volume variables of the neighboring elements + for (auto globalJ : neighborStencil) + { + const auto& elementJ = problem_().model().fvGeometries().element(globalJ); + const auto& scvJ = problem_().model().fvGeometries().subControlVolume(globalJ); + const auto& solJ = problem_().model().curSol()[globalJ]; + // tmp.update(solJ, problem_(), elementJ, scvJ); + // volumeVariables_.push_back(tmp); + // volVarIndices_.push_back(scvJ.index()); + volumeVariables_[localIdx].update(solJ, problem_(), elementJ, scvJ); + volVarIndices_[localIdx] = scvJ.index(); + localIdx++; + } + + // Update boundary volume variables + for (const auto& scvFace : fvGeometry.scvfs()) + { + // if we are not on a boundary, skip the rest + if (!scvFace.boundary()) + continue; + + // When complex boundary handling is inactive, we only use BC vol vars on pure Dirichlet boundaries + const auto bcTypes = problem_().boundaryTypes(element, scvFace); + if (/*TODO !GET_PROP_VALUE(TypeTag, BoundaryReconstruction) && */bcTypes.hasNeumann() || bcTypes.hasOutflow()) + continue; + + const auto dirichletPriVars = problem_().dirichlet(element, scvFace); + // tmp.update(dirichletPriVars, problem_(), element, scvI); + // volumeVariables_.push_back(tmp); + // volVarIndices_.push_back(scvI.index()); + volumeVariables_.resize(localIdx+1); + volVarIndices_.resize(localIdx+1); + volumeVariables_[localIdx].update(dirichletPriVars, problem_(), element, scvI); + volVarIndices_[localIdx] = scvFace.outsideScvIdx(); + localIdx++; + } + } + + // specialization for box models, simply forwards to the bindElement method + template <typename T = TypeTag> + typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox)>::type + bind(const Element& element) + { + bindElement(element); + } + + // Binding of an element, prepares only the volume variables of the element + // specialization for cc models + template <typename T = TypeTag> + typename std::enable_if<!GET_PROP_VALUE(T, ImplicitIsBox)>::type + bindElement(const Element& element) + { + const auto eIdx = problem_().elementMapper().index(element); + if (eIdx == eIdxBound_ || std::find(volVarIndices_.begin(), volVarIndices_.end(), eIdx) != volVarIndices_.end()) + return; + + volumeVariables_.resize(1); + volVarIndices_.resize(1); + eIdxBound_ = eIdx; + + // make sure the FVElementGeometry is bound to the element + problem_().model().fvGeometries_().bindElement(element); + + // update the volume variables of the element at hand + const auto& scv = problem_().model().fvGeometries().subControlVolume(eIdx); + const auto& sol = problem_().model().curSol()[eIdx]; + volumeVariables_[0].update(sol, problem_(), element, scv); + volVarIndices_[0] = scv.index(); + } + + // In the box method, the vol vars within the elements adjacent to a vertex need to be bound (TODO: IMPLEMENT) + template <typename T = TypeTag> + typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox)>::type + bind(const Vertex& vertex) const {} + + // specialization for box models + template <typename T = TypeTag> + typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox)>::type + bindElement(const Element& element) + { + const auto eIdx = problem_().elementMapper().index(element); + if (eIdx == eIdxBound_) + return; + + eIdxBound_ = eIdx; + + // make sure the FVElementGeometry is bound to the element + problem_().model().fvGeometries_().bind(element); + const auto& fvGeometry = problem_().model().fvGeometries(element); + + // get stencil information + const auto numDofs = element.subEntities(dim); + + // resize volume variables to the required size + volumeVariables_.resize(numDofs); + // volVarIndices_.resize(numDofs); + + int localIdx = 0; + for (const auto& scv : fvGeometry.scvs()) + { + // std::cout << "scv index: " << scv.index() << ", dofIdx: " << scv.dofIndex() << ", localIdx: " << scv.indexInElement() << std::endl; + const auto& sol = problem_().model().curSol()[scv.dofIndex()]; + // let the interface solver update the volvars + // volVarIndices_[localIdx] = scv.index(); + // TODO: INTERFACE SOLVER + // problem_().model().boxInterfaceConditionSolver().updateScvVolVars(element, scv, sol); + volumeVariables_[scv.indexInElement()].update(sol, problem_(), element, scv); + localIdx++; + } + // std::cout << "finished\n"; + } + + const VolumeVariables& operator [](IndexType scvIdx) const + { + return volumeVariables_[scvIdx]; + } + + VolumeVariables& operator [](IndexType scvIdx) + { + return volumeVariables_[scvIdx]; + } + + const VolumeVariables& operator [](const SubControlVolume& scv) const + { + return volumeVariables_[scv.indexInElement()]; + } + + VolumeVariables& operator [](const SubControlVolume& scv) + { + return volumeVariables_[scv.indexInElement()]; + } + +private: + + void release_() + { + volumeVariables_.clear(); + volVarIndices_.clear(); + } + + const int getLocalIdx_(const int volVarIdx) const + { + auto it = std::find(volVarIndices_.begin(), volVarIndices_.end(), volVarIdx); + + if (it != volVarIndices_.end()) + return std::distance(volVarIndices_.begin(), it); + else + DUNE_THROW(Dune::InvalidStateException, "Could not find the current volume variables for volVarIdx = " << volVarIdx << + ", make sure to properly bind the volume variables to the element before using them"); + } + + Problem& problem_() const + { return *problemPtr_;} + + Problem* problemPtr_; + IndexType eIdxBound_; + std::vector<IndexType> volVarIndices_; + std::vector<VolumeVariables> volumeVariables_; +}; + +// Specialization when the previous volume variables are not stored +template<class TypeTag> +class BoxVolumeVariablesVector<TypeTag, /*isOldSol*/true, /*enableVolVarCaching*/false> +{ + // current vol vars have to be a friend class in order for the assignment operator to work + friend BoxVolumeVariablesVector<TypeTag, false, false>; + friend ImplicitModel<TypeTag>; + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector); + using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using IndexType = typename GridView::IndexSet::IndexType; + + static const int dim = GridView::dimension; + using Element = typename GridView::template Codim<0>::Entity; + using Vertex = typename GridView::template Codim<dim>::Entity; + + BoxVolumeVariablesVector& operator= (const BoxVolumeVariablesVector<TypeTag, /*isOldSol*/false, /*enableVolVarCaching*/false>& other) + { + release_(); + problemPtr_ = other.problemPtr_; + eIdxBound_ = -1; + return *this; + } + + BoxVolumeVariablesVector() : problemPtr_(nullptr), eIdxBound_(-1) {} + + +public: + + void update(const Problem& problem, const SolutionVector& sol) + { + problemPtr_ = &problem; + } + + // Binding of an element, prepares the volume variables of only the element + // specialization for cc models + template <typename T = TypeTag> + typename std::enable_if<!GET_PROP_VALUE(T, ImplicitIsBox)>::type + bindElement(const Element& element) + { + const auto eIdx = problem_().elementMapper().index(element); + if (eIdx == eIdxBound_) + return; + + volumeVariables_.resize(1); + volVarIndices_.resize(1); + eIdxBound_ = eIdx; + + // make sure FVElementGeometry is bound to the element + problem_().model().fvGeometries_().bindElement(element); + + // update the volume variables of the element at hand + const auto& scv = problem_().model().fvGeometries().subControlVolume(eIdx); + const auto& sol = problem_().model().prevSol()[eIdx]; + volumeVariables_[0].update(sol, problem_(), element, scv); + volVarIndices_[0] = scv.index(); + } + + // specialization for box models + template <typename T = TypeTag> + typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox)>::type + bindElement(const Element& element) + { + const auto eIdx = problem_().elementMapper().index(element); + if (eIdx == eIdxBound_) + return; + + eIdxBound_ = eIdx; + + // make sure the FVElementGeometry is bound to the element + problem_().model().fvGeometries_().bind(element); + const auto& fvGeometry = problem_().model().fvGeometries(element); + + // get stencil information + const auto numDofs = element.subEntities(dim); + + // resize volume variables to the required size + volumeVariables_.resize(numDofs); + // volVarIndices_.resize(numDofs); + + int localIdx = 0; + for (const auto& scv : fvGeometry.scvs()) + { + const auto& sol = problem_().model().prevSol()[scv.dofIndex()]; + // let the interface solver update the volvars + // volVarIndices_[localIdx] = scv.index(); + //TODO: INTERFACE SOLVER? + // problem_().model().boxInterfaceConditionSolver().updateScvVolVars(element, scv, sol); + volumeVariables_[localIdx].update(sol, problem_(), element, scv); + localIdx++; + } + } + + // In the box method, the vol vars within the elements adjacent to a vertex need to be bound (TODO: IMPLEMENT) + template <typename T = TypeTag> + typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox)>::type + bind(const Vertex& vertex) const {} + + // const VolumeVariables& operator [](IndexType scvIdx) const + // { + // return volumeVariables_[getLocalIdx_(scvIdx)]; + // } + + // VolumeVariables& operator [](IndexType scvIdx) + // { + // return volumeVariables_[getLocalIdx_(scvIdx)]; + // } + + const VolumeVariables& operator [](const SubControlVolume& scv) const + { + return volumeVariables_[scv.indexInElement()]; + } + + VolumeVariables& operator [](const SubControlVolume& scv) + { + return volumeVariables_[scv.indexInElement()]; + } + +private: + + void release_() + { + volumeVariables_.clear(); + volVarIndices_.clear(); + } + + const int getLocalIdx_(const int volVarIdx) const + { + auto it = std::find(volVarIndices_.begin(), volVarIndices_.end(), volVarIdx); + + if (it != volVarIndices_.end()) + return std::distance(volVarIndices_.begin(), it); + else + DUNE_THROW(Dune::InvalidStateException, "Could not find the previous volume variables for volVarIdx = " << volVarIdx << + ", make sure to properly bind the volume variables to the element before using them"); + } + + Problem& problem_() const + { return *problemPtr_;} + + Problem* problemPtr_; + IndexType eIdxBound_; + std::vector<IndexType> volVarIndices_; + std::vector<VolumeVariables> volumeVariables_; +}; + +} // end namespace + +#endif