Line | Branch | Exec | Source |
---|---|---|---|
1 | // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- | ||
2 | // vi: set et ts=4 sw=4 sts=4: | ||
3 | // | ||
4 | // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder | ||
5 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
6 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup CCTpfaFlux | ||
10 | * \brief Fourier's law for cell-centered finite volume schemes with two-point flux approximation | ||
11 | */ | ||
12 | #ifndef DUMUX_DISCRETIZATION_CC_TPFA_FOURIERS_LAW_HH | ||
13 | #define DUMUX_DISCRETIZATION_CC_TPFA_FOURIERS_LAW_HH | ||
14 | |||
15 | #include <dumux/common/parameters.hh> | ||
16 | #include <dumux/common/properties.hh> | ||
17 | |||
18 | #include <dumux/discretization/method.hh> | ||
19 | #include <dumux/discretization/extrusion.hh> | ||
20 | #include <dumux/discretization/cellcentered/tpfa/computetransmissibility.hh> | ||
21 | |||
22 | namespace Dumux { | ||
23 | |||
24 | // forward declaration | ||
25 | template<class TypeTag, class DiscretizationMethod> | ||
26 | class FouriersLawImplementation; | ||
27 | |||
28 | /*! | ||
29 | * \ingroup CCTpfaFlux | ||
30 | * \brief Fourier's law for cell-centered finite volume schemes with two-point flux approximation | ||
31 | */ | ||
32 | template <class TypeTag> | ||
33 | class FouriersLawImplementation<TypeTag, DiscretizationMethods::CCTpfa> | ||
34 | { | ||
35 | using Implementation = FouriersLawImplementation<TypeTag, DiscretizationMethods::CCTpfa>; | ||
36 | using Scalar = GetPropType<TypeTag, Properties::Scalar>; | ||
37 | using Problem = GetPropType<TypeTag, Properties::Problem>; | ||
38 | using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; | ||
39 | using FVElementGeometry = typename GridGeometry::LocalView; | ||
40 | using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace; | ||
41 | using Extrusion = Extrusion_t<GridGeometry>; | ||
42 | using GridView = typename GridGeometry::GridView; | ||
43 | using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView; | ||
44 | using VolumeVariables = typename ElementVolumeVariables::VolumeVariables; | ||
45 | using Element = typename GridView::template Codim<0>::Entity; | ||
46 | using GridFluxVariablesCache = GetPropType<TypeTag, Properties::GridFluxVariablesCache>; | ||
47 | using ElementFluxVarsCache = typename GridFluxVariablesCache::LocalView; | ||
48 | using FluxVariablesCache = typename GridFluxVariablesCache::FluxVariablesCache; | ||
49 | |||
50 | static const int dim = GridView::dimension; | ||
51 | static const int dimWorld = GridView::dimensionworld; | ||
52 | |||
53 | //! Class that fills the cache corresponding to tpfa Fick's Law | ||
54 | class TpfaFouriersLawCacheFiller | ||
55 | { | ||
56 | public: | ||
57 | //! Function to fill a TpfaFicksLawCache of a given scvf | ||
58 | //! This interface has to be met by any diffusion-related cache filler class | ||
59 | template<class FluxVariablesCacheFiller> | ||
60 | ✗ | static void fill(FluxVariablesCache& scvfFluxVarsCache, | |
61 | const Problem& problem, | ||
62 | const Element& element, | ||
63 | const FVElementGeometry& fvGeometry, | ||
64 | const ElementVolumeVariables& elemVolVars, | ||
65 | const SubControlVolumeFace& scvf, | ||
66 | const FluxVariablesCacheFiller& fluxVarsCacheFiller) | ||
67 | { | ||
68 | 143414696 | scvfFluxVarsCache.updateHeatConduction(problem, element, fvGeometry, elemVolVars, scvf); | |
69 | ✗ | } | |
70 | }; | ||
71 | |||
72 | //! Class that caches the transmissibility | ||
73 | class TpfaFouriersLawCache | ||
74 | { | ||
75 | public: | ||
76 | using Filler = TpfaFouriersLawCacheFiller; | ||
77 | |||
78 | ✗ | void updateHeatConduction(const Problem& problem, | |
79 | const Element& element, | ||
80 | const FVElementGeometry& fvGeometry, | ||
81 | const ElementVolumeVariables& elemVolVars, | ||
82 | const SubControlVolumeFace &scvf) | ||
83 | { | ||
84 | 68323276 | tij_ = Implementation::calculateTransmissibility(problem, element, fvGeometry, elemVolVars, scvf); | |
85 | ✗ | } | |
86 | |||
87 | const Scalar& heatConductionTij() const | ||
88 | { return tij_; } | ||
89 | |||
90 | private: | ||
91 | Scalar tij_; | ||
92 | }; | ||
93 | |||
94 | public: | ||
95 | using DiscretizationMethod = DiscretizationMethods::CCTpfa; | ||
96 | //! state the discretization method this implementation belongs to | ||
97 | static constexpr DiscretizationMethod discMethod{}; | ||
98 | |||
99 | //! export the type for the corresponding cache | ||
100 | using Cache = TpfaFouriersLawCache; | ||
101 | |||
102 | /*! | ||
103 | * \brief Returns the heat flux within the porous medium | ||
104 | * (in J/s) across the given sub-control volume face. | ||
105 | * \note This law assumes thermal equilibrium between the fluid | ||
106 | * and solid phases, and uses an effective thermal conductivity | ||
107 | * for the overall aggregate. | ||
108 | * This overload allows to explicitly specify the inside and outside volume variables | ||
109 | * which can be useful to evaluate conductive fluxes at boundaries with given outside values. | ||
110 | * This only works if scvf.numOutsideScv() == 1. | ||
111 | * | ||
112 | */ | ||
113 | static Scalar flux(const Problem& problem, | ||
114 | const Element& element, | ||
115 | const FVElementGeometry& fvGeometry, | ||
116 | const VolumeVariables& insideVolVars, | ||
117 | const VolumeVariables& outsideVolVars, | ||
118 | const SubControlVolumeFace& scvf, | ||
119 | const ElementFluxVarsCache& elemFluxVarsCache) | ||
120 | { | ||
121 | if constexpr (isMixedDimensional_) | ||
122 | if (scvf.numOutsideScv() != 1) | ||
123 | DUNE_THROW(Dune::Exception, "This flux overload requires scvf.numOutsideScv() == 1"); | ||
124 | |||
125 | // heat conductivities are always solution dependent (?) | ||
126 | Scalar tij = elemFluxVarsCache[scvf].heatConductionTij(); | ||
127 | |||
128 | // get the inside/outside temperatures | ||
129 | const auto tInside = insideVolVars.temperature(); | ||
130 | const auto tOutside = outsideVolVars.temperature(); | ||
131 | |||
132 | return tij*(tInside - tOutside); | ||
133 | } | ||
134 | |||
135 | /*! | ||
136 | * \brief Returns the heat flux within the porous medium | ||
137 | * (in J/s) across the given sub-control volume face. | ||
138 | * \note This law assumes thermal equilibrium between the fluid | ||
139 | * and solid phases, and uses an effective thermal conductivity | ||
140 | * for the overall aggregate. | ||
141 | */ | ||
142 | 73923861 | static Scalar flux(const Problem& problem, | |
143 | const Element& element, | ||
144 | const FVElementGeometry& fvGeometry, | ||
145 | const ElementVolumeVariables& elemVolVars, | ||
146 | const SubControlVolumeFace& scvf, | ||
147 | const ElementFluxVarsCache& elemFluxVarsCache) | ||
148 | { | ||
149 | // heat conductivities are always solution dependent (?) | ||
150 | 73923861 | Scalar tij = elemFluxVarsCache[scvf].heatConductionTij(); | |
151 | |||
152 | // get the inside/outside temperatures | ||
153 |
1/2✓ Branch 2 taken 71478741 times.
✗ Branch 3 not taken.
|
147847722 | const auto tInside = elemVolVars[scvf.insideScvIdx()].temperature(); |
154 |
2/4✓ Branch 0 taken 71478741 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 71478741 times.
✗ Branch 3 not taken.
|
147847722 | const auto tOutside = scvf.numOutsideScvs() == 1 ? elemVolVars[scvf.outsideScvIdx()].temperature() |
155 | ✗ | : branchingFacetTemperature_(problem, element, fvGeometry, elemVolVars, elemFluxVarsCache, scvf, tInside, tij); | |
156 | |||
157 | 73923861 | return tij*(tInside - tOutside); | |
158 | } | ||
159 | |||
160 | //! Compute transmissibilities | ||
161 | 74955124 | static Scalar calculateTransmissibility(const Problem& problem, | |
162 | const Element& element, | ||
163 | const FVElementGeometry& fvGeometry, | ||
164 | const ElementVolumeVariables& elemVolVars, | ||
165 | const SubControlVolumeFace& scvf) | ||
166 | { | ||
167 | Scalar tij; | ||
168 | |||
169 |
2/2✓ Branch 0 taken 28681176 times.
✓ Branch 1 taken 26831068 times.
|
74955124 | const auto insideScvIdx = scvf.insideScvIdx(); |
170 |
2/2✓ Branch 0 taken 28681176 times.
✓ Branch 1 taken 26831068 times.
|
74955124 | const auto& insideScv = fvGeometry.scv(insideScvIdx); |
171 | 74955124 | const auto& insideVolVars = elemVolVars[insideScvIdx]; | |
172 | |||
173 |
2/2✓ Branch 0 taken 124504 times.
✓ Branch 1 taken 788 times.
|
74955124 | const auto insideLambda = insideVolVars.effectiveThermalConductivity(); |
174 |
2/2✓ Branch 0 taken 124504 times.
✓ Branch 1 taken 788 times.
|
74955124 | const Scalar ti = computeTpfaTransmissibility(fvGeometry, scvf, insideScv, insideLambda, insideVolVars.extrusionFactor()); |
175 | |||
176 | // for the boundary (dirichlet) or at branching points we only need ti | ||
177 |
4/6✓ Branch 0 taken 69468074 times.
✓ Branch 1 taken 2156546 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69468074 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 69468074 times.
|
74955124 | if (scvf.boundary() || scvf.numOutsideScvs() > 1) |
178 | { | ||
179 | 4431892 | tij = Extrusion::area(fvGeometry, scvf)*ti; | |
180 | } | ||
181 | // otherwise we compute a tpfa harmonic mean | ||
182 | else | ||
183 | { | ||
184 |
2/2✓ Branch 0 taken 26831068 times.
✓ Branch 1 taken 26831068 times.
|
72739178 | const auto outsideScvIdx = scvf.outsideScvIdx(); |
185 |
2/2✓ Branch 0 taken 26831068 times.
✓ Branch 1 taken 26831068 times.
|
72739178 | const auto& outsideScv = fvGeometry.scv(outsideScvIdx); |
186 | 72739178 | const auto& outsideVolVars = elemVolVars[outsideScvIdx]; | |
187 | |||
188 |
1/2✓ Branch 0 taken 124504 times.
✗ Branch 1 not taken.
|
72739178 | const auto outsideLambda = outsideVolVars.effectiveThermalConductivity(); |
189 | Scalar tj; | ||
190 | if constexpr (dim == dimWorld) | ||
191 | // assume the normal vector from outside is anti parallel so we save flipping a vector | ||
192 |
1/2✓ Branch 0 taken 124504 times.
✗ Branch 1 not taken.
|
69410874 | tj = -1.0*computeTpfaTransmissibility(fvGeometry, scvf, outsideScv, outsideLambda, outsideVolVars.extrusionFactor()); |
193 | else | ||
194 | 3328304 | tj = computeTpfaTransmissibility(fvGeometry, fvGeometry.flipScvf(scvf.index()), outsideScv, outsideLambda, outsideVolVars.extrusionFactor()); | |
195 | |||
196 | // check for division by zero! | ||
197 |
1/2✓ Branch 0 taken 69468074 times.
✗ Branch 1 not taken.
|
72739178 | if (ti*tj <= 0.0) |
198 | tij = 0; | ||
199 | else | ||
200 | 145478356 | tij = Extrusion::area(fvGeometry, scvf)*(ti * tj)/(ti + tj); | |
201 | } | ||
202 | |||
203 | 74955124 | return tij; | |
204 | } | ||
205 | |||
206 | private: | ||
207 | |||
208 | //! compute the temperature at branching facets for network grids | ||
209 | ✗ | static Scalar branchingFacetTemperature_(const Problem& problem, | |
210 | const Element& element, | ||
211 | const FVElementGeometry& fvGeometry, | ||
212 | const ElementVolumeVariables& elemVolVars, | ||
213 | const ElementFluxVarsCache& elemFluxVarsCache, | ||
214 | const SubControlVolumeFace& scvf, | ||
215 | Scalar insideTemperature, | ||
216 | Scalar insideTi) | ||
217 | { | ||
218 | ✗ | Scalar sumTi(insideTi); | |
219 | ✗ | Scalar sumTempTi(insideTi*insideTemperature); | |
220 | |||
221 | ✗ | for (unsigned int i = 0; i < scvf.numOutsideScvs(); ++i) | |
222 | { | ||
223 | ✗ | const auto outsideScvIdx = scvf.outsideScvIdx(i); | |
224 | ✗ | const auto& outsideVolVars = elemVolVars[outsideScvIdx]; | |
225 | ✗ | const auto& flippedScvf = fvGeometry.flipScvf(scvf.index(), i); | |
226 | ✗ | const auto& outsideFluxVarsCache = elemFluxVarsCache[flippedScvf]; | |
227 | |||
228 | ✗ | auto outsideTi = outsideFluxVarsCache.heatConductionTij(); | |
229 | ✗ | sumTi += outsideTi; | |
230 | ✗ | sumTempTi += outsideTi*outsideVolVars.temperature(); | |
231 | } | ||
232 | ✗ | return sumTempTi/sumTi; | |
233 | } | ||
234 | |||
235 | static constexpr bool isMixedDimensional_ = static_cast<int>(GridView::dimension) < static_cast<int>(GridView::dimensionworld); | ||
236 | }; | ||
237 | |||
238 | } // end namespace Dumux | ||
239 | |||
240 | #endif | ||
241 |