opm-simulators
blackoildispersionmodule.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_DISPERSION_MODULE_HH
29 #define EWOMS_DISPERSION_MODULE_HH
30 
31 #include <dune/common/fvector.hh>
32 
33 #include <opm/material/common/MathToolbox.hpp>
34 #include <opm/material/common/Valgrind.hpp>
35 
39 
40 #include <opm/input/eclipse/EclipseState/EclipseState.hpp>
41 #include <opm/common/OpmLog/OpmLog.hpp>
42 
43 #include <array>
44 #include <cmath>
45 #include <stdexcept>
46 
47 namespace Opm {
48 
55 template <class TypeTag, bool enableDispersion>
57 
58 template <class TypeTag, bool enableDispersion>
60 
64 template <class TypeTag>
65 class BlackOilDispersionModule<TypeTag, /*enableDispersion=*/false>
66 {
72 
73 public:
75 
76  static void initFromState(const EclipseState&)
77  {}
78 
83  template <class Context>
84  static void addDispersiveFlux(RateVector&,
85  const Context&,
86  unsigned,
87  unsigned)
88  {}
89 
90  template<class IntensiveQuantities, class Scalar>
91  static void addDispersiveFlux(RateVector&,
92  const IntensiveQuantities&,
93  const IntensiveQuantities&,
94  const Evaluation&,
95  const Scalar&)
96  {}
97 };
98 
102 template <class TypeTag>
103 class BlackOilDispersionModule<TypeTag, /*enableDispersion=*/true>
104 {
108  using IntensiveQuantities = GetPropType<TypeTag, Properties::IntensiveQuantities>;
115 
116  enum { numPhases = FluidSystem::numPhases };
117  enum { numComponents = FluidSystem::numComponents };
118  enum { conti0EqIdx = Indices::conti0EqIdx };
119  enum { enableDispersion = getPropValue<TypeTag, Properties::EnableDispersion>() };
120  enum { enableBioeffects = getPropValue<TypeTag, Properties::EnableBioeffects>() };
121  enum { enableMICP = Indices::enableMICP };
122 
123  static constexpr unsigned contiMicrobialEqIdx = Indices::contiMicrobialEqIdx;
124  static constexpr unsigned contiOxygenEqIdx = Indices::contiOxygenEqIdx;
125  static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
126  static constexpr unsigned contiUreaEqIdx = Indices::contiUreaEqIdx;
127 
128  using Toolbox = MathToolbox<Evaluation>;
129 
130 public:
132 
133  static void initFromState(const EclipseState& eclState)
134  {
135  if (!eclState.getSimulationConfig().rock_config().dispersion()) {
136  return;
137  }
138 
139  if (eclState.getSimulationConfig().hasVAPWAT() || eclState.getSimulationConfig().hasVAPOIL()) {
140  OpmLog::warning("Dispersion is activated in combination with VAPWAT/VAPOIL. \n"
141  "Water/oil is still allowed to vaporize, but dispersion in the "
142  "gas phase is ignored.");
143  }
144  }
145 
150  template <class Context>
151  static void addDispersiveFlux(RateVector& flux, const Context& context,
152  unsigned spaceIdx, unsigned timeIdx)
153  {
154  // Only work if dispersion is enabled by DISPERC in the deck
155  if (!context.simulator().vanguard().eclState().getSimulationConfig().rock_config().dispersion()) {
156  return;
157  }
158  const auto& extQuants = context.extensiveQuantities(spaceIdx, timeIdx);
159  const auto& inIq = context.intensiveQuantities(extQuants.interiorIndex(), timeIdx);
160  const auto& exIq = context.intensiveQuantities(extQuants.exteriorIndex(), timeIdx);
161  const auto& dispersivity = extQuants.dispersivity();
162  const auto& normVelocityAvg = extQuants.normVelocityAvg();
163  addDispersiveFlux(flux, inIq, exIq, dispersivity, normVelocityAvg);
164  }
165 
186  template<class IntensiveQuantities, class Scalar>
187  static void addDispersiveFlux(RateVector& flux,
188  const IntensiveQuantities& inIq,
189  const IntensiveQuantities& exIq,
190  const Evaluation& dispersivity,
191  const Scalar& normVelocityAvg)
192  {
193  const auto& inFs = inIq.fluidState();
194  const auto& exFs = exIq.fluidState();
195  Evaluation diffR = 0.0;
196  if constexpr(enableBioeffects) {
197  // The dispersion coefficients are given for mass concentrations
198  const Evaluation bAvg = (inFs.invB(waterPhaseIdx) + Toolbox::value(exFs.invB(waterPhaseIdx))) / 2;
199  diffR = inIq.microbialConcentration() - Toolbox::value(exIq.microbialConcentration());
200  flux[contiMicrobialEqIdx] +=
201  bAvg *
202  normVelocityAvg[waterPhaseIdx] *
203  dispersivity *
204  diffR;
205  if constexpr(enableMICP) {
206  diffR = inIq.oxygenConcentration() - Toolbox::value(exIq.oxygenConcentration());
207  flux[contiOxygenEqIdx] +=
208  bAvg *
209  normVelocityAvg[waterPhaseIdx] *
210  dispersivity *
211  diffR;
212  diffR = inIq.ureaConcentration() - Toolbox::value(exIq.ureaConcentration());
213  flux[contiUreaEqIdx] +=
214  bAvg *
215  normVelocityAvg[waterPhaseIdx] *
216  dispersivity *
217  diffR;
218  return;
219  }
220  }
221 
222  unsigned pvtRegionIndex = inFs.pvtRegionIndex();
223  for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
224  if (!FluidSystem::phaseIsActive(phaseIdx)) {
225  continue;
226  }
227 
228  // no dispersion in water for blackoil models unless water can contain dissolved gas
229  if (!FluidSystem::enableDissolvedGasInWater() && FluidSystem::waterPhaseIdx == phaseIdx) {
230  continue;
231  }
232 
233  // adding dispersion in the gas phase leads to
234  // convergence issues and unphysical results.
235  // we disable dispersion in the gas phase for now
236  if (FluidSystem::gasPhaseIdx == phaseIdx) {
237  continue;
238  }
239 
240  // arithmetic mean of the phase's b factor
241  Evaluation bAvg = inFs.invB(phaseIdx);
242  bAvg += Toolbox::value(exFs.invB(phaseIdx));
243  bAvg /= 2;
244 
245  Evaluation convFactor = 1.0;
246  if (FluidSystem::enableDissolvedGas() &&
247  FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx) &&
248  phaseIdx == FluidSystem::oilPhaseIdx)
249  {
250  const Evaluation rsAvg = (inFs.Rs() + Toolbox::value(exFs.Rs())) / 2;
251  convFactor = 1.0 / (toMassFractionGasOil(pvtRegionIndex) + rsAvg);
252  diffR = inFs.Rs() - Toolbox::value(exFs.Rs());
253  }
254  if (FluidSystem::enableVaporizedOil() &&
255  FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) &&
256  phaseIdx == FluidSystem::gasPhaseIdx)
257  {
258  const Evaluation rvAvg = (inFs.Rv() + Toolbox::value(exFs.Rv())) / 2;
259  convFactor = toMassFractionGasOil(pvtRegionIndex) /
260  (1.0 + rvAvg * toMassFractionGasOil(pvtRegionIndex));
261  diffR = inFs.Rv() - Toolbox::value(exFs.Rv());
262  }
263  if (FluidSystem::enableDissolvedGasInWater() && phaseIdx == FluidSystem::waterPhaseIdx) {
264  const Evaluation rsAvg = (inFs.Rsw() + Toolbox::value(exFs.Rsw())) / 2;
265  convFactor = 1.0 / (toMassFractionGasWater(pvtRegionIndex) + rsAvg);
266  diffR = inFs.Rsw() - Toolbox::value(exFs.Rsw());
267  }
268  if (FluidSystem::enableVaporizedWater() && phaseIdx == FluidSystem::gasPhaseIdx) {
269  const Evaluation rvAvg = (inFs.Rvw() + Toolbox::value(exFs.Rvw())) / 2;
270  convFactor = toMassFractionGasWater(pvtRegionIndex) /
271  (1.0 + rvAvg * toMassFractionGasWater(pvtRegionIndex));
272  diffR = inFs.Rvw() - Toolbox::value(exFs.Rvw());
273  }
274 
275  // mass flux of solvent component
276  const unsigned solventCompIdx = FluidSystem::solventComponentIndex(phaseIdx);
277  const unsigned activeSolventCompIdx = FluidSystem::canonicalToActiveCompIdx(solventCompIdx);
278  flux[conti0EqIdx + activeSolventCompIdx] +=
279  -bAvg *
280  normVelocityAvg[phaseIdx] *
281  convFactor *
282  dispersivity *
283  diffR;
284 
285  // mass flux of solute component
286  const unsigned soluteCompIdx = FluidSystem::soluteComponentIndex(phaseIdx);
287  const unsigned activeSoluteCompIdx = FluidSystem::canonicalToActiveCompIdx(soluteCompIdx);
288  flux[conti0EqIdx + activeSoluteCompIdx] +=
289  bAvg *
290  normVelocityAvg[phaseIdx] *
291  convFactor *
292  dispersivity *
293  diffR;
294  }
295  }
296 
297 private:
298  static Scalar toMassFractionGasOil (unsigned regionIdx)
299  {
300  const Scalar rhoO = FluidSystem::referenceDensity(FluidSystem::oilPhaseIdx, regionIdx);
301  const Scalar rhoG = FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx, regionIdx);
302  return rhoO / rhoG;
303  }
304 
305  static Scalar toMassFractionGasWater (unsigned regionIdx)
306  {
307  const Scalar rhoW = FluidSystem::referenceDensity(FluidSystem::waterPhaseIdx, regionIdx);
308  const Scalar rhoG = FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx, regionIdx);
309  return rhoW / rhoG;
310  }
311 };
312 
320 template <class TypeTag, bool enableDispersion>
322 
326 template <class TypeTag>
327 class BlackOilDispersionIntensiveQuantities<TypeTag, /*enableDispersion=*/false>
328 {
331 
332 public:
336  Scalar normVelocityCell(unsigned, unsigned) const
337  {
338  throw std::logic_error("Method normVelocityCell() "
339  "does not make sense if dispersion is disabled");
340  }
341 
342 protected:
347  template<class ElementContext>
348  void update_(ElementContext&,
349  unsigned,
350  unsigned)
351  {}
352 };
353 
357 template <class TypeTag>
358 class BlackOilDispersionIntensiveQuantities<TypeTag, /*enableDispersion=*/true>
359 {
364 
365  enum { numPhases = FluidSystem::numPhases };
366  enum { numComponents = FluidSystem::numComponents };
367  enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
368  enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
369  enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
370  enum { gasCompIdx = FluidSystem::gasCompIdx };
371  enum { oilCompIdx = FluidSystem::oilCompIdx };
372  enum { waterCompIdx = FluidSystem::waterCompIdx };
373  enum { conti0EqIdx = Indices::conti0EqIdx };
374  enum { enableDispersion = getPropValue<TypeTag, Properties::EnableDispersion>() };
375 
376 public:
380  Scalar normVelocityCell(unsigned phaseIdx) const
381  { return normVelocityCell_[phaseIdx]; }
382 
383 protected:
393  template<class ElementContext>
394  void update_(const ElementContext& elemCtx, unsigned dofIdx, unsigned timeIdx)
395  {
396  // Only work if dispersion is enabled by DISPERC in the deck
397  if (!elemCtx.simulator().vanguard().eclState().getSimulationConfig().rock_config().dispersion()) {
398  return;
399  }
400  const auto& problem = elemCtx.simulator().problem();
401  if (problem.model().linearizer().getVelocityInfo().empty()) {
402  return;
403  }
404  const std::array<int, 3> phaseIdxs = {gasPhaseIdx, oilPhaseIdx, waterPhaseIdx};
405  const std::array<int, 3> compIdxs = {gasCompIdx, oilCompIdx, waterCompIdx};
406  const auto& velocityInf = problem.model().linearizer().getVelocityInfo();
407  const unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, timeIdx);
408  const auto& velocityInfos = velocityInf[globalDofIdx];
409  for (unsigned i = 0; i < phaseIdxs.size(); ++i) {
410  normVelocityCell_[i] = 0;
411  }
412  for (const auto& velocityInfo : velocityInfos) {
413  for (unsigned i = 0; i < phaseIdxs.size(); ++i) {
414  if (FluidSystem::phaseIsActive(phaseIdxs[i])) {
415  normVelocityCell_[phaseIdxs[i]] = std::max(normVelocityCell_[phaseIdxs[i]],
416  std::abs(velocityInfo.velocity[conti0EqIdx +
417  FluidSystem::canonicalToActiveCompIdx(compIdxs[i])]));
418  }
419  }
420  }
421  }
422 
423 private:
424  std::array<Scalar, numPhases> normVelocityCell_{};
425 };
426 
433 template <class TypeTag, bool enableDispersion>
434 class BlackOilDispersionExtensiveQuantities;
435 
439 template <class TypeTag>
440 class BlackOilDispersionExtensiveQuantities<TypeTag, /*enableDispersion=*/false>
441 {
445  using IntensiveQuantities = GetPropType<TypeTag, Properties::IntensiveQuantities>;
446 
447  enum { numPhases = FluidSystem::numPhases };
448 
449 protected:
454  void update_(const ElementContext&,
455  unsigned,
456  unsigned)
457  {}
458 
459  template <class Context, class FluidState>
460  void updateBoundary_(const Context&,
461  unsigned,
462  unsigned,
463  const FluidState&)
464  {}
465 
466 public:
467  using ScalarArray = Scalar[numPhases];
468 
469  static void update(ScalarArray&,
470  const IntensiveQuantities&,
471  const IntensiveQuantities&)
472  {}
473 
478  Scalar dispersivity() const
479  {
480  throw std::logic_error("The method dispersivity() does not "
481  "make sense if dispersion is disabled.");
482  }
483 
491  Scalar normVelocityAvg(unsigned) const
492  {
493  throw std::logic_error("The method normVelocityAvg() "
494  "does not make sense if dispersion is disabled.");
495  }
496 };
497 
501 template <class TypeTag>
502 class BlackOilDispersionExtensiveQuantities<TypeTag, /*enableDispersion=*/true>
503 {
506  using IntensiveQuantities = GetPropType<TypeTag, Properties::IntensiveQuantities>;
507 
508  enum { numPhases = getPropValue<TypeTag, Properties::NumPhases>() };
509 
510 public:
511  using ScalarArray = std::array<Scalar, numPhases>;
512  static void update(ScalarArray& normVelocityAvg,
513  const IntensiveQuantities& intQuantsInside,
514  const IntensiveQuantities& intQuantsOutside)
515  {
516  for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
517  if (!FluidSystem::phaseIsActive(phaseIdx)) {
518  continue;
519  }
520  // use the arithmetic average for the effective
521  // velocity coefficients at the face's integration point.
522  normVelocityAvg[phaseIdx] =
523  0.5 * (intQuantsInside.normVelocityCell(phaseIdx) +
524  intQuantsOutside.normVelocityCell(phaseIdx));
525  Valgrind::CheckDefined(normVelocityAvg[phaseIdx]);
526  }
527  }
528 
529 protected:
530  template <class Context, class FluidState>
531  void updateBoundary_(const Context&,
532  unsigned,
533  unsigned,
534  const FluidState&)
535  { throw std::runtime_error("Not implemented: Dispersion across boundary not implemented for blackoil"); }
536 
537 public:
544  Scalar dispersivity() const
545  { return dispersivity_; }
546 
554  Scalar normVelocityAvg(unsigned phaseIdx) const
555  { return normVelocityAvg_[phaseIdx]; }
556 
557  const auto& normVelocityAvg() const
558  { return normVelocityAvg_; }
559 
560 private:
561  Scalar dispersivity_;
562  ScalarArray normVelocityAvg_;
563 };
564 
565 } // namespace Opm
566 
567 #endif
void update_(ElementContext &, unsigned, unsigned)
Update the quantities required to calculate dispersive fluxes.
Definition: blackoildispersionmodule.hh:348
static void addDispersiveFlux(RateVector &flux, const Context &context, unsigned spaceIdx, unsigned timeIdx)
Adds the mass flux due to dispersion to the flux vector over the flux integration point...
Definition: blackoildispersionmodule.hh:151
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:233
static void addDispersiveFlux(RateVector &, const Context &, unsigned, unsigned)
Adds the dispersive flux to the flux vector over a flux integration point.
Definition: blackoildispersionmodule.hh:84
Defines the common properties required by the porous medium multi-phase models.
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: blackoilbioeffectsmodules.hh:45
Scalar dispersivity() const
The dispersivity of the face.
Definition: blackoildispersionmodule.hh:544
Declares the properties required by the black oil model.
Provides the quantities required to calculate dispersive mass fluxes.
Definition: blackoildispersionmodule.hh:502
Scalar normVelocityCell(unsigned, unsigned) const
Returns the max.
Definition: blackoildispersionmodule.hh:336
Declare the properties used by the infrastructure code of the finite volume discretizations.
static void addDispersiveFlux(RateVector &flux, const IntensiveQuantities &inIq, const IntensiveQuantities &exIq, const Evaluation &dispersivity, const Scalar &normVelocityAvg)
Adds the mass flux due to dispersion to the flux vector over the integration point.
Definition: blackoildispersionmodule.hh:187
Scalar dispersivity() const
The dispersivity the face.
Definition: blackoildispersionmodule.hh:478
void update_(const ElementContext &elemCtx, unsigned dofIdx, unsigned timeIdx)
Update the quantities required to calculate dispersive mass fluxes.
Definition: blackoildispersionmodule.hh:394
Provides the volumetric quantities required for the calculation of dispersive fluxes.
Definition: blackoildispersionmodule.hh:321
Definition: blackoildispersionmodule.hh:440
Provides the auxiliary methods required for consideration of the dispersion equation.
Definition: blackoildispersionmodule.hh:56
Scalar normVelocityCell(unsigned phaseIdx) const
Returns the max.
Definition: blackoildispersionmodule.hh:380
Scalar normVelocityAvg(unsigned) const
The effective filter velocity coefficient in a fluid phase at the face&#39;s integration point...
Definition: blackoildispersionmodule.hh:491
void update_(const ElementContext &, unsigned, unsigned)
Update the quantities required to calculate the dispersive fluxes.
Definition: blackoildispersionmodule.hh:454
Provides the quantities required to calculate dispersive mass fluxes.
Definition: blackoildispersionmodule.hh:59
Scalar normVelocityAvg(unsigned phaseIdx) const
The effective velocity coefficient in a fluid phase at the face&#39;s integration point.
Definition: blackoildispersionmodule.hh:554