GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/test/multidomain/dualnetwork/fourierslaw.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 71 160 44.4%
Functions: 4 8 50.0%
Branches: 61 206 29.6%

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 * \brief This file contains the data which is required to calculate
10 * diffusive heat fluxes with Fourier's law.
11 */
12 #ifndef DUMUX_TEST_MULTIDOMAIN_DUALNETWORK_FLUID_FOURIERS_LAW_HH
13 #define DUMUX_TEST_MULTIDOMAIN_DUALNETWORK_FLUID_FOURIERS_LAW_HH
14
15 #include <dumux/common/math.hh>
16 #include <dumux/common/parameters.hh>
17
18 namespace Dumux::PoreNetwork {
19
20 /*!
21 * \ingroup DualNetworkCoupling
22 * \brief Implements a Fourier's law assuming pyramid frustum shapes for the geometry from pore bodies to pore throats.
23 */
24 template<bool isFluid>
25 struct FluidOrGrainPyramidFouriersLaw
26 {
27 template<class Problem, class Element, class FVElementGeometry,
28 class ElementVolumeVariables, class ElementFluxVariablesCache>
29 static auto flux(const Problem& problem,
30 const Element& element,
31 const FVElementGeometry& fvGeometry,
32 const ElementVolumeVariables& elemVolVars,
33 const typename FVElementGeometry::SubControlVolumeFace& scvf,
34 const ElementFluxVariablesCache& elemFluxVarsCache)
35 {
36 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
37 const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx());
38 const auto& insideVolVars = elemVolVars[insideScv];
39 const auto& outsideVolVars = elemVolVars[outsideScv];
40 const auto deltaT = insideVolVars.temperature() - outsideVolVars.temperature();
41 return transmissibility(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache) * deltaT;
42 }
43
44 template<class Problem, class Element, class FVElementGeometry,
45 class ElementVolumeVariables, class ElementFluxVariablesCache>
46 static auto transmissibility(const Problem& problem,
47 const Element& element,
48 const FVElementGeometry& fvGeometry,
49 const ElementVolumeVariables& elemVolVars,
50 const typename FVElementGeometry::SubControlVolumeFace& scvf,
51 const ElementFluxVariablesCache& elemFluxVarsCache)
52 {
53 using Scalar = typename ElementVolumeVariables::VolumeVariables::PrimaryVariables::value_type;
54 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
55 const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx());
56 const auto& insideVolVars = elemVolVars[insideScv];
57 const auto& outsideVolVars = elemVolVars[outsideScv];
58 const auto& fluxVarsCache = elemFluxVarsCache[scvf];
59
60 const auto getConductivity = [&](const auto& volVars)
61 {
62 if constexpr (isFluid)
63 return volVars.fluidThermalConductivity(0);
64 else
65 return volVars.solidThermalConductivity();
66 };
67
68 const auto insideThermalConducitivity = getConductivity(insideVolVars);
69 const auto outsideThermalConducitivity = getConductivity(outsideVolVars);
70
71 const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(element);
72 const auto throatCenter = problem.spatialParams().throatCenter(eIdx);
73 const auto distanceInside = (insideScv.dofPosition() - throatCenter).two_norm();
74 const auto distanceOutside = (outsideScv.dofPosition() - throatCenter).two_norm();
75
76 const auto throatArea = [&]()
77 {
78 static const Scalar givenArea = getParamFromGroup<Scalar>(problem.paramGroup(), "FouriersLaw.ThroatArea", 0.0);
79 if (givenArea > 0.0)
80 return givenArea;
81
82 if constexpr (isFluid)
83 return fluxVarsCache.throatCrossSectionalArea(0);
84 else
85 return fluxVarsCache.grainContactArea();
86 }();
87
88
89 const Scalar pyramidFrustumTopArea = [&]()
90 {
91 static const bool realArea = getParamFromGroup<bool>(problem.paramGroup(), "FouriersLaw.UseRealThroatAreaInPyramid", true);
92 if (realArea)
93 return throatArea;
94 else
95 {
96 // use inscribed throat diameter as square side length
97 const Scalar baseLength = fluxVarsCache.throatInscribedRadius() * 2.0;
98 return baseLength*baseLength;
99 }
100 }();
101
102 const auto getPyramidFrustumBaseArea = [&](const auto& volVars, const Scalar distance)
103 {
104 static const Scalar givenArea = getParamFromGroup<Scalar>(problem.paramGroup(), "FouriersLaw.PoreArea", 0.0);
105 if (givenArea > 0.0)
106 return givenArea;
107
108 static const bool realVolume = getParamFromGroup<bool>(problem.paramGroup(), "FouriersLaw.UseVolumeEqualPyramid", true);
109 if (realVolume)
110 {
111 // Using the formula for the volume of a pyramid frustum to calculate its base length and base area:
112 // v = 1/3 h * (a^2 + a*b + b^2), where a is the base side length, b the top side length,
113 // h the height and v the volume of the frustum .
114 using std::sqrt;
115 const Scalar vol = 0.5 * volVars.poreVolume();
116 const Scalar baseLenTop = sqrt(pyramidFrustumTopArea);
117 const Scalar height = distance;
118 // see https://en.wikipedia.org/wiki/Moscow_Mathematical_Papyrus
119 const Scalar baseLenBot = 0.5*sqrt(3.0) * sqrt(-(baseLenTop*baseLenTop*height-4.0*vol)/height) -0.5*baseLenTop;
120 return baseLenBot*baseLenBot;
121 }
122 else
123 return volVars.poreVolume() / (2.0*distance);
124 };
125
126 using std::sqrt;
127 const auto baseAreaInside = getPyramidFrustumBaseArea(insideVolVars, distanceInside);
128 const auto baseAreaOutside = getPyramidFrustumBaseArea(outsideVolVars, distanceOutside);
129 const auto topArea = pyramidFrustumTopArea;
130 const auto insideTransmissibility = insideThermalConducitivity * sqrt(baseAreaInside*topArea) / distanceInside;
131 const auto outsideTransmissibility = outsideThermalConducitivity * sqrt(baseAreaOutside*topArea) / distanceOutside;
132
133 return 1.0 / (1.0/insideTransmissibility + 1.0/outsideTransmissibility);
134 }
135 };
136
137 /*!
138 * \ingroup DualNetworkCoupling
139 * \brief Implements a Fourier's law and scales the transmissibillity with a fixed, user-defined factor.
140 */
141 template<bool isFluid>
142 struct FixedFactorFouriersLaw
143 {
144 template<class Problem, class Element, class FVElementGeometry,
145 class ElementVolumeVariables, class ElementFluxVariablesCache>
146 static auto flux(const Problem& problem,
147 const Element& element,
148 const FVElementGeometry& fvGeometry,
149 const ElementVolumeVariables& elemVolVars,
150 const typename FVElementGeometry::SubControlVolumeFace& scvf,
151 const ElementFluxVariablesCache& elemFluxVarsCache)
152 {
153 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
154 const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx());
155 const auto& insideVolVars = elemVolVars[insideScv];
156 const auto& outsideVolVars = elemVolVars[outsideScv];
157 const auto deltaT = insideVolVars.temperature() - outsideVolVars.temperature();
158 return transmissibility(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache) * deltaT;
159 }
160
161 template<class Problem, class Element, class FVElementGeometry,
162 class ElementVolumeVariables, class ElementFluxVariablesCache>
163 static auto transmissibility(const Problem& problem,
164 const Element& element,
165 const FVElementGeometry& fvGeometry,
166 const ElementVolumeVariables& elemVolVars,
167 const typename FVElementGeometry::SubControlVolumeFace& scvf,
168 const ElementFluxVariablesCache& elemFluxVarsCache)
169 {
170 using Scalar = typename ElementVolumeVariables::VolumeVariables::PrimaryVariables::value_type;
171
172 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
173 const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx());
174 const auto& insideVolVars = elemVolVars[insideScv];
175 const auto& outsideVolVars = elemVolVars[outsideScv];
176
177 const auto getConductivity = [&](const auto& volVars)
178 {
179 if constexpr (isFluid)
180 return volVars.fluidThermalConductivity(0);
181 else
182 return volVars.solidThermalConductivity();
183 };
184
185 const auto insideThermalConducitivity = getConductivity(insideVolVars);
186 const auto outsideThermalConducitivity = getConductivity(outsideVolVars);
187
188 const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(element);
189 const auto throatCenter = problem.spatialParams().throatCenter(eIdx);
190 const auto distanceInside = (insideScv.dofPosition() - throatCenter).two_norm();
191 const auto distanceOutside = (outsideScv.dofPosition() - throatCenter).two_norm();
192
193 static const Scalar fixedFactor = getParamFromGroup<Scalar>(problem.paramGroup(), "FouriersLaw.FixedFourierFactor");
194 const auto insideTransmissibility = insideThermalConducitivity*4*distanceInside*fixedFactor;
195 const auto outsideTransmissibility = outsideThermalConducitivity*4*distanceOutside*fixedFactor;
196
197 return 1.0 / (1.0/insideTransmissibility + 1.0/outsideTransmissibility);
198 }
199 };
200
201 /*!
202 * \ingroup DualNetworkCoupling
203 * \brief Implements a Fourier's law taking effective areas available for conduction into account.
204 *
205 * This Fourier's law is based on the work of Koch et al (2021) https://doi.org/10.1007/s11242-021-01602-5.
206 * It assumes pyramid frustum shapes for the geometry from pore bodies to pore throats, but not taking the full area
207 * of pore bodies into account, but the effective areas available for conduction.
208 *
209 * Depending on the conductivity ratio between the fluid and the solid \f$ \kappa = \frac{\łambda_s}{\lambda_s}\f$,
210 * the area available for conduction of heat through each phase might be restricted due to the other phase.
211 * The effective areas available for heat conduction in the solid are shown in the picture below:
212 * \image html effectiveareasforconduction_dnm.png
213 * This picture (figure 3) was taken from Koch et al (2021) https://doi.org/10.1007/s11242-021-01602-5.
214 * \f$A_{A}\f$ denotes here the contact area between two grains (solid bodies) and
215 * \f$\tilde{A}\f$ denotes the effective area of the solid body.
216 */
217 template<bool isFluid>
218 struct FluidSolidEffectiveAreasFouriersLaw
219 {
220 template<class Problem, class Element, class FVElementGeometry,
221 class ElementVolumeVariables, class ElementFluxVariablesCache>
222 static auto flux(const Problem& problem,
223 const Element& element,
224 const FVElementGeometry& fvGeometry,
225 const ElementVolumeVariables& elemVolVars,
226 const typename FVElementGeometry::SubControlVolumeFace& scvf,
227 const ElementFluxVariablesCache& elemFluxVarsCache)
228 {
229 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
230 const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx());
231 const auto& insideVolVars = elemVolVars[insideScv];
232 const auto& outsideVolVars = elemVolVars[outsideScv];
233 const auto deltaT = insideVolVars.temperature() - outsideVolVars.temperature();
234 return transmissibility(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache) * deltaT;
235 }
236
237 template<class Problem, class Element, class FVElementGeometry,
238 class ElementVolumeVariables, class ElementFluxVariablesCache>
239 111842 static auto transmissibility(const Problem& problem,
240 const Element& element,
241 const FVElementGeometry& fvGeometry,
242 const ElementVolumeVariables& elemVolVars,
243 const typename FVElementGeometry::SubControlVolumeFace& scvf,
244 const ElementFluxVariablesCache& elemFluxVarsCache)
245 {
246 //For transmissibillity calculation see section 5.2 in Koch et al (2021) https://doi.org/10.1007/s11242-021-01602-5
247 using Scalar = typename ElementVolumeVariables::VolumeVariables::PrimaryVariables::value_type;
248
249 223684 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
250 223684 const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx());
251 111842 const auto& insideVolVars = elemVolVars[insideScv];
252 111842 const auto& outsideVolVars = elemVolVars[outsideScv];
253
254 const auto getConductivity = [&](const auto& volVars)
255 {
256 if constexpr (isFluid)
257 185288 return volVars.fluidThermalConductivity(0);
258 else
259 262080 return volVars.solidThermalConductivity();
260 };
261
262 111842 const auto insideThermalConducitivity = getConductivity(insideVolVars);
263 111842 const auto outsideThermalConducitivity = getConductivity(outsideVolVars);
264
265 223684 const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(element);
266
267 223684 const auto distance = [&](const auto& scv)
268 {
269
10/16
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 46321 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 65519 times.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
111842 static const bool useThroatCenter = getParamFromGroup<bool>(problem.paramGroup(), "FouriersLaw.UseThroatCenter", true);
270
2/4
✓ Branch 0 taken 46322 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65520 times.
✗ Branch 3 not taken.
111842 if (useThroatCenter)
271 {
272 223684 const auto throatCenter = problem.spatialParams().throatCenter(eIdx);
273 335526 return (scv.dofPosition() - throatCenter).two_norm();
274 }
275 else
276 {
277 static const Scalar R = getParam<Scalar>("DualNetwork.SphereRadius", 50e-6);
278 static const Scalar overlapFactor = getParam<Scalar>("DualNetwork.OverlapFactor");
279 static const auto dx = overlapFactor*R;
280 return dx;
281 }
282 };
283
284 111842 const Scalar distanceInside = distance(insideScv);
285 111842 const Scalar distanceOutside = distance(outsideScv);
286
287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55921 times.
111842 assert(distanceInside > 0.0);
288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55921 times.
111842 assert(distanceOutside > 0.0);
289
290
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 55919 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
111842 static const Scalar liquidThermalConductivity = getParam<Scalar>("2.Component.LiquidThermalConductivity");
291
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 55919 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
111842 static const Scalar solidThermalConductivity = getParam<Scalar>("1.Component.SolidThermalConductivity");
292
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 55919 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
111842 static const Scalar kappa = liquidThermalConductivity / solidThermalConductivity;
293
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 55919 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
111842 static const Scalar kappaFactor = isFluid ? kappa : 1.0/kappa;
294
295 111842 const Scalar ApInside = insideVolVars.poreVolume()/(2.0*distanceInside);
296 111842 const Scalar ApOutside = outsideVolVars.poreVolume()/(2.0*distanceOutside);
297
298 //For effective areas see figure 3 in Koch et al (2021) https://doi.org/10.1007/s11242-021-01602-5
299 111842 Scalar effectiveAreaInside = 0.0;
300 111842 Scalar effectiveAreaOutside = 0.0;
301 111842 Scalar At = 0.0;
302
303 111842 const auto effectiveArea = [kappaFactor = kappaFactor](const Scalar At, const Scalar Cinf, const Scalar C0)
304 {
305 223684 return At*(Cinf + ((C0 - Cinf)*(Cinf - 1.0))/((Cinf - 1.0) + kappaFactor*(1.0 - C0)));
306 };
307
308
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 55919 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
111842 static const Scalar useExactThroatAreaSphere = getParam<bool>("DualNetwork.UseExactThroatAreaSphere", false);
309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55921 times.
111842 if (useExactThroatAreaSphere)
310 {
311 static const Scalar R = getParamFromGroup<Scalar>(problem.paramGroup(), "DualNetwork.SphereRadius", 50e-6);
312 const auto As = [](Scalar x, Scalar dx, Scalar R) { return M_PI*(R - x)*(R + x); };
313 const auto Asq = [](Scalar x, Scalar dx, Scalar R) { return 4*dx*dx; };
314 const auto Asemicirc = [](Scalar x, Scalar dx, Scalar R) {
315 const auto r = std::sqrt((R - x)*(R + x));
316 return (r*r)*std::acos(dx/r) - dx*std::sqrt(r*r - dx*dx);
317 };
318 const auto A1s = [&](Scalar x, Scalar dx, Scalar R) { return As(x, dx, R) - 4*Asemicirc(x, dx, R); };
319 const auto A2s = [&](Scalar x, Scalar dx, Scalar R) { return As(x, dx, R); };
320 const auto A1f = [&](Scalar x, Scalar dx, Scalar R) { return Asq(x, dx, R) - A1s(x, dx, R); };
321 // const auto A2f = [&](Scalar x, Scalar dx, Scalar R) { return Asq(x, dx, R) - A2s(x, dx, R); }; // TODO unused?
322
323 At = isFluid ? A1f(0, distanceInside, R) : A2s(distanceInside, distanceInside, R);
324 const Scalar C0 = isFluid ? 0.1 : 0.45;
325 const Scalar Cinf = isFluid ? ApInside/At : ApInside/At*1.45;
326 effectiveAreaInside = effectiveArea(At, Cinf, C0);
327 effectiveAreaOutside = effectiveAreaInside;
328 assert(std::isnormal(effectiveAreaInside));
329 }
330 else
331 {
332 At = [&]
333 {
334 if constexpr (isFluid)
335 92644 return elemFluxVarsCache[scvf].throatCrossSectionalArea(0);
336 else
337 131040 return elemFluxVarsCache[scvf].grainContactArea();
338
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 55919 times.
111842 }();
339
340
5/8
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 55919 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
111844 static const Scalar C0 = isFluid ? getParamFromGroup<Scalar>(problem.paramGroup(), "FouriersLaw.C0Fluid")
341
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
4 : getParamFromGroup<Scalar>(problem.paramGroup(), "FouriersLaw.C0Solid");
342
5/8
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 55919 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
111844 static const Scalar CinfFactor = isFluid ? getParamFromGroup<Scalar>(problem.paramGroup(), "FouriersLaw.CInfFactorFluid")
343
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
4 : getParamFromGroup<Scalar>(problem.paramGroup(), "FouriersLaw.CInfFactorSolid");
344 using std::max;
345
2/2
✓ Branch 0 taken 13048 times.
✓ Branch 1 taken 42873 times.
111842 const Scalar CinfInside = max(ApInside/At*CinfFactor, 1.0);
346
2/2
✓ Branch 0 taken 12403 times.
✓ Branch 1 taken 43518 times.
111842 const Scalar CinfOutside = max(ApOutside/At*CinfFactor, 1.0);
347 223684 effectiveAreaInside = effectiveArea(At, CinfInside, C0);
348 111842 effectiveAreaOutside = effectiveArea(At, CinfOutside, C0);
349 }
350
351
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 55921 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55921 times.
223684 assert(std::isnormal(effectiveAreaInside));
352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55921 times.
111842 assert(effectiveAreaInside > 0.0);
353
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 55921 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55921 times.
223684 assert(std::isnormal(effectiveAreaOutside));
354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55921 times.
111842 assert(effectiveAreaOutside > 0.0);
355
356 111842 const Scalar tInside = std::sqrt(effectiveAreaInside*At)/distanceInside;
357 111842 const Scalar tOutside = std::sqrt(effectiveAreaOutside*At)/distanceOutside;
358
359 111842 const auto insideTransmissibility = insideThermalConducitivity*tInside;
360 111842 const auto outsideTransmissibility = outsideThermalConducitivity*tOutside;
361 111842 const auto result = 1.0 / (1.0/insideTransmissibility + 1.0/outsideTransmissibility);
362
363
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 55921 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55921 times.
223684 if (!std::isnormal(result))
364 DUNE_THROW(Dune::InvalidStateException, "Error in heat conductivity. Check your grid and your factors.");
365
366 111842 return result;
367 }
368 };
369
370 /*!
371 * \ingroup DualNetworkCoupling
372 * \brief Implements a Fourier's law and scales a fixed transmissibillity with a factor
373 * depending on the position of the throat.
374 */
375 template<class BaseLaw>
376 struct ScalingFouriersLaw
377 {
378 template<class Problem, class Element, class FVElementGeometry,
379 class ElementVolumeVariables, class ElementFluxVariablesCache>
380 static auto flux(const Problem& problem,
381 const Element& element,
382 const FVElementGeometry& fvGeometry,
383 const ElementVolumeVariables& elemVolVars,
384 const typename FVElementGeometry::SubControlVolumeFace& scvf,
385 const ElementFluxVariablesCache& elemFluxVarsCache)
386 {
387 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
388 const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx());
389 const auto& insideVolVars = elemVolVars[insideScv];
390 const auto& outsideVolVars = elemVolVars[outsideScv];
391 using Scalar = typename ElementVolumeVariables::VolumeVariables::PrimaryVariables::value_type;
392 const auto deltaT = insideVolVars.temperature() - outsideVolVars.temperature();
393
394 static const bool useScaling = getParamFromGroup<bool>(problem.paramGroup(), "FouriersLaw.UseFourierScaling", true);
395 if (!useScaling)
396 return transmissibility(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache) * deltaT;
397
398
399 Scalar factor = 1.0;
400 const auto& bBoxMin = problem.gridGeometry().bBoxMin();
401 const auto& bBoxMax = problem.gridGeometry().bBoxMax();
402 const auto throatCenter = element.geometry().center();
403
404 for (int i = 0; i < throatCenter.size(); ++i)
405 {
406 constexpr Scalar eps = 1e-8; // TODO
407 if (throatCenter[i] < bBoxMin[i] + eps || throatCenter[i] > bBoxMax[i] - eps)
408 factor *= 0.5;
409 }
410
411 static const Scalar baseTransmissibility = problem.getInternalReferenceHeatTransmissibility();
412 return baseTransmissibility * factor * deltaT;
413 }
414
415 template<class Problem, class Element, class FVElementGeometry,
416 class ElementVolumeVariables, class ElementFluxVariablesCache>
417 static auto transmissibility(const Problem& problem,
418 const Element& element,
419 const FVElementGeometry& fvGeometry,
420 const ElementVolumeVariables& elemVolVars,
421 const typename FVElementGeometry::SubControlVolumeFace& scvf,
422 const ElementFluxVariablesCache& elemFluxVarsCache)
423 {
424 return BaseLaw::transmissibility(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
425 }
426 };
427
428 template<bool isFluid>
429 struct FlexibleFouriersLaw
430 {
431 enum class Mode {pyramid, fixedFactor, fluidSolidEffectiveAreas, tpfa};
432
433 template<class Problem, class Element, class FVElementGeometry,
434 class ElementVolumeVariables, class ElementFluxVariablesCache>
435 111842 static auto flux(const Problem& problem,
436 const Element& element,
437 const FVElementGeometry& fvGeometry,
438 const ElementVolumeVariables& elemVolVars,
439 const typename FVElementGeometry::SubControlVolumeFace& scvf,
440 const ElementFluxVariablesCache& elemFluxVarsCache)
441 {
442 223684 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
443 223684 const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx());
444 111842 const auto& insideVolVars = elemVolVars[insideScv];
445 111842 const auto& outsideVolVars = elemVolVars[outsideScv];
446 223684 const auto deltaT = insideVolVars.temperature() - outsideVolVars.temperature();
447 111842 return transmissibility(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache) * deltaT;
448 }
449
450 template<class Problem, class Element, class FVElementGeometry,
451 class ElementVolumeVariables, class ElementFluxVariablesCache>
452 55921 static auto transmissibility(const Problem& problem,
453 const Element& element,
454 const FVElementGeometry& fvGeometry,
455 const ElementVolumeVariables& elemVolVars,
456 const typename FVElementGeometry::SubControlVolumeFace& scvf,
457 const ElementFluxVariablesCache& elemFluxVarsCache)
458 {
459 55925 static const Mode mode = [&]()
460 {
461 6 const auto m = getParamFromGroup<std::string>(problem.paramGroup(), "FouriersLaw.ThroatConductionType");
462 2 if (m == "Pyramid")
463 return Mode::pyramid;
464 2 else if (m == "FluidSolidEffectiveAreas")
465 return Mode::fluidSolidEffectiveAreas;
466 else if (m == "FixedFactor")
467 return Mode::fixedFactor;
468 else
469 return Mode::tpfa;
470 4 }();
471
472 55921 if (mode == Mode::pyramid)
473 return FluidOrGrainPyramidFouriersLaw<isFluid>::transmissibility(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
474 55921 else if (mode == Mode::fixedFactor)
475 return FixedFactorFouriersLaw<isFluid>::transmissibility(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
476 55921 else if (mode == Mode::fluidSolidEffectiveAreas)
477 55921 return FluidSolidEffectiveAreasFouriersLaw<isFluid>::transmissibility(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
478 else return 0.0; // TODO implement TPFA
479 }
480 };
481
482
483 } // end namespace Dumux::PoreNetwork
484
485 #endif
486