From 1684060cf83584297e4833af7fc91b67c22fd2c1 Mon Sep 17 00:00:00 2001 From: DennisGlaeser <dennis.glaeser@iws.uni-stuttgart.de> Date: Sun, 29 Jan 2017 18:30:23 +0100 Subject: [PATCH] [mpfa] change to new flux vars cache concept The flux variables cache now inherits from caches defined in the different laws. These also define a respective filler class that is called when updating the flux variables caches. That enables us to define different caches for different laws. --- .../cellcentered/mpfa/darcyslaw.hh | 104 ++- .../mpfa/elementfluxvariablescache.hh | 58 +- .../cellcentered/mpfa/fickslaw.hh | 101 +- .../mpfa/fluxvariablescachefiller.hh | 872 +++++++----------- .../mpfa/fluxvariablescachefillerbase.hh | 247 ----- .../cellcentered/mpfa/fourierslaw.hh | 79 +- .../mpfa/globalfluxvariablescache.hh | 20 +- .../mpfa/interactionvolumebase.hh | 3 + .../mpfa/omethod/interactionvolume.hh | 301 +++--- .../omethod/localsubcontrolentityseeds.hh | 2 +- .../implicit/fluxvariablescache.hh | 258 +----- 11 files changed, 804 insertions(+), 1241 deletions(-) delete mode 100644 dumux/discretization/cellcentered/mpfa/fluxvariablescachefillerbase.hh diff --git a/dumux/discretization/cellcentered/mpfa/darcyslaw.hh b/dumux/discretization/cellcentered/mpfa/darcyslaw.hh index 3aedae63d4..c26b0bca72 100644 --- a/dumux/discretization/cellcentered/mpfa/darcyslaw.hh +++ b/dumux/discretization/cellcentered/mpfa/darcyslaw.hh @@ -53,38 +53,126 @@ class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> 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 Element = typename GridView::template Codim<0>::Entity; using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper); using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); - using ElementFluxVarsCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); using ElementSolutionVector = typename GET_PROP_TYPE(TypeTag, ElementSolutionVector); // Always use the dynamic type for vectors (compatibility with the boundary) using BoundaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, BoundaryInteractionVolume); - using DynamicVector = typename BoundaryInteractionVolume::Vector; - - using Element = typename GridView::template Codim<0>::Entity; - using IndexType = typename GridView::IndexSet::IndexType; - using Stencil = std::vector<IndexType>; + using CoefficientVector = typename BoundaryInteractionVolume::Vector; + static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); static constexpr bool facetCoupling = GET_PROP_VALUE(TypeTag, MpfaFacetCoupling); static constexpr bool useTpfaBoundary = GET_PROP_VALUE(TypeTag, UseTpfaBoundary); static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries); + //! The cache used in conjunction with the mpfa Darcy's Law + class MpfaDarcysLawCache + { + // We always use the dynamic types here to be compatible on the boundary + using Stencil = typename BoundaryInteractionVolume::GlobalIndexSet; + using PositionVector = typename BoundaryInteractionVolume::PositionVector; + + public: + //! update cached objects + template<class InteractionVolume> + void updateAdvection(const InteractionVolume& iv, const SubControlVolumeFace &scvf) + { + const auto& localFaceData = iv.getLocalFaceData(scvf); + // update the quantities that are equal for all phases + advectionVolVarsStencil_ = iv.volVarsStencil(); + advectionVolVarsPositions_ = iv.volVarsPositions(); + advectionTij_ = iv.getTransmissibilities(localFaceData); + + // we will need the neumann flux transformation only on interior boundaries with facet coupling + if (enableInteriorBoundaries && facetCoupling) + advectionCij_ = iv.getNeumannFluxTransformationCoefficients(localFaceData); + + // The neumann fluxes always have to be set per phase + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + phaseNeumannFluxes_[phaseIdx] = iv.getNeumannFlux(localFaceData, phaseIdx); + } + + //! Returns the volume variables indices necessary for flux computation + //! This includes all participating boundary volume variables. Since we + //! do not allow mixed BC for the mpfa this is the same for all phases. + const Stencil& advectionVolVarsStencil() const + { return advectionVolVarsStencil_; } + + //! Returns the position on which the volume variables live. This is + //! necessary as we need to evaluate gravity also for the boundary volvars + const PositionVector& advectionVolVarsPositions() const + { return advectionVolVarsPositions_; } + + //! Returns the transmissibilities associated with the volume variables + //! All phases flow through the same rock, thus, tij are equal for all phases + const CoefficientVector& advectionTij() const + { return advectionTij_; } + + //! Returns the vector of coefficients with which the vector of neumann boundary conditions + //! has to be multiplied in order to transform them on the scvf this cache belongs to + const CoefficientVector& advectionCij() const + { return advectionCij_; } + + //! If the useTpfaBoundary property is set to false, the boundary conditions + //! are put into the local systems leading to possible contributions on all faces + Scalar advectionNeumannFlux(unsigned int phaseIdx) const + { return phaseNeumannFluxes_[phaseIdx]; } + + private: + // Quantities associated with advection + Stencil advectionVolVarsStencil_; + PositionVector advectionVolVarsPositions_; + CoefficientVector advectionTij_; + CoefficientVector advectionCij_; + std::array<Scalar, numPhases> phaseNeumannFluxes_; + }; + + //! Class that fills the cache corresponding to mpfa Darcy's Law + class MpfaDarcysLawCacheFiller + { + public: + //! Function to fill an MpfaDarcysLawCache of a given scvf + //! This interface has to be met by any advection-related cache filler class + template<class FluxVariablesCacheFiller> + static void fill(FluxVariablesCache& scvfFluxVarsCache, + const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf, + const FluxVariablesCacheFiller& fluxVarsCacheFiller) + { + // get interaction volume from the flux vars cache filler & upate the cache + if (problem.model().globalFvGeometry().touchesInteriorOrDomainBoundary(scvf)) + scvfFluxVarsCache.updateAdvection(fluxVarsCacheFiller.boundaryInteractionVolume(), scvf); + else + scvfFluxVarsCache.updateAdvection(fluxVarsCacheFiller.interactionVolume(), scvf); + } + }; + public: // state the discretization method this implementation belongs to static const DiscretizationMethods myDiscretizationMethod = DiscretizationMethods::CCMpfa; + // state the type for the corresponding cache and its filler + using Cache = MpfaDarcysLawCache; + using CacheFiller = MpfaDarcysLawCacheFiller; + static Scalar flux(const Problem& problem, const Element& element, const FVElementGeometry& fvGeometry, const ElementVolumeVariables& elemVolVars, const SubControlVolumeFace& scvf, const unsigned int phaseIdx, - const ElementFluxVarsCache& elemFluxVarsCache) + const ElementFluxVariablesCache& elemFluxVarsCache) { const bool gravity = GET_PARAM_FROM_GROUP(TypeTag, bool, Problem, EnableGravity); @@ -160,7 +248,7 @@ public: const auto& cij = fluxVarsCache.advectionCij(); // The vector of interior neumann fluxes - DynamicVector facetCouplingFluxes(cij.size(), 0.0); + CoefficientVector facetCouplingFluxes(cij.size(), 0.0); for (auto&& data : fluxVarsCache.interiorBoundaryData()) { // Add additional Dirichlet fluxes for interior Dirichlet faces diff --git a/dumux/discretization/cellcentered/mpfa/elementfluxvariablescache.hh b/dumux/discretization/cellcentered/mpfa/elementfluxvariablescache.hh index 2bae60663e..954afca4c2 100644 --- a/dumux/discretization/cellcentered/mpfa/elementfluxvariablescache.hh +++ b/dumux/discretization/cellcentered/mpfa/elementfluxvariablescache.hh @@ -140,7 +140,6 @@ public: globalScvfIndices_.clear(); const auto& problem = globalFluxVarsCache().problem_(); - const auto& globalFvGeometry = problem.model().globalFvGeometry(); const auto globalI = problem.elementMapper().index(element); const auto& assemblyMapI = problem.model().localJacobian().assemblyMap()[globalI]; @@ -160,11 +159,17 @@ public: for (auto scvfIdx : dataJ.scvfsJ) globalScvfIndices_.push_back(scvfIdx); - // prepare all the caches of the scvfs inside the corresponding interaction volumes using helper class + // helper class to fill flux variables caches + FluxVariablesCacheFiller filler(problem); + + // prepare all the caches of the scvfs inside the corresponding interaction volumes fluxVarsCache_.resize(globalScvfIndices_.size()); for (auto&& scvf : scvfs(fvGeometry)) - if (!(*this)[scvf].isUpdated()) - FluxVariablesCacheFiller::fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, *this); + { + auto& scvfCache = (*this)[scvf]; + if (!scvfCache.isUpdated()) + filler.fill(*this, scvfCache, element, fvGeometry, elemVolVars, scvf); + } // prepare the caches in the remaining neighbors for (auto&& dataJ : assemblyMapI) @@ -172,10 +177,11 @@ public: for (auto scvfIdx : dataJ.scvfsJ) { const auto& scvf = fvGeometry.scvf(scvfIdx); - if (!(*this)[scvf].isUpdated()) + auto& scvfCache = (*this)[scvf]; + if (!scvfCache.isUpdated()) { - auto elementJ = globalFvGeometry.element(dataJ.globalJ); - FluxVariablesCacheFiller::fillFluxVarCache(problem, elementJ, fvGeometry, elemVolVars, scvf, *this); + auto elementJ = problem.model().globalFvGeometry().element(dataJ.globalJ); + filler.fill(*this, scvfCache, elementJ, fvGeometry, elemVolVars, scvf); } } } @@ -215,12 +221,40 @@ private: const FVElementGeometry& fvGeometry, const ElementVolumeVariables& elemVolVars) { - for (auto&& scvf : scvfs(fvGeometry)) - (*this)[scvf].setUpdateStatus(false); + static const bool isSolIndependent = FluxVariablesCacheFiller::isSolutionIndependent(); - for (auto&& scvf : scvfs(fvGeometry)) - if (!(*this)[scvf].isUpdated()) - FluxVariablesCacheFiller::updateFluxVarCache(globalFluxVarsCache().problem_(), element, fvGeometry, elemVolVars, scvf, *this); + if (!isSolIndependent) + { + const auto& problem = globalFluxVarsCache().problem_(); + + // helper class to fill flux variables caches + FluxVariablesCacheFiller filler(problem); + + // set all the caches to "outdated" + for (auto& cache : fluxVarsCache_) + cache.setUpdateStatus(false); + + // the global index of the element at hand + const auto globalI = problem.elementMapper().index(element); + + // Let the filler do the update of the cache + for (unsigned int localScvfIdx = 0; localScvfIdx < globalScvfIndices_.size(); ++localScvfIdx) + { + const auto& scvf = fvGeometry.scvf(globalScvfIndices_[localScvfIdx]); + + auto& scvfCache = fluxVarsCache_[localScvfIdx]; + if (!scvfCache.isUpdated()) + { + // obtain the corresponding element + const auto scvfInsideScvIdx = scvf.insideScvIdx(); + const auto insideElement = scvfInsideScvIdx == globalI ? + element : + problem.model().globalFvGeometry().element(scvfInsideScvIdx); + + filler.update(*this, scvfCache, insideElement, fvGeometry, elemVolVars, scvf); + } + } + } } // get index of an scvf in the local container diff --git a/dumux/discretization/cellcentered/mpfa/fickslaw.hh b/dumux/discretization/cellcentered/mpfa/fickslaw.hh index 6aaf11e188..34cdec1077 100644 --- a/dumux/discretization/cellcentered/mpfa/fickslaw.hh +++ b/dumux/discretization/cellcentered/mpfa/fickslaw.hh @@ -54,10 +54,11 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); // Always use the dynamic type for vectors (compatibility with the boundary) using BoundaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, BoundaryInteractionVolume); - using DynamicVector = typename BoundaryInteractionVolume::Vector; + using CoefficientVector = typename BoundaryInteractionVolume::Vector; using Element = typename GridView::template Codim<0>::Entity; using IndexType = typename GridView::IndexSet::IndexType; @@ -67,10 +68,106 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> static constexpr bool facetCoupling = GET_PROP_VALUE(TypeTag, MpfaFacetCoupling); static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries); + //! The cache used in conjunction with the mpfa Fick's Law + class MpfaFicksLawCache + { + static const int numComponents = GET_PROP_VALUE(TypeTag, NumComponents); + + // We always use the dynamic types here to be compatible on the boundary + using Stencil = typename BoundaryInteractionVolume::GlobalIndexSet; + using PositionVector = typename BoundaryInteractionVolume::PositionVector; + + public: + //! The constructor. Initializes the Neumann flux to zero + MpfaFicksLawCache() { componentNeumannFluxes_.fill(0.0); } + + // update cached objects for the diffusive fluxes + template<typename InteractionVolume> + void updateDiffusion(const InteractionVolume& iv, const SubControlVolumeFace &scvf, + unsigned int phaseIdx, unsigned int compIdx) + { + const auto& localFaceData = iv.getLocalFaceData(scvf); + diffusionVolVarsStencils_[phaseIdx][compIdx] = iv.volVarsStencil(); + diffusionTij_[phaseIdx][compIdx] = iv.getTransmissibilities(localFaceData); + + if (enableInteriorBoundaries) + diffusionCij_[phaseIdx][compIdx] = iv.getNeumannFluxTransformationCoefficients(localFaceData); + + //! For compositional models, we associate neumann fluxes with the phases (main components) + //! This is done in the AdvectionCache. However, in single-phasic models we solve the phase AND + //! the component mass balance equations. Thus, in this case we have diffusive neumann contributions. + //! we assume compIdx = eqIdx + if (numPhases == 1 && phaseIdx != compIdx) + componentNeumannFluxes_[compIdx] = iv.getNeumannFlux(localFaceData, compIdx); + + } + + //! Returns the volume variables indices necessary for diffusive flux + //! computation. This includes all participating boundary volume variables + //! and it can be different for the phases & components. + const Stencil& diffusionVolVarsStencil(unsigned int phaseIdx, unsigned int compIdx) const + { return diffusionVolVarsStencils_[phaseIdx][compIdx]; } + + //! Returns the transmissibilities associated with the volume variables + //! This can be different for the phases & components. + const CoefficientVector& diffusionTij(unsigned int phaseIdx, unsigned int compIdx) const + { return diffusionTij_[phaseIdx][compIdx]; } + + //! Returns the vector of coefficients with which the vector of neumann boundary conditions + //! has to be multiplied in order to transform them on the scvf this cache belongs to + const CoefficientVector& diffusionCij(unsigned int phaseIdx, unsigned int compIdx) const + { return diffusionCij_[phaseIdx][compIdx]; } + + //! If the useTpfaBoundary property is set to false, the boundary conditions + //! are put into the local systems leading to possible contributions on all faces + Scalar componentNeumannFlux(unsigned int compIdx) const + { + assert(numPhases == 1); + return componentNeumannFluxes_[compIdx]; + } + + private: + // Quantities associated with molecular diffusion + std::array< std::array<Stencil, numComponents>, numPhases> diffusionVolVarsStencils_; + std::array< std::array<CoefficientVector, numComponents>, numPhases> diffusionTij_; + std::array< std::array<CoefficientVector, numComponents>, numPhases> diffusionCij_; + + // diffusive neumann flux for single-phasic models + std::array<Scalar, numComponents> componentNeumannFluxes_; + }; + + //! Class that fills the cache corresponding to mpfa Darcy's Law + class MpfaFicksLawCacheFiller + { + public: + //! Function to fill an MpfaFicksLawCache of a given scvf + //! This interface has to be met by any diffusion-related cache filler class + template<class FluxVariablesCacheFiller> + static void fill(FluxVariablesCache& scvfFluxVarsCache, + unsigned int phaseIdx, unsigned int compIdx, + const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf, + const FluxVariablesCacheFiller& fluxVarsCacheFiller) + { + // get interaction volume from the flux vars cache filler & upate the cache + if (problem.model().globalFvGeometry().touchesInteriorOrDomainBoundary(scvf)) + scvfFluxVarsCache.updateDiffusion(fluxVarsCacheFiller.boundaryInteractionVolume(), scvf, phaseIdx, compIdx); + else + scvfFluxVarsCache.updateDiffusion(fluxVarsCacheFiller.interactionVolume(), scvf, phaseIdx, compIdx); + } + }; + public: // state the discretization method this implementation belongs to static const DiscretizationMethods myDiscretizationMethod = DiscretizationMethods::CCMpfa; + // state the type for the corresponding cache and its filler + using Cache = MpfaFicksLawCache; + using CacheFiller = MpfaFicksLawCacheFiller; + static Scalar flux(const Problem& problem, const Element& element, const FVElementGeometry& fvGeometry, @@ -180,7 +277,7 @@ public: const auto& cij = fluxVarsCache.diffusionCij(phaseIdx, compIdx); // The vector of interior neumann fluxes - DynamicVector facetCouplingFluxes(cij.size(), 0.0); + CoefficientVector facetCouplingFluxes(cij.size(), 0.0); for (auto&& data : fluxVarsCache.interiorBoundaryData()) { // Add additional Dirichlet fluxes for interior Dirichlet faces diff --git a/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh b/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh index 0ca84820d8..79504a910e 100644 --- a/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh +++ b/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh @@ -20,616 +20,422 @@ * \file * \brief The flux variables cache filler class */ -#ifndef DUMUX_DISCRETIZATION_CCMPFA_GLOBAL_FLUXVARSCACHE_FILLER_HH -#define DUMUX_DISCRETIZATION_CCMPFA_GLOBAL_FLUXVARSCACHE_FILLER_HH +#ifndef DUMUX_DISCRETIZATION_CCMPFA_FLUXVARSCACHE_FILLER_HH +#define DUMUX_DISCRETIZATION_CCMPFA_FLUXVARSCACHE_FILLER_HH #include <dumux/implicit/properties.hh> #include <dumux/discretization/methods.hh> -#include "fluxvariablescachefillerbase.hh" namespace Dumux { -//! Forward declaration of the actual implementation -template<class TypeTag, bool advection, bool diffusion, bool energy> -class CCMpfaFluxVariablesCacheFillerImplementation; + +//! forward declaration of properties +namespace Properties +{ +NEW_PROP_TAG(NumPhases); +NEW_PROP_TAG(NumComponents); +NEW_PROP_TAG(ThermalConductivityModel); +}; /*! * \ingroup ImplicitModel * \brief Helper class to fill the flux var caches */ template<class TypeTag> -using CCMpfaFluxVariablesCacheFiller = CCMpfaFluxVariablesCacheFillerImplementation<TypeTag, - GET_PROP_VALUE(TypeTag, EnableAdvection), - GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion), - GET_PROP_VALUE(TypeTag, EnableEnergyBalance)>; - -//! Implementation for purely advective problems -template<class TypeTag> -class CCMpfaFluxVariablesCacheFillerImplementation<TypeTag, true, false, false> : public CCMpfaAdvectionCacheFiller<TypeTag> +class CCMpfaFluxVariablesCacheFiller { - using AdvectionFiller = CCMpfaAdvectionCacheFiller<TypeTag>; - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); - using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); using InteractionVolume = typename GET_PROP_TYPE(TypeTag, InteractionVolume); using BoundaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, BoundaryInteractionVolume); using Element = typename GridView::template Codim<0>::Entity; - static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); - static constexpr bool useTpfaBoundary = GET_PROP_VALUE(TypeTag, UseTpfaBoundary); - static constexpr bool solDependentAdvection = GET_PROP_VALUE(TypeTag, SolutionDependentAdvection); - static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries); + static constexpr bool doAdvection = GET_PROP_VALUE(TypeTag, EnableAdvection); + static constexpr bool doDiffusion = GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion); + static constexpr bool doHeatConduction = GET_PROP_VALUE(TypeTag, EnableEnergyBalance); + + static constexpr bool soldependentAdvection = GET_PROP_VALUE(TypeTag, SolutionDependentAdvection); + static constexpr bool soldependentDiffusion = GET_PROP_VALUE(TypeTag, SolutionDependentMolecularDiffusion); + static constexpr bool soldependentHeatConduction = GET_PROP_VALUE(TypeTag, SolutionDependentHeatConduction); + + enum ProcessIndices : unsigned int + { + advectionIdx, + diffusionIdx, + heatConductionIdx + }; public: - //! function to fill the flux var caches - template<class FluxVarsCacheContainer> - static void fillFluxVarCache(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace& scvf, - FluxVarsCacheContainer& fluxVarsCacheContainer) + //! The constructor. Sets the problem pointer + CCMpfaFluxVariablesCacheFiller(const Problem& problem) : problemPtr_(&problem) {} + + /*! + * \brief function to fill the flux variables caches + * + * \param fluxVarsCacheContainer Either the element or global flux variables cache + * \param scvfFluxVarsCache The flux var cache to be updated corresponding to the given scvf + * \param element The finite element + * \param fvGeometry The finite volume geometry + * \param elemVolVars The element volume variables + * \param scvf The corresponding sub-control volume face + * \param doSubCaches Array of bools indicating which sub caches have to be updated + */ + template<class FluxVariablesCacheContainer> + void fill(FluxVariablesCacheContainer& fluxVarsCacheContainer, + FluxVariablesCache& scvfFluxVarsCache, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf, + const std::array<bool, 3>& doSubCaches = std::array<bool, 3>({true, true, true})) { - // Instantiate interaction volume depending on if scvf touches the boundary or not - if (problem.model().globalFvGeometry().touchesInteriorOrDomainBoundary(scvf)) + // Set pointers + elementPtr_ = &element; + fvGeometryPtr_ = &fvGeometry; + elemVolVarsPtr_ = &elemVolVars; + scvfPtr_ = &scvf; + + // prepare interaction volume and fill caches of all the scvfs connected to it + const auto& globalFvGeometry = problem().model().globalFvGeometry(); + if (globalFvGeometry.touchesInteriorOrDomainBoundary(scvf)) { - BoundaryInteractionVolume iv(problem.model().globalFvGeometry().boundaryInteractionVolumeSeed(scvf), - problem, - fvGeometry, - elemVolVars); - - // forward to the filler for the advective quantities - AdvectionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - //set update status and maybe update data on interior boundaries - for (const auto scvfIdxJ : iv.globalScvfs()) - { - if (enableInteriorBoundaries) - fluxVarsCacheContainer[scvfIdxJ].updateInteriorBoundaryData(iv, fvGeometry.scvf(scvfIdxJ)); - fluxVarsCacheContainer[scvfIdxJ].setUpdateStatus(true); - } + bIv_ = std::make_unique<BoundaryInteractionVolume>(globalFvGeometry.boundaryInteractionVolumeSeed(scvf), + problem(), + fvGeometry, + elemVolVars); + + // fill the caches for all the scvfs in the interaction volume + fillCachesInInteractionVolume_(fluxVarsCacheContainer, scvfFluxVarsCache, boundaryInteractionVolume(), doSubCaches); } else { - InteractionVolume iv(problem.model().globalFvGeometry().interactionVolumeSeed(scvf), - problem, - fvGeometry, - elemVolVars); - - // forward to the filler for the advective quantities - AdvectionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // set update status - for (const auto scvfIdxJ : iv.globalScvfs()) - fluxVarsCacheContainer[scvfIdxJ].setUpdateStatus(true); + iv_ = std::make_unique<InteractionVolume>(globalFvGeometry.interactionVolumeSeed(scvf), + problem(), + fvGeometry, + elemVolVars); + + // fill the caches for all the scvfs in the interaction volume + fillCachesInInteractionVolume_(fluxVarsCacheContainer, scvfFluxVarsCache, interactionVolume(), doSubCaches); } } - //! function to update the flux var caches during derivative calculation - template<class FluxVarsCacheContainer> - static void updateFluxVarCache(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace& scvf, - FluxVarsCacheContainer& fluxVarsCacheContainer) + /*! + * \brief function to update the flux variables caches during derivative calculation + * + * \copydoc fill + */ + template<class FluxVariablesCacheContainer> + void update(FluxVariablesCacheContainer& fluxVarsCacheContainer, + FluxVariablesCache& scvfFluxVarsCache, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf) { - //! If advection is solution-independent, only update the caches for scvfs that touch - //! a boundary as we have to update the boundary contributions (possibly solution-dependent) - if (!solDependentAdvection) + // array of bool with which we indicate the sub-caches which have to be + // filled. During update, we only update solution-dependent quantities. + static const std::array<bool, 3> doSubCaches = []() { - const bool touchesBoundary = problem.model().globalFvGeometry().touchesInteriorOrDomainBoundary(scvf); - - //! Do the whole update where a boundary is touched - if (!useTpfaBoundary && touchesBoundary) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer); - //! Simply tell the cache that it is up to date - else - fluxVarsCacheContainer[scvf.index()].setUpdateStatus(true); - } - else - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer); + std::array<bool, 3> doCaches; + doCaches[ProcessIndices::advectionIdx] = doAdvection && soldependentAdvection; + doCaches[ProcessIndices::diffusionIdx] = doDiffusion && soldependentDiffusion; + doCaches[ProcessIndices::heatConductionIdx] = doHeatConduction && soldependentHeatConduction; + return doCaches; + } (); + + // forward to fill routine + fill(fluxVarsCacheContainer, scvfFluxVarsCache, element, fvGeometry, elemVolVars, scvf, doSubCaches); } -}; -//! Implementation for problems considering advection & diffusion -template<class TypeTag> -class CCMpfaFluxVariablesCacheFillerImplementation<TypeTag, true, true, false> : public CCMpfaAdvectionCacheFiller<TypeTag>, - public CCMpfaDiffusionCacheFiller<TypeTag> -{ - using AdvectionFiller = CCMpfaAdvectionCacheFiller<TypeTag>; - using DiffusionFiller = CCMpfaDiffusionCacheFiller<TypeTag>; + static bool isSolutionIndependent() + { + static const bool isSolDependent = (doAdvection && soldependentAdvection) || + (doDiffusion && soldependentDiffusion) || + (doHeatConduction && soldependentHeatConduction); + return !isSolDependent; + } - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); - using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); - using InteractionVolume = typename GET_PROP_TYPE(TypeTag, InteractionVolume); - using BoundaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, BoundaryInteractionVolume); - using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); - using MolecularDiffusionType = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType); + const InteractionVolume& interactionVolume() const + { return *iv_.get(); } - using Element = typename GridView::template Codim<0>::Entity; + const BoundaryInteractionVolume& boundaryInteractionVolume() const + { return *bIv_.get(); } - static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); +private: - static constexpr bool useTpfaBoundary = GET_PROP_VALUE(TypeTag, UseTpfaBoundary); - static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries); + const Problem& problem() const + { return *problemPtr_; } - static constexpr bool solDependentAdvection = GET_PROP_VALUE(TypeTag, SolutionDependentAdvection); - static constexpr bool advectionUsesMpfa = AdvectionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa; + const Element& element() const + { return *elementPtr_; } - static constexpr bool solDependentDiffusion = GET_PROP_VALUE(TypeTag, SolutionDependentMolecularDiffusion); - static constexpr bool diffusionUsesMpfa = MolecularDiffusionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa; + const FVElementGeometry& fvGeometry() const + { return *fvGeometryPtr_; } - //! Whether or not the caches have to be updated after solution deflection depends on - //! - the solution dependency of the parameters - //! - if tpfa is used on the boundaries (advection has to be updated because of neumann boundaries) - //! - if single-phasic compositional model is used - //! (diffusion has to be updated because of neumann boundaries for the transported component) - static constexpr bool doAdvectionUpdate = (solDependentAdvection || !useTpfaBoundary) && advectionUsesMpfa ; - static constexpr bool doDiffusionUpdate = (solDependentDiffusion || (numPhases == 1 && !useTpfaBoundary)) && diffusionUsesMpfa; + const ElementVolumeVariables& elemVolVars() const + { return *elemVolVarsPtr_; } - using BoolPair = std::pair<bool, bool>; + const SubControlVolumeFace& scvFace() const + { return *scvfPtr_; } -public: - //! function to fill the flux var caches - template<class FluxVarsCacheContainer> - static void fillFluxVarCache(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace& scvf, - FluxVarsCacheContainer& fluxVarsCacheContainer, - const BoolPair doAdvectionOrDiffusion = BoolPair(true, true)) + InteractionVolume& interactionVolume() + { return *iv_.get(); } + + BoundaryInteractionVolume& boundaryInteractionVolume() + { return *bIv_.get(); } + + //! Method to fill the flux var caches within an interaction volume + template<class FluxVariablesCacheContainer, class InteractionVolumeType> + void fillCachesInInteractionVolume_(FluxVariablesCacheContainer& fluxVarsCacheContainer, + FluxVariablesCache& scvfFluxVarsCache, + InteractionVolumeType& iv, + const std::array<bool, 3>& doSubCaches) { - // Instantiate interaction volume depending on if scvf touches the boundary or not - if (problem.model().globalFvGeometry().touchesInteriorOrDomainBoundary(scvf)) + // First we upate the interior boundary data and set the update status. + // We store pointers to the other flux var caches and the elements they are embedded in simultaneously. + // This way we have to obtain this data only once and can use it again in the sub-cache fillers. + std::vector<FluxVariablesCache*> otherFluxVarCaches(iv.globalLocalScvfPairedData().size()-1); + std::vector<Element> otherElements(iv.globalLocalScvfPairedData().size()-1); + + scvfFluxVarsCache.updateInteriorBoundaryData(iv, scvFace()); + scvfFluxVarsCache.setUpdateStatus(true); + + const auto curScvfIdx = scvFace().index(); + unsigned int otherScvfIdx = 0; + for (const auto& dataPair : iv.globalLocalScvfPairedData()) { - BoundaryInteractionVolume iv(problem.model().globalFvGeometry().boundaryInteractionVolumeSeed(scvf), - problem, - fvGeometry, - elemVolVars); - - // forward to the filler for the advective quantities - if (doAdvectionOrDiffusion.first) - AdvectionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // forward to the filler for the diffusive quantities - if (doAdvectionOrDiffusion.second) - DiffusionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - //set update status and maybe update data on interior boundaries - for (const auto scvfIdxJ : iv.globalScvfs()) - { - if (enableInteriorBoundaries) - fluxVarsCacheContainer[scvfIdxJ].updateInteriorBoundaryData(iv, fvGeometry.scvf(scvfIdxJ)); - fluxVarsCacheContainer[scvfIdxJ].setUpdateStatus(true); - } - } - else - { - InteractionVolume iv(problem.model().globalFvGeometry().interactionVolumeSeed(scvf), - problem, - fvGeometry, - elemVolVars); - - // forward to the filler for the advective quantities - if (doAdvectionOrDiffusion.first) - AdvectionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // forward to the filler for the diffusive quantities - if (doAdvectionOrDiffusion.second) - DiffusionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // set update status - for (const auto scvfIdxJ : iv.globalScvfs()) - fluxVarsCacheContainer[scvfIdxJ].setUpdateStatus(true); + const auto& scvfJ = *dataPair.first; + if (curScvfIdx == scvfJ.index()) + continue; + + // get the element scvfJ is embedded in + const auto scvfJInsideScvIndex = scvfJ.insideScvIdx(); + otherElements[otherScvfIdx] = scvfJInsideScvIndex == scvFace().insideScvIdx() ? + element() : + problem().model().globalFvGeometry().element(scvfJInsideScvIndex); + + // get the corresponding flux var cache + otherFluxVarCaches[otherScvfIdx] = &fluxVarsCacheContainer[scvfJ]; + otherFluxVarCaches[otherScvfIdx]->updateInteriorBoundaryData(iv, scvfJ); + otherFluxVarCaches[otherScvfIdx]->setUpdateStatus(true); + otherScvfIdx++; } - } - //! function to update the flux var caches during derivative calculation - template<class FluxVarsCacheContainer> - static void updateFluxVarCache(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace& scvf, - FluxVarsCacheContainer& fluxVarsCacheContainer) - { - const bool touchesDomainBoundary = problem.model().globalFvGeometry().touchesDomainBoundary(scvf); - - // maybe update Advection or diffusion or both - const bool updateAdvection = doAdvectionUpdate && touchesDomainBoundary; - const bool updateDiffusion = doDiffusionUpdate && touchesDomainBoundary; + //! Maybe update the advective quantities + if (doSubCaches[ProcessIndices::advectionIdx]) + fillAdvection(fluxVarsCacheContainer, scvfFluxVarsCache, iv, otherFluxVarCaches, otherElements); - if (updateAdvection && updateDiffusion) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolPair(true, true)); - else if (updateAdvection && !updateDiffusion) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolPair(true, false)); - else if (!updateAdvection && updateDiffusion) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolPair(false, true)); + //! Maybe update the diffusive quantities + if (doSubCaches[ProcessIndices::diffusionIdx]) + fillDiffusion(fluxVarsCacheContainer, scvfFluxVarsCache, iv, otherFluxVarCaches, otherElements); - // tell the cache that it has been updated in any case - fluxVarsCacheContainer[scvf.index()].setUpdateStatus(true); + //! Maybe update quantities related to heat conduction + if (doSubCaches[ProcessIndices::heatConductionIdx]) + fillHeatConduction(fluxVarsCacheContainer, scvfFluxVarsCache, iv, otherFluxVarCaches, otherElements); } -}; - -//! Implementation for problems considering advection & heat conduction -template<class TypeTag> -class CCMpfaFluxVariablesCacheFillerImplementation<TypeTag, true, false, true> : public CCMpfaAdvectionCacheFiller<TypeTag>, - public CCMpfaHeatConductionCacheFiller<TypeTag> -{ - using AdvectionFiller = CCMpfaAdvectionCacheFiller<TypeTag>; - using HeatConductionFiller = CCMpfaHeatConductionCacheFiller<TypeTag>; - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); - using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using InteractionVolume = typename GET_PROP_TYPE(TypeTag, InteractionVolume); - using BoundaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, BoundaryInteractionVolume); - using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); - using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); - using HeatConductionType = typename GET_PROP_TYPE(TypeTag, HeatConductionType); + //! method to fill the advective quantities + template<class FluxVariablesCacheContainer, class InteractionVolumeType, bool advectionEnabled = doAdvection> + typename std::enable_if<advectionEnabled>::type + fillAdvection(FluxVariablesCacheContainer& fluxVarsCacheContainer, + FluxVariablesCache& scvfFluxVarsCache, + InteractionVolumeType& iv, + const std::vector<FluxVariablesCache*> otherFluxVarCaches, + const std::vector<Element> otherElements) + { + using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); + using AdvectionFiller = typename AdvectionType::CacheFiller; - using Element = typename GridView::template Codim<0>::Entity; + static constexpr bool usesMpfa = AdvectionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa; - static constexpr bool useTpfaBoundary = GET_PROP_VALUE(TypeTag, UseTpfaBoundary); - static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries); + // maybe solve the local system subject to K + if (usesMpfa) + { + auto K = [] (const Element& element, const auto& volVars, const SubControlVolume& scv) + { return volVars.permeability(); }; + iv.solveLocalSystem(K); + } - static constexpr bool solDependentAdvection = GET_PROP_VALUE(TypeTag, SolutionDependentAdvection); - static constexpr bool advectionUsesMpfa = AdvectionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa; + // fill the caches of all scvfs within this interaction volume + AdvectionFiller::fill(scvfFluxVarsCache, problem(), element(), fvGeometry(), elemVolVars(), scvFace(), *this); - static constexpr bool solDependentHeatConduction = GET_PROP_VALUE(TypeTag, SolutionDependentHeatConduction); - static constexpr bool heatConductionUsesMpfa = HeatConductionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa; + unsigned int otherScvfIdx = 0; + const auto curScvfIdx = scvFace().index(); + for (const auto& dataPair : iv.globalLocalScvfPairedData()) + { + const auto& scvfJ = *dataPair.first; + if (curScvfIdx == scvfJ.index()) + continue; + + // fill corresponding cache + AdvectionFiller::fill(*otherFluxVarCaches[otherScvfIdx], + problem(), + otherElements[otherScvfIdx], + fvGeometry(), + elemVolVars(), + scvfJ, + *this); + otherScvfIdx++; + } + } - //! Whether or not the caches have to be updated after solution deflection depends on - //! - the solution dependency of the parameters - //! - if tpfa is used on the boundaries (advection has to be updated because of neumann boundaries) - static constexpr bool doAdvectionUpdate = (solDependentAdvection || !useTpfaBoundary) && advectionUsesMpfa ; - static constexpr bool doHeatConductionUpdate = (solDependentHeatConduction || !useTpfaBoundary) && heatConductionUsesMpfa; + //! do nothing if advection is not enabled + template<class FluxVariablesCacheContainer, class InteractionVolumeType, bool advectionEnabled = doAdvection> + typename std::enable_if<!advectionEnabled>::type + fillAdvection(FluxVariablesCacheContainer& fluxVarsCacheContainer, + FluxVariablesCache& scvfFluxVarsCache, + InteractionVolumeType& iv, + const std::vector<FluxVariablesCache*> otherFluxVarCaches, + const std::vector<Element> otherElements) + {} + + //! method to fill the diffusive quantities + template<class FluxVariablesCacheContainer, class InteractionVolumeType, bool diffusionEnabled = doDiffusion> + typename std::enable_if<diffusionEnabled>::type + fillDiffusion(FluxVariablesCacheContainer& fluxVarsCacheContainer, + FluxVariablesCache& scvfFluxVarsCache, + InteractionVolumeType& iv, + const std::vector<FluxVariablesCache*> otherFluxVarCaches, + const std::vector<Element> otherElements) + { + using DiffusionType = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType); + using DiffusionFiller = typename DiffusionType::CacheFiller; - using BoolPair = std::pair<bool, bool>; + static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); + static constexpr int numComponents = GET_PROP_VALUE(TypeTag, NumComponents); + static constexpr bool usesMpfa = DiffusionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa; -public: - //! function to fill the flux var caches - template<class FluxVarsCacheContainer> - static void fillFluxVarCache(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace& scvf, - FluxVarsCacheContainer& fluxVarsCacheContainer, - const BoolPair doAdvectionOrHeatConduction = BoolPair(true, true)) - { - // Instantiate interaction volume depending on if scvf touches the boundary or not - if (problem.model().globalFvGeometry().touchesInteriorOrDomainBoundary(scvf)) + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - BoundaryInteractionVolume iv(problem.model().globalFvGeometry().boundaryInteractionVolumeSeed(scvf), - problem, - fvGeometry, - elemVolVars); - - // forward to the filler for the advective quantities - if (doAdvectionOrHeatConduction.first) - AdvectionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // forward to the filler for the heat conduction quantities - if (doAdvectionOrHeatConduction.second) - HeatConductionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - //set update status and maybe update data on interior boundaries - for (const auto scvfIdxJ : iv.globalScvfs()) + for (unsigned int compIdx = 0; compIdx < numComponents; ++compIdx) { - if (enableInteriorBoundaries) - fluxVarsCacheContainer[scvfIdxJ].updateInteriorBoundaryData(iv, fvGeometry.scvf(scvfIdxJ)); - fluxVarsCacheContainer[scvfIdxJ].setUpdateStatus(true); + if (phaseIdx == compIdx) + continue; + + // solve the local system subject to the diffusion tensor (if uses mpfa) + if (usesMpfa) + { + auto D = [phaseIdx, compIdx](const Element& element, const auto& volVars, const SubControlVolume& scv) + { return volVars.diffusionCoefficient(phaseIdx, compIdx); }; + iv.solveLocalSystem(D); + } + + // fill the caches of all scvfs within this interaction volume + DiffusionFiller::fill(scvfFluxVarsCache, phaseIdx, compIdx, problem(), element(), fvGeometry(), elemVolVars(), scvFace(), *this); + + unsigned int otherScvfIdx = 0; + const auto curScvfIdx = scvFace().index(); + for (const auto& dataPair : iv.globalLocalScvfPairedData()) + { + const auto& scvfJ = *dataPair.first; + if (curScvfIdx == scvfJ.index()) + continue; + + // fill corresponding cache + DiffusionFiller::fill(*otherFluxVarCaches[otherScvfIdx], + phaseIdx, + compIdx, + problem(), + otherElements[otherScvfIdx], + fvGeometry(), + elemVolVars(), + scvfJ, + *this); + otherScvfIdx++; + } } } - else - { - InteractionVolume iv(problem.model().globalFvGeometry().interactionVolumeSeed(scvf), - problem, - fvGeometry, - elemVolVars); - - // forward to the filler for the advective quantities - if (doAdvectionOrHeatConduction.first) - AdvectionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // forward to the filler for the heat conduction quantities - if (doAdvectionOrHeatConduction.second) - HeatConductionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // set update status - for (const auto scvfIdxJ : iv.globalScvfs()) - fluxVarsCacheContainer[scvfIdxJ].setUpdateStatus(true); - } } - //! function to update the flux var caches during derivative calculation - template<class FluxVarsCacheContainer> - static void updateFluxVarCache(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace& scvf, - FluxVarsCacheContainer& fluxVarsCacheContainer) + //! do nothing if diffusion is not enabled + template<class FluxVariablesCacheContainer, class InteractionVolumeType, bool diffusionEnabled = doDiffusion> + typename std::enable_if<!diffusionEnabled>::type + fillDiffusion(FluxVariablesCacheContainer& fluxVarsCacheContainer, + FluxVariablesCache& scvfFluxVarsCache, + InteractionVolumeType& iv, + const std::vector<FluxVariablesCache*> otherFluxVarCaches, + const std::vector<Element> otherElements) + {} + + //! method to fill the quantities related to heat conduction + template<class FluxVariablesCacheContainer, class InteractionVolumeType, bool heatConductionEnabled = doHeatConduction> + typename std::enable_if<heatConductionEnabled>::type + fillHeatConduction(FluxVariablesCacheContainer& fluxVarsCacheContainer, + FluxVariablesCache& scvfFluxVarsCache, + InteractionVolumeType& iv, + const std::vector<FluxVariablesCache*> otherFluxVarCaches, + const std::vector<Element> otherElements) { - const bool touchesDomainBoundary = problem.model().globalFvGeometry().touchesDomainBoundary(scvf); - - // maybe update Advection or diffusion or both - const bool updateAdvection = doAdvectionUpdate && touchesDomainBoundary; - const bool updateHeatConduction = doHeatConductionUpdate && touchesDomainBoundary; - - if (updateAdvection && updateHeatConduction) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolPair(true, true)); - else if (updateAdvection && !updateHeatConduction) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolPair(true, false)); - else if (!updateAdvection && updateHeatConduction) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolPair(false, true)); - - // tell the cache that it has been updated in any case - fluxVarsCacheContainer[scvf.index()].setUpdateStatus(true); - } -}; + using HeatConductionType = typename GET_PROP_TYPE(TypeTag, HeatConductionType); + using HeatConductionFiller = typename HeatConductionType::CacheFiller; + using ThermalConductivityModel = typename GET_PROP_TYPE(TypeTag, ThermalConductivityModel); -//! Implementation for problems considering advection, diffusion & heat conduction -template<class TypeTag> -class CCMpfaFluxVariablesCacheFillerImplementation<TypeTag, true, true, true> : public CCMpfaAdvectionCacheFiller<TypeTag>, - public CCMpfaDiffusionCacheFiller<TypeTag>, - public CCMpfaHeatConductionCacheFiller<TypeTag> -{ - using AdvectionFiller = CCMpfaAdvectionCacheFiller<TypeTag>; - using DiffusionFiller = CCMpfaDiffusionCacheFiller<TypeTag>; - using HeatConductionFiller = CCMpfaHeatConductionCacheFiller<TypeTag>; + static constexpr bool usesMpfa = HeatConductionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa; - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); - using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); - using InteractionVolume = typename GET_PROP_TYPE(TypeTag, InteractionVolume); - using BoundaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, BoundaryInteractionVolume); - using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); - using HeatConductionType = typename GET_PROP_TYPE(TypeTag, HeatConductionType); - using MolecularDiffusionType = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType); - - using Element = typename GridView::template Codim<0>::Entity; - - static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); - - static constexpr bool useTpfaBoundary = GET_PROP_VALUE(TypeTag, UseTpfaBoundary); - static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries); - - static constexpr bool solDependentAdvection = GET_PROP_VALUE(TypeTag, SolutionDependentAdvection); - static constexpr bool advectionUsesMpfa = AdvectionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa; - - static constexpr bool solDependentDiffusion = GET_PROP_VALUE(TypeTag, SolutionDependentMolecularDiffusion); - static constexpr bool diffusionUsesMpfa = MolecularDiffusionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa; - - static constexpr bool solDependentHeatConduction = GET_PROP_VALUE(TypeTag, SolutionDependentHeatConduction); - static constexpr bool heatConductionUsesMpfa = HeatConductionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa; - - //! - if single-phasic compositional model is used - //! (diffusion has to be updated because of neumann boundaries for the transported component) - static constexpr bool doAdvectionUpdate = (solDependentAdvection || !useTpfaBoundary) && advectionUsesMpfa ; - static constexpr bool doDiffusionUpdate = (solDependentDiffusion || (numPhases == 1 && !useTpfaBoundary)) && diffusionUsesMpfa; - static constexpr bool doHeatConductionUpdate = (solDependentHeatConduction || !useTpfaBoundary) && heatConductionUsesMpfa; - - using BoolTriplet = std::array<bool, 3>; - -public: - //! function to fill the flux var caches - template<class FluxVarsCacheContainer> - static void fillFluxVarCache(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace& scvf, - FluxVarsCacheContainer& fluxVarsCacheContainer, - const BoolTriplet doAdvectionOrDiffusionOrHeatConduction = BoolTriplet({true, true, true})) - { - // Instantiate interaction volume depending on if scvf touches the boundary or not - if (problem.model().globalFvGeometry().touchesInteriorOrDomainBoundary(scvf)) + // maybe solve the local system subject to K + if (usesMpfa) { - BoundaryInteractionVolume iv(problem.model().globalFvGeometry().boundaryInteractionVolumeSeed(scvf), - problem, - fvGeometry, - elemVolVars); - - // forward to the filler for the advective quantities - if (doAdvectionOrDiffusionOrHeatConduction[0]) - AdvectionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // forward to the filler for the diffusive quantities - if (doAdvectionOrDiffusionOrHeatConduction[1]) - DiffusionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // forward to the filler for the diffusive quantities - if (doAdvectionOrDiffusionOrHeatConduction[2]) - HeatConductionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - //set update status and maybe update data on interior boundaries - for (const auto scvfIdxJ : iv.globalScvfs()) - { - if (enableInteriorBoundaries) - fluxVarsCacheContainer[scvfIdxJ].updateInteriorBoundaryData(iv, fvGeometry.scvf(scvfIdxJ)); - fluxVarsCacheContainer[scvfIdxJ].setUpdateStatus(true); - } + const auto& prob = problem(); + const auto& fvGeom = fvGeometry(); + auto lambda = [&prob, &fvGeom](const Element& element, const auto& volVars, const SubControlVolume& scv) + { return ThermalConductivityModel::effectiveThermalConductivity(volVars, + prob.spatialParams(), + element, + fvGeom, + scv); }; + iv.solveLocalSystem(lambda); } - else + + // fill the caches of all scvfs within this interaction volume + HeatConductionFiller::fill(scvfFluxVarsCache, problem(), element(), fvGeometry(), elemVolVars(), scvFace(), *this); + + unsigned int otherScvfIdx = 0; + const auto curScvfIdx = scvFace().index(); + for (const auto& dataPair : iv.globalLocalScvfPairedData()) { - InteractionVolume iv(problem.model().globalFvGeometry().interactionVolumeSeed(scvf), - problem, - fvGeometry, - elemVolVars); - - // forward to the filler for the advective quantities - if (doAdvectionOrDiffusionOrHeatConduction[0]) - AdvectionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // forward to the filler for the diffusive quantities - if (doAdvectionOrDiffusionOrHeatConduction[1]) - DiffusionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // forward to the filler for the diffusive quantities - if (doAdvectionOrDiffusionOrHeatConduction[2]) - HeatConductionFiller::fillCaches(problem, - element, - fvGeometry, - elemVolVars, - scvf, - iv, - fluxVarsCacheContainer); - - // set update status - for (const auto scvfIdxJ : iv.globalScvfs()) - fluxVarsCacheContainer[scvfIdxJ].setUpdateStatus(true); + const auto& scvfJ = *dataPair.first; + if (curScvfIdx == scvfJ.index()) + continue; + + // fill corresponding cache + HeatConductionFiller::fill(*otherFluxVarCaches[otherScvfIdx], + problem(), + otherElements[otherScvfIdx], + fvGeometry(), + elemVolVars(), + scvfJ, + *this); + otherScvfIdx++; } } - //! function to update the flux var caches during derivative calculation - template<class FluxVarsCacheContainer> - static void updateFluxVarCache(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace& scvf, - FluxVarsCacheContainer& fluxVarsCacheContainer) - { - const bool touchesDomainBoundary = problem.model().globalFvGeometry().touchesDomainBoundary(scvf); - - // maybe update Advection or diffusion or both - const bool updateAdvection = doAdvectionUpdate && touchesDomainBoundary; - const bool updateDiffusion = doDiffusionUpdate && touchesDomainBoundary; - const bool updateHeatConduction = doHeatConductionUpdate && touchesDomainBoundary; - - if (updateAdvection && updateDiffusion && updateHeatConduction) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolTriplet({true, true, true})); - else if (updateAdvection && updateDiffusion && !updateHeatConduction) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolTriplet({true, true, false})); - else if (updateAdvection && !updateDiffusion && !updateHeatConduction) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolTriplet({true, false, false})); - else if (updateAdvection && !updateDiffusion && updateHeatConduction) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolTriplet({true, false, true})); - else if (!updateAdvection && updateDiffusion && updateHeatConduction) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolTriplet({false, true, true})); - else if (!updateAdvection && updateDiffusion && !updateHeatConduction) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolTriplet({false, true, false})); - else if (!updateAdvection && !updateDiffusion && !updateHeatConduction) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolTriplet({false, false, false})); - else if (!updateAdvection && !updateDiffusion && updateHeatConduction) - fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCacheContainer, BoolTriplet({false, false, true})); - - - // tell the cache that it has been updated in any case - fluxVarsCacheContainer[scvf.index()].setUpdateStatus(true); - } + //! do nothing if heat conduction is disabled + template<class FluxVariablesCacheContainer, class InteractionVolumeType, bool heatConductionEnabled = doHeatConduction> + typename std::enable_if<!heatConductionEnabled>::type + fillHeatConduction(FluxVariablesCacheContainer& fluxVarsCacheContainer, + FluxVariablesCache& scvfFluxVarsCache, + InteractionVolumeType& iv, + const std::vector<FluxVariablesCache*> otherFluxVarCaches, + const std::vector<Element> otherElements) + {} + + const Problem* problemPtr_; + const Element* elementPtr_; + const FVElementGeometry* fvGeometryPtr_; + const ElementVolumeVariables* elemVolVarsPtr_; + const SubControlVolumeFace* scvfPtr_; + + // We store pointers to an inner and boundary interaction volume + // these are updated during the filling of the caches and the + // physics-related caches have access to them + std::unique_ptr<InteractionVolume> iv_; + std::unique_ptr<BoundaryInteractionVolume> bIv_; }; } // end namespace diff --git a/dumux/discretization/cellcentered/mpfa/fluxvariablescachefillerbase.hh b/dumux/discretization/cellcentered/mpfa/fluxvariablescachefillerbase.hh deleted file mode 100644 index 9ef0820f3a..0000000000 --- a/dumux/discretization/cellcentered/mpfa/fluxvariablescachefillerbase.hh +++ /dev/null @@ -1,247 +0,0 @@ -// -*- 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 classes for the flux variables cache filler - */ -#ifndef DUMUX_DISCRETIZATION_CCMPFA_GLOBAL_FLUXVARSCACHE_FILLER_BASE_HH -#define DUMUX_DISCRETIZATION_CCMPFA_GLOBAL_FLUXVARSCACHE_FILLER_BASE_HH - -#include <dumux/implicit/properties.hh> -#include <dumux/discretization/methods.hh> - -namespace Dumux -{ - -//! Forward declaration of property tags -namespace Properties -{ -NEW_PROP_TAG(Indices); -NEW_PROP_TAG(NumPhases); -NEW_PROP_TAG(NumComponents); -NEW_PROP_TAG(ThermalConductivityModel); -NEW_PROP_TAG(EffectiveDiffusivityModel); -} - -//! Fills the advective quantities in the caches -template<class TypeTag> -class CCMpfaAdvectionCacheFiller -{ - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); - using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); - using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); - using ElementSolution = typename GET_PROP_TYPE(TypeTag, ElementSolutionVector); - - using Element = typename GridView::template Codim<0>::Entity; - - static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); - static constexpr bool useTpfaBoundary = GET_PROP_VALUE(TypeTag, UseTpfaBoundary); - static constexpr bool enableDiffusion = GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion); - -public: - //! function to fill the flux var caches - template<class FluxVarsCacheContainer, class InteractionVolume> - static void fillCaches(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace& scvf, - InteractionVolume& iv, - FluxVarsCacheContainer& fluxVarsCacheContainer) - { - // lambda function to get the permeability tensor - auto getK = [&problem](const Element& element, - const VolumeVariables& volVars, - const SubControlVolume& scv) - { return volVars.permeability(); }; - - // solve the local system subject to the permeability - iv.solveLocalSystem(getK); - - // update the transmissibilities etc for each phase - const auto scvfIdx = scvf.index(); - const auto scvfLocalFaceData = iv.getLocalFaceData(scvf); - auto& scvfCache = fluxVarsCacheContainer[scvfIdx]; - scvfCache.updateAdvection(iv, scvf, scvfLocalFaceData); - - //! Update the transmissibilities in the other scvfs of the interaction volume - for (auto scvfIdxJ : iv.globalScvfs()) - { - if (scvfIdxJ != scvfIdx) - { - // update cache of scvfJ - const auto& scvfJ = fvGeometry.scvf(scvfIdxJ); - const auto scvfJLocalFaceData = iv.getLocalFaceData(scvfJ); - fluxVarsCacheContainer[scvfIdxJ].updateAdvection(iv, scvfJ, scvfJLocalFaceData); - } - } - } -}; - -//! Fills the diffusive quantities in the caches -template<class TypeTag> -class CCMpfaDiffusionCacheFiller -{ - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using EffDiffModel = typename GET_PROP_TYPE(TypeTag, EffectiveDiffusivityModel); - using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using MolecularDiffusionType = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType); - using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); - using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); - - using Element = typename GridView::template Codim<0>::Entity; - - static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); - static constexpr int numComponents = GET_PROP_VALUE(TypeTag, NumComponents); - static constexpr bool useTpfaBoundary = GET_PROP_VALUE(TypeTag, UseTpfaBoundary); - -public: - //! function to fill the flux var caches - template<class FluxVarsCacheContainer, class InteractionVolume> - static void fillCaches(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace& scvf, - InteractionVolume& iv, - FluxVarsCacheContainer& fluxVarsCacheContainer) - { - //! update the cache for all components in all phases. We exclude the case - //! phaseIdx = compIdx here, as diffusive fluxes of the major component in its - //! own phase are not calculated explicitly during assembly (see compositional local residual) - for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - for (unsigned int compIdx = 0; compIdx < numComponents; ++compIdx) - { - if (phaseIdx == compIdx) - continue; - - // lambda function to get the diffusion coefficient/tensor - auto getD = [phaseIdx, compIdx](const Element& element, - const VolumeVariables& volVars, - const SubControlVolume& scv) - { return volVars.diffusionCoefficient(phaseIdx, compIdx); }; - - // solve for the transmissibilities - iv.solveLocalSystem(getD); - - // update the caches - const auto scvfIdx = scvf.index(); - const auto scvfLocalFaceData = iv.getLocalFaceData(scvf); - auto& scvfCache = fluxVarsCacheContainer[scvfIdx]; - scvfCache.updateDiffusion(iv, scvf, scvfLocalFaceData, phaseIdx, compIdx); - - //! Update the caches in the other scvfs of the interaction volume - for (auto scvfIdxJ : iv.globalScvfs()) - { - if (scvfIdxJ != scvfIdx) - { - // store scvf pointer and local face data - const auto& scvfJ = fvGeometry.scvf(scvfIdxJ); - const auto scvfJLocalFaceData = iv.getLocalFaceData(scvfJ); - - // update cache - fluxVarsCacheContainer[scvfIdxJ].updateDiffusion(iv, scvfJ, scvfJLocalFaceData, phaseIdx, compIdx); - } - } - } - } - } -}; - -//! Fills the quantities for heat conduction in the caches -template<class TypeTag> -class CCMpfaHeatConductionCacheFiller -{ - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - using Indices = typename GET_PROP_TYPE(TypeTag, Indices); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); - using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using InteractionVolume = typename GET_PROP_TYPE(TypeTag, InteractionVolume); - using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); - using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); - using ThermalConductivityModel = typename GET_PROP_TYPE(TypeTag, ThermalConductivityModel); - using HeatConductionType = typename GET_PROP_TYPE(TypeTag, HeatConductionType); - - using Element = typename GridView::template Codim<0>::Entity; - - static const int energyEqIdx = Indices::energyEqIdx; - static const int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); - static const bool useTpfaBoundary = GET_PROP_VALUE(TypeTag, UseTpfaBoundary); - -public: - //! function to fill the flux var caches - template<class FluxVarsCacheContainer, class InteractionVolume> - static void fillCaches(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace& scvf, - InteractionVolume& iv, - FluxVarsCacheContainer& fluxVarsCacheContainer) - { - // lambda function to get the thermal conductivity - auto getLambda = [&problem, &fvGeometry](const Element& element, - const VolumeVariables& volVars, - const SubControlVolume& scv) - { return ThermalConductivityModel::effectiveThermalConductivity(volVars, - problem.spatialParams(), - element, - fvGeometry, - scv); }; - - // solve for the transmissibilities - iv.solveLocalSystem(getLambda); - - // update the caches - const auto scvfIdx = scvf.index(); - const auto scvfLocalFaceData = iv.getLocalFaceData(scvf); - auto& scvfCache = fluxVarsCacheContainer[scvfIdx]; - scvfCache.updateHeatConduction(iv, scvf, scvfLocalFaceData); - - //! Update the caches in the other scvfs of the interaction volume - for (auto scvfIdxJ : iv.globalScvfs()) - { - if (scvfIdxJ != scvfIdx) - { - // store scvf pointer and local face data - const auto& scvfJ = fvGeometry.scvf(scvfIdxJ); - const auto scvfJLocalFaceData = iv.getLocalFaceData(scvfJ); - - // update cache - fluxVarsCacheContainer[scvfIdxJ].updateHeatConduction(iv, scvfJ, scvfJLocalFaceData); - } - } - } -}; - - - -} // end namespace - -#endif diff --git a/dumux/discretization/cellcentered/mpfa/fourierslaw.hh b/dumux/discretization/cellcentered/mpfa/fourierslaw.hh index 03d00e0db4..76f15e411d 100644 --- a/dumux/discretization/cellcentered/mpfa/fourierslaw.hh +++ b/dumux/discretization/cellcentered/mpfa/fourierslaw.hh @@ -48,11 +48,12 @@ class FouriersLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); using ElementFluxVarsCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); using ThermalConductivityModel = typename GET_PROP_TYPE(TypeTag, ThermalConductivityModel); // Always use the dynamic type for vectors (compatibility with the boundary) using BoundaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, BoundaryInteractionVolume); - using DynamicVector = typename BoundaryInteractionVolume::Vector; + using CoefficientVector = typename BoundaryInteractionVolume::Vector; using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using Element = typename GridView::template Codim<0>::Entity; @@ -64,10 +65,84 @@ class FouriersLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> static constexpr int energyEqIdx = GET_PROP_TYPE(TypeTag, Indices)::energyEqIdx; + //! The cache used in conjunction with the mpfa Fourier's Law + class MpfaFouriersLawCache + { + using Stencil = typename BoundaryInteractionVolume::GlobalIndexSet; + public: + // update cached objects for heat conduction + template<typename InteractionVolume> + void updateHeatConduction(const InteractionVolume& iv, const SubControlVolumeFace &scvf) + { + const auto& localFaceData = iv.getLocalFaceData(scvf); + heatConductionVolVarsStencil_ = iv.volVarsStencil(); + heatConductionTij_ = iv.getTransmissibilities(localFaceData); + heatNeumannFlux_ = iv.getNeumannFlux(localFaceData, energyEqIdx); + + if (enableInteriorBoundaries) + heatConductionCij_ = iv.getNeumannFluxTransformationCoefficients(localFaceData); + } + + //! Returns the volume variables indices necessary for heat conduction flux + //! computation. This includes all participating boundary volume variables + //! and it can be different for the phases & components. + const Stencil& heatConductionVolVarsStencil() const + { return heatConductionVolVarsStencil_; } + + //! Returns the transmissibilities associated with the volume variables + //! This can be different for the phases & components. + const CoefficientVector& heatConductionTij() const + { return heatConductionTij_; } + + //! Returns the vector of coefficients with which the vector of neumann boundary conditions + //! has to be multiplied in order to transform them on the scvf this cache belongs to + const CoefficientVector& heatConductionCij() const + { return heatConductionCij_; } + + //! If the useTpfaBoundary property is set to false, the boundary conditions + //! are put into the local systems leading to possible contributions on all faces + Scalar heatNeumannFlux() const + { return heatNeumannFlux_; } + + private: + // Quantities associated with heat conduction + Stencil heatConductionVolVarsStencil_; + CoefficientVector heatConductionTij_; + CoefficientVector heatConductionCij_; + Scalar heatNeumannFlux_; + }; + + //! Class that fills the cache corresponding to mpfa Darcy's Law + class MpfaFouriersLawCacheFiller + { + public: + //! Function to fill an MpfaDarcysLawCache of a given scvf + //! This interface has to be met by any cache filler class for heat conduction quantities + template<class FluxVariablesCacheFiller> + static void fill(FluxVariablesCache& scvfFluxVarsCache, + const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf, + const FluxVariablesCacheFiller& fluxVarsCacheFiller) + { + // get interaction volume from the flux vars cache filler & upate the cache + if (problem.model().globalFvGeometry().touchesInteriorOrDomainBoundary(scvf)) + scvfFluxVarsCache.updateHeatConduction(fluxVarsCacheFiller.boundaryInteractionVolume(), scvf); + else + scvfFluxVarsCache.updateHeatConduction(fluxVarsCacheFiller.interactionVolume(), scvf); + } + }; + public: // state the discretization method this implementation belongs to static const DiscretizationMethods myDiscretizationMethod = DiscretizationMethods::CCMpfa; + // state the type for the corresponding cache and its filler + using Cache = MpfaFouriersLawCache; + using CacheFiller = MpfaFouriersLawCacheFiller; + static Scalar flux(const Problem& problem, const Element& element, const FVElementGeometry& fvGeometry, @@ -110,7 +185,7 @@ public: const auto& cij = fluxVarsCache.heatConductionCij(); // The Vector of interior neumann fluxes - DynamicVector facetCouplingFluxes(cij.size(), 0.0); + CoefficientVector facetCouplingFluxes(cij.size(), 0.0); for (auto&& data : fluxVarsCache.interiorBoundaryData()) { // Add additional Dirichlet fluxes for interior Dirichlet faces diff --git a/dumux/discretization/cellcentered/mpfa/globalfluxvariablescache.hh b/dumux/discretization/cellcentered/mpfa/globalfluxvariablescache.hh index 6bafe80a78..79ace006a3 100644 --- a/dumux/discretization/cellcentered/mpfa/globalfluxvariablescache.hh +++ b/dumux/discretization/cellcentered/mpfa/globalfluxvariablescache.hh @@ -24,8 +24,7 @@ #define DUMUX_DISCRETIZATION_CCMPFA_GLOBAL_FLUXVARSCACHE_HH #include <dumux/implicit/properties.hh> - -#include "fluxvariablescachefiller.hh" +#include <dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh> namespace Dumux { @@ -45,8 +44,11 @@ class CCMpfaGlobalFluxVariablesCache; template<class TypeTag> class CCMpfaGlobalFluxVariablesCache<TypeTag, true> { - // the local class needs access to the problem + // the local class need access to the problem friend typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + // the filler needs access to the operators + friend CCMpfaFluxVariablesCacheFiller<TypeTag>; + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using IndexType = typename GridView::IndexSet::IndexType; @@ -66,6 +68,10 @@ public: void update(Problem& problem) { problemPtr_ = &problem; + + // instantiate helper class to fill the caches + FluxVariablesCacheFiller filler(problem); + const auto& globalFvGeometry = problem.model().globalFvGeometry(); fluxVarsCache_.resize(globalFvGeometry.numScvf()); for (const auto& element : elements(problem.gridView())) @@ -81,7 +87,7 @@ public: for (auto&& scvf : scvfs(fvGeometry)) { if (!fluxVarsCache_[scvf.index()].isUpdated()) - FluxVariablesCacheFiller::fillFluxVarCache(problem, element, fvGeometry, elemVolVars, scvf, fluxVarsCache_); + filler.fill(*this, fluxVarsCache_[scvf.index()], element, fvGeometry, elemVolVars, scvf); } } } @@ -97,6 +103,12 @@ public: private: // access operators in the case of caching + const FluxVariablesCache& operator [](const SubControlVolumeFace& scvf) const + { return fluxVarsCache_[scvf.index()]; } + + FluxVariablesCache& operator [](const SubControlVolumeFace& scvf) + { return fluxVarsCache_[scvf.index()]; } + const FluxVariablesCache& operator [](IndexType scvfIdx) const { return fluxVarsCache_[scvfIdx]; } diff --git a/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh b/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh index af8c2d793f..32af446ad2 100644 --- a/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh +++ b/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh @@ -79,6 +79,9 @@ public: LocalIndexType localScvIndex; bool isOutside; + //! default constructor + LocalFaceData() = default; + //! Constructor fully initializing the members LocalFaceData(const LocalIndexType faceIndex, const LocalIndexType scvIndex, diff --git a/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh b/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh index 9450d4da51..7d3bb189bc 100644 --- a/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh +++ b/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh @@ -135,6 +135,9 @@ public: using typename ParentType::PositionVector; using typename ParentType::Seed; + // structure to store global and local face data + using GlobalLocalFaceDataPair = std::pair<const SubControlVolumeFace*, LocalFaceData>; + CCMpfaOInteractionVolume(const Seed& seed, const Problem& problem, const FVElementGeometry& fvGeometry, @@ -142,69 +145,10 @@ public: : problemPtr_(&problem), fvGeometryPtr_(&fvGeometry), elemVolVarsPtr_(&elemVolVars), - onDomainOrInteriorBoundary_(seed.onDomainOrInteriorBoundary()), - globalScvfIndices_(seed.globalScvfIndices()) + onDomainOrInteriorBoundary_(seed.onDomainOrInteriorBoundary()) { - // create local sub control entities from the seed - createLocalEntities_(seed); - - // reserve memory - auto numLocalScvs = localScvs_.size(); - auto numLocalScvfs = localScvfs_.size(); - auto maxNumVolVars = numLocalScvs + numLocalScvfs; - volVarsStencil_ = seed.globalScvIndices(); // boundary vol vars are placed at the end - volVarsStencil_.reserve(maxNumVolVars); - volVarsPositions_.reserve(maxNumVolVars); - dirichletFaceIndexSet_.reserve(numLocalScvfs); - interiorDirichletFaceIndexSet_.reserve(numLocalScvfs); - interiorBoundaryFaceIndexSet_.reserve(numLocalScvfs); - interiorBoundaryData_.reserve(numLocalScvfs); - fluxFaceIndexSet_.reserve(numLocalScvfs); - - // the positions where the vol vars are defined at (required for the gravitational acceleration) - for (auto&& localScv : localScvs_) - volVarsPositions_.push_back(localScv.center()); - - // maybe add dirichlet vol var indices and set up local index sets of flux and dirichlet faces - LocalIndexType localScvfIdx = 0; - for (auto&& localScvf : localScvfs_) - { - auto faceType = localScvf.faceType(); - - // eventually add vol var index and corresponding position - if (faceType == MpfaFaceTypes::dirichlet) - { - volVarsStencil_.push_back(localScvf.outsideGlobalScvIndex()); - volVarsPositions_.push_back(localScvf.ip()); - dirichletFaceIndexSet_.push_back(localScvfIdx++); - } - else if (faceType == MpfaFaceTypes::interior || faceType == MpfaFaceTypes::neumann) - { - fluxFaceIndexSet_.push_back(localScvfIdx++); - } - else if (faceType == MpfaFaceTypes::interiorNeumann) - { - interiorBoundaryData_.push_back(InteriorBoundaryData(problem, - localScvf.insideGlobalScvIndex(), - localScvf.insideGlobalScvfIndex(), - fluxFaceIndexSet_.size(), - faceType)); - fluxFaceIndexSet_.push_back(localScvfIdx); - interiorBoundaryFaceIndexSet_.push_back(localScvfIdx++); - } - else if(faceType == MpfaFaceTypes::interiorDirichlet) - { - interiorBoundaryData_.push_back(InteriorBoundaryData(problem, - localScvf.insideGlobalScvIndex(), - localScvf.insideGlobalScvfIndex(), - interiorDirichletFaceIndexSet_.size(), - faceType)); - interiorDirichletFaceIndexSet_.push_back(localScvfIdx); - interiorBoundaryFaceIndexSet_.push_back(localScvfIdx++); - } - else - DUNE_THROW(Dune::InvalidStateException, "Unknown mpfa face type."); - } + // set up the local scope of this interaction volume + bind(seed); // initialize the vector containing the neumann fluxes assembleNeumannFluxVector_(); @@ -239,123 +183,6 @@ public: T_ += D; } - //! gets local data on a global scvf within the interaction volume - //! specialization for dim = dimWorld - template<int d = dim, int dw = dimWorld> - typename std::enable_if< (d == dw), LocalFaceData >::type - getLocalFaceData(const SubControlVolumeFace& scvf) const - { - auto scvfGlobalIdx = scvf.index(); - - // if interior boundaries are disabled, do simplified search - if (!enableInteriorBoundaries) - { - LocalIndexType localIdx = 0; - for (auto&& localScvf : localScvfs_) - { - if (localScvf.insideGlobalScvfIndex() == scvfGlobalIdx) - return LocalFaceData(localIdx, localScvf.insideLocalScvIndex(), false); - - if (!localScvf.boundary() && localScvf.outsideGlobalScvfIndex() == scvfGlobalIdx) - return LocalFaceData(localIdx, localScvf.outsideLocalScvIndex(), true); - - localIdx++; - } - } - else - { - // first check the inside data of the faces - LocalIndexType localIdx = 0; - for (auto&& localScvf : localScvfs_) - { - if (localScvf.insideGlobalScvfIndex() == scvfGlobalIdx) - return LocalFaceData(localIdx, localScvf.insideLocalScvIndex(), false); - localIdx++; - } - - // then check the outside data of the faces - localIdx = 0; - for (auto&& localScvf : localScvfs_) - { - if (!localScvf.boundary() && localScvf.outsideGlobalScvfIndex() == scvfGlobalIdx) - return LocalFaceData(localIdx, localScvf.outsideLocalScvIndex(), true); - localIdx++; - } - } - - DUNE_THROW(Dune::InvalidStateException, "Could not find the local scv face in the interaction volume for the given scvf with index: " << scvf.index()); - } - - //! gets local data on a global scvf within the interaction volume - //! specialization for dim < dimWorld - template<int d = dim, int dw = dimWorld> - typename std::enable_if< (d < dw), LocalFaceData >::type - getLocalFaceData(const SubControlVolumeFace& scvf) const - { - const auto scvfGlobalIdx = scvf.index(); - - // if interior boundaries are disabled, do simplified search - if (!enableInteriorBoundaries) - { - LocalIndexType localFaceIdx = 0; - for (auto&& localScvf : localScvfs_) - { - if (localScvf.insideGlobalScvfIndex() == scvfGlobalIdx) - return LocalFaceData(localFaceIdx, localScvf.insideLocalScvIndex(), false); - - if (!localScvf.boundary() && MpfaHelper::contains(localScvf.outsideGlobalScvfIndices(), scvfGlobalIdx)) - { - if (localScvf.outsideLocalScvIndices().size() == 1) - return LocalFaceData(localFaceIdx, localScvf.outsideLocalScvIndex(), true); - - // Now we have to find wich local scv is the one the global scvf is embedded in - const auto scvGlobalIdx = scvf.insideScvIdx(); - for (auto localScvIdx : localScvf.outsideLocalScvIndices()) - if (localScv_(localScvIdx).globalIndex() == scvGlobalIdx) - return LocalFaceData(localFaceIdx, localScvIdx, true); - - DUNE_THROW(Dune::InvalidStateException, "Could not find the local scv in the interaction volume for the given scvf with index: " << scvfGlobalIdx); - } - - localFaceIdx++; - } - } - else - { - // first check the inside data of the faces - LocalIndexType localFaceIdx = 0; - for (auto&& localScvf : localScvfs_) - { - if (localScvf.insideGlobalScvfIndex() == scvfGlobalIdx) - return LocalFaceData(localFaceIdx, localScvf.insideLocalScvIndex(), false); - localFaceIdx++; - } - - // then check the outside data - localFaceIdx = 0; - for (auto&& localScvf : localScvfs_) - { - if (!localScvf.boundary() && MpfaHelper::contains(localScvf.outsideGlobalScvfIndices(), scvfGlobalIdx)) - { - if (localScvf.outsideLocalScvIndices().size() == 1) - return LocalFaceData(localFaceIdx, localScvf.outsideLocalScvIndex(), true); - - // Now we have to find wich local scv is the one the global scvf is embedded in - const auto scvGlobalIdx = scvf.insideScvIdx(); - for (auto localScvIdx : localScvf.outsideLocalScvIndices()) - if (localScv_(localScvIdx).globalIndex() == scvGlobalIdx) - return LocalFaceData(localFaceIdx, localScvIdx, true); - - DUNE_THROW(Dune::InvalidStateException, "Could not find the local scv in the interaction volume for the given scvf with index: " << scvfGlobalIdx); - } - - localFaceIdx++; - } - } - - DUNE_THROW(Dune::InvalidStateException, "Could not find the local scv face in the interaction volume for the given scvf with index: " << scvfGlobalIdx); - } - //! Gets the transmissibilities for a sub-control volume face within the interaction volume. //! specialization for dim == dimWorld template<int d = dim, int dw = dimWorld> @@ -455,6 +282,9 @@ public: return flux; } + const LocalFaceData& getLocalFaceData(const SubControlVolumeFace& scvf) const + { return globalLocalScvfPairedData_[this->findIndexInVector(globalScvfIndices_, scvf.index())].second; } + bool onDomainOrInteriorBoundary() const { return onDomainOrInteriorBoundary_; } @@ -464,8 +294,8 @@ public: const PositionVector& volVarsPositions() const { return volVarsPositions_; } - const GlobalIndexSet& globalScvfs() const - { return globalScvfIndices_; } + const std::vector<GlobalLocalFaceDataPair>& globalLocalScvfPairedData() const + { return globalLocalScvfPairedData_; } const std::vector<InteriorBoundaryData>& interiorBoundaryData() const { return interiorBoundaryData_; } @@ -493,27 +323,107 @@ private: const Element& localElement_(const LocalIndexType localScvIdx) const { return localElements_[localScvIdx]; } - void createLocalEntities_(const Seed& seed) + void bind(const Seed& seed) { - const auto numScvs = seed.scvSeeds().size(); - const auto numScvfs = seed.scvfSeeds().size(); - - localElements_.reserve(numScvs); - localScvs_.reserve(numScvs); - localScvfs_.reserve(numScvfs); + const auto numLocalScvs = seed.scvSeeds().size(); + const auto numLocalScvfs = seed.scvfSeeds().size(); + const auto numGlobalScvfs = seed.globalScvfIndices().size(); + const auto maxNumVolVars = numLocalScvs + numLocalScvfs; + + //! reserve memory for local entities + localElements_.reserve(numLocalScvs); + localScvs_.reserve(numLocalScvs); + localScvfs_.reserve(numLocalScvfs); + globalLocalScvfPairedData_.reserve(numGlobalScvfs); + globalScvfIndices_.reserve(numGlobalScvfs); + + //! reserve memory for the index sets + volVarsStencil_ = seed.globalScvIndices(); // boundary vol vars are placed at the end + volVarsStencil_.reserve(maxNumVolVars); + volVarsPositions_.reserve(maxNumVolVars); + dirichletFaceIndexSet_.reserve(numLocalScvfs); + interiorDirichletFaceIndexSet_.reserve(numLocalScvfs); + interiorBoundaryFaceIndexSet_.reserve(numLocalScvfs); + interiorBoundaryData_.reserve(numLocalScvfs); + fluxFaceIndexSet_.reserve(numLocalScvfs); + // set up quantities related to sub-control volumes for (auto&& scvSeed : seed.scvSeeds()) { - auto element = problem_().model().globalFvGeometry().element(scvSeed.globalIndex()); - localScvs_.emplace_back(LocalScvType(problem_(), element, fvGeometry_(), scvSeed)); + const auto element = problem_().model().globalFvGeometry().element(scvSeed.globalIndex()); + localScvs_.emplace_back(problem_(), element, fvGeometry_(), scvSeed); localElements_.emplace_back(std::move(element)); + volVarsPositions_.push_back(localScvs_.back().center()); } + // set up quantitites related to sub-control volume faces + LocalIndexType localFaceIdx = 0; for (auto&& scvfSeed : seed.scvfSeeds()) { + const auto faceType = scvfSeed.faceType(); + // we have to use the "inside" scv face here - auto&& scvf = fvGeometry_().scvf(scvfSeed.insideGlobalScvfIndex()); - localScvfs_.emplace_back(LocalScvfType(scvfSeed, scvf)); + const auto& scvf = fvGeometry_().scvf(scvfSeed.insideGlobalScvfIndex()); + localScvfs_.emplace_back(scvfSeed, scvf); + + // create global/local face data for this face + // we simultaneously store the corresponding global scvf indices (allows global to local mapping later) + globalLocalScvfPairedData_.emplace_back(&scvf, LocalFaceData(localFaceIdx, scvfSeed.insideLocalScvIndex(), false)); + globalScvfIndices_.push_back(scvf.index()); + + // set data depending on the face type + // obtain the local scvf entity just inserted + const auto& localScvf = localScvfs_.back(); + + // interior faces are flux faces + // also, set up outside global/local data for all the neighbors + if (faceType == MpfaFaceTypes::interior) + { + for (unsigned int i = 0; i < localScvf.outsideGlobalScvfIndices().size(); ++i) + { + const auto& outsideScvf = fvGeometry_().scvf(localScvf.outsideGlobalScvfIndex(i)); + globalLocalScvfPairedData_.emplace_back( &outsideScvf, + LocalFaceData(localFaceIdx, scvfSeed.outsideLocalScvIndex(i), true) ); + globalScvfIndices_.push_back(outsideScvf.index()); + } + fluxFaceIndexSet_.push_back(localFaceIdx++); + } + // dirichlet faces are in the "stencil" + else if (faceType == MpfaFaceTypes::dirichlet) + { + volVarsStencil_.push_back(localScvf.outsideGlobalScvIndex()); + volVarsPositions_.push_back(localScvf.ip()); + dirichletFaceIndexSet_.push_back(localFaceIdx++); + } + // neumann faces have an unknown associated with them + else if (faceType == MpfaFaceTypes::neumann) + { + fluxFaceIndexSet_.push_back(localFaceIdx++); + } + // interior neumann faces additionally produce interior boundary data + else if (faceType == MpfaFaceTypes::interiorNeumann) + { + interiorBoundaryData_.push_back(InteriorBoundaryData(problem_(), + localScvf.insideGlobalScvIndex(), + localScvf.insideGlobalScvfIndex(), + fluxFaceIndexSet_.size(), + faceType)); + fluxFaceIndexSet_.push_back(localFaceIdx); + interiorBoundaryFaceIndexSet_.push_back(localFaceIdx++); + } + // as well as interior Dirichlet boundaries + else if (faceType == MpfaFaceTypes::interiorDirichlet) + { + interiorBoundaryData_.push_back(InteriorBoundaryData(problem_(), + localScvf.insideGlobalScvIndex(), + localScvf.insideGlobalScvfIndex(), + interiorDirichletFaceIndexSet_.size(), + faceType)); + interiorDirichletFaceIndexSet_.push_back(localFaceIdx); + interiorBoundaryFaceIndexSet_.push_back(localFaceIdx++); + } + else + DUNE_THROW(Dune::InvalidStateException, "Face type can not be handled by the mpfa o-method."); } } @@ -867,11 +777,13 @@ private: bool onDomainOrInteriorBoundary_; + // Variables defining the local scope std::vector<Element> localElements_; std::vector<LocalScvType> localScvs_; std::vector<LocalScvfType> localScvfs_; - + std::vector<GlobalLocalFaceDataPair> globalLocalScvfPairedData_; GlobalIndexSet globalScvfIndices_; + GlobalIndexSet volVarsStencil_; PositionVector volVarsPositions_; @@ -881,12 +793,13 @@ private: LocalIndexSet interiorBoundaryFaceIndexSet_; std::vector<InteriorBoundaryData> interiorBoundaryData_; + // Quantities depending on the tensor the system is solved for std::vector< std::vector< DimVector > > wijk_; - DynamicMatrix T_; DynamicMatrix AinvB_; DynamicMatrix CAinv_; + // stores all the neumann fluxes appearing in this interaction volume std::vector<PrimaryVariables> neumannFluxes_; }; diff --git a/dumux/discretization/cellcentered/mpfa/omethod/localsubcontrolentityseeds.hh b/dumux/discretization/cellcentered/mpfa/omethod/localsubcontrolentityseeds.hh index db5884a5ec..730017018c 100644 --- a/dumux/discretization/cellcentered/mpfa/omethod/localsubcontrolentityseeds.hh +++ b/dumux/discretization/cellcentered/mpfa/omethod/localsubcontrolentityseeds.hh @@ -165,7 +165,7 @@ public: // for grids with dim < dimWorld, some outside indices might be doubled // we want to make the outside indices unique, but, the i-th outside global scvf face - // should correspond to the j-th outside local scv.Therefore we apply the same operations on both containers + // should correspond to the i-th outside local scv.Therefore we apply the same operations on both containers void makeOutsideDataUnique() { auto scvIt = outsideLocalScvIndices_.begin(); diff --git a/dumux/porousmediumflow/implicit/fluxvariablescache.hh b/dumux/porousmediumflow/implicit/fluxvariablescache.hh index 1e01be146b..181aa3240c 100644 --- a/dumux/porousmediumflow/implicit/fluxvariablescache.hh +++ b/dumux/porousmediumflow/implicit/fluxvariablescache.hh @@ -162,240 +162,20 @@ private: // forward declaration of the base class of the mpfa flux variables cache template<class TypeTag, bool EnableAdvection, bool EnableMolecularDiffusion, bool EnableEnergyBalance> -class MpfaPorousMediumFluxVariablesCache; +class CCMpfaPorousMediumFluxVariablesCache; -//! Base class for the advective cache in mpfa methods -template<class TypeTag> -class MpfaAdvectionCache -{ - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using BoundaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, BoundaryInteractionVolume); - - static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); - - static constexpr bool facetCoupling = GET_PROP_VALUE(TypeTag, MpfaFacetCoupling); - static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries); - - // We always use the dynamic types here to be compatible on the boundary - using IndexType = typename GridView::IndexSet::IndexType; - using Stencil = typename BoundaryInteractionVolume::GlobalIndexSet; - using CoefficientVector = typename BoundaryInteractionVolume::Vector; - using PositionVector = typename BoundaryInteractionVolume::PositionVector; - -public: - //! update cached objects - template<class InteractionVolume, class LocalFaceData> - void updateAdvection(const InteractionVolume& interactionVolume, - const SubControlVolumeFace &scvf, - const LocalFaceData& scvfLocalFaceData) - { - // update the quantities that are equal for all phases - advectionVolVarsStencil_ = interactionVolume.volVarsStencil(); - advectionVolVarsPositions_ = interactionVolume.volVarsPositions(); - advectionTij_ = interactionVolume.getTransmissibilities(scvfLocalFaceData); - - // we will need the neumann flux transformation only on interior boundaries with facet coupling - if (enableInteriorBoundaries && facetCoupling) - advectionCij_ = interactionVolume.getNeumannFluxTransformationCoefficients(scvfLocalFaceData); - - // The neumann fluxes always have to be set per phase - for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - phaseNeumannFluxes_[phaseIdx] = interactionVolume.getNeumannFlux(scvfLocalFaceData, phaseIdx); - } - - //! Returns the volume variables indices necessary for flux computation - //! This includes all participating boundary volume variables. Since we - //! do not allow mixed BC for the mpfa this is the same for all phases. - const Stencil& advectionVolVarsStencil() const - { return advectionVolVarsStencil_; } - - //! Returns the position on which the volume variables live. This is - //! necessary as we need to evaluate gravity also for the boundary volvars - const PositionVector& advectionVolVarsPositions() const - { return advectionVolVarsPositions_; } - - //! Returns the transmissibilities associated with the volume variables - //! All phases flow through the same rock, thus, tij are equal for all phases - const CoefficientVector& advectionTij() const - { return advectionTij_; } - - //! Returns the vector of coefficients with which the vector of neumann boundary conditions - //! has to be multiplied in order to transform them on the scvf this cache belongs to - const CoefficientVector& advectionCij() const - { return advectionCij_; } - - //! If the useTpfaBoundary property is set to false, the boundary conditions - //! are put into the local systems leading to possible contributions on all faces - Scalar advectionNeumannFlux(unsigned int phaseIdx) const - { return phaseNeumannFluxes_[phaseIdx]; } - -private: - // Quantities associated with advection - Stencil advectionVolVarsStencil_; - PositionVector advectionVolVarsPositions_; - CoefficientVector advectionTij_; - CoefficientVector advectionCij_; - std::array<Scalar, numPhases> phaseNeumannFluxes_; -}; - -//! Base class for the diffusive cache in mpfa methods -template<class TypeTag> -class MpfaDiffusionCache -{ - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using BoundaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, BoundaryInteractionVolume); - - static const int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); - static const int numComponents = GET_PROP_VALUE(TypeTag, NumComponents); - static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries); - - // We always use the dynamic types here to be compatible on the boundary - using IndexType = typename GridView::IndexSet::IndexType; - using Stencil = typename BoundaryInteractionVolume::GlobalIndexSet; - using CoefficientVector = typename BoundaryInteractionVolume::Vector; - using PositionVector = typename BoundaryInteractionVolume::PositionVector; - -public: - //! The constructor. Initializes the Neumann flux to zero - MpfaDiffusionCache() { componentNeumannFluxes_.fill(0.0); } - - // update cached objects for the diffusive fluxes - template<typename InteractionVolume, class LocalFaceData> - void updateDiffusion(const InteractionVolume& interactionVolume, - const SubControlVolumeFace &scvf, - const LocalFaceData& scvfLocalFaceData, - unsigned int phaseIdx, - unsigned int compIdx) - { - diffusionVolVarsStencils_[phaseIdx][compIdx] = interactionVolume.volVarsStencil(); - diffusionTij_[phaseIdx][compIdx] = interactionVolume.getTransmissibilities(scvfLocalFaceData); - - if (enableInteriorBoundaries) - diffusionCij_[phaseIdx][compIdx] = interactionVolume.getNeumannFluxTransformationCoefficients(scvfLocalFaceData); - - //! For compositional models, we associate neumann fluxes with the phases (main components) - //! This is done in the AdvectionCache. However, in single-phasic models we solve the phase AND - //! the component mass balance equations. Thus, in this case we have diffusive neumann contributions. - //! we assume compIdx = eqIdx - if (numPhases == 1 && phaseIdx != compIdx) - componentNeumannFluxes_[compIdx] = interactionVolume.getNeumannFlux(scvfLocalFaceData, compIdx); - - } - - //! Returns the volume variables indices necessary for diffusive flux - //! computation. This includes all participating boundary volume variables - //! and it can be different for the phases & components. - const Stencil& diffusionVolVarsStencil(unsigned int phaseIdx, - unsigned int compIdx) const - { return diffusionVolVarsStencils_[phaseIdx][compIdx]; } - - //! Returns the transmissibilities associated with the volume variables - //! This can be different for the phases & components. - const CoefficientVector& diffusionTij(unsigned int phaseIdx, - unsigned int compIdx) const - { return diffusionTij_[phaseIdx][compIdx]; } - - //! Returns the vector of coefficients with which the vector of neumann boundary conditions - //! has to be multiplied in order to transform them on the scvf this cache belongs to - const CoefficientVector& diffusionCij(unsigned int phaseIdx, - unsigned int compIdx) const - { return diffusionCij_[phaseIdx][compIdx]; } - - //! If the useTpfaBoundary property is set to false, the boundary conditions - //! are put into the local systems leading to possible contributions on all faces - Scalar componentNeumannFlux(unsigned int compIdx) const - { - assert(numPhases == 1); - return componentNeumannFluxes_[compIdx]; - } - -private: - // Quantities associated with molecular diffusion - std::array< std::array<Stencil, numComponents>, numPhases> diffusionVolVarsStencils_; - std::array< std::array<CoefficientVector, numComponents>, numPhases> diffusionTij_; - std::array< std::array<CoefficientVector, numComponents>, numPhases> diffusionCij_; - - // diffusive neumann flux for single-phasic models - std::array<Scalar, numComponents> componentNeumannFluxes_; -}; - -//! Base class for the heat conduction cache in mpfa methods -template<class TypeTag> -class MpfaHeatConductionCache -{ - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using BoundaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, BoundaryInteractionVolume); - - // We always use the dynamic types here to be compatible on the boundary - using IndexType = typename GridView::IndexSet::IndexType; - using Stencil = typename BoundaryInteractionVolume::GlobalIndexSet; - using CoefficientVector = typename BoundaryInteractionVolume::Vector; - - static constexpr int energyEqIdx = GET_PROP_TYPE(TypeTag, Indices)::energyEqIdx; - static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries); -public: - // update cached objects for heat conduction - template<typename InteractionVolume, class LocalFaceData> - void updateHeatConduction(const InteractionVolume& interactionVolume, - const SubControlVolumeFace &scvf, - const LocalFaceData& scvfLocalFaceData) - { - heatConductionVolVarsStencil_ = interactionVolume.volVarsStencil(); - heatConductionTij_ = interactionVolume.getTransmissibilities(scvfLocalFaceData); - heatNeumannFlux_ = interactionVolume.getNeumannFlux(scvfLocalFaceData, energyEqIdx); - - if (enableInteriorBoundaries) - heatConductionCij_ = interactionVolume.getNeumannFluxTransformationCoefficients(scvfLocalFaceData); - } - - //! Returns the volume variables indices necessary for heat conduction flux - //! computation. This includes all participating boundary volume variables - //! and it can be different for the phases & components. - const Stencil& heatConductionVolVarsStencil() const - { return heatConductionVolVarsStencil_; } - - //! Returns the transmissibilities associated with the volume variables - //! This can be different for the phases & components. - const CoefficientVector& heatConductionTij() const - { return heatConductionTij_; } - - //! Returns the vector of coefficients with which the vector of neumann boundary conditions - //! has to be multiplied in order to transform them on the scvf this cache belongs to - const CoefficientVector& heatConductionCij() const - { return heatConductionCij_; } - - //! If the useTpfaBoundary property is set to false, the boundary conditions - //! are put into the local systems leading to possible contributions on all faces - Scalar heatNeumannFlux() const - { return heatNeumannFlux_; } - -private: - // Quantities associated with heat conduction - Stencil heatConductionVolVarsStencil_; - CoefficientVector heatConductionTij_; - CoefficientVector heatConductionCij_; - Scalar heatNeumannFlux_; -}; - -// specialization of the flux variables cache for cell centered mpfa methods +// specialization of the flux variables cache for the cell centered finite volume mpfa scheme template<class TypeTag> class PorousMediumFluxVariablesCacheImplementation<TypeTag, DiscretizationMethods::CCMpfa> - : public MpfaPorousMediumFluxVariablesCache<TypeTag, - GET_PROP_VALUE(TypeTag, EnableAdvection), - GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion), - GET_PROP_VALUE(TypeTag, EnableEnergyBalance)> + : public CCMpfaPorousMediumFluxVariablesCache<TypeTag, GET_PROP_VALUE(TypeTag, EnableAdvection), + GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion), + GET_PROP_VALUE(TypeTag, EnableEnergyBalance)> { using InteriorBoundaryData = typename GET_PROP_TYPE(TypeTag, InteriorBoundaryData); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using ParentType = MpfaPorousMediumFluxVariablesCache<TypeTag, GET_PROP_VALUE(TypeTag, EnableAdvection), - GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion), - GET_PROP_VALUE(TypeTag, EnableEnergyBalance)>; + using ParentType = CCMpfaPorousMediumFluxVariablesCache<TypeTag, GET_PROP_VALUE(TypeTag, EnableAdvection), + GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion), + GET_PROP_VALUE(TypeTag, EnableEnergyBalance)>; static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries); @@ -421,12 +201,12 @@ public: //! maybe update data on interior Dirichlet boundaries template<class InteractionVolume> - void updateInteriorBoundaryData(const InteractionVolume& interactionVolume, + void updateInteriorBoundaryData(const InteractionVolume& iv, const SubControlVolumeFace &scvf) { if (enableInteriorBoundaries) { - interiorBoundaryData_ = interactionVolume.interiorBoundaryData(); + interiorBoundaryData_ = iv.interiorBoundaryData(); // check if the actual scvf is on an interior Dirichlet boundary const auto scvfIdx = scvf.index(); @@ -470,23 +250,25 @@ private: // specialization for the case of pure advection template<class TypeTag> -class MpfaPorousMediumFluxVariablesCache<TypeTag, true, false, false> : public MpfaAdvectionCache<TypeTag> {}; +class CCMpfaPorousMediumFluxVariablesCache<TypeTag, true, false, false> : public GET_PROP_TYPE(TypeTag, AdvectionType)::Cache {}; // specialization for the case of advection & diffusion template<class TypeTag> -class MpfaPorousMediumFluxVariablesCache<TypeTag, true, true, false> : public MpfaAdvectionCache<TypeTag>, - public MpfaDiffusionCache<TypeTag> {}; +class CCMpfaPorousMediumFluxVariablesCache<TypeTag, true, true, false> : public GET_PROP_TYPE(TypeTag, AdvectionType)::Cache, + public GET_PROP_TYPE(TypeTag, MolecularDiffusionType)::Cache {}; // specialization for the case of advection & heat conduction template<class TypeTag> -class MpfaPorousMediumFluxVariablesCache<TypeTag, true, false, true> : public MpfaAdvectionCache<TypeTag>, - public MpfaHeatConductionCache<TypeTag> {}; +class CCMpfaPorousMediumFluxVariablesCache<TypeTag, true, false, true> : public GET_PROP_TYPE(TypeTag, AdvectionType)::Cache, + public GET_PROP_TYPE(TypeTag, HeatConductionType)::Cache {}; // specialization for the case of advection, diffusion & heat conduction template<class TypeTag> -class MpfaPorousMediumFluxVariablesCache<TypeTag, true, true, true> : public MpfaAdvectionCache<TypeTag>, - public MpfaDiffusionCache<TypeTag>, - public MpfaHeatConductionCache<TypeTag> {}; +class CCMpfaPorousMediumFluxVariablesCache<TypeTag, true, true, true> : public GET_PROP_TYPE(TypeTag, AdvectionType)::Cache, + public GET_PROP_TYPE(TypeTag, MolecularDiffusionType)::Cache, + public GET_PROP_TYPE(TypeTag, HeatConductionType)::Cache {}; + +// TODO further specializations } // end namespace -- GitLab