From 22e7ecb85c224357691af8705857abb2b714d9fb Mon Sep 17 00:00:00 2001 From: "Dennis.Glaeser" <dennis.glaeser@iws.uni-stuttgart.de> Date: Tue, 17 Mar 2020 10:48:18 +0100 Subject: [PATCH] [facet][tpfa] implement fouriers law --- .../facet/cellcentered/tpfa/CMakeLists.txt | 1 + .../facet/cellcentered/tpfa/fourierslaw.hh | 429 ++++++++++++++++++ .../facet/cellcentered/tpfa/properties.hh | 8 + 3 files changed, 438 insertions(+) create mode 100644 dumux/multidomain/facet/cellcentered/tpfa/fourierslaw.hh diff --git a/dumux/multidomain/facet/cellcentered/tpfa/CMakeLists.txt b/dumux/multidomain/facet/cellcentered/tpfa/CMakeLists.txt index 9175158d75..0f21d29c22 100644 --- a/dumux/multidomain/facet/cellcentered/tpfa/CMakeLists.txt +++ b/dumux/multidomain/facet/cellcentered/tpfa/CMakeLists.txt @@ -3,5 +3,6 @@ couplingmanager.hh couplingmapper.hh darcyslaw.hh fickslaw.hh +fourierslaw.hh properties.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/multidomain/facet/cellcentered/tpfa) diff --git a/dumux/multidomain/facet/cellcentered/tpfa/fourierslaw.hh b/dumux/multidomain/facet/cellcentered/tpfa/fourierslaw.hh new file mode 100644 index 0000000000..c8e6bb38fc --- /dev/null +++ b/dumux/multidomain/facet/cellcentered/tpfa/fourierslaw.hh @@ -0,0 +1,429 @@ +// -*- 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 3 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 + * \ingroup FacetCoupling + * \copydoc Dumux::CCTpfaFacetCouplingFouriersLaw + */ +#ifndef DUMUX_DISCRETIZATION_CC_TPFA_FACET_COUPLING_FOURIERS_LAW_HH +#define DUMUX_DISCRETIZATION_CC_TPFA_FACET_COUPLING_FOURIERS_LAW_HH + +#include <array> +#include <cmath> + +#include <dune/common/float_cmp.hh> +#include <dune/common/fvector.hh> + +#include <dumux/common/math.hh> +#include <dumux/common/parameters.hh> +#include <dumux/common/properties.hh> + +#include <dumux/discretization/method.hh> +#include <dumux/discretization/cellcentered/tpfa/computetransmissibility.hh> + +#include <dumux/flux/cctpfa/fourierslaw.hh> + +namespace Dumux { + +//! Forward declaration of the implementation +template<class TypeTag, + bool isNetwork> +class CCTpfaFacetCouplingFouriersLawImpl; + +/*! + * \ingroup FacetCoupling + * \brief Fouriers's law for cell-centered finite volume schemes with two-point flux approximation + * in the context of coupled models where the coupling occurs across the facets of the bulk + * domain elements with a lower-dimensional domain defined on these facets. + */ +template<class TypeTag> +using CCTpfaFacetCouplingFouriersLaw = + CCTpfaFacetCouplingFouriersLawImpl< TypeTag, ( int(GetPropType<TypeTag, Properties::GridGeometry>::GridView::dimension) + < int(GetPropType<TypeTag, Properties::GridGeometry>::GridView::dimensionworld) ) >; + +/*! + * \ingroup FacetCoupling + * \brief Specialization of CCTpfaFacetCouplingFouriersLawImpl for dim=dimWorld + */ +template<class TypeTag> +class CCTpfaFacetCouplingFouriersLawImpl<TypeTag, /*isNetwork*/false> +: public FouriersLawImplementation<TypeTag, DiscretizationMethod::cctpfa> +{ + using Implementation = CCTpfaFacetCouplingFouriersLawImpl<TypeTag, false>; + using ParentType = FouriersLawImplementation<TypeTag, DiscretizationMethod::cctpfa>; + + using Scalar = GetPropType<TypeTag, Properties::Scalar>; + using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; + using FVElementGeometry = typename GridGeometry::LocalView; + using SubControlVolume = typename GridGeometry::SubControlVolume; + using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace; + + using GridView = typename GridGeometry::GridView; + using Element = typename GridView::template Codim<0>::Entity; + + /*! + * \brief The cache class used with this specialization of Fourier's law. + */ + class FacetCouplingFouriersLawCache + { + public: + //! export the corresponding filler class + using Filler = typename ParentType::Cache::Filler; + + //! we store the transmissibilities associated with the interior + //! cell, outside cell, and the fracture facet in an array. Access + //! to this array should be done using the following indices: + static constexpr int insideTijIdx = 0; + static constexpr int outsideTijIdx = 1; + static constexpr int facetTijIdx = 2; + + //! Export transmissibility storage type + using HeatConductionTransmissibilityContainer = std::array<Scalar, 3>; + + //! update subject to a given problem + template< class Problem, class ElementVolumeVariables > + void updateHeatConduction(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvf) + { + tij_ = Implementation::calculateTransmissibility(problem, element, fvGeometry, elemVolVars, scvf); + } + + //! We use the same name as in the TpfaFouriersLawCache 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 heatConductionTij() const + { return tij_[insideTijIdx]; } + + //! returns the transmissibility associated with the inside cell + Scalar heatConductionTijInside() const + { return tij_[insideTijIdx]; } + + //! returns the transmissibility associated with the outside cell + Scalar heatConductionTijOutside() const + { return tij_[outsideTijIdx]; } + + //! returns the transmissibility associated with the outside cell + Scalar heatConductionTijFacet() const + { return tij_[facetTijIdx]; } + + private: + HeatConductionTransmissibilityContainer tij_; + }; + +public: + //! export the type for the corresponding cache + using Cache = FacetCouplingFouriersLawCache; + + //! state the discretization method this implementation belongs to + static const DiscretizationMethod discMethod = DiscretizationMethod::cctpfa; + + //! Compute the conductive heat flux + template< class Problem, class ElementVolumeVariables, class ElementFluxVarsCache > + static Scalar flux(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf, + const ElementFluxVarsCache& elemFluxVarsCache) + { + if (!problem.couplingManager().isOnInteriorBoundary(element, scvf)) + return ParentType::flux(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache); + + // get inside/outside volume variables + const auto& fluxVarsCache = elemFluxVarsCache[scvf]; + const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()]; + const auto& facetVolVars = problem.couplingManager().getLowDimVolVars(element, scvf); + const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()]; + + // the inside and outside temperatures + const Scalar tInside = insideVolVars.temperature(); + const Scalar tFacet = facetVolVars.temperature(); + const Scalar tOutside = outsideVolVars.temperature(); + + Scalar flux = fluxVarsCache.heatConductionTijInside()*tInside + + fluxVarsCache.heatConductionTijFacet()*tFacet; + + if (!scvf.boundary()) + flux += fluxVarsCache.heatConductionTijOutside()*tOutside; + return flux; + } + + // The flux variables cache has to be bound to an element prior to flux calculations + // During the binding, the transmissibility will be computed and stored using the method below. + template< class Problem, class ElementVolumeVariables > + static typename Cache::HeatConductionTransmissibilityContainer + calculateTransmissibility(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf) + { + typename Cache::HeatConductionTransmissibilityContainer tij; + if (!problem.couplingManager().isCoupled(element, scvf)) + { + //! use the standard Fourier's law and only compute one transmissibility + tij[Cache::insideTijIdx] = ParentType::calculateTransmissibility(problem, element, fvGeometry, elemVolVars, scvf); + return tij; + } + + //! xi factor for the coupling conditions + static const Scalar xi = getParamFromGroup<Scalar>(problem.paramGroup(), "FacetCoupling.Xi", 1.0); + + const auto insideScvIdx = scvf.insideScvIdx(); + const auto& insideScv = fvGeometry.scv(insideScvIdx); + const auto& insideVolVars = elemVolVars[insideScvIdx]; + const auto wIn = scvf.area()*computeTpfaTransmissibility(scvf, + insideScv, + insideVolVars.effectiveThermalConductivity(), + insideVolVars.extrusionFactor()); + + // proceed depending on the interior BC types used + const auto iBcTypes = problem.interiorBoundaryTypes(element, scvf); + + // neumann-coupling + if (iBcTypes.hasOnlyNeumann()) + { + const auto& facetVolVars = problem.couplingManager().getLowDimVolVars(element, scvf); + const auto wFacet = 2.0*scvf.area()*insideVolVars.extrusionFactor() + /facetVolVars.extrusionFactor() + *vtmv(scvf.unitOuterNormal(), + facetVolVars.effectiveThermalConductivity(), + scvf.unitOuterNormal()); + + // The fluxes across this face and the outside face can be expressed in matrix form: + // \f$\mathbf{C} \bar{\mathbf{u}} + \mathbf{D} \mathbf{u} + \mathbf{E} \mathbf{u}_\gamma\f$, + // 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 + // that allow the description of the fluxes as functions of the cell and Dirichlet temperatures only. + if (!scvf.boundary()) + { + const auto outsideScvIdx = scvf.outsideScvIdx(); + const auto& outsideVolVars = elemVolVars[outsideScvIdx]; + const auto wOut = -1.0*scvf.area()*computeTpfaTransmissibility(scvf, + fvGeometry.scv(outsideScvIdx), + outsideVolVars.effectiveThermalConductivity(), + outsideVolVars.extrusionFactor()); + + if ( !Dune::FloatCmp::eq(xi, 1.0, 1e-6) ) + { + // optimized implementation: factorization obtained using sympy + // see CCTpfaFacetCouplingDarcysLaw for more details + 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 + { + tij[Cache::insideTijIdx] = wFacet*wIn/(wIn+wFacet); + tij[Cache::facetTijIdx] = -tij[Cache::insideTijIdx]; + tij[Cache::outsideTijIdx] = 0.0; + } + } + else + { + tij[Cache::insideTijIdx] = wFacet*wIn/(wIn+wFacet); + tij[Cache::facetTijIdx] = -tij[Cache::insideTijIdx]; + tij[Cache::outsideTijIdx] = 0.0; + } + } + else if (iBcTypes.hasOnlyDirichlet()) + { + tij[Cache::insideTijIdx] = wIn; + tij[Cache::outsideTijIdx] = 0.0; + tij[Cache::facetTijIdx] = -wIn; + } + else + DUNE_THROW(Dune::NotImplemented, "Interior boundary types other than pure Dirichlet or Neumann"); + + return tij; + } +}; + +/*! + * \ingroup FacetCoupling + * \brief Specialization of CCTpfaFacetCouplingFouriersLawImpl for dim<dimWorld + */ +template<class TypeTag> +class CCTpfaFacetCouplingFouriersLawImpl<TypeTag, /*isNetwork*/true> +: public FouriersLawImplementation<TypeTag, DiscretizationMethod::cctpfa> +{ + using Implementation = CCTpfaFacetCouplingFouriersLawImpl<TypeTag, true>; + using ParentType = FouriersLawImplementation<TypeTag, DiscretizationMethod::cctpfa>; + + using Scalar = GetPropType<TypeTag, Properties::Scalar>; + using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; + using FVElementGeometry = typename GridGeometry::LocalView; + using SubControlVolume = typename GridGeometry::SubControlVolume; + using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace; + + using GridView = typename GridGeometry::GridView; + using Element = typename GridView::template Codim<0>::Entity; + + /*! + * \brief The cache class used with this specialization of Fourier's law. + */ + class FacetCouplingFouriersLawCache + { + public: + //! export the corresponding filler class + using Filler = typename ParentType::Cache::Filler; + + //! we store the transmissibilities associated with the interior + //! cell and the fracture facet in an array. Access to this array + //! should be done using the following indices: + static constexpr int insideTijIdx = 0; + static constexpr int facetTijIdx = 1; + + //! Export transmissibility storage type + using HeatConductionTransmissibilityContainer = std::array<Scalar, 2>; + + //! update subject to a given problem + template< class Problem, class ElementVolumeVariables > + void updateHeatConduction(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace &scvf) + { + tij_ = Implementation::calculateTransmissibility(problem, element, fvGeometry, elemVolVars, scvf); + } + + //! We use the same name as in the TpfaFouriersLawCache 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 heatConductionTij() const + { return tij_[insideTijIdx]; } + + //! returns the transmissibility associated with the inside cell + Scalar heatConductionTijInside() const + { return tij_[insideTijIdx]; } + + //! returns the transmissibility associated with the outside cell + Scalar heatConductionTijFacet() const + { return tij_[facetTijIdx]; } + + private: + HeatConductionTransmissibilityContainer tij_; + }; + +public: + //! export the type for the corresponding cache + using Cache = FacetCouplingFouriersLawCache; + + //! state the discretization method this implementation belongs to + static const DiscretizationMethod discMethod = DiscretizationMethod::cctpfa; + + //! Compute the conductive heat flux + template< class Problem, class ElementVolumeVariables, class ElementFluxVarsCache > + static Scalar flux(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf, + const ElementFluxVarsCache& elemFluxVarsCache) + { + if (!problem.couplingManager().isOnInteriorBoundary(element, scvf)) + return ParentType::flux(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache); + + // get inside/facet volume variables + const auto& fluxVarsCache = elemFluxVarsCache[scvf]; + const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()]; + const auto& facetVolVars = problem.couplingManager().getLowDimVolVars(element, scvf); + + return fluxVarsCache.heatConductionTijInside()*insideVolVars.temperature() + + fluxVarsCache.heatConductionTijFacet()*facetVolVars.temperature(); + } + + // The flux variables cache has to be bound to an element prior to flux calculations + // During the binding, the transmissibility will be computed and stored using the method below. + template< class Problem, class ElementVolumeVariables > + static typename Cache::HeatConductionTransmissibilityContainer + calculateTransmissibility(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf) + { + typename Cache::HeatConductionTransmissibilityContainer tij; + if (!problem.couplingManager().isCoupled(element, scvf)) + { + //! use the standard Fourier's law and only compute one transmissibility + tij[Cache::insideTijIdx] = ParentType::calculateTransmissibility(problem, element, fvGeometry, elemVolVars, scvf); + return tij; + } + + //! xi factor for the coupling conditions + static const Scalar xi = getParamFromGroup<Scalar>(problem.paramGroup(), "FacetCoupling.Xi", 1.0); + + // On surface grids only xi = 1.0 can be used, as the coupling condition + // for xi != 1.0 does not generalize for surface grids where the normal + // vectors of the inside/outside elements have different orientations. + if (Dune::FloatCmp::ne(xi, 1.0, 1e-6)) + DUNE_THROW(Dune::InvalidStateException, "Xi != 1.0 cannot be used on surface grids"); + + const auto insideScvIdx = scvf.insideScvIdx(); + const auto& insideScv = fvGeometry.scv(insideScvIdx); + const auto& insideVolVars = elemVolVars[insideScvIdx]; + const auto wIn = scvf.area()*computeTpfaTransmissibility(scvf, + insideScv, + insideVolVars.effectiveThermalConductivity(), + insideVolVars.extrusionFactor()); + + // proceed depending on the interior BC types used + const auto iBcTypes = problem.interiorBoundaryTypes(element, scvf); + + // neumann-coupling + if (iBcTypes.hasOnlyNeumann()) + { + // Here we use the square root of the facet extrusion factor + // as an approximate average distance from scvf ip to facet center + using std::sqrt; + const auto& facetVolVars = problem.couplingManager().getLowDimVolVars(element, scvf); + const auto wFacet = 2.0*scvf.area()*insideVolVars.extrusionFactor() + /sqrt(facetVolVars.extrusionFactor()) + *vtmv(scvf.unitOuterNormal(), + facetVolVars.effectiveThermalConductivity(), + scvf.unitOuterNormal()); + + tij[Cache::insideTijIdx] = wFacet*wIn/(wIn+wFacet); + tij[Cache::facetTijIdx] = -tij[Cache::insideTijIdx]; + } + else if (iBcTypes.hasOnlyDirichlet()) + { + tij[Cache::insideTijIdx] = wIn; + tij[Cache::facetTijIdx] = -wIn; + } + else + DUNE_THROW(Dune::NotImplemented, "Interior boundary types other than pure Dirichlet or Neumann"); + + return tij; + } +}; + +} // end namespace Dumux + +#endif diff --git a/dumux/multidomain/facet/cellcentered/tpfa/properties.hh b/dumux/multidomain/facet/cellcentered/tpfa/properties.hh index 073a51f713..3e32b3cdf6 100644 --- a/dumux/multidomain/facet/cellcentered/tpfa/properties.hh +++ b/dumux/multidomain/facet/cellcentered/tpfa/properties.hh @@ -35,6 +35,7 @@ #include <dumux/multidomain/facet/cellcentered/localresidual.hh> #include <dumux/multidomain/facet/cellcentered/tpfa/darcyslaw.hh> #include <dumux/multidomain/facet/cellcentered/tpfa/fickslaw.hh> +#include <dumux/multidomain/facet/cellcentered/tpfa/fourierslaw.hh> #include <dumux/porousmediumflow/fluxvariables.hh> @@ -64,6 +65,13 @@ struct MolecularDiffusionType<TypeTag, TTag::CCTpfaFacetCouplingModel> using type = CCTpfaFacetCouplingFicksLaw< TypeTag >; }; +//! Use the tpfa facet coupling-specific Ficks's law +template<class TypeTag> +struct HeatConductionType<TypeTag, TTag::CCTpfaFacetCouplingModel> +{ + using type = CCTpfaFacetCouplingFouriersLaw< TypeTag >; +}; + //! Use the cc local residual for models with facet coupling template<class TypeTag> struct BaseLocalResidual<TypeTag, TTag::CCTpfaFacetCouplingModel> { using type = CCFacetCouplingLocalResidual<TypeTag>; }; -- GitLab