3.4
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
advection.hh
Go to the documentation of this file.
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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
25#ifndef DUMUX_FLUX_PNM_ADVECTION_HH
26#define DUMUX_FLUX_PNM_ADVECTION_HH
27
28#include <array>
30
32
33template<class... TransmissibilityLawTypes>
34struct Transmissibility : public TransmissibilityLawTypes... {};
35
36} // end namespace Dumux::PoreNetwork::Detail
37
38namespace Dumux::PoreNetwork {
39
45template<class ScalarT, class... TransmissibilityLawTypes>
47{
48
49public:
51 using Scalar = ScalarT;
52
54 using Transmissibility = Detail::Transmissibility<TransmissibilityLawTypes...>;
55
63 template<class Problem, class Element, class FVElementGeometry,
64 class ElementVolumeVariables, class SubControlVolumeFace, class ElemFluxVarsCache>
65 static Scalar flux(const Problem& problem,
66 const Element& element,
67 const FVElementGeometry& fvGeometry,
68 const ElementVolumeVariables& elemVolVars,
69 const SubControlVolumeFace& scvf,
70 const int phaseIdx,
71 const ElemFluxVarsCache& elemFluxVarsCache)
72 {
73 const auto& fluxVarsCache = elemFluxVarsCache[scvf];
74
75 // Get the inside and outside volume variables
76 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
77 const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx());
78 const auto& insideVolVars = elemVolVars[insideScv];
79 const auto& outsideVolVars = elemVolVars[outsideScv];
80
81 // calculate the pressure difference
82 const Scalar deltaP = insideVolVars.pressure(phaseIdx) - outsideVolVars.pressure(phaseIdx);
83 const Scalar transmissibility = fluxVarsCache.transmissibility(phaseIdx);
84
85 Scalar volumeFlow = transmissibility*deltaP;
86
87 // add gravity term
88 static const bool enableGravity = getParamFromGroup<bool>(problem.paramGroup(), "Problem.EnableGravity");
89 if (enableGravity)
90 {
91 const Scalar rho = 0.5*insideVolVars.density(phaseIdx) + 0.5*outsideVolVars.density(phaseIdx);
92 const Scalar g = problem.spatialParams().gravity(scvf.center()) * scvf.unitOuterNormal();
93
94 // The transmissibility is with respect to the effective throat length (potentially dropping the pore body radii).
95 // For gravity, we need to consider the total throat length (i.e., the cell-center to cell-center distance).
96 // This might cause some inconsistencies TODO: is there a better way?
97 volumeFlow += transmissibility * fluxVarsCache.poreToPoreDistance() * rho * g;
98 }
99
100 return volumeFlow;
101 }
102
106 template<class Problem, class Element, class FVElementGeometry, class ElementVolumeVariables, class FluxVariablesCache>
107 static Scalar calculateTransmissibility(const Problem& problem,
108 const Element& element,
109 const FVElementGeometry& fvGeometry,
110 const typename FVElementGeometry::SubControlVolumeFace& scvf,
111 const ElementVolumeVariables& elemVolVars,
112 const FluxVariablesCache& fluxVarsCache,
113 const int phaseIdx)
114 {
115 if constexpr (ElementVolumeVariables::VolumeVariables::numFluidPhases() == 1)
116 return Transmissibility::singlePhaseTransmissibility(problem, element, fvGeometry, scvf, elemVolVars, fluxVarsCache, phaseIdx);
117 else
118 {
119 static_assert(ElementVolumeVariables::VolumeVariables::numFluidPhases() == 2);
120
121 const auto& spatialParams = problem.spatialParams();
122 using FluidSystem = typename ElementVolumeVariables::VolumeVariables::FluidSystem;
123 const int wPhaseIdx = spatialParams.template wettingPhase<FluidSystem>(element, elemVolVars);
124 const bool invaded = fluxVarsCache.invaded();
125
126 if (phaseIdx == wPhaseIdx)
127 {
128 return invaded ? Transmissibility::wettingLayerTransmissibility(element, fvGeometry, scvf, fluxVarsCache)
129 : Transmissibility::singlePhaseTransmissibility(problem, element, fvGeometry, scvf, elemVolVars, fluxVarsCache, phaseIdx);
130 }
131 else // non-wetting phase
132 {
133 return invaded ? Transmissibility::nonWettingPhaseTransmissibility(element, fvGeometry, scvf, fluxVarsCache)
134 : 0.0;
135 }
136 }
137 }
138
139 template<class Problem, class Element, class FVElementGeometry, class ElementVolumeVariables, class FluxVariablesCache>
140 static std::array<Scalar, 2> calculateTransmissibilities(const Problem& problem,
141 const Element& element,
142 const FVElementGeometry& fvGeometry,
143 const ElementVolumeVariables& elemVolVars,
144 const typename FVElementGeometry::SubControlVolumeFace& scvf,
145 const FluxVariablesCache& fluxVarsCache)
146 {
147 static_assert(ElementVolumeVariables::VolumeVariables::numFluidPhases() == 1);
148 const Scalar t = calculateTransmissibility(problem, element, fvGeometry, scvf, elemVolVars, fluxVarsCache, 0);
149 return {t, -t};
150 }
151};
152
160template <class ScalarT, class... TransmissibilityLawTypes>
162{
163public:
165 using Scalar = ScalarT;
166
168 using TransmissibilityCreepingFlow = Detail::Transmissibility<TransmissibilityLawTypes...>;
169
172 {
173 public:
174 class SinglePhaseCache : public TransmissibilityCreepingFlow::SinglePhaseCache
175 {
176 using ParentType = typename TransmissibilityCreepingFlow::SinglePhaseCache;
177 public:
178 using Scalar = ScalarT;
179
180 template<class Problem, class Element, class FVElementGeometry, class ElementVolumeVariables, class FluxVariablesCache>
181 void fill(const Problem& problem,
182 const Element& element,
183 const FVElementGeometry& fvGeometry,
184 const typename FVElementGeometry::SubControlVolumeFace& scvf,
185 const ElementVolumeVariables& elemVolVars,
186 const FluxVariablesCache& fluxVarsCache,
187 const int phaseIdx)
188 {
189 ParentType::fill(problem, element, fvGeometry,scvf, elemVolVars, fluxVarsCache, phaseIdx);
190 const auto elemSol = elementSolution(element, elemVolVars, fvGeometry);
191
192 for (const auto& scv : scvs(fvGeometry))
193 {
194 const auto localIdx = scv.indexInElement();
195 const Scalar throatToPoreAreaRatio = fluxVarsCache.throatCrossSectionalArea() / problem.spatialParams().poreCrossSectionalArea(element, scv, elemSol);
196
197 // dimensionless momentum coefficient
198 const Scalar momentumCoefficient = problem.spatialParams().momentumCoefficient(element, scv, elemSol);
199
200 // dimensionless kinetik-energy coefficient
201 const Scalar kineticEnergyCoefficient = problem.spatialParams().kineticEnergyCoefficient(element, scv, elemSol);
202
203 expansionCoefficient_[localIdx] = getExpansionCoefficient_(throatToPoreAreaRatio, momentumCoefficient, kineticEnergyCoefficient);
204 contractionCoefficient_[localIdx] = getContractionCoefficient_(throatToPoreAreaRatio, momentumCoefficient, kineticEnergyCoefficient);
205 }
206 }
207
208 Scalar expansionCoefficient(int downstreamIdx) const
209 { return expansionCoefficient_[downstreamIdx]; }
210
211 Scalar contractionCoefficient(int upstreamIdx) const
212 { return contractionCoefficient_[upstreamIdx]; }
213
214 private:
215
216 Scalar getExpansionCoefficient_(const Scalar throatToPoreAreaRatio, const Scalar momentumCoefficient, const Scalar kineticEnergyCoefficient) const
217 {
218 Scalar expansionCoefficient = throatToPoreAreaRatio * throatToPoreAreaRatio * (2 * momentumCoefficient - kineticEnergyCoefficient)
219 + kineticEnergyCoefficient - 2 * momentumCoefficient * throatToPoreAreaRatio
220 - (1 - throatToPoreAreaRatio * throatToPoreAreaRatio);
221
223 }
224
225 Scalar getContractionCoefficient_(const Scalar throatToPoreAreaRatio, const Scalar momentumCoefficient, const Scalar kineticEnergyCoefficient) const
226 {
227 const Scalar contractionAreaRatio = getContractionAreaRatio_(throatToPoreAreaRatio);
228 Scalar contractionCoefficient = (1 - (throatToPoreAreaRatio * throatToPoreAreaRatio * kineticEnergyCoefficient - 2 * momentumCoefficient /*+1-throatToPoreAreaRatio*throatToPoreAreaRatio*/)
229 * contractionAreaRatio * contractionAreaRatio - 2 * contractionAreaRatio) / (contractionAreaRatio * contractionAreaRatio);
230
232 }
233
234 Scalar getContractionAreaRatio_(const Scalar throatToPoreAreaRatio) const
235 {
236 return 1.0-(1.0-throatToPoreAreaRatio)/(2.08*(1.0-throatToPoreAreaRatio)+0.5371);
237 }
238
239 std::array<Scalar, 2> expansionCoefficient_;
240 std::array<Scalar, 2> contractionCoefficient_;
241 };
242 };
243
251 template<class Problem, class Element, class FVElementGeometry,
252 class ElementVolumeVariables, class SubControlVolumeFace, class ElemFluxVarsCache>
253 static Scalar flux(const Problem& problem,
254 const Element& element,
255 const FVElementGeometry& fvGeometry,
256 const ElementVolumeVariables& elemVolVars,
257 const SubControlVolumeFace& scvf,
258 const int phaseIdx,
259 const ElemFluxVarsCache& elemFluxVarsCache)
260 {
261 const auto& fluxVarsCache = elemFluxVarsCache[scvf];
262
263 // Get the inside and outside volume variables
264 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
265 const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx());
266 const auto& insideVolVars = elemVolVars[insideScv];
267 const auto& outsideVolVars = elemVolVars[outsideScv];
268
269 // calculate the pressure difference
270 Scalar deltaP = insideVolVars.pressure(phaseIdx) - outsideVolVars.pressure(phaseIdx);
271
272 // add gravity term
273 static const bool enableGravity = getParamFromGroup<bool>(problem.paramGroup(), "Problem.EnableGravity");
274 if (enableGravity)
275 {
276 const Scalar rho = 0.5*insideVolVars.density(phaseIdx) + 0.5*outsideVolVars.density(phaseIdx);
277
278 // projected distance between pores in gravity field direction
279 const auto poreToPoreVector = fluxVarsCache.poreToPoreDistance() * scvf.unitOuterNormal();
280 const auto& gravityVector = problem.spatialParams().gravity(scvf.center());
281
282 deltaP += rho * (gravityVector * poreToPoreVector);
283 }
284 const Scalar creepingFlowTransmissibility = fluxVarsCache.transmissibility(phaseIdx);
285 const Scalar throatCrossSectionalArea = fluxVarsCache.throatCrossSectionalArea();
286
287 assert(scvf.insideScvIdx() == 0);
288 assert(scvf.outsideScvIdx() == 1);
289
290 // determine the flow direction to predict contraction and expansion
291 const auto [upstreamIdx, downstreamIdx] = deltaP > 0 ? std::pair(0, 1) : std::pair(1, 0);
292
293 const Scalar contractionCoefficient = fluxVarsCache.singlePhaseFlowVariables().contractionCoefficient(upstreamIdx);
294 const Scalar expansionCoefficient = fluxVarsCache.singlePhaseFlowVariables().expansionCoefficient(downstreamIdx);
295 const Scalar mu = elemVolVars[upstreamIdx].viscosity();
296
306 const Scalar A = (contractionCoefficient * elemVolVars[upstreamIdx].density() + expansionCoefficient * elemVolVars[downstreamIdx].density())
307 / (2.0 * mu * mu * throatCrossSectionalArea * throatCrossSectionalArea);
308 const Scalar B = 1.0/creepingFlowTransmissibility;
309 using std::abs;
310 const Scalar C = -abs(deltaP);
311
312 using std::sqrt;
313 const auto discriminant = B*B - 4*A*C;
314 const auto q = (-B + sqrt(discriminant)) / (2*A);
315
317 if (upstreamIdx == 0)
318 return q;
319 else
320 return -q;
321
322 }
323
324 template<class Problem, class Element, class FVElementGeometry, class ElementVolumeVariables, class FluxVariablesCache>
325 static Scalar calculateTransmissibility(const Problem& problem,
326 const Element& element,
327 const FVElementGeometry& fvGeometry,
328 const typename FVElementGeometry::SubControlVolumeFace& scvf,
329 const ElementVolumeVariables& elemVolVars,
330 const FluxVariablesCache& fluxVarsCache,
331 const int phaseIdx)
332 {
333 static_assert(ElementVolumeVariables::VolumeVariables::numFluidPhases() == 1);
334 return Transmissibility::singlePhaseTransmissibility(problem, element, fvGeometry, scvf, elemVolVars, fluxVarsCache, phaseIdx);
335 }
336
337 template<class Problem, class Element, class FVElementGeometry, class ElementVolumeVariables, class FluxVariablesCache>
338 static std::array<Scalar, 2> calculateTransmissibilities(const Problem& problem,
339 const Element& element,
340 const FVElementGeometry& fvGeometry,
341 const ElementVolumeVariables& elemVolVars,
342 const typename FVElementGeometry::SubControlVolumeFace& scvf,
343 const FluxVariablesCache& fluxVarsCache)
344 {
345 static_assert(ElementVolumeVariables::VolumeVariables::numFluidPhases() == 1);
346 const Scalar t = calculateTransmissibility(problem, element, fvGeometry, scvf, elemVolVars, fluxVarsCache, 0);
347 return {t, -t};
348 }
349
350};
351
352} // end namespace Dumux
353
354#endif
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
auto elementSolution(const Element &element, const SolutionVector &sol, const GridGeometry &gg) -> std::enable_if_t< GridGeometry::discMethod==DiscretizationMethod::box, BoxElementSolution< typename GridGeometry::LocalView, std::decay_t< decltype(std::declval< SolutionVector >()[0])> > >
Make an element solution for box schemes.
Definition: box/elementsolution.hh:118
Definition: discretization/porenetwork/fvelementgeometry.hh:33
Definition: advection.hh:31
Definition: advection.hh:47
static std::array< Scalar, 2 > calculateTransmissibilities(const Problem &problem, const Element &element, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const typename FVElementGeometry::SubControlVolumeFace &scvf, const FluxVariablesCache &fluxVarsCache)
Definition: advection.hh:140
ScalarT Scalar
Export the Scalar type.
Definition: advection.hh:51
static Scalar calculateTransmissibility(const Problem &problem, const Element &element, const FVElementGeometry &fvGeometry, const typename FVElementGeometry::SubControlVolumeFace &scvf, const ElementVolumeVariables &elemVolVars, const FluxVariablesCache &fluxVarsCache, const int phaseIdx)
Returns the throat conductivity.
Definition: advection.hh:107
static Scalar flux(const Problem &problem, const Element &element, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const SubControlVolumeFace &scvf, const int phaseIdx, const ElemFluxVarsCache &elemFluxVarsCache)
Returns the advective flux of a fluid phase across the given sub-control volume face (corresponding t...
Definition: advection.hh:65
Definition: advection.hh:162
static Scalar flux(const Problem &problem, const Element &element, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const SubControlVolumeFace &scvf, const int phaseIdx, const ElemFluxVarsCache &elemFluxVarsCache)
Returns the advective flux of a fluid phase across the given sub-control volume face (corresponding t...
Definition: advection.hh:253
ScalarT Scalar
Export the Scalar type.
Definition: advection.hh:165
static Scalar calculateTransmissibility(const Problem &problem, const Element &element, const FVElementGeometry &fvGeometry, const typename FVElementGeometry::SubControlVolumeFace &scvf, const ElementVolumeVariables &elemVolVars, const FluxVariablesCache &fluxVarsCache, const int phaseIdx)
Definition: advection.hh:325
static std::array< Scalar, 2 > calculateTransmissibilities(const Problem &problem, const Element &element, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const typename FVElementGeometry::SubControlVolumeFace &scvf, const FluxVariablesCache &fluxVarsCache)
Definition: advection.hh:338
Inherit transmissibility from creeping flow transmissibility law to cache non-creeping flow-related p...
Definition: advection.hh:172
void fill(const Problem &problem, const Element &element, const FVElementGeometry &fvGeometry, const typename FVElementGeometry::SubControlVolumeFace &scvf, const ElementVolumeVariables &elemVolVars, const FluxVariablesCache &fluxVarsCache, const int phaseIdx)
Definition: advection.hh:181
Scalar contractionCoefficient(int upstreamIdx) const
Definition: advection.hh:211
Scalar expansionCoefficient(int downstreamIdx) const
Definition: advection.hh:208