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 PoreNetworkFlux | ||
10 | * \brief This file contains the data which is required to calculate | ||
11 | * diffusive heat fluxes with Fourier's law. | ||
12 | */ | ||
13 | #ifndef DUMUX_FLUX_PNM_GRAIN_FOURIERS_LAW_HH | ||
14 | #define DUMUX_FLUX_PNM_GRAIN_FOURIERS_LAW_HH | ||
15 | |||
16 | #include <cmath> | ||
17 | #include <dumux/common/math.hh> | ||
18 | #include <dumux/common/parameters.hh> | ||
19 | |||
20 | namespace Dumux::PoreNetwork { | ||
21 | |||
22 | /*! | ||
23 | * \ingroup PoreNetworkFlux | ||
24 | * \brief Specialization of Fourier's Law for the pore-network SOLID model. | ||
25 | * \note See Koch et al (2021) https://doi.org/10.1007/s11242-021-01602-5 | ||
26 | * and Khan et al (2019) https://doi.org/10.1016/j.compchemeng.2018.12.025 | ||
27 | */ | ||
28 | template <class Scalar> | ||
29 | struct TruncatedPyramidGrainFouriersLaw | ||
30 | { | ||
31 | template<class Problem, class Element, class FVElementGeometry, class ElementVolumeVariables, class ElementFluxVariablesCache> | ||
32 | 112320 | static Scalar flux(const Problem& problem, | |
33 | const Element& element, | ||
34 | const FVElementGeometry& fvGeometry, | ||
35 | const ElementVolumeVariables& elemVolVars, | ||
36 | const typename FVElementGeometry::SubControlVolumeFace& scvf, | ||
37 | const ElementFluxVariablesCache& elemFluxVarsCache) | ||
38 | { | ||
39 | 224640 | const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx()); | |
40 | 224640 | const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx()); | |
41 | 112320 | const auto& insideVolVars = elemVolVars[insideScv]; | |
42 | 112320 | const auto& outsideVolVars = elemVolVars[outsideScv]; | |
43 | 112320 | const auto& fluxVarsCache = elemFluxVarsCache[scvf]; | |
44 | |||
45 | 112320 | const Scalar topSideLength = 2.0*fluxVarsCache.throatInscribedRadius(); | |
46 | |||
47 | // We assume that the distance between pore centroid and throat | ||
48 | // centroid (i.e., the height of the pyramid) equals the inscribed pore radius. | ||
49 | 112320 | const Scalar insideHeight = insideVolVars.poreInscribedRadius(); | |
50 | 112320 | const Scalar outsideHeight = outsideVolVars.poreInscribedRadius(); | |
51 | |||
52 | 112320 | auto getPyramidBaseLengthFromVolume = [&](const Scalar v, const Scalar h) | |
53 | { | ||
54 | // Using the formula for the volume of a pyramid frustum to calculate its base length: | ||
55 | // v = 1/3 h * (a^2 + a*b + b^2), where a is the base side length, b the top side length, | ||
56 | // h the height and v the volume of the frustum. | ||
57 | ✗ | const Scalar b = topSideLength; | |
58 | using std::sqrt; | ||
59 | ✗ | return 0.5*sqrt(3.0) * sqrt(-(b*b*h-4.0*v)/h) -0.5*b; | |
60 | }; | ||
61 | |||
62 | // the pyramid base length of the inside pore | ||
63 | 112320 | const Scalar insideBaseSideLength = [&]() | |
64 | { | ||
65 |
5/8✓ Branch 0 taken 2 times.
✓ Branch 1 taken 112318 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
|
112320 | static const bool useAdaptedVolume = getParamFromGroup<bool>(problem.paramGroup(), "FouriersLaw.UseVolumeEqualPyramid", false); |
66 | |||
67 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 112320 times.
|
112320 | if (useAdaptedVolume) |
68 | ✗ | return getPyramidBaseLengthFromVolume(0.5*insideVolVars.poreVolume(), insideHeight); | |
69 | else | ||
70 | 112320 | return 2.0 * insideVolVars.poreInscribedRadius(); | |
71 | 112320 | }(); | |
72 | |||
73 | // the pyramid base length of the outside pore | ||
74 | 112320 | const Scalar outsideBaseSideLength = [&]() | |
75 | { | ||
76 |
5/8✓ Branch 0 taken 2 times.
✓ Branch 1 taken 112318 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
|
112320 | static const bool useAdaptedVolume = getParamFromGroup<bool>(problem.paramGroup(), "FouriersLaw.UseVolumeEqualPyramid", false); |
77 | |||
78 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 112320 times.
|
112320 | if (useAdaptedVolume) |
79 | ✗ | return getPyramidBaseLengthFromVolume(0.5*outsideVolVars.poreVolume(), outsideHeight); | |
80 | else | ||
81 | 112320 | return 2.0 * outsideVolVars.poreInscribedRadius(); | |
82 | 112320 | }(); | |
83 | |||
84 |
1/2✓ Branch 0 taken 112320 times.
✗ Branch 1 not taken.
|
112320 | auto insideThermalConducitivity = insideVolVars.solidThermalConductivity(); |
85 |
1/2✓ Branch 0 taken 112320 times.
✗ Branch 1 not taken.
|
112320 | auto outsideThermalConducitivity = outsideVolVars.solidThermalConductivity(); |
86 | |||
87 | 112320 | const Scalar gInside = 4.0*insideThermalConducitivity * 0.5*topSideLength * 0.5*insideBaseSideLength / insideHeight; | |
88 | 112320 | const Scalar gOutside = 4.0*outsideThermalConducitivity * 0.5*topSideLength * 0.5*outsideBaseSideLength / outsideHeight; | |
89 |
1/2✓ Branch 0 taken 112320 times.
✗ Branch 1 not taken.
|
112320 | const Scalar gThroat = Dumux::harmonicMean(insideThermalConducitivity, outsideThermalConducitivity) |
90 | 112320 | * fluxVarsCache.grainContactArea() / fluxVarsCache.throatLength(); | |
91 | |||
92 | 112320 | const Scalar g = 1.0 / (1.0/gInside + 1.0/gOutside + 1.0/gThroat); | |
93 | |||
94 | // calculate the temperature gradient | ||
95 | 336960 | const Scalar deltaT = insideVolVars.temperature() - outsideVolVars.temperature(); | |
96 | |||
97 | 112320 | return deltaT * g; | |
98 | } | ||
99 | }; | ||
100 | |||
101 | /*! | ||
102 | * \ingroup PoreNetworkFlux | ||
103 | * \brief Specialization of Fourier's Law for the pore-network SOLID model. | ||
104 | * \note See Koch et al (2021) https://doi.org/10.1007/s11242-021-01602-5 | ||
105 | */ | ||
106 | template <class Scalar> | ||
107 | struct SphereCapGrainFouriersLaw | ||
108 | { | ||
109 | template<class Problem, class Element, class FVElementGeometry, class ElementVolumeVariables, class ElementFluxVariablesCache> | ||
110 | static Scalar flux(const Problem& problem, | ||
111 | const Element& element, | ||
112 | const FVElementGeometry& fvGeometry, | ||
113 | const ElementVolumeVariables& elemVolVars, | ||
114 | const typename FVElementGeometry::SubControlVolumeFace& scvf, | ||
115 | const ElementFluxVariablesCache& elemFluxVarsCache) | ||
116 | { | ||
117 | const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx()); | ||
118 | const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx()); | ||
119 | const auto& insideVolVars = elemVolVars[insideScv]; | ||
120 | const auto& outsideVolVars = elemVolVars[outsideScv]; | ||
121 | const auto& fluxVarsCache = elemFluxVarsCache[scvf]; | ||
122 | |||
123 | auto gSphereCap = [&](const auto& scv, const auto& volVars) | ||
124 | { | ||
125 | const Scalar R = problem.spatialParams.extendedPoreRadius(scv.dofIndex()); | ||
126 | const Scalar lambda = volVars.solidThermalConductivity(); | ||
127 | const Scalar rC = volVars.poreRadius(); | ||
128 | using std::atanh; | ||
129 | return (lambda*M_PI*R) / atanh(rC/R); | ||
130 | }; | ||
131 | |||
132 | auto insideThermalConducitivity = insideVolVars.solidThermalConductivity(); | ||
133 | auto outsideThermalConducitivity = outsideVolVars.solidThermalConductivity(); | ||
134 | |||
135 | const Scalar gInside = gSphereCap(insideScv, insideVolVars); | ||
136 | const Scalar gOutside = gSphereCap(outsideScv, outsideVolVars); | ||
137 | const Scalar gThroat = Dumux::harmonicMean(insideThermalConducitivity, outsideThermalConducitivity) | ||
138 | * fluxVarsCache.grainContactArea() / fluxVarsCache.throatLength(); | ||
139 | |||
140 | const Scalar g = 1.0 / (1.0/gInside + 1.0/gOutside + 1.0/gThroat); | ||
141 | |||
142 | // calculate the temperature gradient | ||
143 | const Scalar deltaT = insideVolVars.temperature() - outsideVolVars.temperature(); | ||
144 | |||
145 | return deltaT * g; | ||
146 | } | ||
147 | |||
148 | }; | ||
149 | |||
150 | } // end namespace Dumux::PoreNetwork | ||
151 | |||
152 | #endif | ||
153 |