From 3133e81eda938ccfc4b52cfd4c2f23ff8a02a9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20Gl=C3=A4ser?= <dennis.glaeser@iws.uni-stuttgart.de> Date: Mon, 12 Nov 2018 19:11:13 +0100 Subject: [PATCH] [facet][tpfa][darcyslaw] implement gravity handling for xi != 1.0 --- .../facet/cellcentered/tpfa/darcyslaw.hh | 106 +++++++++++++----- test/multidomain/facet/1p_1p/CMakeLists.txt | 1 + 2 files changed, 81 insertions(+), 26 deletions(-) diff --git a/dumux/multidomain/facet/cellcentered/tpfa/darcyslaw.hh b/dumux/multidomain/facet/cellcentered/tpfa/darcyslaw.hh index 0875ddf35f..921630cce9 100644 --- a/dumux/multidomain/facet/cellcentered/tpfa/darcyslaw.hh +++ b/dumux/multidomain/facet/cellcentered/tpfa/darcyslaw.hh @@ -90,6 +90,9 @@ public: //! Export transmissibility storage type using AdvectionTransmissibilityContainer = std::array<Scalar, 3>; + //! Export the type used for the gravity coefficients + using GravityCoefficients = std::array<Scalar, 2>; + //! update subject to a given problem template< class Problem, class ElementVolumeVariables > void updateAdvection(const Problem& problem, @@ -98,26 +101,35 @@ public: const ElementVolumeVariables& elemVolVars, const SubControlVolumeFace &scvf) { - tij_ = AdvectionType::calculateTransmissibility(problem, element, fvGeometry, elemVolVars, scvf); + tij_ = AdvectionType::calculateTransmissibility(problem, element, fvGeometry, elemVolVars, scvf, g_); } //! We use the same name as in the TpfaDarcysLawCache so //! that this cache and the law implementation for non-coupled //! models can be reused here on facets that do not lie on an //! interior boundary, i.e. do not coincide with a facet element - Scalar advectionTij() const { return tij_[insideTijIdx]; } + Scalar advectionTij() const + { return tij_[insideTijIdx]; } //! returns the transmissibility associated with the inside cell - Scalar advectionTijInside() const { return tij_[insideTijIdx]; } + Scalar advectionTijInside() const + { return tij_[insideTijIdx]; } //! returns the transmissibility associated with the outside cell - Scalar advectionTijOutside() const {return tij_[outsideTijIdx]; } + Scalar advectionTijOutside() const + { return tij_[outsideTijIdx]; } //! returns the transmissibility associated with the outside cell - Scalar advectionTijFacet() const {return tij_[facetTijIdx]; } + Scalar advectionTijFacet() const + { return tij_[facetTijIdx]; } + + //! return the coefficients for the computation of gravity at the scvf + const GravityCoefficients& gravityCoefficients() const + { return g_; } private: std::array<Scalar, 3> tij_; + GravityCoefficients g_; }; /*! @@ -188,27 +200,33 @@ class CCTpfaFacetCouplingDarcysLawImpl<ScalarType, FVGridGeometry, /*isNetwork*/ static const Scalar gravity = getParamFromGroup<bool>(problem.paramGroup(), "Problem.EnableGravity"); if (gravity) { - // this is inconsistent for xi != 1 - static const Scalar xi = getParamFromGroup<Scalar>(problem.paramGroup(), "FacetCoupling.Xi", 1.0); - if (xi != 1.0) - DUNE_THROW(Dune::NotImplemented, "Gravitational acceleration for facet coupling and xi != 1.0"); - - // compute alpha := n^T*K*g + // compute alpha := n^T*K*g and add to flux (use arithmetic mean for density) const auto& g = problem.gravityAtPos(scvf.ipGlobal()); - const auto alpha_inside = vtmv(scvf.unitOuterNormal(), insideVolVars.permeability(), g)*insideVolVars.extrusionFactor(); - - // for the density, use arithmetic average const auto rho = 0.5*(insideVolVars.density(phaseIdx) + facetVolVars.density(phaseIdx)); - flux += rho*scvf.area()*alpha_inside; + const auto rhoTimesArea = rho*scvf.area(); + const auto alpha_inside = rhoTimesArea*insideVolVars.extrusionFactor() + *vtmv(scvf.unitOuterNormal(), insideVolVars.permeability(), g); - // maybe add K-weighted gravitational contribution + flux += alpha_inside; if (!scvf.boundary()) { const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()]; - const auto wFacet = computeFacetTransmissibility_(insideVolVars, facetVolVars, scvf); - const auto alpha_outside = vtmv(scvf.unitOuterNormal(), outsideVolVars.permeability(), g)*outsideVolVars.extrusionFactor(); - flux += rho*fluxVarsCache.advectionTijInside()/wFacet*(alpha_inside - alpha_outside); + // add further gravitational contributions + if ( problem.interiorBoundaryTypes(element, scvf).hasOnlyNeumann() ) + { + static const Scalar xi = getParamFromGroup<Scalar>(problem.paramGroup(), "FacetCoupling.Xi", 1.0); + const auto alpha_facet = rhoTimesArea*insideVolVars.extrusionFactor() + *vtmv(scvf.unitOuterNormal(), facetVolVars.permeability(), g); + const auto alpha_outside = rhoTimesArea*outsideVolVars.extrusionFactor() + *vtmv(scvf.unitOuterNormal(), outsideVolVars.permeability(), g); + + flux -= fluxVarsCache.gravityCoefficients()[0]*(xi*alpha_inside - alpha_facet + (1.0 - xi)*alpha_outside); + flux += fluxVarsCache.gravityCoefficients()[1]*(xi*alpha_outside - alpha_facet + (1.0 - xi)*alpha_inside); + } + + // add outside contribution + flux += fluxVarsCache.advectionTijOutside()*outsideVolVars.pressure(phaseIdx); } return flux; @@ -226,6 +244,20 @@ class CCTpfaFacetCouplingDarcysLawImpl<ScalarType, FVGridGeometry, /*isNetwork*/ const FVElementGeometry& fvGeometry, const ElementVolumeVariables& elemVolVars, const SubControlVolumeFace& scvf) + { + typename Cache::GravityCoefficients g; + return calculateTransmissibility(problem, element, fvGeometry, elemVolVars, scvf, g); + } + + // This overload additionally receives a container in which the coefficients required + // for the computation of the gravitational acceleration ar the scvf are stored + template< class Problem, class ElementVolumeVariables > + static TijContainer calculateTransmissibility(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf, + typename Cache::GravityCoefficients& g) { TijContainer tij; if (!problem.couplingManager().isCoupled(element, scvf)) @@ -260,8 +292,9 @@ class CCTpfaFacetCouplingDarcysLawImpl<ScalarType, FVGridGeometry, /*isNetwork*/ // where \f$\gamma$\f denotes the domain living on the facets and \f$\bar{\mathbf{u}}$\f are // intermediate face unknowns in the matrix domain. Equivalently, flux continuity reads: // \f$\mathbf{A} \bar{\mathbf{u}} = \mathbf{B} \mathbf{u} + \mathbf{M} \mathbf{u}_\gamma\f$. - // Combining the two, we can eliminate the intermediate unknowns and compute the transmissibilities. - if (!scvf.boundary() && xi != 1.0) + // Combining the two, we can eliminate the intermediate unknowns and compute the transmissibilities + // that allow the description of the fluxes as functions of the cell and Dirichlet pressures only. + if (!scvf.boundary()) { const auto outsideScvIdx = scvf.outsideScvIdx(); const auto& outsideVolVars = elemVolVars[outsideScvIdx]; @@ -270,11 +303,32 @@ class CCTpfaFacetCouplingDarcysLawImpl<ScalarType, FVGridGeometry, /*isNetwork*/ outsideVolVars.permeability(), outsideVolVars.extrusionFactor()); - const Scalar factor = wIn * wFacet / ( wIn * wOut * ( 2.0 * xi - 1.0 ) + wFacet * ( xi * ( wIn + wOut ) + wFacet ) ); - - tij[Cache::insideTijIdx] = factor * ( wOut * xi + wFacet ); - tij[Cache::outsideTijIdx] = factor * ( wOut * ( 1.0 - xi ) ); - tij[Cache::facetTijIdx] = factor * ( - wOut - wFacet ); + if (xi != 1.0) + { + // The gravity coefficients are the first row of the inverse of the A matrix in the local eq system + // multiplied with wIn. Note that we never compute the inverse but use an optimized implementation below. + // The A matrix has the following coefficients: + // A = | xi*wIn + wFacet, (xi - 1.0)*wOut | -> AInv = 1/detA | xi*wOut + wFacet, -(xi - 1.0)*wOut | + // | wIn*(xi - 1.0) , xi*wOut + wFacet | | -wIn*(xi - 1.0) , xi*wIn + wFacet | + const Scalar xiMinusOne = (xi - 1.0); + const Scalar a01 = xiMinusOne*wOut; + const Scalar a11 = xi*wOut + wFacet; + const Scalar detA = (xi*wIn + wFacet)*a11 - xiMinusOne*wIn*a01; + g[0] = wIn*a11/detA; g[1] = -wIn*a01/detA; + + // optimized implementation: factorization obtained using sympy + const Scalar factor = wIn * wFacet / ( wIn * wOut * ( 2.0 * xi - 1.0 ) + wFacet * ( xi * ( wIn + wOut ) + wFacet ) ); + tij[Cache::insideTijIdx] = factor * ( wOut * xi + wFacet ); + tij[Cache::outsideTijIdx] = factor * ( wOut * ( 1.0 - xi ) ); + tij[Cache::facetTijIdx] = factor * ( - wOut - wFacet ); + } + else + { + g[0] = wIn/(wIn+wFacet); g[1] = 0.0; + tij[Cache::insideTijIdx] = wFacet*g[0]; + tij[Cache::facetTijIdx] = -tij[Cache::insideTijIdx]; + tij[Cache::outsideTijIdx] = 0.0; + } } else { diff --git a/test/multidomain/facet/1p_1p/CMakeLists.txt b/test/multidomain/facet/1p_1p/CMakeLists.txt index f15f388ce1..fc3443e51e 100644 --- a/test/multidomain/facet/1p_1p/CMakeLists.txt +++ b/test/multidomain/facet/1p_1p/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(analytical) +add_subdirectory(gravity) add_subdirectory(linearprofile) add_subdirectory(threedomain) -- GitLab