13#ifndef DUMUX_TWOPVE_QUANTITY_RECONSTRUCTION_HH
14#define DUMUX_TWOPVE_QUANTITY_RECONSTRUCTION_HH
20#include <dune/common/exceptions.hh>
33template<
typename Scalar>
44template<
typename Scalar>
55template<
typename Scalar>
66template<
typename Scalar>
77template<
typename Scalar>
98template<
class Scalar,
class Flu
idSystem>
101 static constexpr int wettingPhaseIdx = FluidSystem::phase0Idx;
102 static constexpr int nonwettingPhaseIdx = FluidSystem::phase1Idx;
103 static constexpr int numPhases = FluidSystem::numPhases;
133 const ResidualSaturations& residualSaturations,
136 Scalar saturationWCoarse,
137 Scalar minGasPlumeDist,
138 const BrooksCoreyParameters& brooksCoreyParameters)
const
140 const Scalar densityW = densities.
wetting;
141 const Scalar densityNw = densities.
nonwetting;
142 const Scalar swr = residualSaturations.
wetting;
143 const Scalar snr = residualSaturations.
nonwetting;
145 if (gravityNorm == 0.0)
146 DUNE_THROW(Dune::InvalidStateException,
"The two-phase vertical-equilibrium model requires nonzero gravity because its reconstruction assumes gravity-driven vertical segregation");
148 if (densityW <= densityNw)
149 DUNE_THROW(Dune::InvalidStateException,
"The two-phase VE reconstruction requires the wetting phase to be denser than the nonwetting phase. Got rho_w=" << densityW <<
" and rho_n=" << densityNw);
153 using std::max;
using std::min;
154 const auto massConservation = [&](
const Scalar gasPlumeDist)
156 const Scalar bottomOfMobileGas = max(gasPlumeDist, 0.0);
157 const Scalar waterBelowMinimum = max(min(gasPlumeDist, minGasPlumeDist), 0.0);
158 const Scalar waterTrappedRegion = (1.0-snr) * max(bottomOfMobileGas - max(minGasPlumeDist, 0.0), 0.0);
159 const Scalar waterAbovePlume = integrateSaturationWAbovePlume_(bottomOfMobileGas, domainHeight, gasPlumeDist, densities, residualSaturations, gravityNorm, brooksCoreyParameters);
160 return waterBelowMinimum + waterTrappedRegion + waterAbovePlume - saturationWCoarse * domainHeight;
163 if (massConservation(domainHeight) <= 0.0)
167 if (saturationWCoarse <= swr)
168 DUNE_THROW(
NumericalProblem,
"The coarse-level wetting-phase saturation " << saturationWCoarse <<
" does not exceed the residual saturation " << swr);
171 const Scalar fringeHeight = brooksCoreyParameters.
entryPressure/((densityW - densityNw)*gravityNorm);
172 Scalar lowerBound = 0.0;
173 Scalar residualAtLowerBound = massConservation(lowerBound);
174 for (Scalar expansion = fringeHeight; residualAtLowerBound > 0.0; expansion *= 2.0)
176 lowerBound -= expansion;
177 residualAtLowerBound = massConservation(lowerBound);
180 if (residualAtLowerBound == 0.0)
195 const PhaseDensities& densities,
197 Scalar entryPressureBC)
const
199 return gravityNorm * gasPlumeDist * (densities.
nonwetting - densities.
wetting) + entryPressureBC;
213 const PhaseDensities& densities,
215 Scalar heightAboveBottom,
216 Scalar pressureWCoarse,
217 Scalar entryPressureBC)
const
219 const Scalar referenceDensityW = densities.
wetting;
220 const Scalar referenceDensityNw = densities.
nonwetting;
223 std::array<Scalar, numPhases> reconstructedPressures;
224 reconstructedPressures[wettingPhaseIdx] = pressureWCoarse - referenceDensityW * gravityNorm * heightAboveBottom;
225 if (heightAboveBottom <= gasPlumeDist)
226 reconstructedPressures[nonwettingPhaseIdx] = reconstructedPressures[wettingPhaseIdx] + entryPressureBC;
228 reconstructedPressures[nonwettingPhaseIdx] = pressureWCoarse - referenceDensityW * gravityNorm * gasPlumeDist - referenceDensityNw * gravityNorm * (heightAboveBottom - gasPlumeDist) + entryPressureBC;
230 return reconstructedPressures;
247 const PhaseDensities& densities,
248 const ResidualSaturations& residualSaturations,
250 Scalar heightAboveBottom,
252 const BrooksCoreyParameters& brooksCoreyParameters)
const
254 const Scalar gasPlumeDist = gasPlumeDistances.
current;
255 const Scalar minGasPlumeDist = gasPlumeDistances.
minimum;
257 const Scalar lowerBound = heightAboveBottom - deltaZ/2.0;
258 const Scalar upperBound = heightAboveBottom + deltaZ/2.0;
259 const Scalar cellHeight = upperBound - lowerBound;
261 const Scalar snr = residualSaturations.
nonwetting;
262 const Scalar saturationWBelowPlume = 1.0;
263 const Scalar saturationWTrappedRegion = 1.0 - snr;
264 const auto integrateSaturationWAbovePlume = [&](
const Scalar lower,
const Scalar upper)
266 return integrateSaturationWAbovePlume_(lower, upper, gasPlumeDist, densities, residualSaturations, gravityNorm, brooksCoreyParameters);
269 Scalar saturationIntegral = 0.0;
279 if (upperBound <= minGasPlumeDist)
280 saturationIntegral = saturationWBelowPlume*cellHeight;
281 else if (lowerBound >= gasPlumeDist)
282 saturationIntegral = integrateSaturationWAbovePlume(lowerBound, upperBound);
283 else if (lowerBound >= minGasPlumeDist && upperBound <= gasPlumeDist)
284 saturationIntegral = saturationWTrappedRegion*cellHeight;
285 else if (lowerBound < minGasPlumeDist && upperBound <= gasPlumeDist)
287 const Scalar integralBelowMinimum = saturationWBelowPlume * (minGasPlumeDist - lowerBound);
288 const Scalar integralTrappedRegion = saturationWTrappedRegion * (upperBound - minGasPlumeDist);
289 saturationIntegral = integralBelowMinimum + integralTrappedRegion;
291 else if (lowerBound >= minGasPlumeDist && upperBound > gasPlumeDist)
293 const Scalar integralTrappedRegion = saturationWTrappedRegion * (gasPlumeDist - lowerBound);
294 const Scalar integralAbovePlume = integrateSaturationWAbovePlume(gasPlumeDist, upperBound);
295 saturationIntegral = integralTrappedRegion + integralAbovePlume;
299 const Scalar integralBelowMinimum = saturationWBelowPlume * (minGasPlumeDist - lowerBound);
300 const Scalar integralTrappedRegion = saturationWTrappedRegion * (gasPlumeDist - minGasPlumeDist);
301 const Scalar integralAbovePlume = integrateSaturationWAbovePlume(gasPlumeDist, upperBound);
302 saturationIntegral = integralBelowMinimum + integralTrappedRegion + integralAbovePlume;
305 return saturationIntegral/cellHeight;
318 const PhaseDensities& densities,
320 Scalar heightAboveBottom,
321 Scalar entryPressureBC)
const
323 const Scalar referenceDensityW = densities.
wetting;
324 const Scalar referenceDensityNw = densities.
nonwetting;
326 if (heightAboveBottom <= gasPlumeDist)
327 return entryPressureBC;
329 return referenceDensityW * gravityNorm * (heightAboveBottom - gasPlumeDist) + entryPressureBC - referenceDensityNw * gravityNorm * (heightAboveBottom - gasPlumeDist);
344 const PhaseDensities& densities,
345 const PhaseViscosities& viscosities,
347 Scalar heightAboveBottom,
349 const BrooksCoreyParameters& brooksCoreyParameters)
const
351 const Scalar gasPlumeDist = gasPlumeDistances.
current;
352 const Scalar lowerBound = heightAboveBottom - deltaZ/2.0;
353 const Scalar upperBound = heightAboveBottom + deltaZ/2.0;
355 const Scalar relPermWBelowPlume = 1.0;
356 const Scalar relPermNwBelowPlume = 0.0;
360 const Scalar lambdaBC = brooksCoreyParameters.
lambda;
361 const auto integratePower = [&](
const Scalar exponent,
const Scalar lower,
const Scalar upper)
363 return integratePowerAbovePlume_(exponent, lower, upper, gasPlumeDist, densities, gravityNorm, brooksCoreyParameters.
entryPressure);
365 const auto integrateRelPermWAbovePlume = [&](
const Scalar lower,
const Scalar upper)
367 return integratePower(2.0 + 3.0*lambdaBC, lower, upper);
369 const auto integrateRelPermNwAbovePlume = [&](
const Scalar lower,
const Scalar upper)
371 const Scalar integral = (upper - lower)
372 - 2.0*integratePower(lambdaBC, lower, upper)
373 + integratePower(2.0*lambdaBC, lower, upper)
374 - integratePower(2.0 + lambdaBC, lower, upper)
375 + 2.0*integratePower(2.0 + 2.0*lambdaBC, lower, upper)
376 - integratePower(2.0 + 3.0*lambdaBC, lower, upper);
380 return max(integral, 0.0);
384 const auto integrateRelativePermeability = [&](
const auto& integralAbovePlume,
const Scalar relPermBelowPlume)
386 const Scalar cellHeight = upperBound - lowerBound;
393 if (upperBound <= gasPlumeDist)
394 return relPermBelowPlume * cellHeight;
395 else if (lowerBound >= gasPlumeDist)
396 return integralAbovePlume(lowerBound, upperBound);
398 return relPermBelowPlume * (gasPlumeDist - lowerBound) + integralAbovePlume(gasPlumeDist, upperBound);
402 std::array<Scalar, numPhases> mobilities;
403 mobilities[wettingPhaseIdx] = integrateRelativePermeability(integrateRelPermWAbovePlume, relPermWBelowPlume)/(upperBound - lowerBound)/viscosities.
wetting;
404 mobilities[nonwettingPhaseIdx] = integrateRelativePermeability(integrateRelPermNwAbovePlume, relPermNwBelowPlume)/(upperBound - lowerBound)/viscosities.
nonwetting;
461 Scalar integratePowerAbovePlume_(Scalar exponent,
465 const PhaseDensities& densities,
467 Scalar entryPressureBC)
const
469 using std::expm1;
using std::log1p;
using std::pow;
470 const Scalar lengthScale = entryPressureBC/((densities.wetting - densities.nonwetting)*gravityNorm);
471 const Scalar uLower = 1.0 + (lowerBound - gasPlumeDist)/lengthScale;
472 const Scalar logRatio = log1p((upperBound - lowerBound)/(lengthScale*uLower));
473 const Scalar k = 1.0 - exponent;
475 return lengthScale*logRatio;
478 return lengthScale*pow(uLower, k)*expm1(k*logRatio)/k;
492 Scalar integrateSaturationWAbovePlume_(Scalar lowerBound,
495 const PhaseDensities& densities,
496 const ResidualSaturations& residualSaturations,
498 const BrooksCoreyParameters& brooksCoreyParameters)
const
500 const Scalar swr = residualSaturations.wetting;
501 const Scalar snr = residualSaturations.nonwetting;
502 const Scalar integralEffectiveSaturation = integratePowerAbovePlume_(brooksCoreyParameters.lambda, lowerBound, upperBound, gasPlumeDist, densities, gravityNorm, brooksCoreyParameters.entryPressure);
503 return swr*(upperBound - lowerBound) + (1.0 - swr - snr)*integralEffectiveSaturation;
Exception thrown if a fixable numerical problem occurs.
Definition exceptions.hh:27
Reconstructs the fine-level quantities of a column from its coarse-level quantities assuming vertical...
Definition quantityreconstruction.hh:100
Scalar reconstructSaturation(const GasPlumeDistances &gasPlumeDistances, const PhaseDensities &densities, const ResidualSaturations &residualSaturations, Scalar gravityNorm, Scalar heightAboveBottom, Scalar deltaZ, const BrooksCoreyParameters &brooksCoreyParameters) const
Reconstructs the fine-level wetting-phase saturation as a mean integral of the saturation across the ...
Definition quantityreconstruction.hh:246
Scalar reconstructCapillaryPressure(Scalar gasPlumeDist, const PhaseDensities &densities, Scalar gravityNorm, Scalar heightAboveBottom, Scalar entryPressureBC) const
Reconstructs the fine-level capillary pressure.
Definition quantityreconstruction.hh:317
std::array< Scalar, numPhases > reconstructPressure(Scalar gasPlumeDist, const PhaseDensities &densities, Scalar gravityNorm, Scalar heightAboveBottom, Scalar pressureWCoarse, Scalar entryPressureBC) const
Reconstructs the fine-level wetting-phase and nonwetting-phase pressures.
Definition quantityreconstruction.hh:212
Scalar computeGasPlumeDist(const PhaseDensities &densities, const ResidualSaturations &residualSaturations, Scalar gravityNorm, Scalar domainHeight, Scalar saturationWCoarse, Scalar minGasPlumeDist, const BrooksCoreyParameters &brooksCoreyParameters) const
Computes the gas plume distance for a coarse column, which is the height of the lower boundary of the...
Definition quantityreconstruction.hh:132
std::array< Scalar, numPhases > reconstructMobilitiesFine(const GasPlumeDistances &gasPlumeDistances, const PhaseDensities &densities, const PhaseViscosities &viscosities, Scalar gravityNorm, Scalar heightAboveBottom, Scalar deltaZ, const BrooksCoreyParameters &brooksCoreyParameters) const
Reconstructs the fine-level wetting-phase and nonwetting-phase mobilities.
Definition quantityreconstruction.hh:343
Scalar computeCapillaryPressureCoarse(Scalar gasPlumeDist, const PhaseDensities &densities, Scalar gravityNorm, Scalar entryPressureBC) const
Computes the capillary pressure on the coarse level.
Definition quantityreconstruction.hh:194
Some exceptions thrown in DuMux.
Root finding algorithms for scalar functions.
Scalar findScalarRootBrent(Scalar a, Scalar b, const ResFunc &residual, const Scalar tol=1e-13, const int maxIter=200)
Brent's root finding algorithm for scalar functions.
Definition findscalarroot.hh:99
Definition quantityreconstruction.hh:27
The parameters of the Brooks-Corey material law.
Definition quantityreconstruction.hh:79
Scalar entryPressure
Definition quantityreconstruction.hh:81
Scalar lambda
Definition quantityreconstruction.hh:80
The gas plume distance of a column and its minimum over all previous time steps.
Definition quantityreconstruction.hh:35
Scalar minimum
Definition quantityreconstruction.hh:37
Scalar current
Definition quantityreconstruction.hh:36
The densities of the wetting and the nonwetting phase.
Definition quantityreconstruction.hh:46
Scalar wetting
Definition quantityreconstruction.hh:47
Scalar nonwetting
Definition quantityreconstruction.hh:48
The viscosities of the wetting and the nonwetting phase.
Definition quantityreconstruction.hh:57
Scalar wetting
Definition quantityreconstruction.hh:58
Scalar nonwetting
Definition quantityreconstruction.hh:59
The residual saturations of the wetting and the nonwetting phase.
Definition quantityreconstruction.hh:68
Scalar wetting
Definition quantityreconstruction.hh:69
Scalar nonwetting
Definition quantityreconstruction.hh:70