opm-simulators
blackoilextbomodules.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 */
32 #ifndef EWOMS_BLACK_OIL_EXTBO_MODULE_HH
33 #define EWOMS_BLACK_OIL_EXTBO_MODULE_HH
34 
35 #include <dune/common/fvector.hh>
36 
37 #include <opm/common/utility/gpuDecorators.hpp>
38 
42 
44 
46 
47 //#include <opm/models/io/vtkBlackOilExtboModule.hh> //TODO: Missing ...
48 
49 #include <cassert>
50 #include <cmath>
51 #include <istream>
52 #include <ostream>
53 #include <stdexcept>
54 #include <string>
55 
56 namespace Opm {
57 
63 template <class TypeTag>
64 class BlackOilExtboModule<TypeTag, true>
65 {
77 
78  using Toolbox = MathToolbox<Evaluation>;
79 
80  static constexpr unsigned zFractionIdx = Indices::zFractionIdx;
81  static constexpr unsigned contiZfracEqIdx = Indices::contiZfracEqIdx;
82  static constexpr bool enableExtbo = true;
83  static constexpr unsigned numEq = getPropValue<TypeTag, Properties::NumEq>();
84  static constexpr unsigned gasPhaseIdx = FluidSystem::gasPhaseIdx;
85  static constexpr unsigned oilPhaseIdx = FluidSystem::oilPhaseIdx;
86  static constexpr bool blackoilConserveSurfaceVolume =
87  getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>();
88 
89 public:
91  static void setParams(BlackOilExtboParams<Scalar>&& params)
92  {
93  params_ = params;
94  }
95 
99  static void registerParameters()
100  {}
101 
105  static void registerOutputModules(Model&,
106  Simulator&)
107  {}
108 
109  static bool primaryVarApplies(unsigned pvIdx)
110  {
111  return pvIdx == zFractionIdx;
112  }
113 
114  static std::string primaryVarName([[maybe_unused]] unsigned pvIdx)
115  {
116  assert(primaryVarApplies(pvIdx));
117 
118  return "z_fraction";
119  }
120 
121  static Scalar primaryVarWeight([[maybe_unused]] unsigned pvIdx)
122  {
123  assert(primaryVarApplies(pvIdx));
124 
125  // TODO: it may be beneficial to chose this differently.
126  return static_cast<Scalar>(1.0);
127  }
128 
129  static bool eqApplies(unsigned eqIdx)
130  {
131  return eqIdx == contiZfracEqIdx;
132  }
133 
134  static std::string eqName([[maybe_unused]] unsigned eqIdx)
135  {
136  assert(eqApplies(eqIdx));
137 
138  return "conti^solvent";
139  }
140 
141  static Scalar eqWeight([[maybe_unused]] unsigned eqIdx)
142  {
143  assert(eqApplies(eqIdx));
144 
145  // TODO: it may be beneficial to chose this differently.
146  return static_cast<Scalar>(1.0);
147  }
148 
149  template <class StorageType>
150  OPM_HOST_DEVICE static void addStorage(StorageType& storage,
151  const IntensiveQuantities& intQuants)
152  {
153  using LhsEval = typename StorageType::value_type;
154 
155  if constexpr (blackoilConserveSurfaceVolume) {
156  storage[contiZfracEqIdx] =
157  Toolbox::template decay<LhsEval>(intQuants.porosity()) *
158  Toolbox::template decay<LhsEval>(intQuants.yVolume()) *
159  Toolbox::template decay<LhsEval>(intQuants.fluidState().saturation(gasPhaseIdx)) *
160  Toolbox::template decay<LhsEval>(intQuants.fluidState().invB(gasPhaseIdx));
161  if (FluidSystem::enableDissolvedGas()) { // account for dissolved z in oil phase
162  storage[contiZfracEqIdx] +=
163  Toolbox::template decay<LhsEval>(intQuants.porosity()) *
164  Toolbox::template decay<LhsEval>(intQuants.xVolume()) *
165  Toolbox::template decay<LhsEval>(intQuants.fluidState().Rs()) *
166  Toolbox::template decay<LhsEval>(intQuants.fluidState().saturation(oilPhaseIdx)) *
167  Toolbox::template decay<LhsEval>(intQuants.fluidState().invB(oilPhaseIdx));
168  }
169  // Reg. terms: Preliminary attempt to avoid singular behaviour when solvent is invading a pure water
170  // region. Results seems insensitive to the weighting factor.
171  // TODO: Further investigations ...
172  const Scalar regWghtFactor = 1.0e-6;
173  storage[contiZfracEqIdx] +=
174  regWghtFactor* (1.0 - Toolbox::template decay<LhsEval>(intQuants.zFraction())) +
175  regWghtFactor*Toolbox::template decay<LhsEval>(intQuants.porosity()) *
176  Toolbox::template decay<LhsEval>(intQuants.fluidState().saturation(gasPhaseIdx)) *
177  Toolbox::template decay<LhsEval>(intQuants.fluidState().invB(gasPhaseIdx));
178  storage[contiZfracEqIdx - 1] += regWghtFactor*Toolbox::template decay<LhsEval>(intQuants.zFraction());
179  }
180  else {
181  OPM_THROW(std::runtime_error, "Only component conservation in terms of surface volumes is implemented. ");
182  }
183  }
184 
185  static void computeFlux(RateVector& flux,
186  const ElementContext& elemCtx,
187  unsigned scvfIdx,
188  unsigned timeIdx)
189  {
190  const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
191 
192  if constexpr (blackoilConserveSurfaceVolume) {
193  const unsigned inIdx = extQuants.interiorIndex();
194 
195  const unsigned upIdxGas = static_cast<unsigned>(extQuants.upstreamIndex(gasPhaseIdx));
196  const auto& upGas = elemCtx.intensiveQuantities(upIdxGas, timeIdx);
197  const auto& fsGas = upGas.fluidState();
198  if (upIdxGas == inIdx) {
199  flux[contiZfracEqIdx] =
200  extQuants.volumeFlux(gasPhaseIdx) *
201  upGas.yVolume() *
202  fsGas.invB(gasPhaseIdx);
203  }
204  else {
205  flux[contiZfracEqIdx] =
206  extQuants.volumeFlux(gasPhaseIdx) *
207  decay<Scalar>(upGas.yVolume()) *
208  decay<Scalar>(fsGas.invB(gasPhaseIdx));
209  }
210  if (FluidSystem::enableDissolvedGas()) { // account for dissolved z in oil phase
211  const unsigned upIdxOil = static_cast<unsigned>(extQuants.upstreamIndex(oilPhaseIdx));
212  const auto& upOil = elemCtx.intensiveQuantities(upIdxOil, timeIdx);
213  const auto& fsOil = upOil.fluidState();
214  if (upIdxOil == inIdx) {
215  flux[contiZfracEqIdx] +=
216  extQuants.volumeFlux(oilPhaseIdx) *
217  upOil.xVolume() *
218  fsOil.Rs() *
219  fsOil.invB(oilPhaseIdx);
220  }
221  else {
222  flux[contiZfracEqIdx] +=
223  extQuants.volumeFlux(oilPhaseIdx) *
224  decay<Scalar>(upOil.xVolume()) *
225  decay<Scalar>(fsOil.Rs()) *
226  decay<Scalar>(fsOil.invB(oilPhaseIdx));
227  }
228  }
229  }
230  else {
231  throw std::runtime_error("Only component conservation in terms of surface volumes is implemented. ");
232  }
233  }
234 
238  static void assignPrimaryVars(PrimaryVariables& priVars,
239  Scalar zFraction)
240  {
241  priVars[zFractionIdx] = zFraction;
242  }
243 
247  static void updatePrimaryVars(PrimaryVariables& newPv,
248  const PrimaryVariables& oldPv,
249  const EqVector& delta)
250  {
251  // do a plain unchopped Newton update
252  newPv[zFractionIdx] = oldPv[zFractionIdx] - delta[zFractionIdx];
253  }
254 
258  static Scalar computeUpdateError(const PrimaryVariables&,
259  const EqVector&)
260  {
261  // do not consider consider the cange of solvent primary variables for
262  // convergence
263  // TODO: maybe this should be changed
264  return static_cast<Scalar>(0.0);
265  }
266 
270  static Scalar computeResidualError(const EqVector& resid)
271  {
272  // do not weight the residual of solvents when it comes to convergence
273  return std::abs(Toolbox::scalarValue(resid[contiZfracEqIdx]));
274  }
275 
276  template <class DofEntity>
277  static void serializeEntity(const Model& model, std::ostream& outstream, const DofEntity& dof)
278  {
279  const unsigned dofIdx = model.dofMapper().index(dof);
280 
281  const PrimaryVariables& priVars = model.solution(/*timeIdx=*/0)[dofIdx];
282  outstream << priVars[zFractionIdx];
283  }
284 
285  template <class DofEntity>
286  static void deserializeEntity(Model& model, std::istream& instream, const DofEntity& dof)
287  {
288  const unsigned dofIdx = model.dofMapper().index(dof);
289 
290  PrimaryVariables& priVars0 = model.solution(/*timeIdx=*/0)[dofIdx];
291  PrimaryVariables& priVars1 = model.solution(/*timeIdx=*/1)[dofIdx];
292 
293  instream >> priVars0[zFractionIdx];
294 
295  // set the primary variables for the beginning of the current time step.
296  priVars1 = priVars0[zFractionIdx];
297  }
298 
299  template <typename Value>
300  static Value xVolume(unsigned pvtRegionIdx, const Value& pressure, const Value& z)
301  { return params_.X_[pvtRegionIdx].eval(z, pressure, true); }
302 
303  template <typename Value>
304  static Value yVolume(unsigned pvtRegionIdx, const Value& pressure, const Value& z)
305  { return params_.Y_[pvtRegionIdx].eval(z, pressure, true); }
306 
307  template <typename Value>
308  static Value pbubRs(unsigned pvtRegionIdx, const Value& z, const Value& rs)
309  { return params_.PBUB_RS_[pvtRegionIdx].eval(z, rs, true); }
310 
311  template <typename Value>
312  static Value pbubRv(unsigned pvtRegionIdx, const Value& z, const Value& rv)
313  { return params_.PBUB_RV_[pvtRegionIdx].eval(z, rv, true); }
314 
315  template <typename Value>
316  static Value oilViscosity(unsigned pvtRegionIdx, const Value& pressure, const Value& z)
317  { return params_.VISCO_[pvtRegionIdx].eval(z, pressure, true); }
318 
319  template <typename Value>
320  static Value gasViscosity(unsigned pvtRegionIdx, const Value& pressure, const Value& z)
321  { return params_.VISCG_[pvtRegionIdx].eval(z, pressure, true); }
322 
323  template <typename Value>
324  static Value bo(unsigned pvtRegionIdx, const Value& pressure, const Value& z)
325  { return params_.BO_[pvtRegionIdx].eval(z, pressure, true); }
326 
327  template <typename Value>
328  static Value bg(unsigned pvtRegionIdx, const Value& pressure, const Value& z)
329  { return params_.BG_[pvtRegionIdx].eval(z, pressure, true); }
330 
331  template <typename Value>
332  static Value rs(unsigned pvtRegionIdx, const Value& pressure, const Value& z)
333  { return params_.RS_[pvtRegionIdx].eval(z, pressure, true); }
334 
335  template <typename Value>
336  static Value rv(unsigned pvtRegionIdx, const Value& pressure, const Value& z)
337  { return params_.RV_[pvtRegionIdx].eval(z, pressure, true); }
338 
339  static Scalar referenceDensity(unsigned regionIdx)
340  { return params_.zReferenceDensity_[regionIdx]; }
341 
342  static Scalar zLim(unsigned regionIdx)
343  { return params_.zLim_[regionIdx]; }
344 
345  template <typename Value>
346  static Value oilCmp(unsigned pvtRegionIdx, const Value& z)
347  { return params_.oilCmp_[pvtRegionIdx].eval(z, true); }
348 
349  template <typename Value>
350  static Value gasCmp(unsigned pvtRegionIdx, const Value& z)
351  { return params_.gasCmp_[pvtRegionIdx].eval(z, true); }
352 
353 private:
354  static BlackOilExtboParams<Scalar> params_;
355 };
356 
357 template <class TypeTag>
358 BlackOilExtboParams<typename BlackOilExtboModule<TypeTag, true>::Scalar>
359 BlackOilExtboModule<TypeTag, true>::params_;
360 
368 template <class TypeTag>
369 class BlackOilExtboIntensiveQuantities<TypeTag, /*enableExtboV=*/true>
370 {
372 
379 
381 
382  static constexpr unsigned zFractionIdx = Indices::zFractionIdx;
383  static constexpr int oilPhaseIdx = FluidSystem::oilPhaseIdx;
384  static constexpr int gasPhaseIdx = FluidSystem::gasPhaseIdx;
385 
386 public:
392  void zFractionUpdate_(const ElementContext& elemCtx,
393  unsigned dofIdx,
394  unsigned timeIdx)
395  {
396  zFractionUpdate_(elemCtx.primaryVars(dofIdx, timeIdx), timeIdx);
397  }
398 
404  void zFractionUpdate_(const PrimaryVariables& priVars,
405  unsigned timeIdx)
406  {
407  const unsigned pvtRegionIdx = priVars.pvtRegionIndex();
408  const auto& fs = asImp_().fluidState_;
409 
410  zFraction_ = priVars.makeEvaluation(zFractionIdx, timeIdx);
411 
412  oilViscosity_ = ExtboModule::oilViscosity(pvtRegionIdx, fs.pressure(oilPhaseIdx), zFraction_);
413  gasViscosity_ = ExtboModule::gasViscosity(pvtRegionIdx, fs.pressure(gasPhaseIdx), zFraction_);
414 
415  bo_ = ExtboModule::bo(pvtRegionIdx, fs.pressure(oilPhaseIdx), zFraction_);
416  bg_ = ExtboModule::bg(pvtRegionIdx, fs.pressure(gasPhaseIdx), zFraction_);
417 
418  bz_ = ExtboModule::bg(pvtRegionIdx, fs.pressure(oilPhaseIdx), Evaluation{0.99});
419 
420  if (FluidSystem::enableDissolvedGas()) {
421  rs_ = ExtboModule::rs(pvtRegionIdx, fs.pressure(oilPhaseIdx), zFraction_);
422  }
423  else {
424  rs_ = 0.0;
425  }
426 
427  if (FluidSystem::enableVaporizedOil()) {
428  rv_ = ExtboModule::rv(pvtRegionIdx, fs.pressure(gasPhaseIdx), zFraction_);
429  }
430  else {
431  rv_ = 0.0;
432  }
433 
434  xVolume_ = ExtboModule::xVolume(pvtRegionIdx, fs.pressure(oilPhaseIdx), zFraction_);
435  yVolume_ = ExtboModule::yVolume(pvtRegionIdx, fs.pressure(oilPhaseIdx), zFraction_);
436 
437  Evaluation pbub = fs.pressure(oilPhaseIdx);
438 
439  if (priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Sw) {
440  static const Scalar thresholdWaterFilledCell = 1.0 - 1e-6;
441  Scalar sw = priVars.makeEvaluation(Indices::waterSwitchIdx, timeIdx).value();
442  if (sw >= thresholdWaterFilledCell) {
443  rs_ = 0.0; // water only, zero rs_ ...
444  }
445  }
446 
447  if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Rs) {
448  rs_ = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx);
449  const Evaluation zLim = ExtboModule::zLim(pvtRegionIdx);
450  if (zFraction_ > zLim) {
451  pbub = ExtboModule::pbubRs(pvtRegionIdx, zLim, rs_);
452  } else {
453  pbub = ExtboModule::pbubRs(pvtRegionIdx, zFraction_, rs_);
454  }
455  bo_ = ExtboModule::bo(pvtRegionIdx, pbub, zFraction_) +
456  ExtboModule::oilCmp(pvtRegionIdx, zFraction_) * (fs.pressure(oilPhaseIdx) - pbub);
457 
458  xVolume_ = ExtboModule::xVolume(pvtRegionIdx, pbub, zFraction_);
459  }
460 
461  if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Rv) {
462  rv_ = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx);
463  const Evaluation rvsat = ExtboModule::rv(pvtRegionIdx, pbub, zFraction_);
464  bg_ = ExtboModule::bg(pvtRegionIdx, pbub, zFraction_) +
465  ExtboModule::gasCmp(pvtRegionIdx, zFraction_) * (rv_ - rvsat);
466 
467  yVolume_ = ExtboModule::yVolume(pvtRegionIdx, pbub, zFraction_);
468  }
469  }
470 
476  void zPvtUpdate_()
477  {
478  const auto& iq = asImp_();
479  auto& fs = asImp_().fluidState_;
480 
481  const unsigned pvtRegionIdx = iq.pvtRegionIndex();
482  zRefDensity_ = ExtboModule::referenceDensity(pvtRegionIdx);
483 
484  fs.setInvB(oilPhaseIdx, 1.0 / bo_);
485  fs.setInvB(gasPhaseIdx, 1.0 / bg_);
486 
487  fs.setDensity(oilPhaseIdx,
488  fs.invB(oilPhaseIdx) *
489  (FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx) +
490  (1.0 - xVolume_) * fs.Rs() * FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx) +
491  xVolume_ * fs.Rs() * zRefDensity_));
492  fs.setDensity(gasPhaseIdx,
493  fs.invB(gasPhaseIdx) *
494  (FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx) *
495  (1.0 - yVolume_) + yVolume_* zRefDensity_ +
496  FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx) * fs.Rv()));
497  }
498 
499  const Evaluation& zFraction() const
500  { return zFraction_; }
501 
502  const Evaluation& xVolume() const
503  { return xVolume_; }
504 
505  const Evaluation& yVolume() const
506  { return yVolume_; }
507 
508  const Evaluation& oilViscosity() const
509  { return oilViscosity_; }
510 
511  const Evaluation& gasViscosity() const
512  { return gasViscosity_; }
513 
514  const Evaluation& bo() const
515  { return bo_; }
516 
517  const Evaluation& bg() const
518  { return bg_; }
519 
520  const Evaluation& rs() const
521  { return rs_; }
522 
523  const Evaluation& rv() const
524  { return rv_; }
525 
526  const Evaluation zPureInvFormationVolumeFactor() const
527  { return 1.0 / bz_; }
528 
529  Scalar zRefDensity() const
530  { return zRefDensity_; }
531 
532 protected:
533  Implementation& asImp_()
534  { return *static_cast<Implementation*>(this); }
535 
536  // Abstract "mass fraction" accounting for the solvent component. The relation between this
537  // quantity and the actual mass fraction of solvent, is implicitly defined from the specific
538  // pvt measurements as provided by kw PVTSOL.
539  Evaluation zFraction_;
540 
541  // The solvent component is assumed gas at surface conditions
542  Evaluation xVolume_; // Solvent volume fraction of Rs
543  Evaluation yVolume_; // Solvent volume fraction of Sg/Bg
544 
545  // Standard black oil parameters modified for presence of solvent
546  Evaluation oilViscosity_;
547  Evaluation gasViscosity_;
548  Evaluation bo_;
549  Evaluation bg_;
550  Evaluation rs_;
551  Evaluation rv_;
552 
553  // Properties of pure solvent
554  Evaluation bz_;
555  Scalar zRefDensity_;
556 };
557 
565 template <class TypeTag>
567 {
569 
570  Implementation& asImp_()
571  { return *static_cast<Implementation*>(this); }
572 };
573 
574 
575 } // namespace Opm
576 
577 #endif
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 registerOutputModules(Model &, Simulator &)
Register all solvent specific VTK and ECL output modules.
Definition: blackoilextbomodules.hh:105
static Scalar computeUpdateError(const PrimaryVariables &, const EqVector &)
Return how much a Newton-Raphson update is considered an error.
Definition: blackoilextbomodules.hh:258
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
Contains classes extending the black-oil model.
void zFractionUpdate_(const PrimaryVariables &priVars, unsigned timeIdx)
Compute extended pvt properties from table lookups.
Definition: blackoilextbomodules.hh:404
Declares the properties required by the black oil model.
static Scalar computeResidualError(const EqVector &resid)
Return how much a residual is considered an error.
Definition: blackoilextbomodules.hh:270
Declare the properties used by the infrastructure code of the finite volume discretizations.
static void assignPrimaryVars(PrimaryVariables &priVars, Scalar zFraction)
Assign the solvent specific primary variables to a PrimaryVariables object.
Definition: blackoilextbomodules.hh:238
static void setParams(BlackOilExtboParams< Scalar > &&params)
Set parameters.
Definition: blackoilextbomodules.hh:91
void zPvtUpdate_()
Re-compute face densities to account for zFraction dependency.
Definition: blackoilextbomodules.hh:476
Provides the solvent specific extensive quantities to the generic black-oil module&#39;s extensive quanti...
Struct holding the parameters for the BlackoilExtboModule class.
Definition: blackoilextboparams.hpp:46
Contains the parameters required to extend the black-oil model by solvent component.
Provides the volumetric quantities required for the equations needed by the solvents extension of the...
static void registerParameters()
Register all run-time parameters for the black-oil solvent module.
Definition: blackoilextbomodules.hh:99
void zFractionUpdate_(const ElementContext &elemCtx, unsigned dofIdx, unsigned timeIdx)
Compute extended pvt properties from table lookups.
Definition: blackoilextbomodules.hh:392
Defines a type tags and some fundamental properties all models.
static void updatePrimaryVars(PrimaryVariables &newPv, const PrimaryVariables &oldPv, const EqVector &delta)
Do a Newton-Raphson update the primary variables of the solvents.
Definition: blackoilextbomodules.hh:247
Contains the high level supplements required to extend the black oil model.
Definition: blackoilextbomodules.hh:64