Commit ff4969a4 authored by Dennis Gläser's avatar Dennis Gläser
Browse files

[mpfa] make fick's/fourier's law work & cleanup

parent 78a559da
......@@ -18,44 +18,35 @@
*****************************************************************************/
/*!
* \file
* \brief This file contains the data which is required to calculate
* \brief This file contains the class which is required to calculate
* volume and mass fluxes of fluid phases over a face of a finite volume by means
* of the Darcy approximation. Specializations are provided for the different discretization methods.
* of the Darcy approximation. This specializations is for cell-centered schemes
* using multi-point flux approximation.
*/
#ifndef DUMUX_DISCRETIZATION_CC_MPFA_DARCYS_LAW_HH
#define DUMUX_DISCRETIZATION_CC_MPFA_DARCYS_LAW_HH
namespace Dumux
{
#include <dumux/common/properties.hh>
namespace Properties
namespace Dumux
{
// forward declaration of properties
NEW_PROP_TAG(MpfaHelper);
}
/*!
* \ingroup DarcysLaw
* \ingroup Mpfa
* \brief Specialization of Darcy's Law for the CCMpfa method.
*/
template <class TypeTag>
class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
{
using Implementation = typename GET_PROP_TYPE(TypeTag, AdvectionType);
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 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 PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume);
......@@ -125,23 +116,19 @@ class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
}
//! Returns the stencil for advective scvf flux computation
const Stencil& advectionVolVarsStencil() const
{ return *advectionVolVarsStencil_; }
const Stencil& advectionVolVarsStencil() const { return *advectionVolVarsStencil_; }
//! 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_; }
const CoefficientVector& advectionTij() const { return *advectionTij_; }
//! On faces that are "outside" w.r.t. a face in the interaction volume,
//! we have to take the negative value of the fluxes, i.e. multiply by -1.0
bool advectionSwitchFluxSign() const
{ return advectionSwitchFluxSign_; }
bool advectionSwitchFluxSign() const { return advectionSwitchFluxSign_; }
//! Returns the data on dirichlet boundary conditions affecting
//! the flux computation on this face
const DirichletDataContainer& advectionDirichletData() const
{ return *advectionDirichletData_; }
const DirichletDataContainer& advectionDirichletData() const { return *advectionDirichletData_; }
private:
bool advectionSwitchFluxSign_;
......@@ -167,17 +154,14 @@ public:
{
static const bool gravity = getParamFromGroup<bool>(GET_PROP_VALUE(TypeTag, ModelParameterGroup), "Problem.EnableGravity");
const auto& fluxVarsCache = elemFluxVarsCache[scvf];
const auto& tij = fluxVarsCache.advectionTij();
// Calculate the interface density for gravity evaluation
const auto rho = interpolateDensity(fvGeometry, elemVolVars, scvf, fluxVarsCache, phaseIdx);
// Variable for the flux to be computed
Scalar scvfFlux(0.0);
const auto rho = interpolateDensity(elemVolVars, scvf, phaseIdx);
// index counter to get corresponding transmissibilities
// prepare computations
unsigned int i = 0;
Scalar scvfFlux(0.0);
const auto& fluxVarsCache = elemFluxVarsCache[scvf];
const auto& tij = fluxVarsCache.advectionTij();
// add contributions from cell-centered unknowns
for (const auto volVarIdx : fluxVarsCache.advectionVolVarsStencil())
......@@ -219,10 +203,8 @@ public:
}
private:
static Scalar interpolateDensity(const FVElementGeometry& fvGeometry,
const ElementVolumeVariables& elemVolVars,
static Scalar interpolateDensity(const ElementVolumeVariables& elemVolVars,
const SubControlVolumeFace& scvf,
const FluxVariablesCache& fluxVarsCache,
const unsigned int phaseIdx)
{
static const bool gravity = getParamFromGroup<bool>(GET_PROP_VALUE(TypeTag, ModelParameterGroup), "Problem.EnableGravity");
......@@ -235,7 +217,7 @@ private:
if (!scvf.boundary())
{
Scalar rho = elemVolVars[scvf.insideScvIdx()].density(phaseIdx);
for (auto outsideIdx : scvf.outsideScvIndices())
for (const auto outsideIdx : scvf.outsideScvIndices())
rho += elemVolVars[outsideIdx].density(phaseIdx);
return rho/(scvf.outsideScvIndices().size()+1);
}
......
......@@ -65,7 +65,7 @@ public:
const IndexType insideScvIdx,
const std::vector<IndexType>& outsideScvIndices)
{
// check if it this really hasn't been called yet
// this should always be called only once
assert( std::find(scvfIndices_.begin(), scvfIndices_.end(), scvfIdx ) == scvfIndices_.end() && "scvf has already been inserted!");
// the local index of the scvf data about to be inserted
......@@ -78,7 +78,8 @@ public:
scvIndices.insert(scvIndices.end(), outsideScvIndices.begin(), outsideScvIndices.end());
// if scvf is on boundary, increase counter
if (boundary) numBoundaryScvfs_++;
if (boundary)
numBoundaryScvfs_++;
// insert data on the new scv
scvfIndices_.push_back(scvfIdx);
......@@ -88,10 +89,7 @@ public:
// if entry for the inside scv exists append scvf local index, create otherwise
auto it = std::find( scvIndices_.begin(), scvIndices_.end(), insideScvIdx );
if (it != scvIndices_.end())
{
const auto localScvIdx = std::distance(scvIndices_.begin(), it);
localScvfIndicesInScv_[localScvIdx].push_back(curScvfLocalIdx);
}
localScvfIndicesInScv_[ std::distance(scvIndices_.begin(), it) ].push_back(curScvfLocalIdx);
else
{
LocalIndexContainer localScvfIndices;
......@@ -103,28 +101,25 @@ public:
}
//! returns the number of scvs
std::size_t numScvs() const
{ return scvIndices_.size(); }
std::size_t numScvs() const { return scvIndices_.size(); }
//! returns the number of scvfs
std::size_t numScvfs() const
{ return scvfIndices_.size(); }
std::size_t numScvfs() const { return scvfIndices_.size(); }
//! returns the number of boundary scvfs
std::size_t numBoundaryScvfs() const
{ return numBoundaryScvfs_; }
std::size_t numBoundaryScvfs() const { return numBoundaryScvfs_; }
//! returns the global scv indices connected to this dual grid node
const GlobalIndexContainer& globalScvIndices() const
{ return scvIndices_; }
const GlobalIndexContainer& globalScvIndices() const { return scvIndices_; }
//! returns the global scvf indices connected to this dual grid node
const GlobalIndexContainer& globalScvfIndices() const
{ return scvfIndices_; }
const GlobalIndexContainer& globalScvfIndices() const { return scvfIndices_; }
//! returns the global scv idx of the i-th scv
IndexType scvIdxGlobal(unsigned int i) const
{ return scvIndices_[i]; }
IndexType scvIdxGlobal(unsigned int i) const { return scvIndices_[i]; }
//! returns the index of the i-th scvf
IndexType scvfIdxGlobal(unsigned int i) const { return scvfIndices_[i]; }
//! returns the global index of the j-th scvf embedded in the i-th scv
IndexType scvfIdxGlobal(unsigned int i, unsigned int j) const
......@@ -140,13 +135,8 @@ public:
return localScvfIndicesInScv_[i][j];
}
//! returns the index of the i-th scvf
IndexType scvfIdxGlobal(unsigned int i) const
{ return scvfIndices_[i]; }
//! returns whether or not the i-th scvf touches the boundary
bool scvfIsOnBoundary(unsigned int i) const
{ return scvfIsOnBoundary_[i]; }
bool scvfIsOnBoundary(unsigned int i) const { return scvfIsOnBoundary_[i]; }
//! returns the indices of the neighboring scvs of the i-th scvf
const GlobalIndexContainer& neighboringScvIndices(unsigned int i) const
......@@ -174,7 +164,7 @@ private:
* \brief Class for the index sets of the dual grid in mpfa schemes.
*/
template<class TypeTag>
class CCMpfaDualGridIndexSet : public std::vector<DualGridNodalIndexSet<TypeTag>>
class CCMpfaDualGridIndexSet
{
using ParentType = std::vector<DualGridNodalIndexSet<TypeTag>>;
......@@ -187,19 +177,26 @@ class CCMpfaDualGridIndexSet : public std::vector<DualGridNodalIndexSet<TypeTag>
public:
using NodalIndexSet = DualGridNodalIndexSet<TypeTag>;
CCMpfaDualGridIndexSet(const GridView& gridView)
{
(*this).resize(gridView.size(dim));
}
//! default constructor
CCMpfaDualGridIndexSet() = delete;
//! constructor
explicit CCMpfaDualGridIndexSet(const GridView& gridView) : nodalIndexSets_(gridView.size(dim)) {}
//! access with an scvf
const NodalIndexSet& operator[] (const SubControlVolumeFace& scvf) const
{ return (*this)[scvf.vertexIndex()]; }
{ return nodalIndexSets_[scvf.vertexIndex()]; }
NodalIndexSet& operator[] (const SubControlVolumeFace& scvf)
{ return (*this)[scvf.vertexIndex()]; }
{ return nodalIndexSets_[scvf.vertexIndex()]; }
//! access with an index
using ParentType::operator[];
const NodalIndexSet& operator[] (IndexType i) const
{ return nodalIndexSets_[i]; }
NodalIndexSet& operator[] (IndexType i)
{ return nodalIndexSets_[i]; }
private:
std::vector<NodalIndexSet> nodalIndexSets_;
};
} // end namespace
......
......@@ -18,41 +18,30 @@
*****************************************************************************/
/*!
* \file
* \brief This file contains the data which is required to calculate
* \brief This file contains the class which is required to calculate
* molar and mass fluxes of a component in a fluid phase over a face of a finite volume by means
* of Fick's Law for cell-centered MPFA models.
*/
#ifndef DUMUX_DISCRETIZATION_CC_MPFA_FICKS_LAW_HH
#define DUMUX_DISCRETIZATION_CC_MPFA_FICKS_LAW_HH
#include <memory>
#include <dune/common/float_cmp.hh>
#include <dumux/common/math.hh>
#include <dumux/common/parameters.hh>
#include <dumux/implicit/properties.hh>
#include <dumux/common/properties.hh>
namespace Dumux
{
/*!
* \ingroup CCMpfaFicksLaw
* \ingroup Mpfa
* \brief Specialization of Fick's Law for the CCMpfa method.
*/
template <class TypeTag>
class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
{
using Implementation = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType);
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
using Model = typename GET_PROP_TYPE(TypeTag, Model);
using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper);
using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
using Element = typename GridView::template Codim<0>::Entity;
using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
......@@ -62,19 +51,17 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
using BalanceEqOpts = typename GET_PROP_TYPE(TypeTag, BalanceEqOpts);
// Always use the dynamic type for vectors (compatibility with the boundary)
using BoundaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, BoundaryInteractionVolume);
using CoefficientVector = typename BoundaryInteractionVolume::Vector;
using Element = typename GridView::template Codim<0>::Entity;
using IndexType = typename GridView::IndexSet::IndexType;
using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume);
using CoefficientVector = typename PrimaryInteractionVolume::Traits::DynamicVector;
using DataHandle = typename PrimaryInteractionVolume::Traits::DataHandle;
static constexpr int dim = GridView::dimension;
static constexpr int dimWorld = GridView::dimensionworld;
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);
static constexpr bool enableInteriorBoundaries = GET_PROP_VALUE(TypeTag, EnableInteriorBoundaries);
using ComponentFluxVector = Dune::FieldVector<Scalar, numComponents>;
//! Class that fills the cache corresponding to mpfa Darcy's Law
//! Class that fills the cache corresponding to mpfa Fick's Law
class MpfaFicksLawCacheFiller
{
public:
......@@ -90,11 +77,15 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
const SubControlVolumeFace& scvf,
const FluxVariablesCacheFiller& fluxVarsCacheFiller)
{
// get interaction volume from the flux vars cache filler & upate the cache
if (problem.model().fvGridGeometry().isInBoundaryInteractionVolume(scvf))
scvfFluxVarsCache.updateDiffusion(fluxVarsCacheFiller.boundaryInteractionVolume(), scvf, phaseIdx, compIdx);
else
scvfFluxVarsCache.updateDiffusion(fluxVarsCacheFiller.interactionVolume(), scvf, phaseIdx, compIdx);
// get interaction volume from the flux vars cache filler & upate the cache
if (fvGeometry.fvGridGeometry().vertexUsesSecondaryInteractionVolume(scvf.vertexIndex()))
scvfFluxVarsCache.updateDiffusion(fluxVarsCacheFiller.secondaryInteractionVolume(),
fluxVarsCacheFiller.dataHandle(),
scvf, phaseIdx, compIdx);
else
scvfFluxVarsCache.updateDiffusion(fluxVarsCacheFiller.primaryInteractionVolume(),
fluxVarsCacheFiller.dataHandle(),
scvf, phaseIdx, compIdx);
}
};
......@@ -102,62 +93,62 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa>
class MpfaFicksLawCache
{
// We always use the dynamic types here to be compatible on the boundary
using Stencil = typename BoundaryInteractionVolume::GlobalIndexSet;
using PositionVector = typename BoundaryInteractionVolume::PositionVector;
using Stencil = typename PrimaryInteractionVolume::Traits::DynamicGlobalIndexContainer;
using DirichletDataContainer = typename PrimaryInteractionVolume::DirichletDataContainer;
public:
// export filler type
using Filler = MpfaFicksLawCacheFiller;
//! 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,
template<class InteractionVolume>
void updateDiffusion(const InteractionVolume& iv,
const DataHandle& dataHandle,
const SubControlVolumeFace &scvf,
unsigned int phaseIdx, unsigned int compIdx)
{
const auto& localFaceData = iv.getLocalFaceData(scvf);
diffusionTij_[phaseIdx][compIdx] = iv.getTransmissibilities(localFaceData);
// get the stencil only for the first call
if (phaseIdx == 0 && compIdx == 0)
diffusionVolVarsStencil_ = iv.volVarsStencil();
//! 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);
// update the quantities that are equal for all phases
diffusionSwitchFluxSign_[phaseIdx][compIdx] = localFaceData.isOutside();
diffusionVolVarsStencil_[phaseIdx][compIdx] = &dataHandle.volVarsStencil();
diffusionDirichletData_[phaseIdx][compIdx] = &dataHandle.dirichletData();
// the transmissibilities on surface grids have to be obtained from the outside
if (dim == dimWorld)
diffusionTij_[phaseIdx][compIdx] = &dataHandle.T()[localFaceData.ivLocalScvfIndex()];
else
diffusionTij_[phaseIdx][compIdx] = localFaceData.isOutside() ?
&dataHandle.outsideTij()[localFaceData.ivLocalOutsideScvfIndex()] :
&dataHandle.T()[localFaceData.ivLocalScvfIndex()];
}
//! 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 diffusionVolVarsStencil_; }
{ return diffusionVolVarsStencil_[phaseIdx][compIdx]; }
//! On faces that are "outside" w.r.t. a face in the interaction volume,
//! we have to take the negative value of the fluxes, i.e. multiply by -1.0
bool diffusionSwitchFluxSign(unsigned int phaseIdx, unsigned int compIdx) const
{ return diffusionSwitchFluxSign_[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]; }
//! 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];
}
//! Returns the data on dirichlet boundary conditions affecting
//! the flux computation on this face
const DirichletDataContainer& diffusionDirichletData(unsigned int phaseIdx, unsigned int compIdx) const
{ return diffusionDirichletData_[phaseIdx][compIdx]; }
private:
// Quantities associated with molecular diffusion
Stencil diffusionVolVarsStencil_;
std::array< std::array<CoefficientVector, numComponents>, numPhases> diffusionTij_;
// diffusive neumann flux for single-phasic models
std::array<Scalar, numComponents> componentNeumannFluxes_;
std::array< std::array<bool, numComponents>, numPhases> diffusionSwitchFluxSign_;
std::array< std::array<const Stencil*, numComponents>, numPhases> diffusionVolVarsStencil_;
std::array< std::array<const DirichletDataContainer*, numComponents>, numPhases> diffusionDirichletData_;
std::array< std::array<const CoefficientVector*, numComponents>, numPhases> diffusionTij_;
};
public:
......@@ -179,66 +170,33 @@ public:
for (int compIdx = 0; compIdx < numComponents; compIdx++)
{
if(compIdx == FluidSystem::getMainComponent(phaseIdx))
continue;
const auto& fluxVarsCache = elemFluxVarsCache[scvf];
const auto& volVarsStencil = fluxVarsCache.diffusionVolVarsStencil(phaseIdx, compIdx);
const auto& tij = fluxVarsCache.diffusionTij(phaseIdx, compIdx);
const bool isInteriorBoundary = enableInteriorBoundaries && fluxVarsCache.isInteriorBoundary();
// For interior Neumann boundaries when using Tpfa for Neumann boundary conditions, we simply
// return the user-specified flux. Note that for compositional models we attribute the influxes
// to the major components, thus we do it per phase in Darcy's law. However, for single-phasic models
// wesolve the phase mass balance equation AND the transport equation, thus, in that case we incorporate
// the Neumann BCs here. We assume compIdx = eqIdx.
// Note that this way of including interior Neumann fluxes fails for mpnc models where n != m.
if (numPhases == 1
&& isInteriorBoundary
&& useTpfaBoundary
&& fluxVarsCache.interiorBoundaryDataSelf().faceType() == MpfaFaceTypes::interiorNeumann)
componentFlux[compIdx] = scvf.area()*
elemVolVars[scvf.insideScvIdx()].extrusionFactor()*
problem.neumann(element, fvGeometry, elemVolVars, scvf)[compIdx];
continue;
// get the scaling factor for the effective diffusive fluxes
const auto effFactor = Implementation::computeEffectivityFactor(fvGeometry, elemVolVars, scvf, fluxVarsCache, phaseIdx, isInteriorBoundary);
const auto effFactor = computeEffectivityFactor(elemVolVars, scvf, phaseIdx);
// if factor is zero, the flux will end up zero anyway
if (effFactor == 0.0)
{
componentFlux[compIdx] = 0.0;
continue;
}
// lambda functions depending on if we use mole or mass fractions
auto getX = [phaseIdx, compIdx] (const auto& volVars)
{ return volVars.moleFraction(phaseIdx, compIdx); };
auto getRho = [phaseIdx] (const auto& volVars)
{ return volVars.molarDensity(phaseIdx); };
// calculate the density at the interface
const auto rho = Implementation::interpolateDensity(fvGeometry, elemVolVars, scvf, fluxVarsCache, getRho, isInteriorBoundary);
const auto rho = interpolateDensity(elemVolVars, scvf, phaseIdx);
// calculate Tij*xj
// prepare computations
Scalar flux(0.0);
unsigned int localIdx = 0;
for (const auto volVarIdx : volVarsStencil)
flux += tij[localIdx++]*getX(elemVolVars[volVarIdx]);
unsigned int i = 0;
const auto& fluxVarsCache = elemFluxVarsCache[scvf];
const auto& tij = fluxVarsCache.diffusionTij(phaseIdx, compIdx);
// if no interior boundaries are present, return effective mass flux
if (!enableInteriorBoundaries)
componentFlux[compIdx] = useTpfaBoundary ? flux*rho*effFactor : flux*rho*effFactor + fluxVarsCache.componentNeumannFlux(compIdx);
// calculate Tij*xj
for (const auto volVarIdx : fluxVarsCache.diffusionVolVarsStencil(phaseIdx, compIdx))
flux += tij[i++]*elemVolVars[volVarIdx].moleFraction(phaseIdx, compIdx);
else
{
// Handle interior boundaries
flux += Implementation::computeInteriorBoundaryContribution(fvGeometry, elemVolVars, fluxVarsCache, getX, phaseIdx, compIdx);
// add contributions from dirichlet BCs
for (const auto& d : fluxVarsCache.diffusionDirichletData(phaseIdx, compIdx))
flux += tij[i++]*elemVolVars[d.volVarIndex()].moleFraction(phaseIdx, compIdx);
// return overall resulting flux
componentFlux[compIdx] = useTpfaBoundary ? flux*rho*effFactor : flux*rho*effFactor + fluxVarsCache.componentNeumannFlux(compIdx);
}
componentFlux[compIdx] = fluxVarsCache.diffusionSwitchFluxSign(phaseIdx, compIdx) ? -1.0*flux*rho*effFactor : flux*rho*effFactor;
}
// accumulate the phase component flux
......@@ -249,69 +207,33 @@ public:
return componentFlux;
}
template<typename GetRhoFunction>
static Scalar interpolateDensity(const FVElementGeometry& fvGeometry,
const ElementVolumeVariables& elemVolVars,
private:
static Scalar interpolateDensity(const ElementVolumeVariables& elemVolVars,
const SubControlVolumeFace& scvf,
const FluxVariablesCache& fluxVarsCache,
const GetRhoFunction& getRho,
const bool isInteriorBoundary)
const unsigned int phaseIdx)
{
// maybe use the density of the interior BC on the facet
if (isInteriorBoundary)
{
const auto& data = fluxVarsCache.interiorBoundaryDataSelf();
if (data.faceType() == MpfaFaceTypes::interiorDirichlet)
return getRho(data.facetVolVars(fvGeometry));
}
// use arithmetic mean of the densities around the scvf
if (!scvf.boundary())
{
Scalar rho = getRho(elemVolVars[scvf.insideScvIdx()]);
for (auto outsideIdx : scvf.outsideScvIndices())
rho += getRho(elemVolVars[outsideIdx]);
Scalar rho = elemVolVars[scvf.insideScvIdx()].molarDensity(phaseIdx);
for (const auto outsideIdx : scvf.outsideScvIndices())
rho += elemVolVars[outsideIdx].molarDensity(phaseIdx);
return rho/(scvf.outsideScvIndices().size()+1);
}
else
return getRho(elemVolVars[scvf.outsideScvIdx()]);
return elemVolVars[scvf.outsideScvIdx()].molarDensity(phaseIdx);
}
//! Here we want to calculate the factors with which the diffusion coefficient has to be
//! scaled to get the effective diffusivity. For this we use the effective diffusivity with
//! a diffusion coefficient of 1.0 as input. Then we scale the transmissibilites during flux
//! calculation (above) with the harmonic average of the two factors
static Scalar computeEffectivityFactor(const FVElementGeometry& fvGeometry,
const ElementVolumeVariables& elemVolVars,
static Scalar computeEffectivityFactor(const ElementVolumeVariables& elemVolVars,
const SubControlVolumeFace& scvf,
const FluxVariablesCache& fluxVarsCache,
const unsigned int phaseIdx,
const bool isInteriorBoundary)
const unsigned int phaseIdx)
{
using EffDiffModel = typename GET_PROP_TYPE(TypeTag, EffectiveDiffusivityModel);
// Treat interior boundaries differently
if (isInteriorBoundary)
{
const auto& data = fluxVarsCache.interiorBoundaryDataSelf();
// use harmonic mean between the interior and the facet volvars
if (data.faceType() == MpfaFaceTypes::interiorDirichlet)
{
const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
const auto factor = EffDiffModel::effectiveDiffusivity(insideVolVars.porosity(),
insideVolVars.saturation(phaseIdx),
/*Diffusion coefficient*/ 1.0);