diff --git a/dumux/discretization/cellcentered/mpfa/darcyslaw.hh b/dumux/discretization/cellcentered/mpfa/darcyslaw.hh index 3aedae63d47b7268288c4c3d0439e20775228a23..c26b0bca72038035425e3a99e633f7b2ada6abb6 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 2bae60663e2c3bcc89f6e56db3790a9e3334032d..954afca4c268a26fe066b2466598c43a25fba82c 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 6aaf11e1881cc9b723bd65c3394dbc17843047ca..34cdec1077d514c4caa29d6ca5eafe8409c9ac3f 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 0ca84820d817e6e4201ff94ffbe873ad8649abf2..dfb3ad9b6f8bb79fa3ce5b220c8af48df4d4716e 100644 --- a/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh +++ b/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh @@ -20,616 +20,409 @@ * \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" +#include <dumux/discretization/cellcentered/mpfa/tensorlambdafactory.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. + const auto numOtherScvfs = iv.globalLocalScvfPairedData().size()-1; + std::vector<FluxVariablesCache*> otherFluxVarCaches(numOtherScvfs); + std::vector<Element> otherElements(numOtherScvfs); + + 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); - } + 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++; } - 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); - } - } - - //! 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>; + //! 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 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); + static constexpr auto AdvectionMethod = AdvectionType::myDiscretizationMethod; + using LambdaFactory = TensorLambdaFactory<TypeTag, AdvectionMethod>; - using Element = typename GridView::template Codim<0>::Entity; + // maybe solve the local system subject to K (if AdvectionType uses mpfa) + if (AdvectionMethod == DiscretizationMethods::CCMpfa) + iv.solveLocalSystem(LambdaFactory::getAdvectionLambda()); - static constexpr bool useTpfaBoundary = GET_PROP_VALUE(TypeTag, UseTpfaBoundary); - static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries); + // fill the caches of all scvfs within this interaction volume + AdvectionFiller::fill(scvfFluxVarsCache, problem(), element(), fvGeometry(), elemVolVars(), scvFace(), *this); - static constexpr bool solDependentAdvection = GET_PROP_VALUE(TypeTag, SolutionDependentAdvection); - static constexpr bool advectionUsesMpfa = AdvectionType::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++; + } + } - static constexpr bool solDependentHeatConduction = GET_PROP_VALUE(TypeTag, SolutionDependentHeatConduction); - static constexpr bool heatConductionUsesMpfa = HeatConductionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa; + //! 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; - //! 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; + static constexpr auto DiffusionMethod = DiffusionType::myDiscretizationMethod; + using LambdaFactory = TensorLambdaFactory<TypeTag, DiffusionMethod>; - using BoolPair = std::pair<bool, bool>; + static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); + static constexpr int numComponents = GET_PROP_VALUE(TypeTag, NumComponents); -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 (DiffusionMethod == DiscretizationMethods::CCMpfa) + iv.solveLocalSystem(LambdaFactory::getDiffusionLambda(phaseIdx, compIdx)); + + // 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); + using HeatConductionType = typename GET_PROP_TYPE(TypeTag, HeatConductionType); + using HeatConductionFiller = typename HeatConductionType::CacheFiller; - // maybe update Advection or diffusion or both - const bool updateAdvection = doAdvectionUpdate && touchesDomainBoundary; - const bool updateHeatConduction = doHeatConductionUpdate && touchesDomainBoundary; + static constexpr auto HeatConductionMethod = HeatConductionType::myDiscretizationMethod; + using LambdaFactory = TensorLambdaFactory<TypeTag, HeatConductionMethod>; - 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); - } -}; + // maybe solve the local system subject to fourier coefficient + if (HeatConductionMethod == DiscretizationMethods::CCMpfa) + iv.solveLocalSystem(LambdaFactory::getHeatConductionLambda()); -//! 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>; + // fill the caches of all scvfs within this interaction volume + HeatConductionFiller::fill(scvfFluxVarsCache, problem(), element(), fvGeometry(), elemVolVars(), scvFace(), *this); - 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)) + unsigned int otherScvfIdx = 0; + const auto curScvfIdx = scvFace().index(); + 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 (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); - } - } - else - { - 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 9ef0820f3a0142428ef6c9d16513b4ca0eb487f9..0000000000000000000000000000000000000000 --- 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 03d00e0db4d1a1370d0714c6edcade186a4a4b08..76f15e411da58c6bc0ee8e70e988e18d2c41653a 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 6bafe80a7834b2cc947d94662bce728e23aa6a5e..79ace006a3b5a534db1cd93b9de4f5d0884aee03 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 af8c2d793f151997880065581d45dc71462047d7..32af446ad2a96ed62aeadc991d5cd6a2222e5ba8 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/interiorboundarydata.hh b/dumux/discretization/cellcentered/mpfa/interiorboundarydata.hh index c1cc25b6b088e56bd0b6191f481f54537418ace9..3244b8c74e3b2bf81d07001e2003fdaf3fe8b427 100644 --- a/dumux/discretization/cellcentered/mpfa/interiorboundarydata.hh +++ b/dumux/discretization/cellcentered/mpfa/interiorboundarydata.hh @@ -55,6 +55,11 @@ class InteriorBoundaryData //! Note that the return types are also "wrong" (Here just to satisfy the compiler) struct CompleteCoupledFacetData { + const Problem& problem() const + { + DUNE_THROW(Dune::NotImplemented, "No implementation of the CompleteCoupledFacetData class provided"); + } + const SpatialParams& spatialParams() const { DUNE_THROW(Dune::NotImplemented, "No implementation of the CompleteCoupledFacetData class provided"); diff --git a/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh b/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh index 9450d4da519ced549991478677a9e486d2277195..444fc6a823bf5866652f14127c7957da6f390c29 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."); } } @@ -575,7 +485,7 @@ private: const auto& posGlobalScv = fvGeometry_().scv(posLocalScv.globalIndex()); const auto& posVolVars = elemVolVars_()[posGlobalScv]; const auto& element = localElement_(posLocalScvIdx); - const auto tensor = getTensor(element, posVolVars, posGlobalScv); + const auto tensor = getTensor(problem_(), element, posVolVars, fvGeometry_(), posGlobalScv); // the omega factors of the "positive" sub volume auto posWijk = calculateOmegas_(posLocalScv, localScvf.unitOuterNormal(), localScvf.area(), tensor); @@ -613,23 +523,28 @@ private: // get interior boundary data const auto& data = interiorBoundaryData_[this->findIndexInVector(interiorBoundaryScvfIndexSet_(), curLocalScvfIdx)]; - // get the volvars on the actual interior boundary face - const auto facetVolVars = data.facetVolVars(fvGeometry_()); + // obtain the complete data on the facet element + const auto completeFacetData = data.completeCoupledFacetData(); // calculate "leakage factor" const auto n = curLocalScvf.unitOuterNormal(); const auto v = [&] () { auto res = n; - res *= -0.5*facetVolVars.extrusionFactor(); + res *= -0.5*completeFacetData.volVars().extrusionFactor(); res -= curLocalScvf.ip(); res += curLocalScvf.globalScvf().facetCorner(); res /= res.two_norm2(); return res; } (); - // substract from matrix entry - A[idxInFluxFaces][curIdxInFluxFaces] -= MpfaHelper::nT_M_v(n, posVolVars.permeability(), v); + // substract n*T*v from diagonal matrix entry + const auto facetTensor = getTensor(completeFacetData.problem(), + completeFacetData.element(), + completeFacetData.volVars(), + completeFacetData.fvGeometry(), + completeFacetData.scv()); + A[idxInFluxFaces][curIdxInFluxFaces] -= MpfaHelper::nT_M_v(n, facetTensor, v); } } // this means we are on an interior face @@ -683,7 +598,7 @@ private: const auto& negGlobalScv = fvGeometry_().scv(negLocalScv.globalIndex()); const auto& negVolVars = elemVolVars_()[negGlobalScv]; const auto& negElement = localElement_(negLocalScvIdx); - const auto negTensor = getTensor(negElement, negVolVars, negGlobalScv); + const auto negTensor = getTensor(problem_(), negElement, negVolVars, fvGeometry_(), negGlobalScv); // the omega factors of the "negative" sub volume DimVector negWijk; @@ -771,7 +686,7 @@ private: const auto& posGlobalScv = fvGeometry_().scv(posLocalScv.globalIndex()); const auto& posVolVars = elemVolVars_()[posGlobalScv]; const auto element = localElement_(posLocalScvIdx); - const auto tensor = getTensor(element, posVolVars, posGlobalScv); + const auto tensor = getTensor(problem_(), element, posVolVars, fvGeometry_(), posGlobalScv); // the omega factors of the "positive" sub volume auto posWijk = calculateOmegas_(posLocalScv, localScvf.unitOuterNormal(), localScvf.area(), tensor); @@ -867,11 +782,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 +798,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 db5884a5ec3595fcd713d55d2cd725ab5af228c8..730017018c7a344f78bc0332192a18bba40707a0 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/discretization/cellcentered/mpfa/tensorlambdafactory.hh b/dumux/discretization/cellcentered/mpfa/tensorlambdafactory.hh new file mode 100644 index 0000000000000000000000000000000000000000..548cd6598e072cd06ba515c80b4d60f6bff6d95a --- /dev/null +++ b/dumux/discretization/cellcentered/mpfa/tensorlambdafactory.hh @@ -0,0 +1,149 @@ +// -*- 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 Helper class to be used to obtain lambda functions for the tensors + * involved in the laws that describe the different kind of fluxes that + * occur in DuMuX models (i.e. advective, diffusive and heat conduction fluxes). + * The local systems appearing in Mpfa methods have to be solved subject to + * the different tensors. This class returns lambda expressions to be used in the + * local systems. The specialization for other discretization methods allows + * compatibility with the TPFA scheme, which could be used for one or more of the tensors. + */ +#ifndef DUMUX_DISCRETIZATION_MPFA_TENSOR_LAMBDA_FACTORY_HH +#define DUMUX_DISCRETIZATION_MPFA_TENSOR_LAMBDA_FACTORY_HH + +#include <dumux/implicit/properties.hh> +#include <dumux/discretization/methods.hh> +#include <dumux/discretization/cellcentered/mpfa/tensorlambdafactory.hh> + +namespace Dumux +{ + +//! forward declaration of properties +namespace Properties +{ +NEW_PROP_TAG(ThermalConductivityModel); +}; + +/*! + * \ingroup MpfaModel + * \brief Helper class to be used to obtain lambda functions for the tensors + * involved in the laws that describe the different kind of fluxes that + * occur in DuMuX models (i.e. advective, diffusive and heat conduction fluxes). + * The local systems appearing in Mpfa methods have to be solved subject to + * the different tensors. This class returns lambda expressions to be used in the + * local systems. The specialization for discretization methods other than mpfa allows + * compatibility with the TPFA scheme, which could be used for one or more of the tensors. + * The interfaces of the lambdas are chosen such that all involved tensors can be extracted + * with the given arguments. + */ +template<class TypeTag, DiscretizationMethods Method> +class TensorLambdaFactory +{ +public: + + //! We return zero scalars here in the functions below. + //! We have to return something as the local systems expect a type + //! to perform actions on. We return 0.0 as this call should never happen + //! for a tensor which is not treated by an mpfa method anyway. + + //! lambda for the law describing the advective term + static auto getAdvectionLambda() + { + return [] (const auto& problem, + const auto& element, + const auto& volVars, + const auto& fvGeometry, + const auto& scv) + { return 0.0; }; + } + + //! lambda for the diffusion coefficient/tensor + static auto getDiffusionLambda(unsigned int phaseIdx, unsigned int compIdx) + { + return [] (const auto& problem, + const auto& element, + const auto& volVars, + const auto& fvGeometry, + const auto& scv) + { return 0.0; }; + } + + //! lambda for the fourier coefficient + static auto getHeatConductionLambda() + { + return [] (const auto& problem, + const auto& element, + const auto& volVars, + const auto& fvGeometry, + const auto& scv) + { return 0.0; }; + } +}; + +//! Specialization for mpfa schemes +template<class TypeTag> +class TensorLambdaFactory<TypeTag, DiscretizationMethods::CCMpfa> +{ +public: + + //! return void lambda here + static auto getAdvectionLambda() + { + return [] (const auto& problem, + const auto& element, + const auto& volVars, + const auto& fvGeometry, + const auto& scv) + { return volVars.permeability(); }; + } + + //! return void lambda here + static auto getDiffusionLambda(unsigned int phaseIdx, unsigned int compIdx) + { + return [phaseIdx, compIdx] (const auto& problem, + const auto& element, + const auto& volVars, + const auto& fvGeometry, + const auto& scv) + { return volVars.diffusionCoefficient(phaseIdx, compIdx); }; + } + + //! return void lambda here + static auto getHeatConductionLambda() + { + using ThermalConductivityModel = typename GET_PROP_TYPE(TypeTag, ThermalConductivityModel); + + return [] (const auto& problem, + const auto& element, + const auto& volVars, + const auto& fvGeometry, + const auto& scv) + { return ThermalConductivityModel::effectiveThermalConductivity(volVars, + problem.spatialParams(), + element, + fvGeometry, + scv); }; + } +}; + +} // end namespace + +#endif diff --git a/dumux/discretization/cellcentered/tpfa/darcyslaw.hh b/dumux/discretization/cellcentered/tpfa/darcyslaw.hh index 3a3143739464163573a757f40d09403c5a765160..73e086080c224ac7cd550dbd4d3d52a979f89c90 100644 --- a/dumux/discretization/cellcentered/tpfa/darcyslaw.hh +++ b/dumux/discretization/cellcentered/tpfa/darcyslaw.hh @@ -51,6 +51,7 @@ NEW_PROP_TAG(ProblemEnableGravity); template <class TypeTag> class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCTpfa> { + using Implementation = DarcysLawImplementation<TypeTag, DiscretizationMethods::CCTpfa>; using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); @@ -60,6 +61,7 @@ class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCTpfa> using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); using ElementFluxVarsCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); using Element = typename GridView::template Codim<0>::Entity; using IndexType = typename GridView::IndexSet::IndexType; @@ -70,10 +72,52 @@ class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCTpfa> using DimWorldMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>; using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>; + class TpfaDarcysLawCache + { + public: + void updateAdvection(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvf) + { + tij_ = Implementation::calculateTransmissibilities(problem, element, fvGeometry, elemVolVars, scvf); + } + + const Scalar& tij() const + { return tij_; } + + private: + Scalar tij_; + }; + + //! Class that fills the cache corresponding to tpfa Darcy's Law + class TpfaDarcysLawCacheFiller + { + public: + //! Function to fill a TpfaDarcysLawCache 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) + { + scvfFluxVarsCache.updateAdvection(problem, element, fvGeometry, elemVolVars, scvf); + } + }; + public: // state the discretization method this implementation belongs to static const DiscretizationMethods myDiscretizationMethod = DiscretizationMethods::CCTpfa; + // state the type for the corresponding cache and its filler + using Cache = TpfaDarcysLawCache; + using CacheFiller = TpfaDarcysLawCacheFiller; + static Scalar flux(const Problem& problem, const Element& element, const FVElementGeometry& fvGeometry, diff --git a/dumux/discretization/cellcentered/tpfa/elementfluxvariablescache.hh b/dumux/discretization/cellcentered/tpfa/elementfluxvariablescache.hh index 343e7d13e7f24c10c755a36d30cfde0813cd7b41..f2360b74848afe0ac31467cdbe70723fdc4c8933 100644 --- a/dumux/discretization/cellcentered/tpfa/elementfluxvariablescache.hh +++ b/dumux/discretization/cellcentered/tpfa/elementfluxvariablescache.hh @@ -24,6 +24,7 @@ #define DUMUX_DISCRETIZATION_CCTPFA_ELEMENT_FLUXVARSCACHE_HH #include <dumux/implicit/properties.hh> +#include <dumux/discretization/cellcentered/tpfa/fluxvariablescachefiller.hh> namespace Dumux { @@ -111,8 +112,7 @@ class CCTpfaElementFluxVariablesCache<TypeTag, false> using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); using GlobalFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, GlobalFluxVariablesCache); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - - static const bool solDependentAdvection = GET_PROP_VALUE(TypeTag, SolutionDependentAdvection); + using FluxVariablesCacheFiller = CCTpfaFluxVariablesCacheFiller<TypeTag>; public: CCTpfaElementFluxVariablesCache(const GlobalFluxVariablesCache& global) @@ -128,12 +128,15 @@ public: const auto numScvf = fvGeometry.numScvf(); fluxVarsCache_.resize(numScvf); globalScvfIndices_.resize(numScvf); - IndexType localScvfIdx = 0; + // instantiate helper class to fill the caches + FluxVariablesCacheFiller filler(globalFluxVarsCache().problem_()); + + IndexType localScvfIdx = 0; // fill the containers for (auto&& scvf : scvfs(fvGeometry)) { - fluxVarsCache_[localScvfIdx].update(globalFluxVarsCache().problem_(), element, fvGeometry, elemVolVars, scvf); + filler.fill(*this, fluxVarsCache_[localScvfIdx], element, fvGeometry, elemVolVars, scvf); globalScvfIndices_[localScvfIdx] = scvf.index(); localScvfIdx++; } @@ -150,6 +153,9 @@ public: const auto& assemblyMapI = problem.model().localJacobian().assemblyMap()[globalI]; const auto numNeighbors = assemblyMapI.size(); + // instantiate helper class to fill the caches + FluxVariablesCacheFiller filler(problem); + // find the number of scv faces that need to be prepared auto numScvf = fvGeometry.numScvf(); for (unsigned int localIdxJ = 0; localIdxJ < numNeighbors; ++localIdxJ) @@ -161,7 +167,7 @@ public: unsigned int localScvfIdx = 0; for (auto&& scvf : scvfs(fvGeometry)) { - fluxVarsCache_[localScvfIdx].update(problem, element, fvGeometry, elemVolVars, scvf); + filler.fill(*this, fluxVarsCache_[localScvfIdx], element, fvGeometry, elemVolVars, scvf); globalScvfIndices_[localScvfIdx] = scvf.index(); localScvfIdx++; } @@ -173,7 +179,7 @@ public: for (auto scvfIdx : assemblyMapI[localIdxJ].scvfsJ) { auto&& scvfJ = fvGeometry.scvf(scvfIdx); - fluxVarsCache_[localScvfIdx].update(problem, elementJ, fvGeometry, elemVolVars, scvfJ); + filler.fill(*this, fluxVarsCache_[localScvfIdx], elementJ, fvGeometry, elemVolVars, scvfJ); globalScvfIndices_[localScvfIdx] = scvfJ.index(); localScvfIdx++; } @@ -188,7 +194,10 @@ public: fluxVarsCache_.resize(1); globalScvfIndices_.resize(1); - fluxVarsCache_[0].update(globalFluxVarsCache().problem_(), element, fvGeometry, elemVolVars, scvf); + // instantiate helper class to fill the caches + FluxVariablesCacheFiller filler(globalFluxVarsCache().problem_()); + + filler.fill(*this, fluxVarsCache_[0], element, fvGeometry, elemVolVars, scvf); globalScvfIndices_[0] = scvf.index(); } @@ -211,8 +220,29 @@ private: const FVElementGeometry& fvGeometry, const ElementVolumeVariables& elemVolVars) { - if (solDependentAdvection) - bind(element, fvGeometry, elemVolVars); + static const bool isSolIndependent = FluxVariablesCacheFiller::isSolutionIndependent(); + + if (!isSolIndependent) + { + const auto& problem = globalFluxVarsCache().problem_(); + const auto globalI = problem.elementMapper().index(element); + + // instantiate filler class + FluxVariablesCacheFiller filler(problem); + + // let the filler class update the caches + for (unsigned int localScvfIdx = 0; localScvfIdx < fluxVarsCache_.size(); ++localScvfIdx) + { + const auto& scvf = fvGeometry.scvf(globalScvfIndices_[localScvfIdx]); + + const auto scvfInsideScvIdx = scvf.insideScvIdx(); + const auto& insideElement = scvfInsideScvIdx == globalI ? + element : + problem.model().globalFvGeometry().element(scvfInsideScvIdx); + + filler.fill(*this, fluxVarsCache_[localScvfIdx], insideElement, fvGeometry, elemVolVars, scvf); + } + } } // get index of scvf in the local container diff --git a/dumux/discretization/cellcentered/tpfa/fickslaw.hh b/dumux/discretization/cellcentered/tpfa/fickslaw.hh index 7b05340bfad569bf72afc7fdff95d0d794c53d9d..a6edbd6a9c807f09a9958ee2c1e2d4d9577b5f9f 100644 --- a/dumux/discretization/cellcentered/tpfa/fickslaw.hh +++ b/dumux/discretization/cellcentered/tpfa/fickslaw.hh @@ -31,6 +31,7 @@ #include <dumux/implicit/properties.hh> #include <dumux/discretization/methods.hh> +#include <dumux/discretization/fluxvariablescaching.hh> namespace Dumux { @@ -61,6 +62,7 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCTpfa > using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); using Element = typename GridView::template Codim<0>::Entity; using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); static const int dim = GridView::dimension; static const int dimWorld = GridView::dimensionworld; @@ -73,6 +75,11 @@ public: // state the discretization method this implementation belongs to static const DiscretizationMethods myDiscretizationMethod = DiscretizationMethods::CCTpfa; + //! state the type for the corresponding cache and its filler + //! We don't cache anything for this law + using Cache = FluxVariablesCaching::EmptyDiffusionCache; + using CacheFiller = FluxVariablesCaching::EmptyCacheFiller<TypeTag>; + static Scalar flux(const Problem& problem, const Element& element, const FVElementGeometry& fvGeometry, diff --git a/dumux/discretization/cellcentered/tpfa/fluxvariablescachefiller.hh b/dumux/discretization/cellcentered/tpfa/fluxvariablescachefiller.hh new file mode 100644 index 0000000000000000000000000000000000000000..0fbddcc66f8bb22ed45e28e04e01173fd7cc6022 --- /dev/null +++ b/dumux/discretization/cellcentered/tpfa/fluxvariablescachefiller.hh @@ -0,0 +1,227 @@ +// -*- 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 The flux variables cache filler class for the cell-centered TPFA scheme + */ +#ifndef DUMUX_DISCRETIZATION_CCTPFA_FLUXVARSCACHE_FILLER_HH +#define DUMUX_DISCRETIZATION_CCTPFA_FLUXVARSCACHE_FILLER_HH + +#include <dumux/implicit/properties.hh> +#include <dumux/discretization/methods.hh> + +namespace Dumux +{ + +/*! + * \ingroup ImplicitModel + * \brief Helper class to fill the flux var caches + */ +template<class TypeTag> +class CCTpfaFluxVariablesCacheFiller +{ + 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 ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); + + using Element = typename GridView::template Codim<0>::Entity; + + 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: + //! The constructor. Sets the problem pointer + CCTpfaFluxVariablesCacheFiller(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})) + { + // fill the physics-related quantities of the caches + if (doSubCaches[ProcessIndices::advectionIdx]) + fillAdvection(scvfFluxVarsCache, element, fvGeometry, elemVolVars, scvf); + if (doSubCaches[ProcessIndices::diffusionIdx]) + fillDiffusion(scvfFluxVarsCache, element, fvGeometry, elemVolVars, scvf); + if (doSubCaches[ProcessIndices::heatConductionIdx]) + fillHeatConduction(scvfFluxVarsCache, element, fvGeometry, elemVolVars, scvf); + } + + /*! + * \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) + { + // 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> updateSubCaches = []() + { + std::array<bool, 3> tmp; + tmp[ProcessIndices::advectionIdx] = doAdvection && soldependentAdvection; + tmp[ProcessIndices::diffusionIdx] = doDiffusion && soldependentDiffusion; + tmp[ProcessIndices::heatConductionIdx] = doHeatConduction && soldependentHeatConduction; + return tmp; + } (); + + // forward to fill routine + fill(fluxVarsCacheContainer, scvfFluxVarsCache, element, fvGeometry, elemVolVars, scvf, updateSubCaches); + } + + static bool isSolutionIndependent() + { + static const bool isSolDependent = (doAdvection && soldependentAdvection) || + (doDiffusion && soldependentDiffusion) || + (doHeatConduction && soldependentHeatConduction); + return !isSolDependent; + } + +private: + + const Problem& problem() const + { return *problemPtr_; } + + //! method to fill the advective quantities + template<bool advectionEnabled = doAdvection> + typename std::enable_if<advectionEnabled>::type + fillAdvection(FluxVariablesCache& scvfFluxVarsCache, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf) + { + using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); + using AdvectionFiller = typename AdvectionType::CacheFiller; + + // forward to the filler for the advective quantities + AdvectionFiller::fill(scvfFluxVarsCache, problem(), element, fvGeometry, elemVolVars, scvf, *this); + } + + //! do nothing if advection is not enabled + template<bool advectionEnabled = doAdvection> + typename std::enable_if<!advectionEnabled>::type + fillAdvection(FluxVariablesCache& scvfFluxVarsCache, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf) + {} + + //! method to fill the diffusive quantities + template<bool diffusionEnabled = doDiffusion> + typename std::enable_if<diffusionEnabled>::type + fillDiffusion(FluxVariablesCache& scvfFluxVarsCache, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf) + { + using DiffusionType = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType); + using DiffusionFiller = typename DiffusionType::CacheFiller; + + static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); + static constexpr int numComponents = GET_PROP_VALUE(TypeTag, NumComponents); + + // forward to the filler of the diffusive quantities + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + for (unsigned int compIdx = 0; compIdx < numComponents; ++compIdx) + if (phaseIdx != compIdx) + DiffusionFiller::fill(scvfFluxVarsCache, phaseIdx, compIdx, problem(), element, fvGeometry, elemVolVars, scvf, *this); + } + + //! do nothing if diffusion is not enabled + template<bool diffusionEnabled = doDiffusion> + typename std::enable_if<!diffusionEnabled>::type + fillDiffusion(FluxVariablesCache& scvfFluxVarsCache, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf) + {} + + //! method to fill the quantities related to heat conduction + template<bool heatConductionEnabled = doHeatConduction> + typename std::enable_if<heatConductionEnabled>::type + fillHeatConduction(FluxVariablesCache& scvfFluxVarsCache, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf) + { + using HeatConductionType = typename GET_PROP_TYPE(TypeTag, HeatConductionType); + using HeatConductionFiller = typename HeatConductionType::CacheFiller; + + // forward to the filler of the diffusive quantities + HeatConductionFiller::fill(scvfFluxVarsCache, problem(), element, fvGeometry, elemVolVars, scvf, *this); + } + + //! do nothing if heat conduction is disabled + template<bool heatConductionEnabled = doHeatConduction> + typename std::enable_if<!heatConductionEnabled>::type + fillHeatConduction(FluxVariablesCache& scvfFluxVarsCache, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf) + {} + + const Problem* problemPtr_; +}; + +} // end namespace + +#endif diff --git a/dumux/discretization/cellcentered/tpfa/fourierslaw.hh b/dumux/discretization/cellcentered/tpfa/fourierslaw.hh index c46876547ae2ff4f9a4f60fb44861d615272fa46..016627964c2f17bf3d938afb2ac33ff42afa0bd7 100644 --- a/dumux/discretization/cellcentered/tpfa/fourierslaw.hh +++ b/dumux/discretization/cellcentered/tpfa/fourierslaw.hh @@ -30,6 +30,7 @@ #include <dumux/common/parameters.hh> #include <dumux/implicit/properties.hh> #include <dumux/discretization/methods.hh> +#include <dumux/discretization/fluxvariablescaching.hh> namespace Dumux { @@ -57,6 +58,7 @@ class FouriersLawImplementation<TypeTag, DiscretizationMethods::CCTpfa> using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); using Element = typename GridView::template Codim<0>::Entity; using ElementFluxVarsCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); static const int dim = GridView::dimension; static const int dimWorld = GridView::dimensionworld; @@ -70,6 +72,11 @@ public: // state the discretization method this implementation belongs to static const DiscretizationMethods myDiscretizationMethod = DiscretizationMethods::CCTpfa; + //! state the type for the corresponding cache and its filler + //! We don't cache anything for this law + using Cache = FluxVariablesCaching::EmptyHeatConductionCache; + using CacheFiller = FluxVariablesCaching::EmptyCacheFiller<TypeTag>; + static Scalar flux(const Problem& problem, const Element& element, const FVElementGeometry& fvGeometry, diff --git a/dumux/discretization/cellcentered/tpfa/globalfluxvariablescache.hh b/dumux/discretization/cellcentered/tpfa/globalfluxvariablescache.hh index 2718ffcf18bcf34b2b695aac548cb3c0e045cc8b..aba839d8eb379c9ce3568829792c3f6f324dc681 100644 --- a/dumux/discretization/cellcentered/tpfa/globalfluxvariablescache.hh +++ b/dumux/discretization/cellcentered/tpfa/globalfluxvariablescache.hh @@ -24,6 +24,7 @@ #define DUMUX_DISCRETIZATION_CCTPFA_GLOBAL_FLUXVARSCACHE_HH #include <dumux/implicit/properties.hh> +#include <dumux/discretization/cellcentered/tpfa/fluxvariablescachefiller.hh> namespace Dumux { @@ -44,18 +45,26 @@ class CCTpfaGlobalFluxVariablesCache<TypeTag, true> { // the local class needs access to the problem friend typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + // the filler class needs access to the access operators + friend CCTpfaFluxVariablesCacheFiller<TypeTag>; + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using IndexType = typename GridView::IndexSet::IndexType; using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FluxVariablesCacheFiller = CCTpfaFluxVariablesCacheFiller<TypeTag>; public: // When global caching is enabled, precompute transmissibilities and stencils for all the scv faces 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())) @@ -69,7 +78,7 @@ public: for (auto&& scvf : scvfs(fvGeometry)) { - fluxVarsCache_[scvf.index()].update(problem, element, fvGeometry, elemVolVars, scvf); + filler.fill(*this, fluxVarsCache_[scvf.index()], element, fvGeometry, elemVolVars, scvf); } } } @@ -83,7 +92,13 @@ public: { return ElementFluxVariablesCache(global); } private: - // access operators in the case of caching + // // 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/fluxvariablescaching.hh b/dumux/discretization/fluxvariablescaching.hh new file mode 100644 index 0000000000000000000000000000000000000000..07e762fac061c7da115c774ba81e0f47bd200cd7 --- /dev/null +++ b/dumux/discretization/fluxvariablescaching.hh @@ -0,0 +1,83 @@ +// -*- 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 Classes related to flux variables caching + */ +#ifndef DUMUX_DISCRETIZATION_FLUXVAR_CACHING_HH +#define DUMUX_DISCRETIZATION_FLUXVAR_CACHING_HH + +namespace Dumux +{ + +namespace FluxVariablesCaching +{ + +class _EmptyCache {}; + +/*! + * \ingroup ImplicitModel + * \brief Empty caches to use in a law/process, e.g. Darcy's law + * \note Never use the _EmptyCache directly as it lead to ambiguous definitions + */ +class EmptyAdvectionCache : public _EmptyCache {}; +class EmptyDiffusionCache : public _EmptyCache {}; +class EmptyHeatConductionCache : public _EmptyCache {}; + +//! The empty filler class corresponding to EmptyCache +template<class TypeTag> +class EmptyCacheFiller +{ + 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 FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); +public: + //! For advection filler + 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) + {} + + //! For diffusion filler + 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) + {} +}; + +} // end namespace FluxVariablesCaching + +} // end namespace Dumux + +#endif diff --git a/dumux/porousmediumflow/3p3c/implicit/localresidual.hh b/dumux/porousmediumflow/3p3c/implicit/localresidual.hh index 7c4cfd92399e59e459fcf093253dd5ac42a5c551..5b4282d8b89740783ab9d549368b816683b06eb4 100644 --- a/dumux/porousmediumflow/3p3c/implicit/localresidual.hh +++ b/dumux/porousmediumflow/3p3c/implicit/localresidual.hh @@ -130,12 +130,7 @@ public: const ElementFluxVariablesCache& elemFluxVarsCache) { FluxVariables fluxVars; - fluxVars.initAndComputeFluxes(this->problem(), - element, - fvGeometry, - elemVolVars, - scvf, - elemFluxVarsCache); + fluxVars.init(this->problem(), element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache); // get upwind weights into local scope PrimaryVariables flux(0.0); diff --git a/dumux/porousmediumflow/compositional/localresidual.hh b/dumux/porousmediumflow/compositional/localresidual.hh index cc178e0cedb04f601e9ac7c7e743869fa8cc2ba9..01ff8dd50d0f9d3c9b4d9f5ee7abe717dd49320f 100644 --- a/dumux/porousmediumflow/compositional/localresidual.hh +++ b/dumux/porousmediumflow/compositional/localresidual.hh @@ -165,12 +165,7 @@ public: bool useMoles = true) { FluxVariables fluxVars; - fluxVars.initAndComputeFluxes(this->problem(), - element, - fvGeometry, - elemVolVars, - scvf, - elemFluxVarsCache); + fluxVars.init(this->problem(), element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache); // get upwind weights into local scope PrimaryVariables flux(0.0); diff --git a/dumux/porousmediumflow/immiscible/localresidual.hh b/dumux/porousmediumflow/immiscible/localresidual.hh index d99d19b2987bd3fbbb54560b64a6fc45e82e8731..a7562d94db0f0d993803193b3e9536c5e8f7d90e 100644 --- a/dumux/porousmediumflow/immiscible/localresidual.hh +++ b/dumux/porousmediumflow/immiscible/localresidual.hh @@ -103,12 +103,7 @@ public: const ElementFluxVariablesCache& elemFluxVarsCache) const { FluxVariables fluxVars; - fluxVars.initAndComputeFluxes(this->problem(), - element, - fvGeometry, - elemVolVars, - scvf, - elemFluxVarsCache); + fluxVars.init(this->problem(), element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache); PrimaryVariables flux; for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) diff --git a/dumux/porousmediumflow/implicit/fluxvariables.hh b/dumux/porousmediumflow/implicit/fluxvariables.hh index 87bd43686a0dadaaba111f73468990d28a286eb4..4e4f54a83b2c02112d17f5d06af8daa23c89d6ee 100644 --- a/dumux/porousmediumflow/implicit/fluxvariables.hh +++ b/dumux/porousmediumflow/implicit/fluxvariables.hh @@ -77,16 +77,6 @@ class PorousMediumFluxVariablesImpl<TypeTag, true, false, false> : public FluxVa public: - void initAndComputeFluxes(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace &scvFace, - const ElementFluxVariablesCache& elemFluxVarsCache) - { - ParentType::init(problem, element, fvGeometry, elemVolVars, scvFace, elemFluxVarsCache); - } - template<typename FunctionType> Scalar advectiveFlux(const int phaseIdx, const FunctionType& upwindTerm) { @@ -124,18 +114,11 @@ class PorousMediumFluxVariablesImpl<TypeTag, true, true, false> : public FluxVar enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; public: - - void initAndComputeFluxes(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace &scvFace, - const ElementFluxVariablesCache& elemFluxVarsCache) + //! The constructor + PorousMediumFluxVariablesImpl() { advFluxCached_.reset(); advPreFlux_.fill(0.0); - - ParentType::init(problem, element, fvGeometry, elemVolVars, scvFace, elemFluxVarsCache); } template<typename FunctionType> @@ -195,16 +178,11 @@ class PorousMediumFluxVariablesImpl<TypeTag, true, false, true> : public FluxVar enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; public: - - void initAndComputeFluxes(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace &scvFace, - const ElementFluxVariablesCache& elemFluxVarsCache) + //! The constructor + PorousMediumFluxVariablesImpl() { advFluxCached_.reset(); - ParentType::init(problem, element, fvGeometry, elemVolVars, scvFace, elemFluxVarsCache); + advPreFlux_.fill(0.0); } template<typename FunctionType> @@ -264,16 +242,11 @@ class PorousMediumFluxVariablesImpl<TypeTag, true, true, true> : public FluxVari enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; public: - - void initAndComputeFluxes(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace &scvFace, - const ElementFluxVariablesCache& elemFluxVarsCache) + //! The constructor + PorousMediumFluxVariablesImpl() { advFluxCached_.reset(); - ParentType::init(problem, element, fvGeometry, elemVolVars, scvFace, elemFluxVarsCache); + advPreFlux_.fill(0.0); } template<typename FunctionType> diff --git a/dumux/porousmediumflow/implicit/fluxvariablescache.hh b/dumux/porousmediumflow/implicit/fluxvariablescache.hh index 1e01be146b4c4486c9bb63d930d105fa56e185da..558d8831545b83cc2f068abf3f317498fc0fa840 100644 --- a/dumux/porousmediumflow/implicit/fluxvariablescache.hh +++ b/dumux/porousmediumflow/implicit/fluxvariablescache.hh @@ -40,15 +40,24 @@ namespace Properties NEW_PROP_TAG(NumPhases); } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//! The cache is dependent on the active physical processes (advection, diffusion, heat conduction) +//! For each type of process there is a base cache storing the data required to compute the respective fluxes +//! Specializations of the overall cache are provided for combinations of processes +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /*! * \ingroup ImplicitModel * \brief The flux variables cache classes for porous media. - * Store flux stencils and data required for flux calculation + * Store data required for flux calculation. For each type of physical process (advection, diffusion, heat conduction) + * there is a base cache storing the data required to compute the respective fluxes. Specializations of the overall + * cache class are provided for different combinations of processes. */ template<class TypeTag> using PorousMediumFluxVariablesCache = PorousMediumFluxVariablesCacheImplementation<TypeTag, GET_PROP_VALUE(TypeTag, DiscretizationMethod)>; -// specialization for the Box Method +//! We only store discretization-related quantities for the box method. +//! Thus, we need no physics-dependent specialization. template<class TypeTag> class PorousMediumFluxVariablesCacheImplementation<TypeTag, DiscretizationMethods::Box> { @@ -100,302 +109,61 @@ public: const JacobianInverseTransposed& jacInvT() const { return jacInvT_; } - // The stencil info is obsolete for the box method. - // It is here for compatibility with cc methods - const Stencil& stencil() const - { - return stencil_; - } - private: std::vector<ShapeJacobian> shapeJacobian_; std::vector<ShapeValue> shapeValues_; JacobianInverseTransposed jacInvT_; - - Stencil stencil_; }; +// forward declaration of the base class of the tpfa flux variables cache +template<class TypeTag, bool EnableAdvection, bool EnableMolecularDiffusion, bool EnableEnergyBalance> +class CCTpfaPorousMediumFluxVariablesCache; + // specialization for the cell centered tpfa method template<class TypeTag> class PorousMediumFluxVariablesCacheImplementation<TypeTag, DiscretizationMethods::CCTpfa> -{ - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables); - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); - using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); - using Element = typename GridView::template Codim<0>::Entity; - using IndexType = typename GridView::IndexSet::IndexType; - using Stencil = std::vector<IndexType>; + : public CCTpfaPorousMediumFluxVariablesCache<TypeTag, GET_PROP_VALUE(TypeTag, EnableAdvection), + GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion), + GET_PROP_VALUE(TypeTag, EnableEnergyBalance)> {}; -public: - void update(const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const ElementVolumeVariables& elemVolVars, - const SubControlVolumeFace &scvf) - { - stencil_ = FluxVariables::computeStencil(problem, element, fvGeometry, scvf); - tij_ = AdvectionType::calculateTransmissibilities(problem, element, fvGeometry, elemVolVars, scvf); - } - - const Stencil& stencil() const - { return stencil_; } - - const Scalar& tij() const - { return tij_; } - -private: - Stencil stencil_; - Scalar tij_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//! Classes building up the porous medium flux variables cache for mpfa methods -//! The cache is dependent on the active physical processes (advection, diffusion, heat conduction) -//! For each type of process there is a base cache storing the data required to compute the respective fluxes -//! Specializations of the overall cache are provided for combinations of processes -////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// forward declaration of the base class of the mpfa flux variables cache -template<class TypeTag, bool EnableAdvection, bool EnableMolecularDiffusion, bool EnableEnergyBalance> -class MpfaPorousMediumFluxVariablesCache; - -//! Base class for the advective cache in mpfa methods +// specialization for the case of pure advection 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_; } +class CCTpfaPorousMediumFluxVariablesCache<TypeTag, true, false, false> : public GET_PROP_TYPE(TypeTag, AdvectionType)::Cache {}; - //! 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 +// specialization for the case of advection & diffusion 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); +class CCTpfaPorousMediumFluxVariablesCache<TypeTag, true, true, false> : public GET_PROP_TYPE(TypeTag, AdvectionType)::Cache, + public GET_PROP_TYPE(TypeTag, MolecularDiffusionType)::Cache {}; - 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 +// specialization for the case of advection & heat conduction 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_; } +class CCTpfaPorousMediumFluxVariablesCache<TypeTag, true, false, true> : public GET_PROP_TYPE(TypeTag, AdvectionType)::Cache, + public GET_PROP_TYPE(TypeTag, HeatConductionType)::Cache {}; - //! 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_; } +// specialization for the case of advection, diffusion & heat conduction +template<class TypeTag> +class CCTpfaPorousMediumFluxVariablesCache<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 {}; - //! 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_; } +// TODO further specializations -private: - // Quantities associated with heat conduction - Stencil heatConductionVolVarsStencil_; - CoefficientVector heatConductionTij_; - CoefficientVector heatConductionCij_; - Scalar heatNeumannFlux_; -}; +// forward declaration of the base class of the mpfa flux variables cache +template<class TypeTag, bool EnableAdvection, bool EnableMolecularDiffusion, bool EnableEnergyBalance> +class CCMpfaPorousMediumFluxVariablesCache; -// 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 +189,11 @@ public: //! maybe update data on interior Dirichlet boundaries template<class InteractionVolume> - void updateInteriorBoundaryData(const InteractionVolume& interactionVolume, - const SubControlVolumeFace &scvf) + 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 +237,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 diff --git a/dumux/porousmediumflow/implicit/velocityoutput.hh b/dumux/porousmediumflow/implicit/velocityoutput.hh index 5980213d44122d7061960440da626cd118ec850a..c2ade4f1eea2df3bc20529bbba6e1638df78234f 100644 --- a/dumux/porousmediumflow/implicit/velocityoutput.hh +++ b/dumux/porousmediumflow/implicit/velocityoutput.hh @@ -172,12 +172,7 @@ public: // insantiate the flux variables FluxVariables fluxVars; - fluxVars.initAndComputeFluxes(problem_, - element, - fvGeometry, - elemVolVars, - scvf, - elemFluxVarsCache); + fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache); // get the volume flux divided by the area of the // subcontrolvolume face in the reference element @@ -244,7 +239,7 @@ public: if (!scvf.boundary()) { FluxVariables fluxVars; - fluxVars.initAndComputeFluxes(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache); + fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache); scvfFluxes[scvfIndexInInside[localScvfIdx]] = fluxVars.advectiveFlux(phaseIdx, upwindTerm); scvfFluxes[scvfIndexInInside[localScvfIdx]] /= problem_.extrusionFactor(element, fvGeometry.scv(scvf.insideScvIdx()), @@ -256,7 +251,7 @@ public: if (bcTypes.hasOnlyDirichlet()) { FluxVariables fluxVars; - fluxVars.initAndComputeFluxes(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache); + fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache); scvfFluxes[scvfIndexInInside[localScvfIdx]] = fluxVars.advectiveFlux(phaseIdx, upwindTerm); scvfFluxes[scvfIndexInInside[localScvfIdx]] /= problem_.extrusionFactor(element, fvGeometry.scv(scvf.insideScvIdx()), diff --git a/dumux/porousmediumflow/richards/implicit/localresidual.hh b/dumux/porousmediumflow/richards/implicit/localresidual.hh index 8e6e8a18e4686c41bec102627dc7bb4a01024ff4..5659a08f071c772ba1e286759ec405b2d4288d9b 100644 --- a/dumux/porousmediumflow/richards/implicit/localresidual.hh +++ b/dumux/porousmediumflow/richards/implicit/localresidual.hh @@ -102,12 +102,7 @@ public: const ElementFluxVariablesCache& elemFluxVarsCache) const { FluxVariables fluxVars; - fluxVars.initAndComputeFluxes(this->problem(), - element, - fvGeometry, - elemVolVars, - scvf, - elemFluxVarsCache); + fluxVars.init(this->problem(), element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache); PrimaryVariables flux; // the physical quantities for which we perform upwinding