blackoilconvectivemixingmodule.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 This file is part of the Open Porous Media project (OPM).
5
6 OPM 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 2 of the License, or
9 (at your option) any later version.
10
11 OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
18
19 Consult the COPYING file in the top-level source directory of this
20 module for the precise wording of the license and the list of
21 copyright holders.
22*/
28#ifndef EWOMS_CONVECTIVEMIXING_MODULE_HH
29#define EWOMS_CONVECTIVEMIXING_MODULE_HH
30
31#include "opm/material/common/MathToolbox.hpp"
32#include <dune/common/fvector.hh>
33
34#include <opm/input/eclipse/Schedule/OilVaporizationProperties.hpp>
35#include <opm/input/eclipse/Schedule/Schedule.hpp>
36
37#include <opm/material/common/Valgrind.hpp>
38
41
42namespace Opm {
43
57template <class TypeTag, bool enableConvectiveMixing>
59
64template <class TypeTag>
65class BlackOilConvectiveMixingModule<TypeTag, /*enableConvectiveMixing=*/false>
66{
74
75 enum { conti0EqIdx = Indices::conti0EqIdx };
76 enum { dimWorld = GridView::dimensionworld };
77
78public:
79 struct ConvectiveMixingModuleParam
80 {};
81
82 #if HAVE_ECL_INPUT
83 static void beginEpisode(const EclipseState&,
84 const Schedule&,
85 const int,
86 ConvectiveMixingModuleParam&)
87 {}
88 #endif
89
90 template <class Context>
91 static bool active(const Context&) {
92 return false;
93 }
94
95 static void modifyAvgDensity(Evaluation&,
96 const IntensiveQuantities&,
97 const IntensiveQuantities&,
98 const unsigned int,
99 const ConvectiveMixingModuleParam&) {
100 }
101
102 template <class Context>
103 static void addConvectiveMixingFlux(RateVector&,
104 const Context&,
105 unsigned,
106 unsigned)
107 {}
108
113 static void addConvectiveMixingFlux(RateVector&,
114 const IntensiveQuantities&,
115 const IntensiveQuantities&,
116 const unsigned,
117 const unsigned,
118 const Scalar,
119 const Scalar,
120 const Scalar,
121 const ConvectiveMixingModuleParam&)
122 {}
123};
124
125template <class TypeTag>
126class BlackOilConvectiveMixingModule<TypeTag, /*enableConvectiveMixing=*/true>
127{
135 using Toolbox = MathToolbox<Evaluation>;
136
137 enum { conti0EqIdx = Indices::conti0EqIdx };
138 enum { dimWorld = GridView::dimensionworld };
139 enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
140 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
141 static constexpr bool enableEnergy = getPropValue<TypeTag, Properties::EnableEnergy>();
142 static constexpr unsigned contiEnergyEqIdx = Indices::contiEnergyEqIdx;
143
144public:
145
146 struct ConvectiveMixingModuleParam
147 {
148 std::vector<bool> active_;
149 std::vector<Scalar> Xhi_;
150 std::vector<Scalar> Psi_;
151 };
152
153 #if HAVE_ECL_INPUT
154 static void beginEpisode(const EclipseState& eclState,
155 const Schedule& schedule,
156 const int episodeIdx,
157 ConvectiveMixingModuleParam& info)
158 {
159 // check that Xhi and Psi didn't change
160 std::size_t numRegions = eclState.runspec().tabdims().getNumPVTTables();
161 const auto& control = schedule[episodeIdx].oilvap();
162 if (info.active_.empty()) {
163 info.active_.resize(numRegions);
164 info.Xhi_.resize(numRegions);
165 info.Psi_.resize(numRegions);
166 }
167 for (size_t i = 0; i < numRegions; ++i ) {
168 info.active_[i] = control.drsdtConvective(i);
169 if (control.drsdtConvective(i)) {
170 info.Xhi_[i] = control.getMaxDRSDT(i);
171 info.Psi_[i] = control.getPsi(i);
172 }
173 }
174 }
175 #endif
176
177 static void modifyAvgDensity(Evaluation& rhoAvg,
178 const IntensiveQuantities& intQuantsIn,
179 const IntensiveQuantities& intQuantsEx,
180 const unsigned phaseIdx,
181 const ConvectiveMixingModuleParam& info) {
182
183 if (info.active_.empty()) {
184 return;
185 }
186 if (!info.active_[ intQuantsIn.pvtRegionIndex()] || !info.active_[ intQuantsEx.pvtRegionIndex()]) {
187 return;
188 }
189
190 if (phaseIdx == FluidSystem::gasPhaseIdx) {
191 return;
192 }
193
194 const auto& liquidPhaseIdx = (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) ?
195 FluidSystem::waterPhaseIdx :
196 FluidSystem::oilPhaseIdx;
197
198 // Compute avg density based on pure water
199 const auto& t_in = intQuantsIn.fluidState().temperature(liquidPhaseIdx);
200 const auto& p_in = intQuantsIn.fluidState().pressure(liquidPhaseIdx);
201 const auto& salt_in = intQuantsIn.fluidState().saltConcentration();
202
203 const auto& bLiquidIn = (FluidSystem::phaseIsActive(waterPhaseIdx)) ?
204 FluidSystem::waterPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(), t_in, p_in, Evaluation(0.0), salt_in) :
205 FluidSystem::oilPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(), t_in, p_in, Evaluation(0.0));
206
207 const auto& refDensityLiquidIn = (FluidSystem::phaseIsActive(waterPhaseIdx)) ?
208 FluidSystem::waterPvt().waterReferenceDensity(intQuantsIn.pvtRegionIndex()) :
209 FluidSystem::oilPvt().oilReferenceDensity(intQuantsIn.pvtRegionIndex());
210
211 const auto& rho_in = bLiquidIn * refDensityLiquidIn;
212
213 const auto t_ex = Toolbox::value(intQuantsEx.fluidState().temperature(liquidPhaseIdx));
214 const auto p_ex = Toolbox::value(intQuantsEx.fluidState().pressure(liquidPhaseIdx));
215 const auto salt_ex = Toolbox::value(intQuantsEx.fluidState().saltConcentration());
216
217 const auto bLiquidEx = (FluidSystem::phaseIsActive(waterPhaseIdx)) ?
218 FluidSystem::waterPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(),
219 t_ex, p_ex, Scalar{0.0}, salt_ex) :
220 FluidSystem::oilPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(),
221 t_ex, p_ex, Scalar{0.0});
222
223 const auto& refDensityLiquidEx = (FluidSystem::phaseIsActive(waterPhaseIdx)) ?
224 FluidSystem::waterPvt().waterReferenceDensity(intQuantsEx.pvtRegionIndex()) :
225 FluidSystem::oilPvt().oilReferenceDensity(intQuantsEx.pvtRegionIndex());
226
227 const auto rho_ex = bLiquidEx * refDensityLiquidEx;
228
229 rhoAvg = (rho_in + rho_ex)/2;
230 }
231
232 template <class Context>
233 static void addConvectiveMixingFlux(RateVector& flux,
234 const Context& elemCtx,
235 unsigned scvfIdx,
236 unsigned timeIdx) {
237 // need for darcy flux calculation
238 const auto& problem = elemCtx.problem();
239 const auto& stencil = elemCtx.stencil(timeIdx);
240 const auto& scvf = stencil.interiorFace(scvfIdx);
241
242 unsigned interiorDofIdx = scvf.interiorIndex();
243 unsigned exteriorDofIdx = scvf.exteriorIndex();
244 assert(interiorDofIdx != exteriorDofIdx);
245
246 const auto& globalIndexIn = stencil.globalSpaceIndex(interiorDofIdx);
247 const auto& globalIndexEx = stencil.globalSpaceIndex(exteriorDofIdx);
248 Scalar trans = problem.transmissibility(elemCtx, interiorDofIdx, exteriorDofIdx);
249 Scalar faceArea = scvf.area();
250 const Scalar g = problem.gravity()[dimWorld - 1];
251 const auto& intQuantsIn = elemCtx.intensiveQuantities(interiorDofIdx, timeIdx);
252 const auto& intQuantsEx = elemCtx.intensiveQuantities(exteriorDofIdx, timeIdx);
253 const Scalar zIn = problem.dofCenterDepth(elemCtx, interiorDofIdx, timeIdx);
254 const Scalar zEx = problem.dofCenterDepth(elemCtx, exteriorDofIdx, timeIdx);
255 const Scalar distZ = zIn - zEx;
256 addConvectiveMixingFlux(flux,
257 intQuantsIn,
258 intQuantsEx,
259 globalIndexIn,
260 globalIndexEx,
261 distZ * g,
262 trans,
263 faceArea,
264 problem.moduleParams().convectiveMixingModuleParam);
265 }
266
271 static void addConvectiveMixingFlux(RateVector& flux,
272 const IntensiveQuantities& intQuantsIn,
273 const IntensiveQuantities& intQuantsEx,
274 const unsigned globalIndexIn,
275 const unsigned globalIndexEx,
276 const Scalar distZg,
277 const Scalar trans,
278 const Scalar faceArea,
279 const ConvectiveMixingModuleParam& info)
280 {
281 if (info.active_.empty()) {
282 return;
283 }
284
285 if (!info.active_[ intQuantsIn.pvtRegionIndex()] || !info.active_[ intQuantsEx.pvtRegionIndex()]) {
286 return;
287 }
288
289 const auto& liquidPhaseIdx = (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) ?
290 FluidSystem::waterPhaseIdx :
291 FluidSystem::oilPhaseIdx;
292 const Evaluation SoMax = 0.0;
293
294 //interiour
295 const auto& t_in = intQuantsIn.fluidState().temperature(liquidPhaseIdx);
296 const auto& p_in = intQuantsIn.fluidState().pressure(liquidPhaseIdx);
297 const auto& rssat_in = FluidSystem::saturatedDissolutionFactor(intQuantsIn.fluidState(),
298 liquidPhaseIdx,
299 intQuantsIn.pvtRegionIndex(),
300 SoMax);
301 const auto& salt_in = intQuantsIn.fluidState().saltSaturation();
302
303 const auto bLiquidSatIn = (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) ?
304 FluidSystem::waterPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(), t_in, p_in, rssat_in, salt_in):
305 FluidSystem::oilPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(), t_in, p_in, rssat_in);
306
307 const auto& densityLiquidIn = (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) ?
308 FluidSystem::waterPvt().waterReferenceDensity(intQuantsIn.pvtRegionIndex()) :
309 FluidSystem::oilPvt().oilReferenceDensity(intQuantsIn.pvtRegionIndex());
310
311 const auto rho_in = Opm::getValue(intQuantsIn.fluidState().invB(liquidPhaseIdx)) * densityLiquidIn;
312 const auto rho_sat_in = bLiquidSatIn
313 * (densityLiquidIn + rssat_in * FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx, intQuantsIn.pvtRegionIndex()));
314
315 //exteriour
316 const auto t_ex = Opm::getValue(intQuantsEx.fluidState().temperature(liquidPhaseIdx));
317 const auto p_ex = Opm::getValue(intQuantsEx.fluidState().pressure(liquidPhaseIdx));
318 const auto rssat_ex = Opm::getValue(FluidSystem::saturatedDissolutionFactor(intQuantsEx.fluidState(),
319 liquidPhaseIdx,
320 intQuantsEx.pvtRegionIndex(),
321 SoMax));
322 const auto salt_ex = Opm::getValue(intQuantsEx.fluidState().saltSaturation());
323 const auto bLiquidSatEx = (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) ?
324 FluidSystem::waterPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(), t_ex, p_ex, rssat_ex, salt_ex):
325 FluidSystem::oilPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(), t_ex, p_ex, rssat_ex);
326
327
328 const auto& densityLiquidEx = (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) ?
329 FluidSystem::waterPvt().waterReferenceDensity(intQuantsEx.pvtRegionIndex()) :
330 FluidSystem::oilPvt().oilReferenceDensity(intQuantsEx.pvtRegionIndex());
331
332 const auto rho_ex = Opm::getValue(intQuantsEx.fluidState().invB(liquidPhaseIdx)) * densityLiquidEx;
333 const auto rho_sat_ex = bLiquidSatEx
334 * (densityLiquidEx + rssat_ex * FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx, intQuantsEx.pvtRegionIndex()));
335 //rho difference approximation
336 const auto delta_rho = (rho_sat_ex + rho_sat_in - rho_in - rho_ex)/2;
337 const auto pressure_difference_convective_mixing = delta_rho * distZg;
338
339 //if change in pressure
340 if (Opm::abs(pressure_difference_convective_mixing) > 1e-12){
341
342 // find new upstream direction
343 short interiorDofIdx = 0;
344 short exteriorDofIdx = 1;
345 short upIdx = 0;
346
347 if (pressure_difference_convective_mixing > 0) {
348 upIdx = exteriorDofIdx;
349 }
350
351 const auto& up = (upIdx == interiorDofIdx) ? intQuantsIn : intQuantsEx;
352 const auto& rssat_up = (upIdx == interiorDofIdx) ? rssat_in : rssat_ex;
353 unsigned globalUpIndex = (upIdx == interiorDofIdx) ? globalIndexIn : globalIndexEx;
354 const auto& Rsup = (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) ?
355 up.fluidState().Rsw() :
356 up.fluidState().Rs();
357
358 const Evaluation& transMult = up.rockCompTransMultiplier();
359 const auto& invB = up.fluidState().invB(liquidPhaseIdx);
360 const auto& visc = up.fluidState().viscosity(liquidPhaseIdx);
361
362 // We restrict the convective mixing mass flux to rssat * Psi.
363 const Evaluation RsupRestricted = Opm::min(Rsup, rssat_up*info.Psi_[up.pvtRegionIndex()]);
364
365 const auto convectiveFlux = -trans*transMult*info.Xhi_[up.pvtRegionIndex()]*invB*pressure_difference_convective_mixing*RsupRestricted/(visc*faceArea);
366 unsigned activeGasCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::gasCompIdx);
367 if (globalUpIndex == globalIndexIn)
368 flux[conti0EqIdx + activeGasCompIdx] += convectiveFlux;
369 else
370 flux[conti0EqIdx + activeGasCompIdx] += Opm::getValue(convectiveFlux);
371
372 if constexpr (enableEnergy) {
373 const auto& h = up.fluidState().enthalpy(liquidPhaseIdx) * FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx, up.pvtRegionIndex());
374 if (globalUpIndex == globalIndexIn) {
375 flux[contiEnergyEqIdx] += convectiveFlux * h;
376 }
377 else {
378 flux[contiEnergyEqIdx] += Opm::getValue(h) * Opm::getValue(convectiveFlux);
379 }
380 }
381 }
382 }
383};
384
385}
386
387#endif
static void addConvectiveMixingFlux(RateVector &, const Context &, unsigned, unsigned)
Definition: blackoilconvectivemixingmodule.hh:103
static bool active(const Context &)
Definition: blackoilconvectivemixingmodule.hh:91
static void modifyAvgDensity(Evaluation &, const IntensiveQuantities &, const IntensiveQuantities &, const unsigned int, const ConvectiveMixingModuleParam &)
Definition: blackoilconvectivemixingmodule.hh:95
static void addConvectiveMixingFlux(RateVector &, const IntensiveQuantities &, const IntensiveQuantities &, const unsigned, const unsigned, const Scalar, const Scalar, const Scalar, const ConvectiveMixingModuleParam &)
Adds the convective mixing mass flux flux to the flux vector over a flux integration point.
Definition: blackoilconvectivemixingmodule.hh:113
static void addConvectiveMixingFlux(RateVector &flux, const IntensiveQuantities &intQuantsIn, const IntensiveQuantities &intQuantsEx, const unsigned globalIndexIn, const unsigned globalIndexEx, const Scalar distZg, const Scalar trans, const Scalar faceArea, const ConvectiveMixingModuleParam &info)
Adds the convective mixing mass flux flux to the flux vector over a flux integration point.
Definition: blackoilconvectivemixingmodule.hh:271
static void addConvectiveMixingFlux(RateVector &flux, const Context &elemCtx, unsigned scvfIdx, unsigned timeIdx)
Definition: blackoilconvectivemixingmodule.hh:233
static void modifyAvgDensity(Evaluation &rhoAvg, const IntensiveQuantities &intQuantsIn, const IntensiveQuantities &intQuantsEx, const unsigned phaseIdx, const ConvectiveMixingModuleParam &info)
Definition: blackoilconvectivemixingmodule.hh:177
Definition: blackoilconvectivemixingmodule.hh:58
Declare the properties used by the infrastructure code of the finite volume discretizations.
Defines the common properties required by the porous medium multi-phase models.
Definition: blackoilboundaryratevector.hh:37
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:235
std::vector< Scalar > Xhi_
Definition: blackoilconvectivemixingmodule.hh:149
std::vector< Scalar > Psi_
Definition: blackoilconvectivemixingmodule.hh:150
std::vector< bool > active_
Definition: blackoilconvectivemixingmodule.hh:148