GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/flux/porenetwork/grainfourierslaw.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 29 33 87.9%
Functions: 3 5 60.0%
Branches: 15 26 57.7%

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