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 Fluidmatrixinteractions | ||
10 | * \ingroup PoreNetworkModels | ||
11 | * \brief Implementation of the single-phase transmissibility laws for throats | ||
12 | */ | ||
13 | #ifndef DUMUX_PNM_THROAT_TRANSMISSIBILITY_1P_HH | ||
14 | #define DUMUX_PNM_THROAT_TRANSMISSIBILITY_1P_HH | ||
15 | |||
16 | #include <dumux/common/parameters.hh> | ||
17 | #include <dumux/porenetwork/common/throatproperties.hh> | ||
18 | #include "emptycache.hh" | ||
19 | |||
20 | namespace Dumux::PoreNetwork { | ||
21 | |||
22 | /*! | ||
23 | * \ingroup Fluidmatrixinteractions | ||
24 | * \ingroup PoreNetworkModels | ||
25 | * \brief Collection of single-phase flow throat transmissibilities based on | ||
26 | * Bruus, H. (2011). Acoustofluidics 1: Governing equations in microfluidics. Lab on a Chip, 11(22), 3742-3751. | ||
27 | * https://backend.orbit.dtu.dk/ws/portalfiles/portal/5900070/rsc%5B1%5D.pdf | ||
28 | */ | ||
29 | template<class Scalar> | ||
30 | class TransmissibilityBruus | ||
31 | { | ||
32 | public: | ||
33 | |||
34 | using SinglePhaseCache = EmptyCache; | ||
35 | |||
36 | template<class Problem, class Element, class FVElementGeometry, class ElementVolumeVariables, class FluxVariablesCache> | ||
37 | ✗ | static Scalar singlePhaseTransmissibility(const Problem& problem, | |
38 | const Element& element, | ||
39 | const FVElementGeometry& fvGeometry, | ||
40 | const typename FVElementGeometry::SubControlVolumeFace& scvf, | ||
41 | const ElementVolumeVariables& elemVolVars, | ||
42 | const FluxVariablesCache& fluxVarsCache, | ||
43 | const int phaseIdx) | ||
44 | { | ||
45 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
780 | const auto shape = fluxVarsCache.throatCrossSectionShape(); |
46 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
780 | const Scalar throatInscribedRadius = fluxVarsCache.throatInscribedRadius(); |
47 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
780 | const Scalar throatLength = fluxVarsCache.throatLength(); |
48 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
780 | const Scalar area = fluxVarsCache.throatCrossSectionalArea(); |
49 | 1560 | return singlePhaseTransmissibility(shape, throatInscribedRadius, throatLength, area); | |
50 | } | ||
51 | |||
52 | //! Returns the conductivity of a throat when only one phase is present. | ||
53 | static Scalar singlePhaseTransmissibility(const Throat::Shape shape, | ||
54 | const Scalar inscribedRadius, | ||
55 | const Scalar throatLength, | ||
56 | const Scalar area) | ||
57 | 780 | { return 1.0 / rHydThroat_(shape, inscribedRadius, throatLength, area); } | |
58 | |||
59 | protected: | ||
60 | |||
61 | 785 | static Scalar rHydThroat_(const Throat::Shape shape, | |
62 | const Scalar radius, | ||
63 | const Scalar length, | ||
64 | const Scalar area) | ||
65 | { | ||
66 |
5/6✓ Branch 0 taken 457 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 325 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
785 | switch(shape) |
67 | { | ||
68 | 457 | case Throat::Shape::square: | |
69 | { | ||
70 | 457 | const Scalar sideLength = 2.0*radius; | |
71 | 457 | return 28.4*length * 1.0/(sideLength*sideLength*sideLength*sideLength); | |
72 | } | ||
73 | 1 | case Throat::Shape::circle: | |
74 | { | ||
75 | 1 | return 8.0/M_PI * length * 1.0/(radius*radius*radius*radius); | |
76 | } | ||
77 | 1 | case Throat::Shape::equilateralTriangle: | |
78 | { | ||
79 | using std::sqrt; | ||
80 | static Scalar sqrt3 = sqrt(3.0); | ||
81 | 1 | const Scalar sideLength = 6.0/sqrt3 * radius; | |
82 | 1 | return 320.0/sqrt3 * length * 1.0/(sideLength*sideLength*sideLength*sideLength); | |
83 | } | ||
84 | 325 | case Throat::Shape::twoPlates: | |
85 | { | ||
86 | // the distance between the two parallel plates | ||
87 | 325 | const Scalar width = 2*radius; | |
88 | 325 | return 12.0/(width*width*width) * length; | |
89 | } | ||
90 | 1 | case Throat::Shape::rectangle: | |
91 | { | ||
92 | // requires width >> height for good accuracy | ||
93 | 1 | Scalar height = 2.0*radius; | |
94 | 1 | Scalar width = area/height; | |
95 | |||
96 | using std::swap; | ||
97 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (width < height) |
98 | ✗ | swap(width, height); | |
99 | |||
100 | 1 | return 12.0*length / (1.0 - 0.63*(height/width)) * 1.0/(height*height*height*width); | |
101 | } | ||
102 | ✗ | default: DUNE_THROW(Dune::InvalidStateException, "Throat geometry not supported"); | |
103 | } | ||
104 | } | ||
105 | }; | ||
106 | |||
107 | /*! | ||
108 | * \ingroup Fluidmatrixinteractions | ||
109 | * \ingroup PoreNetworkModels | ||
110 | * \brief Single-phase flow throat transmissibility based on Patzek & Silin (2001) https://doi.org/10.1006/jcis.2000.7413 | ||
111 | */ | ||
112 | template<class Scalar, bool considerPoreResistance = false, bool interpolateK = false> | ||
113 | class TransmissibilityPatzekSilin | ||
114 | { | ||
115 | static_assert(!interpolateK, "Interpolation of k not implemented"); | ||
116 | public: | ||
117 | |||
118 | using SinglePhaseCache = EmptyCache; | ||
119 | |||
120 | template<class Problem, class Element, class FVElementGeometry, class ElementVolumeVariables, class FluxVariablesCache> | ||
121 | 7230483 | static Scalar singlePhaseTransmissibility(const Problem& problem, | |
122 | const Element& element, | ||
123 | const FVElementGeometry& fvGeometry, | ||
124 | const typename FVElementGeometry::SubControlVolumeFace& scvf, | ||
125 | const ElementVolumeVariables& elemVolVars, | ||
126 | const FluxVariablesCache& fluxVarsCache, | ||
127 | const int phaseIdx) | ||
128 | { | ||
129 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 3615243 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
7230486 | assert(fluxVarsCache.throatCrossSectionShape() != Throat::Shape::twoPlates && "TwoPlates not supported. Use TransmissibilityBruus instead!"); |
130 | |||
131 | 7230483 | const Scalar shapeFactor = fluxVarsCache.throatShapeFactor(); | |
132 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
7230483 | const Scalar area = fluxVarsCache.throatCrossSectionalArea(); |
133 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
7230483 | const Scalar throatLength = fluxVarsCache.throatLength(); |
134 | 14460966 | const Scalar throatTransmissibility = singlePhaseTransmissibility(shapeFactor, throatLength, area); | |
135 | |||
136 | if constexpr (!considerPoreResistance) | ||
137 | 3 | return throatTransmissibility; | |
138 | else | ||
139 | { | ||
140 |
3/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
|
4 | static const bool considerPoreResistanceOnRuntime = getParamFromGroup<bool>(problem.paramGroup(), "Transmissibility.ConsiderPoreResistance", true); |
141 |
1/2✓ Branch 0 taken 3615240 times.
✗ Branch 1 not taken.
|
7230480 | if (!considerPoreResistanceOnRuntime) |
142 | return throatTransmissibility; | ||
143 | |||
144 |
2/4✓ Branch 0 taken 3615240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3615240 times.
✗ Branch 3 not taken.
|
14460960 | const auto& scv0 = fvGeometry.scv(scvf.insideScvIdx()); |
145 |
2/4✓ Branch 0 taken 3615240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3615240 times.
✗ Branch 3 not taken.
|
14460960 | const auto& scv1 = fvGeometry.scv(scvf.outsideScvIdx()); |
146 | |||
147 |
1/2✓ Branch 0 taken 3615240 times.
✗ Branch 1 not taken.
|
7230480 | const auto& spatialParams = problem.spatialParams(); |
148 |
1/2✓ Branch 0 taken 3615240 times.
✗ Branch 1 not taken.
|
7230480 | const auto elemSol = elementSolution(element, elemVolVars, fvGeometry); |
149 | |||
150 | // TODO maybe include this in fluxVarsCache if this is general enough | ||
151 |
1/2✓ Branch 0 taken 3615240 times.
✗ Branch 1 not taken.
|
7230480 | const Scalar poreLength0 = spatialParams.poreLength(element, scv0, elemSol); |
152 |
1/2✓ Branch 0 taken 3615240 times.
✗ Branch 1 not taken.
|
7230480 | const Scalar poreLength1 = spatialParams.poreLength(element, scv1, elemSol); |
153 | |||
154 |
1/2✓ Branch 0 taken 3615240 times.
✗ Branch 1 not taken.
|
7230480 | const Scalar poreShapeFactor0 = spatialParams.poreShapeFactor(element, scv0, elemSol); |
155 |
1/2✓ Branch 0 taken 3615240 times.
✗ Branch 1 not taken.
|
7230480 | const Scalar poreShapeFactor1 = spatialParams.poreShapeFactor(element, scv1, elemSol); |
156 | |||
157 |
1/2✓ Branch 0 taken 3615240 times.
✗ Branch 1 not taken.
|
7230480 | const Scalar poreCrossSectionalArea0 = spatialParams.poreCrossSectionalArea(element, scv0, elemSol); |
158 |
1/2✓ Branch 0 taken 3615240 times.
✗ Branch 1 not taken.
|
7230480 | const Scalar poreCrossSectionalArea1 = spatialParams.poreCrossSectionalArea(element, scv1, elemSol); |
159 | |||
160 | 14460960 | const Scalar poreTransmissibility0 = singlePhaseTransmissibility(poreShapeFactor0, poreLength0, poreCrossSectionalArea0); | |
161 | 14460960 | const Scalar poreTransmissibility1 = singlePhaseTransmissibility(poreShapeFactor1, poreLength1, poreCrossSectionalArea1); | |
162 | |||
163 | 7230480 | return 1 / (1.0/throatTransmissibility + 1.0/poreTransmissibility0 + 1.0/poreTransmissibility1); | |
164 | } | ||
165 | } | ||
166 | |||
167 | //! Returns the conductivity of a throat when only one phase is present. See Patzek & Silin (2001) | ||
168 | static Scalar singlePhaseTransmissibility(const Scalar shapeFactor, | ||
169 | const Scalar length, | ||
170 | const Scalar area) | ||
171 | { | ||
172 | 21691446 | const Scalar k = k_(shapeFactor); | |
173 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2522975 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1092263 times.
|
7230483 | return k * area*area * shapeFactor / length; |
174 | } | ||
175 | |||
176 | private: | ||
177 | static Scalar k_(const Scalar shapeFactor) | ||
178 | { | ||
179 |
7/12✓ Branch 0 taken 2522978 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2522976 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2522976 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1092264 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1092264 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1092264 times.
✗ Branch 11 not taken.
|
10845723 | if (shapeFactor <= Throat::shapeFactorEquilateralTriangle<Scalar>()) |
180 | return 0.6; // == 3/5 | ||
181 |
7/12✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2522977 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2522976 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2522976 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1092264 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1092264 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1092264 times.
|
10845722 | else if (shapeFactor <= Throat::shapeFactorSquare<Scalar>()) |
182 | return 0.5623; | ||
183 | else // circle | ||
184 | return 0.5; | ||
185 | } | ||
186 | |||
187 | // TODO interpolation | ||
188 | }; | ||
189 | |||
190 | |||
191 | //! Used by Joeakar-Niasar | ||
192 | template<class Scalar> | ||
193 | class TransmissibilityAzzamDullien | ||
194 | { | ||
195 | public: | ||
196 | |||
197 | using SinglePhaseCache = EmptyCache; | ||
198 | |||
199 | template<class Problem, class Element, class FVElementGeometry, class ElementVolumeVariables, class FluxVariablesCache> | ||
200 | ✗ | static Scalar singlePhaseTransmissibility(const Problem& problem, | |
201 | const Element& element, | ||
202 | const FVElementGeometry& fvGeometry, | ||
203 | const typename FVElementGeometry::SubControlVolumeFace& scvf, | ||
204 | const ElementVolumeVariables& elemVolVars, | ||
205 | const FluxVariablesCache& fluxVarsCache, | ||
206 | const int phaseIdx) | ||
207 | { | ||
208 | 328526 | const Scalar throatInscribedRadius = fluxVarsCache.throatInscribedRadius(); | |
209 | 328526 | const Scalar throatLength = fluxVarsCache.throatLength(); | |
210 | 657052 | return singlePhaseTransmissibility(throatInscribedRadius, throatLength); | |
211 | } | ||
212 | |||
213 | //! Returns the conductivity of a throat when only one phase is present. | ||
214 | static Scalar singlePhaseTransmissibility(const Scalar radius, | ||
215 | const Scalar length) | ||
216 | { | ||
217 | 328526 | const Scalar rEff= std::sqrt(4.0/M_PI)*radius ; | |
218 | 328526 | return M_PI/(8.0*length) *rEff*rEff*rEff*rEff ; | |
219 | } | ||
220 | }; | ||
221 | |||
222 | } // end namespace Dumux::Porenetwork | ||
223 | |||
224 | #endif | ||
225 |