diff --git a/dumux/porousmediumflow/constitutivelaws/darcyslaw.hh b/dumux/porousmediumflow/constitutivelaws/darcyslaw.hh index 38c154c3db3e44ac322fd941644f074cda71b0a8..f5f6fb07fd441175f3235c606e40b444f3ea1576 100644 --- a/dumux/porousmediumflow/constitutivelaws/darcyslaw.hh +++ b/dumux/porousmediumflow/constitutivelaws/darcyslaw.hh @@ -33,6 +33,7 @@ #include <dumux/common/parameters.hh> #include <dumux/implicit/properties.hh> +#include <dune/localfunctions/lagrange/pqkfactory.hh> namespace Dumux @@ -201,175 +202,110 @@ private: template <class TypeTag> class DarcysLaw<TypeTag, typename std::enable_if<GET_PROP_VALUE(TypeTag, DiscretizationMethod) == GET_PROP(TypeTag, DiscretizationMethods)::Box>::type > { - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - 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 BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using IndexType = typename GridView::IndexSet::IndexType; - using Element = typename GridView::template Codim<0>::Entity; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, SubControlVolume) SubControlVolume; + typedef typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace) SubControlVolumeFace; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariablesCache) FluxVariablesCache; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GridView::IndexSet::IndexType IndexType; + typedef typename GridView::ctype CoordScalar; + typedef std::vector<IndexType> Stencil; enum { dim = GridView::dimension} ; enum { dimWorld = GridView::dimensionworld} ; - enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases)} ; - - using DimWorldMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>; - using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>; - -public: - - void update(const Problem& problem, - const Element& element, - const SubControlVolumeFace& scvFace) - { - DUNE_THROW(Dune::NotImplemented, "Darcy's law for the Box method is not yet implemented!"); - - problemPtr_ = &problem; - scvFacePtr_ = &scvFace; - elementPtr_ = &element; - enableGravity_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Problem, EnableGravity); - updateTransmissibilities_(); - } + typedef Dune::FieldMatrix<Scalar, dimWorld, dimWorld> DimWorldMatrix; + typedef Dune::FieldVector<Scalar, dimWorld> DimVector; - void update(const Problem& problem, - const Element& element, - const SubControlVolumeFace &scvFace, - VolumeVariables* boundaryVolVars) - { - update(problem, element, scvFace); - } + typedef Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1> FeCache; + typedef typename FeCache::FiniteElementType::Traits::LocalBasisType FeLocalBasis; + typedef typename FluxVariablesCache::FaceData FaceData; - void updateTransmissibilities(const Problem &problem, const SubControlVolumeFace &scvFace) - { - updateTransmissibilities_(); - } +public: - void beginFluxComputation(bool boundaryVolVarsUpdated = false) + static Scalar flux(const Problem& problem, + const Element& element, + const SubControlVolumeFace& scvFace, + const IndexType phaseIdx) { - // Get the inside volume variables - const auto insideScvIdx = scvFace_().insideScvIdx(); - const auto& insideScv = problem_().model().fvGeometries().subControlVolume(insideScvIdx); - const auto* insideVolVars = &problem_().model().curVolVars(insideScv); + // get the precalculated local jacobian and shape values at the integration point + const auto& faceData = problem.model().fluxVarsCache()[scvFace].faceData(); - // and the outside volume variables - const VolumeVariables* outsideVolVars; - outsideVolVars = &problem_().model().curVolVars(scvFace_().outsideScvIdx()); + const auto& fvGeometry = problem.model().fvGeometries(element); + const auto& insideScv = problem.model().fvGeometries().subControlVolume(scvFace.insideScvIdx()); + const auto extrusionFactor = problem.model().curVolVars(insideScv).extrusionFactor(); + const auto K = problem.spatialParams().intrinsicPermeability(insideScv); - // loop over all phases to compute the volume flux - for (int phaseIdx = 0; phaseIdx < numPhases; phaseIdx++) + // evaluate gradP - rho*g at integration point + DimVector gradP(0.0); + for (const auto& scv : fvGeometry.scvs()) { - auto hInside = insideVolVars->pressure(phaseIdx); - auto hOutside = outsideVolVars->pressure(phaseIdx); - - if (enableGravity_) - { - // do averaging for the density - const auto rhoInside = insideVolVars->density(phaseIdx); - const auto rhoOutide = outsideVolVars->density(phaseIdx); - const auto rho = (rhoInside + rhoOutide)*0.5; + // the global shape function gradient + DimVector gradI; + faceData.jacInvT.mv(faceData.localJacobian[scv.indexInElement()][0], gradI); + gradI *= problem.model().curVolVars(scv).pressure(phaseIdx); + gradP += gradI; + } + if (GET_PARAM_FROM_GROUP(TypeTag, bool, Problem, EnableGravity)) + { + // gravitational acceleration + DimVector g(problem.gravityAtPos(scvFace.center())); - // ask for the gravitational acceleration in the inside neighbor - const auto xInside = insideScv.center(); - const auto gInside = problem_().gravityAtPos(xInside); - - hInside -= rho*(gInside*xInside); - - const auto outsideScvIdx = scvFace_().outsideScvIdx(); - const auto& outsideScv = problem_().model().fvGeometries().subControlVolume(outsideScvIdx); - const auto xOutside = outsideScv.center(); - const auto gOutside = problem_().gravityAtPos(xOutside); - hOutside -= rho*(gOutside*xOutside); - } + // interpolate the density at the IP + const auto& insideVolVars = problem.model().curVolVars(insideScv); + const auto& outsideScv = problem.model().fvGeometries().subControlVolume(scvFace.outsideScvIdx()); + const auto& outsideVolVars = problem.model().curVolVars(outsideScv); + Scalar rho = 0.5*(insideVolVars.density(phaseIdx) + outsideVolVars.density(phaseIdx)); - kGradPNormal_[phaseIdx] = tij_*(hInside - hOutside); + // turn gravity into a force + g *= rho; - if (std::signbit(kGradPNormal_[phaseIdx])) - { - upWindIndices_[phaseIdx] = std::make_pair(scvFace_().outsideScvIdx(), scvFace_().insideScvIdx()); - } - else - { - upWindIndices_[phaseIdx] = std::make_pair(scvFace_().insideScvIdx(), scvFace_().outsideScvIdx()); - } + // subtract from pressure gradient + gradP -= g; } - } - /*! - * \brief A function to calculate the mass flux over a sub control volume face - * - * \param phaseIdx The index of the phase of which the flux is to be calculated - * \param upwindFunction A function which does the upwinding - */ - template<typename FunctionType> - Scalar flux(IndexType phaseIdx, FunctionType upwindFunction) const - { - return kGradPNormal_[phaseIdx]*upwindFunction(upVolVars(phaseIdx), dnVolVars(phaseIdx)); + // apply the permeability and return the flux + auto KGradP = applyPermeability(K, gradP); + return -1.0*(KGradP*scvFace.unitOuterNormal())*scvFace.area()*extrusionFactor; } - // for compatibility with cell-centered models - const std::set<IndexType>& stencil() const + static DimVector applyPermeability(const DimWorldMatrix& K, const DimVector& gradI) { - return std::set<IndexType>(); - } + DimVector result(0.0); + K.mv(gradI, result); - const VolumeVariables& upVolVars(IndexType phaseIdx) const - { - return problem_().model().curVolVars(upWindIndices_[phaseIdx].first); + return result; } - const VolumeVariables& dnVolVars(IndexType phaseIdx) const + static DimVector applyPermeability(const Scalar k, const DimVector& gradI) { - return problem_().model().curVolVars(upWindIndices_[phaseIdx].second); + DimVector result(gradI); + result *= k; + return result; } -private: - - void updateTransmissibilities_() + // This is for compatibility with the cc methods. The flux stencil info is obsolete for the box method. + static Stencil stencil(const Problem& problem, const Element& element, const SubControlVolumeFace& scvFace) { - const auto insideScvIdx = scvFace_().insideScvIdx(); - const auto& insideScv = problem_().model().fvGeometries().subControlVolume(insideScvIdx); - const auto insideK = problem_().spatialParams().intrinsicPermeability(insideScv); - Scalar ti = calculateOmega_(insideK, insideScv); - - const auto outsideScvIdx = scvFace_().outsideScvIdx(); - const auto& outsideScv = problem_().model().fvGeometries().subControlVolume(outsideScvIdx); - const auto outsideK = problem_().spatialParams().intrinsicPermeability(outsideScv); - Scalar tj = -1.0*calculateOmega_(outsideK, outsideScv); - - tij_ = scvFace_().area()*(ti * tj)/(ti + tj); + return Stencil(0); } - const Problem &problem_() const + static FaceData calculateFaceData(const Problem& problem, const Element& element, const typename Element::Geometry& geometry, const FeLocalBasis& localBasis, const SubControlVolumeFace& scvFace) { - return *problemPtr_; - } + FaceData faceData; - const SubControlVolumeFace& scvFace_() const - { - return *scvFacePtr_; - } + // evaluate shape functions and gradients at the integration point + const auto ipLocal = geometry.local(scvFace.center()); + faceData.jacInvT = geometry.jacobianInverseTransposed(ipLocal); + localBasis.evaluateJacobian(ipLocal, faceData.localJacobian); + localBasis.evaluateFunction(ipLocal, faceData.shapeValues); - const Element& element_() const - { - return *elementPtr_; + return std::move(faceData); } - - const Problem *problemPtr_; //! Pointer to the problem - const SubControlVolumeFace *scvFacePtr_; //! Pointer to the sub control volume face for which the flux variables are created - const Element *elementPtr_; //! Point to the element - bool enableGravity_; //! If we have a problem considering gravitational effects - - //! The upstream (first) and downstream (second) volume variable indices - std::array<std::pair<IndexType, IndexType>, numPhases> upWindIndices_; - Scalar tij_ = 0; - - //! Precomputed values - std::array<Scalar, numPhases> kGradPNormal_; //! K(grad(p) - rho*g)*n - GlobalPosition normalK_; //! (K^T)n }; } // end namespace