diff --git a/dumux/discretization/staggered/darcyslaw.hh b/dumux/discretization/staggered/darcyslaw.hh index 06c5d58d1cf646f0ac88e5a217b775ceb3d98476..a9d6fdf3aa580549544f00a86531dc22b56a9c9f 100644 --- a/dumux/discretization/staggered/darcyslaw.hh +++ b/dumux/discretization/staggered/darcyslaw.hh @@ -80,67 +80,81 @@ public: int phaseIdx, const FluxVarsCache& fluxVarsCache) { - const auto& tij = fluxVarsCache.tij(); - - // Get the inside and outside volume variables - const auto& insideScv = fvGeometry.scv(scvFace.insideScvIdx()); - const auto& insideVolVars = elemVolVars[insideScv]; - const auto& outsideVolVars = elemVolVars[scvFace.outsideScvIdx()]; - - auto hInside = insideVolVars.pressure(phaseIdx); - auto hOutside = outsideVolVars.pressure(phaseIdx); - - if (GET_PARAM_FROM_GROUP(TypeTag, bool, Problem, EnableGravity)) - { - // do averaging for the density - const auto rhoInside = insideVolVars.density(phaseIdx); - const auto rhoOutide = outsideVolVars.density(phaseIdx); - const auto rho = (rhoInside + rhoOutide)*0.5; - - // ask for the gravitational acceleration in the inside neighbor - const auto xInside = insideScv.center(); - const auto gInside = problem.gravityAtPos(xInside); - - hInside -= rho*(gInside*xInside); - - // and the outside neighbor - if (scvFace.boundary()) - { - const auto xOutside = scvFace.center(); - const auto gOutside = problem.gravityAtPos(xOutside); - hOutside -= rho*(gOutside*xOutside); - } - else - { - const auto outsideScvIdx = scvFace.outsideScvIdx(); - // as we assemble fluxes from the neighbor to our element the outside index - // refers to the scv of our element, so we use the scv method - const auto& outsideScv = fvGeometry.scv(outsideScvIdx); - const auto xOutside = outsideScv.center(); - const auto gOutside = problem.gravityAtPos(xOutside); - hOutside -= rho*(gOutside*xOutside); - } - } - - return tij*(hInside - hOutside); +// const auto& tij = fluxVarsCache.tij(); +// +// // Get the inside and outside volume variables +// const auto& insideScv = fvGeometry.scv(scvFace.insideScvIdx()); +// const auto& insideVolVars = elemVolVars[insideScv]; +// const auto& outsideVolVars = elemVolVars[scvFace.outsideScvIdx()]; +// +// auto hInside = insideVolVars.pressure(phaseIdx); +// auto hOutside = outsideVolVars.pressure(phaseIdx); +// +// if (GET_PARAM_FROM_GROUP(TypeTag, bool, Problem, EnableGravity)) +// { +// // do averaging for the density +// const auto rhoInside = insideVolVars.density(phaseIdx); +// const auto rhoOutide = outsideVolVars.density(phaseIdx); +// const auto rho = (rhoInside + rhoOutide)*0.5; +// +// // ask for the gravitational acceleration in the inside neighbor +// const auto xInside = insideScv.center(); +// const auto gInside = problem.gravityAtPos(xInside); +// +// hInside -= rho*(gInside*xInside); +// +// // and the outside neighbor +// if (scvFace.boundary()) +// { +// const auto xOutside = scvFace.center(); +// const auto gOutside = problem.gravityAtPos(xOutside); +// hOutside -= rho*(gOutside*xOutside); +// } +// else +// { +// const auto outsideScvIdx = scvFace.outsideScvIdx(); +// // as we assemble fluxes from the neighbor to our element the outside index +// // refers to the scv of our element, so we use the scv method +// const auto& outsideScv = fvGeometry.scv(outsideScvIdx); +// const auto xOutside = outsideScv.center(); +// const auto gOutside = problem.gravityAtPos(xOutside); +// hOutside -= rho*(gOutside*xOutside); +// } +// } +// +// const GlobalPosition vector = {1,0}; +// const Scalar angle = std::acos(scvFace.unitOuterNormal() * vector / scvFace.unitOuterNormal().two_norm() / vector.two_norm())*180.0/M_PI; +// const Scalar threshold = 1e-6; +// +// if(std::abs(angle) < threshold) + return 1.0; +// // else if(std::abs(angle-180) < threshold) +// // return -1.0; +// else +// return 0; +// +// // if(std::abs(angle) < threshold || std::abs(angle-180) < threshold) +// // return tij*(hInside - hOutside); +// // std::cout << "normal " << scvFace.unitOuterNormal() << std::endl; +// } - static Stencil stencil(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const SubControlVolumeFace& scvFace) - { - Stencil stencil; - if (!scvFace.boundary()) - { - stencil.push_back(scvFace.insideScvIdx()); - stencil.push_back(scvFace.outsideScvIdx()); - } - else - stencil.push_back(scvFace.insideScvIdx()); - - return stencil; - } +// static Stencil pressureStencil(const Problem& problem, +// const Element& element, +// const FVElementGeometry& fvGeometry, +// const SubControlVolumeFace& scvFace) +// { +// Stencil pressureStencil; +// if (!scvFace.boundary()) +// { +// pressureStencil.push_back(scvFace.insideScvIdx()); +// pressureStencil.push_back(scvFace.outsideScvIdx()); +// } +// else +// pressureStencil.push_back(scvFace.insideScvIdx()); +// +// return pressureStencil; +// } // The flux variables cache has to be bound to an element prior to flux calculations // During the binding, the transmissibilities will be computed and stored using the method below. diff --git a/dumux/discretization/staggered/stencils.hh b/dumux/discretization/staggered/stencils.hh new file mode 100644 index 0000000000000000000000000000000000000000..a51d5bf075a52c75f506fc9f21eeb95ff885cbeb --- /dev/null +++ b/dumux/discretization/staggered/stencils.hh @@ -0,0 +1,228 @@ +// -*- 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 Implements the notion of stencils for cell-centered models + */ +#ifndef DUMUX_DISCRETIZATION_STAGGERED_STENCILS_HH +#define DUMUX_DISCRETIZATION_STAGGERED_STENCILS_HH + +#include <set> +#include <dumux/implicit/cellcentered/properties.hh> + +namespace Dumux +{ + +/*! + * \brief Element-related stencils + */ +template<class TypeTag> +class StaggeredCellCenterStencils +{ + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using IndexType = typename GridView::IndexSet::IndexType; + using Element = typename GridView::template Codim<0>::Entity; + // TODO a separate stencil class all stencils can derive from? + using Stencil = std::vector<IndexType>; +public: + //! Update the stencil. We expect a bound fvGeometry + void update(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry) + { + elementStencil_.clear(); + + // loop over sub control faces + for (auto&& scvf : scvfs(fvGeometry)) + { + FluxVariables fluxVars; + const auto& centerStencil = fluxVars.computeCellCenterStencil(problem, element, fvGeometry, scvf); + elementStencil_.insert(elementStencil_.end(), centerStencil.begin(), centerStencil.end()); + } + // make values in elementstencil unique + std::sort(elementStencil_.begin(), elementStencil_.end()); + elementStencil_.erase(std::unique(elementStencil_.begin(), elementStencil_.end()), elementStencil_.end()); + + auto globalI = problem.elementMapper().index(element); + neighborStencil_ = elementStencil_; + + // remove the element itself and possible ghost neighbors from the neighbor stencil + neighborStencil_.erase(std::remove_if(neighborStencil_.begin(), neighborStencil_.end(), + [globalI](int i){ return (i == globalI); }), + neighborStencil_.end()); + } + + //! The full element stencil (all element this element is interacting with) + const Stencil& elementStencil() const + { + return elementStencil_; + } + + //! The full element stencil without this element + const Stencil& neighborStencil() const + { + return neighborStencil_; + } + +private: + Stencil elementStencil_; + Stencil neighborStencil_; +}; + +template<class TypeTag> +class StaggeredFaceStencils +{ + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using IndexType = typename GridView::IndexSet::IndexType; + using Element = typename GridView::template Codim<0>::Entity; + // TODO a separate stencil class all stencils can derive from? + using Stencil = std::vector<IndexType>; + +public: + void update(const Problem& problem, + const SubControlVolumeFace& scvf) + { + faceStencil_.clear(); + FluxVariables fluxVars; + + const auto& faceStencil = fluxVars.computeFaceStencil(problem, scvf); + faceStencil_.insert(faceStencil_.end(), faceStencil.begin(), faceStencil.end()); + std::sort(faceStencil_.begin(), faceStencil_.end()); + faceStencil_.erase(std::unique(faceStencil_.begin(), faceStencil_.end()), faceStencil_.end()); + } + + //! The full face stencil (all dofs this face is interacting with) + const Stencil& faceStencil() const + { + return faceStencil_; + } + +private: + Stencil faceStencil_; +}; + + +/*! + * \ingroup CCModel + * \brief The global stencil container class + */ +template<class TypeTag> +class StaggeredStencilsVector +{ + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using StencilType = StaggeredCellCenterStencils<TypeTag>; + using Element = typename GridView::template Codim<0>::Entity; + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using IndexType = typename GridView::IndexSet::IndexType; + using Stencil = std::vector<IndexType>; + + +public: + void update(Problem& problem) + { + problemPtr_ = &problem; + + const IndexType numElements = problem.gridView().size(0); + const IndexType numFacets = problem.gridView().size(1); + const IndexType numBoundaryFacets = problem.gridView().grid().numBoundarySegments(); + elementStencils_.resize(numElements); + faceStencils_.resize(2*numFacets - numBoundaryFacets); + + std::vector<Stencil> fullFaceStencils; + fullFaceStencils.resize(numFacets); + + for (const auto& element : elements(problem.gridView())) + { + auto eIdx = problem.elementMapper().index(element); + // restrict the FvGeometry locally and bind to the element + auto fvGeometry = localView(problem.model().globalFvGeometry()); + fvGeometry.bindElement(element); // for TPFA bind element is enough + elementStencils_[eIdx].update(problem, element, fvGeometry); + + // loop over sub control faces + for (auto&& scvf : scvfs(fvGeometry)) + { + faceStencils_[scvf.index()].update(problem, scvf); + + const IndexType idx = scvf.dofIndexSelf() - numElements; + const auto& faceStencil = faceStencils_[scvf.index()].faceStencil(); + fullFaceStencils[idx].insert(fullFaceStencils[idx].end(), faceStencil.begin(), faceStencil.end()); + std::sort(fullFaceStencils[idx].begin(), fullFaceStencils[idx].end()); + fullFaceStencils[idx].erase(std::unique(fullFaceStencils[idx].begin(), fullFaceStencils[idx].end()), fullFaceStencils[idx].end()); + } + } + // TODO: is this a good idea? + fullFaceDofStencils_ = std::make_unique<decltype(fullFaceStencils)>(fullFaceStencils); + } + + + //! overload for elements + auto& get(const Element& entity) const + { + return elementStencils_[problemPtr_->elementMapper().index(entity)]; + } + + //! overload for faces + auto& get(const SubControlVolumeFace& scvFace) const + { + const IndexType numElements = problemPtr_->gridView().size(0); + return faceStencils_[scvFace.dofIndexSelf() - numElements]; + } + + size_t completeFaceDofStencilSize(const int idx) const + { +// const IndexType numElements = problemPtr_->gridView().size(0); + return fullFaceDofStencils_.get()[0][idx/*-numElements*/].size(); + // TODO: why does this not work? + } + + void getFullFaceDofStencils(std::unique_ptr<std::vector<Stencil>>& ptr) + { + std::cout << "before move: "; + if(fullFaceDofStencils_) + std::cout << "object still there" << std::endl; + ptr = std::move(fullFaceDofStencils_); + + std::cout << "after move: "; + if(fullFaceDofStencils_) + std::cout << "object still there" << std::endl; + } + + +private: + std::vector<StaggeredCellCenterStencils<TypeTag>> elementStencils_; + std::vector<StaggeredFaceStencils<TypeTag>> faceStencils_; + std::unique_ptr<std::vector<Stencil>> fullFaceDofStencils_; + + + const Problem* problemPtr_; +}; + +} // end namespace + +#endif diff --git a/dumux/discretization/staggered/subcontrolvolumeface.hh b/dumux/discretization/staggered/subcontrolvolumeface.hh index 9ab065a2812eedecd366e3b07cab422d2b4da86d..2dd1b61f0b84f58edda97365f0ecc8bc3260bc58 100644 --- a/dumux/discretization/staggered/subcontrolvolumeface.hh +++ b/dumux/discretization/staggered/subcontrolvolumeface.hh @@ -214,6 +214,11 @@ public: return pairData_[idx]; } + auto& pairData() const + { + return pairData_; + } + private: Dune::GeometryType geomType_; std::vector<GlobalPosition> corners_; diff --git a/dumux/freeflow/CMakeLists.txt b/dumux/freeflow/CMakeLists.txt index 2793132c662d2bdd130b378e77e474f388ce2430..aff2016afb1aa6c9440e1850b201fb6bcc4b1c05 100644 --- a/dumux/freeflow/CMakeLists.txt +++ b/dumux/freeflow/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory("staggered") add_subdirectory("stokes") add_subdirectory("stokesnc") add_subdirectory("stokesncni") diff --git a/dumux/freeflow/staggered/CMakeLists.txt b/dumux/freeflow/staggered/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8baf812d982cc188659813332319df4a48e74783 --- /dev/null +++ b/dumux/freeflow/staggered/CMakeLists.txt @@ -0,0 +1,10 @@ + +#install headers +install(FILES +indices.hh +localresidual.hh +model.hh +properties.hh +propertydefaults.hh +volumevariables.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/porousmediumflow/1p/implicit) diff --git a/dumux/freeflow/staggered/fluxvariables.hh b/dumux/freeflow/staggered/fluxvariables.hh new file mode 100644 index 0000000000000000000000000000000000000000..5107f731df43734153610e68cd89a3f7f6e59e42 --- /dev/null +++ b/dumux/freeflow/staggered/fluxvariables.hh @@ -0,0 +1,466 @@ +// -*- 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 flux variables + */ +#ifndef DUMUX_FREELOW_IMPLICIT_FLUXVARIABLES_HH +#define DUMUX_FREELOW_IMPLICIT_FLUXVARIABLES_HH + +#include <dumux/implicit/properties.hh> +#include <dumux/discretization/fluxvariablesbase.hh> + +namespace Dumux +{ + +namespace Properties +{ +// forward declaration +NEW_PROP_TAG(NumPhases); +NEW_PROP_TAG(EnableAdvection); +NEW_PROP_TAG(EnableMolecularDiffusion); +NEW_PROP_TAG(EnableEnergyBalance); +} + +// forward declaration +template<class TypeTag, bool enableAdvection, bool enableMolecularDiffusion, bool enableEnergyBalance> +class FreeFlowFluxVariablesImpl; + +/*! + * \ingroup ImplicitModel + * \brief The flux variables class + * specializations are provided for combinations of physical processes + * \note Not all specializations are currently implemented + */ +template<class TypeTag> +using FreeFlowFluxVariables = FreeFlowFluxVariablesImpl<TypeTag, GET_PROP_VALUE(TypeTag, EnableAdvection), + GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion), + GET_PROP_VALUE(TypeTag, EnableEnergyBalance)>; + + +// specialization for pure advective flow (e.g. 1p/2p/3p immiscible darcy flow) +template<class TypeTag> +class FreeFlowFluxVariablesImpl<TypeTag, true, false, false> +: public FluxVariablesBase<TypeTag, FreeFlowFluxVariablesImpl<TypeTag, true, false, false>> +{ + using ParentType = FluxVariablesBase<TypeTag, FreeFlowFluxVariablesImpl<TypeTag, true, false, false>>; + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using Element = typename GridView::template Codim<0>::Entity; + using IndexType = typename GridView::IndexSet::IndexType; + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using Stencil = std::vector<IndexType>; + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); + using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); + using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); + +public: + + void initAndComputeFluxes(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvFace, + const FluxVariablesCache& fluxVarsCache) + { + ParentType::init(problem, element, fvGeometry, elemVolVars, scvFace, fluxVarsCache); + } + + template<typename FunctionType> + Scalar advectiveFlux(const int phaseIdx, const FunctionType& upwindFunction) + { + Scalar flux = AdvectionType::flux(this->problem(), + this->element(), + this->fvGeometry(), + this->elemVolVars(), + this->scvFace(), + phaseIdx, + this->fluxVarsCache()); + + const auto& insideScv = this->fvGeometry().scv(this->scvFace().insideScvIdx()); + const auto& insideVolVars = this->elemVolVars()[insideScv]; + const auto& outsideVolVars = this->elemVolVars()[this->scvFace().outsideScvIdx()]; + + if (std::signbit(flux)) + return flux*upwindFunction(outsideVolVars, insideVolVars); + else + return flux*upwindFunction(insideVolVars, outsideVolVars); + } + + Stencil computeCellCenterStencil(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvFace) + { + Stencil cellCenterStencil; + if (!scvFace.boundary()) + { + // the cell center dof indices + cellCenterStencil.push_back(scvFace.insideScvIdx()); + cellCenterStencil.push_back(scvFace.outsideScvIdx()); + + // the face dof indices + cellCenterStencil.push_back(scvFace.dofIndexSelf()); + } + else + cellCenterStencil.push_back(scvFace.insideScvIdx()); + + return cellCenterStencil; + } + + Stencil computeFaceStencil(const Problem& problem, + const SubControlVolumeFace& scvFace) + { + Stencil faceStencil; + if (!scvFace.boundary()) + { + // the cell center dof indices normal to the face + faceStencil.push_back(scvFace.insideScvIdx()); + faceStencil.push_back(scvFace.outsideScvIdx()); + + // the cell center dof indices parallel to the face + for(const auto& data : scvFace.pairData()) + { + faceStencil.push_back(data.outerParallelElementDofIdx); + faceStencil.push_back(data.outerParallelFaceDofIdx); + faceStencil.push_back(data.normalPair.first); + faceStencil.push_back(data.normalPair.second); + } + + // the face dof indices + faceStencil.push_back(scvFace.dofIndexSelf()); + faceStencil.push_back(scvFace.dofIndexOpposite()); + } + else + faceStencil.push_back(scvFace.dofIndexSelf()); + + return faceStencil; + } +}; + + +// specialization for isothermal advection molecularDiffusion equations +template<class TypeTag> +class FreeFlowFluxVariablesImpl<TypeTag, true, true, false> +: public FluxVariablesBase<TypeTag, FreeFlowFluxVariablesImpl<TypeTag, true, true, false>> +{ + using ParentType = FluxVariablesBase<TypeTag, FreeFlowFluxVariablesImpl<TypeTag, true, true, false>>; + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using Element = typename GridView::template Codim<0>::Entity; + using IndexType = typename GridView::IndexSet::IndexType; + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using Stencil = std::vector<IndexType>; + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); + + using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); + using MolecularDiffusionType = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType); + + enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; + +public: + + void initAndComputeFluxes(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvFace, + const FluxVariablesCache& fluxVarsCache) + { + advFluxCached_.reset(); + ParentType::init(problem, element, fvGeometry, elemVolVars, scvFace, fluxVarsCache); + } + + template<typename FunctionType> + Scalar advectiveFlux(const int phaseIdx, const FunctionType& upwindFunction) + { + if (!advFluxCached_[phaseIdx]) + { + + advPreFlux_[phaseIdx] = AdvectionType::flux(this->problem(), + this->element(), + this->fvGeometry(), + this->elemVolVars(), + this->scvFace(), + phaseIdx, + this->fluxVarsCache()); + advFluxCached_.set(phaseIdx, true); + } + + + + const auto& insideScv = this->fvGeometry().scv(this->scvFace().insideScvIdx()); + const auto& insideVolVars = this->elemVolVars()[insideScv]; + const auto& outsideVolVars = this->elemVolVars()[this->scvFace().outsideScvIdx()]; + + if (std::signbit(advPreFlux_[phaseIdx])) + return advPreFlux_[phaseIdx]*upwindFunction(outsideVolVars, insideVolVars); + else + return advPreFlux_[phaseIdx]*upwindFunction(insideVolVars, outsideVolVars); + } + + Scalar molecularDiffusionFlux(const int phaseIdx, const int compIdx) + { + Scalar flux = MolecularDiffusionType::flux(this->problem(), + this->element(), + this->fvGeometry(), + this->elemVolVars(), + this->scvFace(), + phaseIdx, compIdx, + this->fluxVarsCache()); + return flux; + } + + Stencil computeStencil(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvFace) + { + // unifiy advective and diffusive stencil + Stencil stencil = AdvectionType::stencil(problem, element, fvGeometry, scvFace); + Stencil diffusionStencil = MolecularDiffusionType::stencil(problem, element, fvGeometry, scvFace); + + stencil.insert(stencil.end(), diffusionStencil.begin(), diffusionStencil.end()); + std::sort(stencil.begin(), stencil.end()); + stencil.erase(std::unique(stencil.begin(), stencil.end()), stencil.end()); + + return stencil; + } +private: + //! simple caching if advection flux is used twice with different upwind function + std::bitset<numPhases> advFluxCached_; + std::array<Scalar, numPhases> advPreFlux_; +}; + +// specialization for non-isothermal advective flow (e.g. non-isothermal one-phase darcy equation) +template<class TypeTag> +class FreeFlowFluxVariablesImpl<TypeTag, true, false, true> +: public FluxVariablesBase<TypeTag, FreeFlowFluxVariablesImpl<TypeTag, true, false, true>> +{ + using ParentType = FluxVariablesBase<TypeTag, FreeFlowFluxVariablesImpl<TypeTag, true, false, true>>; + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using Element = typename GridView::template Codim<0>::Entity; + using IndexType = typename GridView::IndexSet::IndexType; + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using Stencil = std::vector<IndexType>; + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); + + using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); + using HeatConductionType = typename GET_PROP_TYPE(TypeTag, HeatConductionType); + + enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; + +public: + + void initAndComputeFluxes(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvFace, + const FluxVariablesCache& fluxVarsCache) + { + advFluxCached_.reset(); + ParentType::init(problem, element, fvGeometry, elemVolVars, scvFace, fluxVarsCache); + } + + template<typename FunctionType> + Scalar advectiveFlux(const int phaseIdx, const FunctionType& upwindFunction) + { + if (!advFluxCached_[phaseIdx]) + { + + advPreFlux_[phaseIdx] = AdvectionType::flux(this->problem(), + this->element(), + this->fvGeometry(), + this->elemVolVars(), + this->scvFace(), + phaseIdx, + this->fluxVarsCache()); + advFluxCached_.set(phaseIdx, true); + } + + + + const auto& insideScv = this->fvGeometry().scv(this->scvFace().insideScvIdx()); + const auto& insideVolVars = this->elemVolVars()[insideScv]; + const auto& outsideVolVars = this->elemVolVars()[this->scvFace().outsideScvIdx()]; + + if (std::signbit(advPreFlux_[phaseIdx])) + return advPreFlux_[phaseIdx]*upwindFunction(outsideVolVars, insideVolVars); + else + return advPreFlux_[phaseIdx]*upwindFunction(insideVolVars, outsideVolVars); + } + + Scalar heatConductionFlux() + { + Scalar flux = HeatConductionType::flux(this->problem(), + this->element(), + this->fvGeometry(), + this->elemVolVars(), + this->scvFace(), + this->fluxVarsCache()); + return flux; + } + + Stencil computeStencil(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvFace) + { + // unifiy advective and diffusive stencil + Stencil stencil = AdvectionType::stencil(problem, element, fvGeometry, scvFace); + Stencil energyStencil = HeatConductionType::stencil(problem, element, fvGeometry, scvFace); + + stencil.insert(stencil.end(), energyStencil.begin(), energyStencil.end()); + std::sort(stencil.begin(), stencil.end()); + stencil.erase(std::unique(stencil.begin(), stencil.end()), stencil.end()); + + return stencil; + } + +private: + //! simple caching if advection flux is used twice with different upwind function + std::bitset<numPhases> advFluxCached_; + std::array<Scalar, numPhases> advPreFlux_; +}; + +// specialization for non-isothermal advection and difussion equations (e.g. non-isothermal three-phase three-component flow) +template<class TypeTag> +class FreeFlowFluxVariablesImpl<TypeTag, true, true, true> +: public FluxVariablesBase<TypeTag, FreeFlowFluxVariablesImpl<TypeTag, true, true, true>> +{ + using ParentType = FluxVariablesBase<TypeTag, FreeFlowFluxVariablesImpl<TypeTag, true, true, true>>; + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using Element = typename GridView::template Codim<0>::Entity; + using IndexType = typename GridView::IndexSet::IndexType; + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using Stencil = std::vector<IndexType>; + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); + + using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); + using MolecularDiffusionType = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType); + using HeatConductionType = typename GET_PROP_TYPE(TypeTag, HeatConductionType); + + enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; + +public: + + void initAndComputeFluxes(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvFace, + const FluxVariablesCache& fluxVarsCache) + { + advFluxCached_.reset(); + ParentType::init(problem, element, fvGeometry, elemVolVars, scvFace, fluxVarsCache); + } + + template<typename FunctionType> + Scalar advectiveFlux(const int phaseIdx, const FunctionType& upwindFunction) + { + if (!advFluxCached_[phaseIdx]) + { + + advPreFlux_[phaseIdx] = AdvectionType::flux(this->problem(), + this->element(), + this->fvGeometry(), + this->elemVolVars(), + this->scvFace(), + phaseIdx, + this->fluxVarsCache()); + advFluxCached_.set(phaseIdx, true); + } + + + + const auto& insideScv = this->fvGeometry().scv(this->scvFace().insideScvIdx()); + const auto& insideVolVars = this->elemVolVars()[insideScv]; + const auto& outsideVolVars = this->elemVolVars()[this->scvFace().outsideScvIdx()]; + + if (std::signbit(advPreFlux_[phaseIdx])) + return advPreFlux_[phaseIdx]*upwindFunction(outsideVolVars, insideVolVars); + else + return advPreFlux_[phaseIdx]*upwindFunction(insideVolVars, outsideVolVars); + } + + Scalar molecularDiffusionFlux(const int phaseIdx, const int compIdx) + { + Scalar flux = MolecularDiffusionType::flux(this->problem(), + this->element(), + this->fvGeometry(), + this->elemVolVars(), + this->scvFace(), + phaseIdx, compIdx, + this->fluxVarsCache()); + return flux; + } + + Scalar heatConductionFlux() + { + Scalar flux = HeatConductionType::flux(this->problem(), + this->element(), + this->fvGeometry(), + this->elemVolVars(), + this->scvFace(), + this->fluxVarsCache()); + return flux; + } + + Stencil computeStencil(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvFace) + { + // unifiy advective and diffusive stencil + Stencil stencil = AdvectionType::stencil(problem, element, fvGeometry, scvFace); + Stencil diffusionStencil = MolecularDiffusionType::stencil(problem, element, fvGeometry, scvFace); + Stencil energyStencil = HeatConductionType::stencil(problem, element, fvGeometry, scvFace); + + stencil.insert(stencil.end(), diffusionStencil.begin(), diffusionStencil.end()); + stencil.insert(stencil.end(), energyStencil.begin(), energyStencil.end()); + std::sort(stencil.begin(), stencil.end()); + stencil.erase(std::unique(stencil.begin(), stencil.end()), stencil.end()); + + return stencil; + } + +private: + //! simple caching if advection flux is used twice with different upwind function + std::bitset<numPhases> advFluxCached_; + std::array<Scalar, numPhases> advPreFlux_; +}; + +} // end namespace + +#endif diff --git a/dumux/freeflow/staggered/fluxvariablescache.hh b/dumux/freeflow/staggered/fluxvariablescache.hh new file mode 100644 index 0000000000000000000000000000000000000000..74aeabf631a5aa23db116acf91deea34ff1b4419 --- /dev/null +++ b/dumux/freeflow/staggered/fluxvariablescache.hh @@ -0,0 +1,193 @@ +// -*- 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 flux variables + */ +#ifndef DUMUX_FREEFLOW_IMPLICIT_FLUXVARIABLESCACHE_HH +#define DUMUX_FREEFLOW_IMPLICIT_FLUXVARIABLESCACHE_HH + +#include <dumux/implicit/properties.hh> +#include <dune/localfunctions/lagrange/pqkfactory.hh> +#include <dumux/discretization/methods.hh> + +namespace Dumux +{ +// forward declaration +template<class TypeTag, DiscretizationMethods Method> +class FreeFlowFluxVariablesCacheImplementation +{}; + +/*! + * \ingroup ImplicitModel + * \brief The flux variables cache classes for porous media. + * Store flux stencils and data required for flux calculation + */ +template<class TypeTag> +using FreeFlowFluxVariablesCache = FreeFlowFluxVariablesCacheImplementation<TypeTag, GET_PROP_VALUE(TypeTag, DiscretizationMethod)>; + +// specialization for the Box Method +template<class TypeTag> +class FreeFlowFluxVariablesCacheImplementation<TypeTag, DiscretizationMethods::Box> +{ + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); + using Element = typename GridView::template Codim<0>::Entity; + using IndexType = typename GridView::IndexSet::IndexType; + using Stencil = std::vector<IndexType>; + using TransmissibilityVector = std::vector<IndexType>; + + using CoordScalar = typename GridView::ctype; + static const int dim = GridView::dimension; + + using FeCache = Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; + using FeLocalBasis = typename FeCache::FiniteElementType::Traits::LocalBasisType; + using ShapeJacobian = typename FeLocalBasis::Traits::JacobianType; + using ShapeValue = typename Dune::FieldVector<Scalar, 1>; + using JacobianInverseTransposed = typename Element::Geometry::JacobianInverseTransposed; + +public: + + void update(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace &scvf) + { + const auto geometry = element.geometry(); + const auto& localBasis = fvGeometry.feLocalBasis(); + + // evaluate shape functions and gradients at the integration point + const auto ipLocal = geometry.local(scvf.center()); + jacInvT_ = geometry.jacobianInverseTransposed(ipLocal); + localBasis.evaluateJacobian(ipLocal, shapeJacobian_); + //localBasis.evaluateFunction(ipLocal, shapeValue_); // do we need the shapeValues for the flux? + + // The stencil info is obsolete for the box method. + // It is here for compatibility with cc methods + stencil_ = Stencil(0); + } + + const std::vector<ShapeJacobian>& shapeJacobian() const + { return shapeJacobian_; } + + /* const std::vector<ShapeValue>& shapeValue() const + { return shapeValue_; }*/ + + const JacobianInverseTransposed& jacInvT() const + { return jacInvT_; } + + const Stencil& stencil() const + { + return stencil_; + } + +private: + std::vector<ShapeJacobian> shapeJacobian_; + //std::vector<ShapeValue> shapeValue_; + JacobianInverseTransposed jacInvT_; + + Stencil stencil_; +}; + +// specialization for the cell centered tpfa method +template<class TypeTag> +class FreeFlowFluxVariablesCacheImplementation<TypeTag, DiscretizationMethods::CCTpfa> +{ + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); + using Element = typename GridView::template Codim<0>::Entity; + using IndexType = typename GridView::IndexSet::IndexType; + using Stencil = std::vector<IndexType>; + +public: + void update(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvf) + { + FluxVariables fluxVars; + stencil_ = fluxVars.computeStencil(problem, element, fvGeometry, scvf); + tij_ = AdvectionType::calculateTransmissibilities(problem, element, fvGeometry, elemVolVars, scvf); + } + + const Stencil& stencil() const + { return stencil_; } + + const Scalar& tij() const + { return tij_; } + +private: + Stencil stencil_; + Scalar tij_; +}; + +// specialization for the cell centered tpfa method +template<class TypeTag> +class FreeFlowFluxVariablesCacheImplementation<TypeTag, DiscretizationMethods::Staggered> +{ + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); + using Element = typename GridView::template Codim<0>::Entity; + using IndexType = typename GridView::IndexSet::IndexType; + using Stencil = std::vector<IndexType>; + +public: + void update(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvf) + { + FluxVariables fluxVars; + stencil_ = fluxVars.computeCellCenterStencil(problem, element, fvGeometry, scvf); + tij_ = AdvectionType::calculateTransmissibilities(problem, element, fvGeometry, elemVolVars, scvf); + } + + const Stencil& stencil() const + { return stencil_; } + + const Scalar& tij() const + { return tij_; } + +private: + Stencil stencil_; + Scalar tij_; +}; + +} // end namespace + +#endif diff --git a/dumux/freeflow/staggered/indices.hh b/dumux/freeflow/staggered/indices.hh new file mode 100644 index 0000000000000000000000000000000000000000..59bff376183fe4ca87d76bfad4b0043405db78d6 --- /dev/null +++ b/dumux/freeflow/staggered/indices.hh @@ -0,0 +1,44 @@ +// -*- 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 Defines the indices for the one-phase fully implicit model. + */ +#ifndef DUMUX_1P_INDICES_HH +#define DUMUX_1P_INDICES_HH + +namespace Dumux +{ +// \{ + +/*! + * \ingroup OnePModel + * \ingroup ImplicitIndices + * \brief Indices for the one-phase model. + */ +struct OnePIndices +{ + static const int conti0EqIdx = 0; //index for the mass balance + static const int pressureIdx = 0; //index of the primary variable +}; + +// \} +} // end namespace + +#endif diff --git a/dumux/freeflow/staggered/model.hh b/dumux/freeflow/staggered/model.hh new file mode 100644 index 0000000000000000000000000000000000000000..bb18ce217f37ab60c85ac975e0d9a13d9aef4279 --- /dev/null +++ b/dumux/freeflow/staggered/model.hh @@ -0,0 +1,164 @@ +// -*- 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 all models which use the one-phase, + * fully implicit model. + * Adaption of the fully implicit scheme to the one-phase flow model. + */ + +#ifndef DUMUX_1P_MODEL_HH +#define DUMUX_1P_MODEL_HH + +#include <dumux/porousmediumflow/implicit/velocityoutput.hh> +#include "properties.hh" + +namespace Dumux +{ +/*! + * \ingroup OnePModel + * \brief A single-phase, isothermal flow model using the fully implicit scheme. + * + * Single-phase, isothermal flow model, which uses a standard Darcy approach as the + * equation for the conservation of momentum: + * \f[ + v = - \frac{\textbf K}{\mu} + \left(\textbf{grad}\, p - \varrho {\textbf g} \right) + * \f] + * + * and solves the mass continuity equation: + * \f[ + \phi \frac{\partial \varrho}{\partial t} + \text{div} \left\lbrace + - \varrho \frac{\textbf K}{\mu} \left( \textbf{grad}\, p -\varrho {\textbf g} \right) \right\rbrace = q, + * \f] + * All equations are discretized using a vertex-centered finite volume (box) + * or cell-centered finite volume scheme as spatial + * and the implicit Euler method as time discretization. + * The model supports compressible as well as incompressible fluids. + */ +template<class TypeTag > +class OnePModel : public GET_PROP_TYPE(TypeTag, BaseModel) +{ + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum { dim = GridView::dimension }; + enum { dimWorld = GridView::dimensionworld }; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + enum { dofCodim = isBox ? dim : 0 }; + using StencilsVector = typename GET_PROP_TYPE(TypeTag, StencilsVector); + using Element = typename GridView::template Codim<0>::Entity; + +public: + /*! + * \brief \copybrief Dumux::ImplicitModel::addOutputVtkFields + * + * Specialization for the OnePModel, adding the pressure and + * the process rank to the VTK writer. + */ + template<class MultiWriter> + void addOutputVtkFields(const SolutionVector &sol, + MultiWriter &writer) + { + // typedef Dune::BlockVector<Dune::FieldVector<double, dimWorld> > VectorField; + + // create the required scalar fields + unsigned numDofs = this->numDofs(); + auto *p = writer.allocateManagedBuffer(numDofs); + auto *K = writer.allocateManagedBuffer(numDofs); + // VectorField *velocity = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); + // ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_()); + + // if (velocityOutput.enableOutput()) + // { + // // initialize velocity field + // for (unsigned int i = 0; i < numDofs; ++i) + // { + // (*velocity)[i] = double(0); + // } + // } + + unsigned numElements = this->gridView_().size(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]; + const auto& spatialParams = this->problem_().spatialParams(); + auto dofIdxGlobal = scv.dofIndex(); + + (*p)[dofIdxGlobal] = volVars.pressure(); + (*K)[dofIdxGlobal] = spatialParams.intrinsicPermeability(scv, volVars); + } + + // velocity output + //velocityOutput.calculateVelocity(*velocity, elemVolVars, fvGeometry, element, /*phaseIdx=*/0); + } + + writer.attachDofData(*p, "p", isBox); + writer.attachDofData(*K, "K", isBox); + // if (velocityOutput.enableOutput()) + // { + // writer.attachDofData(*velocity, "velocity", isBox, dim); + // } + writer.attachCellData(*rank, "process rank"); + } + + /*! + * \brief Returns the number of global degrees of freedoms (DOFs) + */ + size_t numDofs() const + { + return this->gridView_().size(0) + this->gridView_().size(1);; + } + + size_t completeFaceDofStencilSize(const int idx) + { + return this->stencilsVector_.completeFaceDofStencilSize(idx); + } + + template<class Stencil> + void getFullFaceDofStencils(std::unique_ptr<std::vector<Stencil>>& ptr) + { + this->stencilsVector_.getFullFaceDofStencils(ptr); + // TODO: find better way to do this + } + +}; +} + +#include "propertydefaults.hh" + +#endif diff --git a/dumux/freeflow/staggered/properties.hh b/dumux/freeflow/staggered/properties.hh new file mode 100644 index 0000000000000000000000000000000000000000..0d648ba01379b78dab4218234aec2d8b2135d96b --- /dev/null +++ b/dumux/freeflow/staggered/properties.hh @@ -0,0 +1,76 @@ +// -*- 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/>. * + *****************************************************************************/ +/*! + * \ingroup Properties + * \ingroup ImplicitProperties + * \ingroup OnePModel + * \file + * + * \brief Defines the properties required for the one-phase fully implicit model. + */ +#ifndef DUMUX_1P_PROPERTIES_HH +#define DUMUX_1P_PROPERTIES_HH + +#include <dumux/implicit/box/properties.hh> +#include <dumux/implicit/cellcentered/properties.hh> +#include <dumux/porousmediumflow/nonisothermal/implicit/properties.hh> + +namespace Dumux +{ +// \{ +/////////////////////////////////////////////////////////////////////////// +// properties for the isothermal single phase model +/////////////////////////////////////////////////////////////////////////// +namespace Properties { + +////////////////////////////////////////////////////////////////// +// Type tags +////////////////////////////////////////////////////////////////// + +//! The type tags for the implicit single-phase problems +NEW_TYPE_TAG(OneP); +NEW_TYPE_TAG(BoxOneP, INHERITS_FROM(BoxModel, OneP)); +NEW_TYPE_TAG(CCOneP, INHERITS_FROM(CCModel, OneP)); + +//! The type tags for the corresponding non-isothermal problems +NEW_TYPE_TAG(OnePNI, INHERITS_FROM(OneP, NonIsothermal)); +NEW_TYPE_TAG(BoxOnePNI, INHERITS_FROM(BoxModel, OnePNI)); +NEW_TYPE_TAG(CCOnePNI, INHERITS_FROM(CCModel, OnePNI)); + +////////////////////////////////////////////////////////////////// +// Property tags +////////////////////////////////////////////////////////////////// + +NEW_PROP_TAG(NumPhases); //!< Number of fluid phases in the system +NEW_PROP_TAG(Indices); //!< Enumerations for the model +NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters object +NEW_PROP_TAG(FluidSystem); //!< The type of the fluid system to use +NEW_PROP_TAG(Fluid); //!< The fluid used for the default fluid system +NEW_PROP_TAG(FluidState); //!< The type of the fluid state to use +NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem +NEW_PROP_TAG(ImplicitMassUpwindWeight); //!< Returns weight of the upwind cell when calculating fluxes +NEW_PROP_TAG(ImplicitMobilityUpwindWeight); //!< Weight for the upwind mobility in the velocity calculation +NEW_PROP_TAG(SpatialParamsForchCoeff); //!< Property for the forchheimer coefficient +NEW_PROP_TAG(VtkAddVelocity); //!< Returns whether velocity vectors are written into the vtk output +// \} +} + +} // end namespace + +#endif diff --git a/dumux/freeflow/staggered/propertydefaults.hh b/dumux/freeflow/staggered/propertydefaults.hh new file mode 100644 index 0000000000000000000000000000000000000000..babb8601204e6596a6c8bf00c9798b36f23c1f8d --- /dev/null +++ b/dumux/freeflow/staggered/propertydefaults.hh @@ -0,0 +1,158 @@ +// -*- 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/>. * + *****************************************************************************/ +/*! + * \ingroup Properties + * \ingroup ImplicitProperties + * \ingroup OnePModel + * \file + * + * \brief Defines the properties required for the one-phase fully implicit model. + */ +#ifndef DUMUX_1P_PROPERTY_DEFAULTS_HH +#define DUMUX_1P_PROPERTY_DEFAULTS_HH + +#include "properties.hh" + +#include "model.hh" +#include "volumevariables.hh" +#include "indices.hh" + +#include <dumux/porousmediumflow/immiscible/localresidual.hh> +#include <dumux/porousmediumflow/nonisothermal/implicit/propertydefaults.hh> +#include <dumux/material/fluidsystems/gasphase.hh> +#include <dumux/material/fluidsystems/liquidphase.hh> +#include <dumux/material/components/nullcomponent.hh> +#include <dumux/material/fluidsystems/1p.hh> +#include <dumux/material/spatialparams/implicit1p.hh> +#include <dumux/material/fluidmatrixinteractions/1p/thermalconductivityaverage.hh> + +namespace Dumux +{ +// \{ + +/////////////////////////////////////////////////////////////////////////// +// default property values for the isothermal single phase model +/////////////////////////////////////////////////////////////////////////// +namespace Properties { +SET_INT_PROP(OneP, NumEq, 1); //!< set the number of equations to 1 +SET_INT_PROP(OneP, NumPhases, 1); //!< The number of phases in the 1p model is 1 + +//! The local residual function +SET_TYPE_PROP(OneP, LocalResidual, ImmiscibleLocalResidual<TypeTag>); + +//! the Model property +SET_TYPE_PROP(OneP, Model, OnePModel<TypeTag>); + +//! the VolumeVariables property +SET_TYPE_PROP(OneP, VolumeVariables, OnePVolumeVariables<TypeTag>); + +//! Enable advection +SET_BOOL_PROP(OneP, EnableAdvection, true); + +//! The one-phase model has no molecular diffusion +SET_BOOL_PROP(OneP, EnableMolecularDiffusion, false); + +//! Isothermal model by default +SET_BOOL_PROP(OneP, EnableEnergyBalance, false); + +//! The indices required by the isothermal single-phase model +SET_TYPE_PROP(OneP, Indices, OnePIndices); + +//! The spatial parameters to be employed. +//! Use ImplicitSpatialParamsOneP by default. +SET_TYPE_PROP(OneP, SpatialParams, ImplicitSpatialParamsOneP<TypeTag>); + +//! The weight of the upwind control volume when calculating +//! fluxes. Use central differences by default. +SET_SCALAR_PROP(OneP, ImplicitMassUpwindWeight, 0.5); + +//! weight for the upwind mobility in the velocity calculation +//! fluxes. Use central differences by default. +SET_SCALAR_PROP(OneP, ImplicitMobilityUpwindWeight, 0.5); + +//! The fluid system to use by default +SET_TYPE_PROP(OneP, FluidSystem, Dumux::FluidSystems::OneP<typename GET_PROP_TYPE(TypeTag, Scalar), typename GET_PROP_TYPE(TypeTag, Fluid)>); + +SET_PROP(OneP, Fluid) +{ private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; +public: + typedef Dumux::LiquidPhase<Scalar, Dumux::NullComponent<Scalar> > type; +}; + +/*! + * \brief The fluid state which is used by the volume variables to + * store the thermodynamic state. This should be chosen + * appropriately for the model ((non-)isothermal, equilibrium, ...). + * This can be done in the problem. + */ +SET_PROP(OneP, FluidState){ + private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + public: + typedef Dumux::ImmiscibleFluidState<Scalar, FluidSystem> type; +}; + +// disable velocity output by default +SET_BOOL_PROP(OneP, VtkAddVelocity, false); + +// enable gravity by default +SET_BOOL_PROP(OneP, ProblemEnableGravity, true); + +//! default value for the forchheimer coefficient +// Source: Ward, J.C. 1964 Turbulent flow in porous media. ASCE J. Hydraul. Div 90. +// Actually the Forchheimer coefficient is also a function of the dimensions of the +// porous medium. Taking it as a constant is only a first approximation +// (Nield, Bejan, Convection in porous media, 2006, p. 10) +SET_SCALAR_PROP(OneP, SpatialParamsForchCoeff, 0.55); + +//! average is used as default model to compute the effective thermal heat conductivity +SET_PROP(OnePNI, ThermalConductivityModel) +{ private : + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + public: + typedef ThermalConductivityAverage<Scalar> type; +}; + +////////////////////////////////////////////////////////////////// +// Property values for isothermal model required for the general non-isothermal model +////////////////////////////////////////////////////////////////// + +// set isothermal Model +SET_TYPE_PROP(OnePNI, IsothermalModel, OnePModel<TypeTag>); + +//set isothermal VolumeVariables +SET_TYPE_PROP(OnePNI, IsothermalVolumeVariables, OnePVolumeVariables<TypeTag>); + +//set isothermal LocalResidual +SET_TYPE_PROP(OnePNI, IsothermalLocalResidual, ImmiscibleLocalResidual<TypeTag>); + +//set isothermal Indices +SET_TYPE_PROP(OnePNI, IsothermalIndices, OnePIndices); + +//set isothermal NumEq +SET_INT_PROP(OnePNI, IsothermalNumEq, 1); + +// \} +} // end namespace Properties + +} // end namespace Dumux + +#endif diff --git a/dumux/freeflow/staggered/volumevariables.hh b/dumux/freeflow/staggered/volumevariables.hh new file mode 100644 index 0000000000000000000000000000000000000000..81c65cb882e661755754353fd8ef1ab0447c38f4 --- /dev/null +++ b/dumux/freeflow/staggered/volumevariables.hh @@ -0,0 +1,183 @@ +// -*- 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 Quantities required by the one-phase fully implicit model defined on a vertex. + */ +#ifndef DUMUX_1P_VOLUME_VARIABLES_HH +#define DUMUX_1P_VOLUME_VARIABLES_HH + +#include "properties.hh" +#include <dumux/discretization/volumevariables.hh> + +#include <dumux/material/fluidstates/immiscible.hh> + +namespace Dumux +{ + +/*! + * \ingroup OnePModel + * \ingroup ImplicitVolumeVariables + * \brief Contains the quantities which are constant within a + * finite volume in the one-phase model. + */ +template <class TypeTag> +class OnePVolumeVariables : public ImplicitVolumeVariables<TypeTag> +{ + using ParentType = ImplicitVolumeVariables<TypeTag>; + using Implementation = typename GET_PROP_TYPE(TypeTag, VolumeVariables); + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables); + using Indices = typename GET_PROP_TYPE(TypeTag, Indices); + using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using Element = typename GridView::template Codim<0>::Entity; + +public: + + using FluidState = typename GET_PROP_TYPE(TypeTag, FluidState); + + /*! + * \copydoc ImplicitVolumeVariables::update + */ + void update(const PrimaryVariables &priVars, + const Problem &problem, + const Element &element, + const SubControlVolume& scv) + { + ParentType::update(priVars, problem, element, scv); + + completeFluidState(priVars, problem, element, scv, fluidState_); + // porosity + porosity_ = problem.spatialParams().porosity(scv); + }; + + /*! + * \copydoc ImplicitModel::completeFluidState + */ + static void completeFluidState(const PrimaryVariables& priVars, + const Problem& problem, + const Element& element, + const SubControlVolume& scv, + FluidState& fluidState) + { + Scalar t = ParentType::temperature(priVars, problem, element, scv); + fluidState.setTemperature(t); + fluidState.setSaturation(/*phaseIdx=*/0, 1.); + + fluidState.setPressure(/*phaseIdx=*/0, priVars[Indices::pressureIdx]); + + // saturation in a single phase is always 1 and thus redundant + // to set. But since we use the fluid state shared by the + // immiscible multi-phase models, so we have to set it here... + fluidState.setSaturation(/*phaseIdx=*/0, 1.0); + + typename FluidSystem::ParameterCache paramCache; + paramCache.updatePhase(fluidState, /*phaseIdx=*/0); + + Scalar value = FluidSystem::density(fluidState, paramCache, /*phaseIdx=*/0); + fluidState.setDensity(/*phaseIdx=*/0, value); + + value = FluidSystem::viscosity(fluidState, paramCache, /*phaseIdx=*/0); + fluidState.setViscosity(/*phaseIdx=*/0, value); + + // compute and set the enthalpy + value = ParentType::enthalpy(fluidState, paramCache, /*phaseIdx=*/0); + fluidState.setEnthalpy(/*phaseIdx=*/0, value); + } + + /*! + * \brief Return temperature \f$\mathrm{[K]}\f$ inside the sub-control volume. + * + * Note that we assume thermodynamic equilibrium, i.e. the + * temperatures of the rock matrix and of all fluid phases are + * identical. + */ + Scalar temperature() const + { return fluidState_.temperature(); } + + /*! + * \brief Return the effective pressure \f$\mathrm{[Pa]}\f$ of a given phase within + * the control volume. + */ + Scalar pressure(int phaseIdx = 0) const + { return fluidState_.pressure(phaseIdx); } + + /*! + * \brief Return the saturation + */ + Scalar saturation(int phaseIdx = 0) const + { return 1.0; } + + /*! + * \brief Return the mass density \f$\mathrm{[kg/m^3]}\f$ of a given phase within the + * control volume. + */ + Scalar density(int phaseIdx = 0) const + { return fluidState_.density(phaseIdx); } + + /*! + * \brief Return the dynamic viscosity \f$\mathrm{[Pa s]}\f$ of the fluid within the + * control volume. + */ + Scalar viscosity(int phaseIdx = 0) const + { return fluidState_.viscosity(phaseIdx); } + + /*! + * \brief Returns the mobility \f$\mathrm{[1/(Pa s)]}\f$. + * + * This function enables the use of ImplicitDarcyFluxVariables + * with the 1p fully implicit model, ALTHOUGH the term mobility is + * usually not employed in the one phase context. + * + * \param phaseIdx The phase index + */ + Scalar mobility(int phaseIdx = 0) const + { return 1.0/fluidState_.viscosity(phaseIdx); } + + /*! + * \brief Return the average porosity \f$\mathrm{[-]}\f$ within the control volume. + */ + Scalar porosity() const + { return porosity_; } + + /*! + * \brief Return the fluid state of the control volume. + */ + const FluidState &fluidState() const + { return fluidState_; } + +protected: + FluidState fluidState_; + Scalar porosity_; + + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } +}; + +} + +#endif diff --git a/dumux/implicit/staggered/assembler.hh b/dumux/implicit/staggered/assembler.hh new file mode 100644 index 0000000000000000000000000000000000000000..4d36f5390e07b98e3453f1c4c8e8116bdb26a5bf --- /dev/null +++ b/dumux/implicit/staggered/assembler.hh @@ -0,0 +1,106 @@ +// -*- 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 An assembler for the global Jacobian matrix for fully implicit models. + */ +#ifndef DUMUX_STAGGERED_ASSEMBLER_HH +#define DUMUX_STAGGERED_ASSEMBLER_HH + +#include <dumux/implicit/properties.hh> +#include <dumux/implicit/assembler.hh> + +namespace Dumux { + +/*! + * \ingroup ImplicitModel + * \brief An assembler for the global Jacobian matrix for fully implicit models. + */ +template<class TypeTag> +class StaggeredAssembler : public ImplicitAssembler<TypeTag> +{ + typedef ImplicitAssembler<TypeTag> ParentType; + friend class ImplicitAssembler<TypeTag>; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GridView::IndexSet::IndexType IndexType; + + void setRowSizes_() + { + for (const auto& element : elements(this->gridView_())) + { + // the global index of the element at hand + const auto globalI = this->elementMapper_().index(element); + const auto& stencil = this->model_().stencils(element).elementStencil(); + + this->matrix().setrowsize(globalI, stencil.size()); + } + + for(int facetIdx = 0; facetIdx < this->gridView_().size(1); ++facetIdx) + { + const int faceDofxIdx = facetIdx + this->gridView_().size(0); + const int size = this->model_().completeFaceDofStencilSize(facetIdx); + this->matrix().setrowsize(faceDofxIdx, size); + } + this->matrix().endrowsizes(); + } + + void addIndices_() + { + for (const auto& element : elements(this->gridView_())) + { + // the global index of the element at hand + const auto globalI = this->elementMapper_().index(element); + const auto& stencil = this->model_().stencils(element).elementStencil(); + + + for (auto&& globalJ : stencil) + this->matrix().addindex(globalI, globalJ); + } + + // TODO: this is a mess. find a better way for the pointer handling! + using Stencil = std::vector<IndexType>; + std::unique_ptr<std::vector<Stencil>> ptr; + + this->model_().getFullFaceDofStencils(ptr); + + if(ptr) + std::cout << "success!!!" << std::endl; + + auto& fullFaceDofStencils = ptr.get()[0]; + + int globalI = this->gridView_().size(0); + for(const auto& stencil : fullFaceDofStencils) + { + for(auto&& globalJ : stencil) + this->matrix().addindex(globalI, globalJ); + ++globalI; + } + + this->matrix().endindices(); + } + +}; + +} // namespace Dumux + +#endif diff --git a/dumux/implicit/staggered/localjacobian.hh b/dumux/implicit/staggered/localjacobian.hh new file mode 100644 index 0000000000000000000000000000000000000000..1791521d0e38b9587bb28635eaca7931ad5c173d --- /dev/null +++ b/dumux/implicit/staggered/localjacobian.hh @@ -0,0 +1,404 @@ +// -*- 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 Caculates the Jacobian of the local residual for fully-implicit models + */ +#ifndef DUMUX_STAGGERED_LOCAL_JACOBIAN_HH +#define DUMUX_STAGGERED_LOCAL_JACOBIAN_HH + +#include <dune/istl/io.hh> +#include <dune/istl/matrix.hh> + +#include <dumux/common/math.hh> +#include <dumux/common/valgrind.hh> + +#include <dumux/implicit/properties.hh> +#include <dumux/implicit/localjacobian.hh> + +namespace Dumux +{ +/*! + * \ingroup ImplicitLocalJacobian + * \brief Calculates the Jacobian of the local residual for fully-implicit models + * + * The default behavior is to use numeric differentiation, i.e. + * forward or backward differences (2nd order), or central + * differences (3rd order). The method used is determined by the + * "NumericDifferenceMethod" property: + * + * - if the value of this property is smaller than 0, backward + * differences are used, i.e.: + * \f[ + \frac{\partial f(x)}{\partial x} \approx \frac{f(x) - f(x - \epsilon)}{\epsilon} + * \f] + * + * - if the value of this property is 0, central + * differences are used, i.e.: + * \f[ + \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x - \epsilon)}{2 \epsilon} + * \f] + * + * - if the value of this property is larger than 0, forward + * differences are used, i.e.: + * \f[ + \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x)}{\epsilon} + * \f] + * + * Here, \f$ f \f$ is the residual function for all equations, \f$x\f$ + * is the value of a sub-control volume's primary variable at the + * evaluation point and \f$\epsilon\f$ is a small value larger than 0. + */ +template<class TypeTag> +class StaggeredLocalJacobian : public ImplicitLocalJacobian<TypeTag> +{ + using ParentType = ImplicitLocalJacobian<TypeTag>; + using Implementation = typename GET_PROP_TYPE(TypeTag, LocalJacobian); + using LocalResidual = typename GET_PROP_TYPE(TypeTag, LocalResidual); + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using JacobianMatrix = typename GET_PROP_TYPE(TypeTag, JacobianMatrix); + + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables); + using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables); + using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); + using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using ElementBoundaryTypes = typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes); + using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector); + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using Element = typename GridView::template Codim<0>::Entity; + using IndexType = typename GridView::IndexSet::IndexType; + + enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; + + using AssemblyMap = std::vector<std::vector<std::vector<IndexType>>>; + +public: + + StaggeredLocalJacobian() : ParentType() + { + numericDifferenceMethod_ = GET_PARAM_FROM_GROUP(TypeTag, int, Implicit, NumericDifferenceMethod); + } + + /*! + * \brief Initialize the local Jacobian object. + * + * At this point we can assume that everything has been allocated, + * although some objects may not yet be completely initialized. + * + * \param problem The problem which we want to simulate. + */ + void init(Problem &problem) + { + ParentType::init(problem); + +// assemblyMap_.resize(problem.gridView().size(0)); +// for (const auto& element : elements(problem.gridView())) +// { +// // get a local finite volume geometry object that is bindable +// auto fvGeometryJ = localView(problem.model().globalFvGeometry()); +// +// auto globalI = problem.elementMapper().index(element); +// const auto& neighborStencil = this->model_().stencils(element).neighborStencil(); +// +// // assemblyMap_[globalI].reserve(neighborStencil.size()); +// for (auto globalJ : neighborStencil) +// { +// const auto& elementJ = fvGeometryJ.globalFvGeometry().element(globalJ); +// +// // find the flux vars needed for the calculation of the flux into element +// std::vector<IndexType> fluxVarIndices; +// +// // only non-ghost neighbors (J) have to be considered, derivatives from non-ghost to ghost dofs +// // are assembled when assembling the ghost element (I) +// if (elementJ.partitionType() != Dune::GhostEntity) +// { +// fvGeometryJ.bindElement(elementJ); +// for (auto&& scvFaceJ : scvfs(fvGeometryJ)) +// { +// auto fluxVarsIdx = scvFaceJ.index(); +// +// // if globalI is in flux var stencil, add to list +// FluxVariables fluxVars; +// const auto fluxStencil = fluxVars.computeStencil(problem, elementJ, fvGeometryJ, scvFaceJ); +// +// for (auto globalIdx : fluxStencil) +// if (globalIdx == globalI) +// fluxVarIndices.push_back(fluxVarsIdx); +// } +// } +// // assemblyMap_[globalI].emplace_back(std::move(fluxVarIndices)); +// } +// } + } + + /*! + * \brief Assemble an element's local Jacobian matrix of the + * defect. + * + * \param element The DUNE Codim<0> entity which we look at. + */ + void assemble(const Element& element, JacobianMatrix& matrix, SolutionVector& residual) + { + const bool isGhost = (element.partitionType() == Dune::GhostEntity); + + // prepare the volvars/fvGeometries in case caching is disabled + auto fvGeometry = localView(this->model_().globalFvGeometry()); + fvGeometry.bind(element); + + auto curElemVolVars = localView(this->model_().curGlobalVolVars()); + curElemVolVars.bind(element, fvGeometry, this->model_().curSol()); + + auto prevElemVolVars = localView(this->model_().prevGlobalVolVars()); + prevElemVolVars.bindElement(element, fvGeometry, this->model_().prevSol()); + + auto elemFluxVarsCache = localView(this->model_().globalFluxVarsCache()); + elemFluxVarsCache.bind(element, fvGeometry, curElemVolVars); + + // set the actual dof index + globalI_ = this->problem_().elementMapper().index(element); + + ElementBoundaryTypes elemBcTypes; + elemBcTypes.update(this->problem_(), element, fvGeometry); + + // calculate the local residual + if (isGhost) + { + this->residual_ = 0.0; + residual[globalI_] = 0.0; + } + else + { + this->localResidual().eval(element, fvGeometry, prevElemVolVars, curElemVolVars, elemBcTypes, elemFluxVarsCache); + this->residual_ = this->localResidual().residual(); + // store residual in global container as well + residual[globalI_] = this->localResidual().residual(0); + } + + this->model_().updatePVWeights(fvGeometry); + + // calculate derivatives of all dofs in stencil with respect to the dofs in the element + evalPartialDerivatives_(element, fvGeometry, prevElemVolVars, curElemVolVars, elemFluxVarsCache, elemBcTypes, matrix, residual, isGhost); + + // TODO: calculate derivatives in the case of an extended source stencil + // const auto& extendedSourceStencil = model_().stencils(element).extendedSourceStencil(); + // for (auto&& globalJ : extendedSourceStencil) + // { + // for (int pvIdx = 0; pvIdx < numEq; pvIdx++) + // { + // evalPartialDerivativeSource_(partialDeriv, globalJ, pvIdx, neighborToFluxVars[globalJ]); + + // // update the local stiffness matrix with the partial derivatives + // updateLocalJacobian_(j, pvIdx, partialDeriv); + // } + // ++j; + // } + } + + const AssemblyMap& assemblyMap() const + { return assemblyMap_; } + +private: + void evalPartialDerivatives_(const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& prevElemVolVars, + ElementVolumeVariables& curElemVolVars, + ElementFluxVariablesCache& elemFluxVarsCache, + const ElementBoundaryTypes& elemBcTypes, + JacobianMatrix& matrix, + SolutionVector& residual, + const bool isGhost) + { + // get stencil informations + const auto& neighborStencil = this->model_().stencils(element).neighborStencil(); + const auto numNeighbors = neighborStencil.size(); + + // the localresidual class used for the flux calculations + LocalResidual localRes; + localRes.init(this->problem_()); + + // container to store the neighboring elements + std::vector<Element> neighborElements; + neighborElements.reserve(numNeighbors); + + // get the elements and calculate the flux into the element in the undeflected state + Dune::BlockVector<PrimaryVariables> origFlux(numNeighbors); + origFlux = 0.0; + + unsigned int j = 0; + for (auto globalJ : neighborStencil) + { + auto elementJ = fvGeometry.globalFvGeometry().element(globalJ); + neighborElements.push_back(elementJ); + + for (auto fluxVarIdx : assemblyMap_[globalI_][j]) + { + auto&& scvf = fvGeometry.scvf(fluxVarIdx); + origFlux[j] += localRes.evalFlux_(elementJ, fvGeometry, curElemVolVars, scvf, elemFluxVarsCache[scvf]); + } + + ++j; + } + + auto&& scv = fvGeometry.scv(globalI_); + auto& curVolVars = getCurVolVars(curElemVolVars, scv); + // save a copy of the original vol vars + VolumeVariables origVolVars(curVolVars); + + // derivatives in the neighbors with repect to the current elements + Dune::BlockVector<PrimaryVariables> neighborDeriv(numNeighbors); + for (int pvIdx = 0; pvIdx < numEq; pvIdx++) + { + // derivatives of element dof with respect to itself + PrimaryVariables partialDeriv(0.0); + + if (isGhost) + partialDeriv[pvIdx] = 1.0; + + neighborDeriv = 0.0; + PrimaryVariables priVars(this->model_().curSol()[globalI_]); + + Scalar eps = this->numericEpsilon(scv, curVolVars, pvIdx); + Scalar delta = 0; + + if (numericDifferenceMethod_ >= 0) + { + // we are not using backward differences, i.e. we need to + // calculate f(x + \epsilon) + + // deflect primary variables + priVars[pvIdx] += eps; + delta += eps; + + // update the volume variables and bind the flux var cache again + curVolVars.update(priVars, this->problem_(), element, scv); + elemFluxVarsCache.bind(element, fvGeometry, curElemVolVars); + + if (!isGhost) + { + // calculate the residual with the deflected primary variables + this->localResidual().eval(element, fvGeometry, prevElemVolVars, curElemVolVars, elemBcTypes, elemFluxVarsCache); + + // store the residual and the storage term + partialDeriv = this->localResidual().residual(0); + } + + // calculate the fluxes into element with the deflected primary variables + for (std::size_t k = 0; k < numNeighbors; ++k) + { + for (auto fluxVarIdx : assemblyMap_[globalI_][k]) + { + auto&& scvf = fvGeometry.scvf(fluxVarIdx); + neighborDeriv[k] += localRes.evalFlux_(neighborElements[k], fvGeometry, curElemVolVars, scvf, elemFluxVarsCache[scvf]); + } + } + } + else + { + // we are using backward differences, i.e. we don't need + // to calculate f(x + \epsilon) and we can recycle the + // (already calculated) residual f(x) + if (!isGhost) + partialDeriv = this->residual(0); + neighborDeriv = origFlux; + } + + if (numericDifferenceMethod_ <= 0) + { + // we are not using forward differences, i.e. we + // need to calculate f(x - \epsilon) + + // deflect the primary variables + priVars[pvIdx] -= delta + eps; + delta += eps; + + // update the volume variables and bind the flux var cache again + curVolVars.update(priVars, this->problem_(), element, scv); + elemFluxVarsCache.bind(element, fvGeometry, curElemVolVars); + + if (!isGhost) + { + // calculate the residual with the deflected primary variables + this->localResidual().eval(element, fvGeometry, prevElemVolVars, curElemVolVars, elemBcTypes, elemFluxVarsCache); + + // subtract the residual from the derivative storage + partialDeriv -= this->localResidual().residual(0); + } + + // calculate the fluxes into element with the deflected primary variables + for (std::size_t k = 0; k < numNeighbors; ++k) + { + for (auto fluxVarIdx : assemblyMap_[globalI_][k]) + { + auto&& scvf = fvGeometry.scvf(fluxVarIdx); + neighborDeriv[k] -= localRes.evalFlux_(neighborElements[k], fvGeometry, curElemVolVars, scvf, elemFluxVarsCache[scvf]); + } + } + } + else + { + // we are using forward differences, i.e. we don't need to + // calculate f(x - \epsilon) and we can recycle the + // (already calculated) residual f(x) + if (!isGhost) + partialDeriv -= this->residual(0); + neighborDeriv -= origFlux; + } + + // divide difference in residuals by the magnitude of the + // deflections between the two function evaluation + if (!isGhost) + partialDeriv /= delta; + neighborDeriv /= delta; + + // restore the original state of the scv's volume variables + curVolVars = origVolVars; + + // update the global jacobian matrix with the current partial derivatives + this->updateGlobalJacobian_(matrix, globalI_, globalI_, pvIdx, partialDeriv); + + j = 0; + for (auto globalJ : neighborStencil) + this->updateGlobalJacobian_(matrix, globalJ, globalI_, pvIdx, neighborDeriv[j++]); + } + } + + //! If the global vol vars caching is enabled we have to modify the global volvar object + template<class T = TypeTag> + typename std::enable_if<GET_PROP_VALUE(T, EnableGlobalVolumeVariablesCache), VolumeVariables>::type& + getCurVolVars(ElementVolumeVariables& elemVolVars, const SubControlVolume& scv) + { return this->model_().nonConstCurGlobalVolVars().volVars(scv.index()); } + + //! When global volume variables caching is disabled, return the local volvar object + template<class T = TypeTag> + typename std::enable_if<!GET_PROP_VALUE(T, EnableGlobalVolumeVariablesCache), VolumeVariables>::type& + getCurVolVars(ElementVolumeVariables& elemVolVars, const SubControlVolume& scv) + { return elemVolVars[scv]; } + + IndexType globalI_; + int numericDifferenceMethod_; + AssemblyMap assemblyMap_; +}; + +} + +#endif diff --git a/dumux/implicit/staggered/localresidual.hh b/dumux/implicit/staggered/localresidual.hh new file mode 100644 index 0000000000000000000000000000000000000000..84e1fd1ff8ebd4a7b979bc8560088ed114482f58 --- /dev/null +++ b/dumux/implicit/staggered/localresidual.hh @@ -0,0 +1,306 @@ +// -*- 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 Calculates the residual of models based on the box scheme element-wise. + */ +#ifndef DUMUX_STAGGERED_LOCAL_RESIDUAL_HH +#define DUMUX_STAGGERED_LOCAL_RESIDUAL_HH + +#include <dune/istl/matrix.hh> + +#include <dumux/common/valgrind.hh> +#include <dumux/implicit/localresidual.hh> + +#include "properties.hh" + +namespace Dumux +{ +/*! + * \ingroup CCModel + * \ingroup StaggeredLocalResidual + * \brief Element-wise calculation of the residual for models + * based on the fully implicit cell-centered scheme. + * + * \todo Please doc me more! + */ +template<class TypeTag> +class StaggeredLocalResidual : public ImplicitLocalResidual<TypeTag> +{ + using ParentType = ImplicitLocalResidual<TypeTag>; + friend class ImplicitLocalResidual<TypeTag>; + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + + enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; + + using Element = typename GridView::template Codim<0>::Entity; + using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables); + using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes); + using ElementBoundaryTypes = typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes); + using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + +public: + // copying the local residual class is not a good idea + StaggeredLocalResidual(const StaggeredLocalResidual &) = delete; + + StaggeredLocalResidual() : ParentType() {} + +protected: + + void evalFluxes_(const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const ElementBoundaryTypes& bcTypes, + const ElementFluxVariablesCache& elemFluxVarsCache) + { + // calculate the mass flux over the scv faces + for (auto&& scvf : scvfs(fvGeometry)) + { + this->residual_[0] += this->asImp_().computeFlux_(element, fvGeometry, elemVolVars, scvf, bcTypes, elemFluxVarsCache[scvf]); + } + } + + PrimaryVariables computeFlux_(const Element &element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvf, + const ElementBoundaryTypes& bcTypes, + const FluxVariablesCache& fluxVarsCache) + { + if (!scvf.boundary() /*TODO: || GET_PROP_VALUE(TypeTag, BoundaryReconstruction)*/) + return this->asImp_().computeFlux(element, fvGeometry, elemVolVars, scvf, fluxVarsCache); + else + return PrimaryVariables(0.0); + + } + + void evalBoundary_(const Element &element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const ElementBoundaryTypes& elemBcTypes, + const ElementFluxVariablesCache& elemFluxVarsCache) + { + for (auto&& scvf : scvfs(fvGeometry)) + { + if (scvf.boundary()) + { + auto bcTypes = this->problem().boundaryTypes(element, scvf); + this->residual_[0] += evalBoundaryFluxes_(element, fvGeometry, elemVolVars, scvf, bcTypes, elemFluxVarsCache[scvf]); + } + } + + // additionally treat mixed D/N conditions in a strong sense + if (elemBcTypes.hasDirichlet()) + { + for (auto&& scvf : scvfs(fvGeometry)) + { + if (scvf.boundary()) + this->asImp_().evalDirichlet_(element, fvGeometry, elemVolVars, scvf); + } + } + } + + /*! + * \brief Add all fluxes resulting from Neumann, outflow and pure Dirichlet + * boundary conditions to the local residual. + */ + PrimaryVariables evalBoundaryFluxes_(const Element &element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvf, + const BoundaryTypes& bcTypes, + const FluxVariablesCache& fluxVarsCache) + { + // evaluate the Neumann conditions at the boundary face + PrimaryVariables flux(0); + if (bcTypes.hasNeumann() /*TODO: && !GET_PROP_VALUE(TypeTag, BoundaryReconstruction)*/) + flux += this->asImp_().evalNeumannSegment_(element, fvGeometry, elemVolVars, scvf, bcTypes); + + // TODO: evaluate the outflow conditions at the boundary face + //if (bcTypes.hasOutflow() /*TODO: && !GET_PROP_VALUE(TypeTag, BoundaryReconstruction)*/) + // flux += this->asImp_().evalOutflowSegment_(&intersection, bcTypes); + + // evaluate the pure Dirichlet conditions at the boundary face + if (bcTypes.hasDirichlet() && !bcTypes.hasNeumann()) + flux += this->asImp_().evalDirichletSegment_(element, fvGeometry, elemVolVars, scvf, bcTypes, fluxVarsCache); + + return flux; + } + + + /*! + * \brief Evaluate Dirichlet conditions on faces that have mixed + * Dirichlet/Neumann boundary conditions. + */ + void evalDirichlet_(const Element &element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvf) + { + BoundaryTypes bcTypes = this->problem().boundaryTypes(element, scvf); + + if (bcTypes.hasDirichlet() && bcTypes.hasNeumann()) + this->asImp_().evalDirichletSegmentMixed_(element, fvGeometry, elemVolVars, scvf, bcTypes); + } + + /*! + * \brief Add Neumann boundary conditions for a single scv face + */ + PrimaryVariables evalNeumannSegment_(const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvf, + const BoundaryTypes &bcTypes) + { + // temporary vector to store the neumann boundary fluxes + PrimaryVariables flux(0); + + auto neumannFluxes = this->problem().neumann(element, fvGeometry, elemVolVars, scvf); + + // multiply neumann fluxes with the area and the extrusion factor + auto&& scv = fvGeometry.scv(scvf.insideScvIdx()); + neumannFluxes *= scvf.area()*elemVolVars[scv].extrusionFactor(); + + // add fluxes to the residual + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) + if (bcTypes.isNeumann(eqIdx)) + flux[eqIdx] += neumannFluxes[eqIdx]; + + return flux; + } + + /*! + * \brief Treat Dirichlet boundary conditions in a weak sense for a single + * intersection that only has Dirichlet boundary conditions + */ + PrimaryVariables evalDirichletSegment_(const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvf, + const BoundaryTypes &bcTypes, + const FluxVariablesCache& fluxVarsCache) + { + // temporary vector to store the Dirichlet boundary fluxes + PrimaryVariables flux(0); + + auto dirichletFlux = this->asImp_().computeFlux(element, fvGeometry, elemVolVars, scvf, fluxVarsCache); + + // add fluxes to the residual + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) + if (bcTypes.isDirichlet(eqIdx)) + flux[eqIdx] += dirichletFlux[eqIdx]; + + return flux; + } + + /*! + * \brief Treat Dirichlet boundary conditions in a strong sense for a + * single intersection that has mixed D/N boundary conditions + */ + void evalDirichletSegmentMixed_(const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvf, + const BoundaryTypes &bcTypes) + { + // temporary vector to store the Dirichlet values + PrimaryVariables dirichletValues = this->problem().dirichlet(element, scvf); + + // get the primary variables + const auto& priVars = elemVolVars[scvf.insideScvIdx()].priVars(); + + // set Dirichlet conditions in a strong sense + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) + { + if (bcTypes.isDirichlet(eqIdx)) + { + auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx); + this->residual_[0][eqIdx] = priVars[pvIdx] - dirichletValues[pvIdx]; + } + } + } + + /*! + * \brief Add outflow boundary conditions for a single intersection + */ + /*template <class IntersectionIterator> + void evalOutflowSegment_(const IntersectionIterator &isIt, + const BoundaryTypes &bcTypes) + { + if (this->element_().geometry().type().isCube() == false) + DUNE_THROW(Dune::InvalidStateException, + "for cell-centered models, outflow BCs only work for cubes."); + + // store pointer to the current FVElementGeometry + const FVElementGeometry *oldFVGeometryPtr = this->fvElemGeomPtr_; + + // copy the current FVElementGeometry to a local variable + // and set the pointer to this local variable + FVElementGeometry fvGeometry = this->fvGeometry_(); + this->fvElemGeomPtr_ = &fvGeometry; + + // get the index of the boundary face + unsigned bfIdx = isIt->indexInInside(); + unsigned oppositeIdx = bfIdx^1; + + // manipulate the corresponding subcontrolvolume face + SCVFace& boundaryFace = fvGeometry.boundaryFace[bfIdx]; + + // set the second flux approximation index for the boundary face + for (int nIdx = 0; nIdx < fvGeometry.numNeighbors-1; nIdx++) + { + // check whether the two faces are opposite of each other + if (fvGeometry.subContVolFace[nIdx].fIdx == oppositeIdx) + { + boundaryFace.j = nIdx+1; + break; + } + } + boundaryFace.fapIndices[1] = boundaryFace.j; + boundaryFace.grad[0] *= -0.5; + boundaryFace.grad[1] *= -0.5; + + // temporary vector to store the outflow boundary fluxes + PrimaryVariables values; + Valgrind::SetUndefined(values); + + this->asImp_().computeFlux(values, bfIdx, true); + values *= this->curVolVars_(0).extrusionFactor(); + + // add fluxes to the residual + Valgrind::CheckDefined(values); + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) + { + if (bcTypes.isOutflow(eqIdx)) + this->residual_[0][eqIdx] += values[eqIdx]; + } + + // restore the pointer to the FVElementGeometry + this->fvElemGeomPtr_ = oldFVGeometryPtr; + }*/ +}; + +} + +#endif // DUMUX_CC_LOCAL_RESIDUAL_HH diff --git a/dumux/implicit/staggered/propertydefaults.hh b/dumux/implicit/staggered/propertydefaults.hh index 6f49cbfaba94a439a408223d3b97765d8b8a170e..1b385410ef3217973c131be0121db124dec21194 100644 --- a/dumux/implicit/staggered/propertydefaults.hh +++ b/dumux/implicit/staggered/propertydefaults.hh @@ -28,13 +28,24 @@ #define DUMUX_STAGGERED_PROPERTY_DEFAULTS_HH #include <dumux/implicit/propertydefaults.hh> -#include <dumux/porousmediumflow/implicit/fluxvariablescache.hh> +// #include <dumux/porousmediumflow/implicit/fluxvariablescache.hh> #include <dumux/discretization/staggered/globalfvgeometry.hh> #include <dumux/discretization/staggered/fvelementgeometry.hh> #include <dumux/discretization/staggered/subcontrolvolumeface.hh> #include <dumux/implicit/staggered/properties.hh> #include <dumux/discretization/methods.hh> -#include <dumux/discretization/cellcentered/stencils.hh> +#include <dumux/discretization/staggered/stencils.hh> + + +#include <dumux/freeflow/staggered/fluxvariables.hh> +#include <dumux/freeflow/staggered/fluxvariablescache.hh> + + + + +#include "assembler.hh" +#include "localresidual.hh" +#include "localjacobian.hh" namespace Dumux { @@ -88,13 +99,13 @@ SET_TYPE_PROP(StaggeredModel, GlobalVolumeVariables, Dumux::CCGlobalVolumeVariab SET_TYPE_PROP(StaggeredModel, GlobalFluxVariablesCache, Dumux::CCGlobalFluxVariablesCache<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFluxVariablesCache)>); //! The local jacobian operator -SET_TYPE_PROP(StaggeredModel, LocalJacobian, Dumux::CCLocalJacobian<TypeTag>); +SET_TYPE_PROP(StaggeredModel, LocalJacobian, Dumux::StaggeredLocalJacobian<TypeTag>); //! Assembler for the global jacobian matrix -SET_TYPE_PROP(StaggeredModel, JacobianAssembler, Dumux::CCAssembler<TypeTag>); +SET_TYPE_PROP(StaggeredModel, JacobianAssembler, Dumux::StaggeredAssembler<TypeTag>); //! The stencil container -SET_TYPE_PROP(StaggeredModel, StencilsVector, Dumux::CCStencilsVector<TypeTag>); +SET_TYPE_PROP(StaggeredModel, StencilsVector, Dumux::StaggeredStencilsVector<TypeTag>); //! The local flux variables cache vector class SET_TYPE_PROP(StaggeredModel, ElementFluxVariablesCache, Dumux::CCElementFluxVariablesCache<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFluxVariablesCache)>); @@ -102,12 +113,19 @@ SET_TYPE_PROP(StaggeredModel, ElementFluxVariablesCache, Dumux::CCElementFluxVar //! The global previous volume variables vector class SET_TYPE_PROP(StaggeredModel, ElementVolumeVariables, Dumux::CCElementVolumeVariables<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalVolumeVariablesCache)>); -//! Set the BaseLocalResidual to CCLocalResidual -SET_TYPE_PROP(StaggeredModel, BaseLocalResidual, Dumux::CCLocalResidual<TypeTag>); +//! Set the BaseLocalResidual to StaggeredLocalResidual +SET_TYPE_PROP(StaggeredModel, BaseLocalResidual, Dumux::StaggeredLocalResidual<TypeTag>); //! indicate that this is no box discretization SET_BOOL_PROP(StaggeredModel, ImplicitIsBox, false); +//! The class that contains the different flux variables (i.e. darcy, diffusion, energy) +//! by default, we set the flux variables to ones for porous media +SET_TYPE_PROP(StaggeredModel, FluxVariables, FreeFlowFluxVariables<TypeTag>); + +//! The flux variables cache class, by default the one for porous media +SET_TYPE_PROP(StaggeredModel, FluxVariablesCache, FreeFlowFluxVariablesCache<TypeTag>); + } // namespace Properties } // namespace Dumux diff --git a/test/freeflow/CMakeLists.txt b/test/freeflow/CMakeLists.txt index 358d7dd60a6ed25ca7df559b628e2edb3ef14c94..f9eb646820fce8066b2aec164a1c436917fdd607 100644 --- a/test/freeflow/CMakeLists.txt +++ b/test/freeflow/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory("navierstokes") +add_subdirectory("staggered") add_subdirectory("stokes") add_subdirectory("stokes2c") add_subdirectory("stokes2cni")