78 using Toolbox = MathToolbox<Evaluation>;
80 using TabulatedFunction =
typename BlackOilPolymerParams<Scalar>::TabulatedFunction;
81 using TabulatedTwoDFunction =
typename BlackOilPolymerParams<Scalar>::TabulatedTwoDFunction;
83 static constexpr unsigned polymerConcentrationIdx = Indices::polymerConcentrationIdx;
84 static constexpr unsigned polymerMoleWeightIdx = Indices::polymerMoleWeightIdx;
85 static constexpr unsigned contiPolymerEqIdx = Indices::contiPolymerEqIdx;
86 static constexpr unsigned contiPolymerMolarWeightEqIdx = Indices::contiPolymerMWEqIdx;
87 static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
89 static constexpr unsigned enablePolymer = enablePolymerV;
106 const auto iterTable = params_.plymwinjTables_.find(tableNumber);
107 if (iterTable != params_.plymwinjTables_.end()) {
108 return iterTable->second;
111 throw std::runtime_error(
" the PLYMWINJ table " + std::to_string(tableNumber) +
" does not exist\n");
120 const auto iterTable = params_.skprwatTables_.find(tableNumber);
121 if (iterTable != params_.skprwatTables_.end()) {
122 return iterTable->second;
125 throw std::runtime_error(
" the SKPRWAT table " + std::to_string(tableNumber) +
" does not exist\n");
135 const auto iterTable = params_.skprpolyTables_.find(tableNumber);
136 if (iterTable != params_.skprpolyTables_.end()) {
137 return iterTable->second;
140 throw std::runtime_error(
" the SKPRPOLY table " + std::to_string(tableNumber) +
" does not exist\n");
149 if constexpr (enablePolymer) {
158 Simulator& simulator)
160 if constexpr (enablePolymer) {
165 static bool primaryVarApplies(
unsigned pvIdx)
167 if constexpr (enablePolymer) {
168 if constexpr (enablePolymerMolarWeight) {
169 return pvIdx == polymerConcentrationIdx || pvIdx == polymerMoleWeightIdx;
172 return pvIdx == polymerConcentrationIdx;
180 static std::string primaryVarName(
unsigned pvIdx)
182 assert(primaryVarApplies(pvIdx));
184 if (pvIdx == polymerConcentrationIdx) {
185 return "polymer_waterconcentration";
188 return "polymer_molecularweight";
192 static Scalar primaryVarWeight([[maybe_unused]]
unsigned pvIdx)
194 assert(primaryVarApplies(pvIdx));
197 return static_cast<Scalar
>(1.0);
200 static bool eqApplies(
unsigned eqIdx)
202 if constexpr (enablePolymer) {
203 if constexpr (enablePolymerMolarWeight) {
204 return eqIdx == contiPolymerEqIdx || eqIdx == contiPolymerMolarWeightEqIdx;
207 return eqIdx == contiPolymerEqIdx;
215 static std::string eqName(
unsigned eqIdx)
217 assert(eqApplies(eqIdx));
219 if (eqIdx == contiPolymerEqIdx) {
220 return "conti^polymer";
223 return "conti^polymer_molecularweight";
227 static Scalar eqWeight([[maybe_unused]]
unsigned eqIdx)
229 assert(eqApplies(eqIdx));
232 return static_cast<Scalar
>(1.0);
236 template <
class StorageType>
237 OPM_HOST_DEVICE
static void addStorage(StorageType& storage,
238 const IntensiveQuantities& intQuants)
240 using LhsEval =
typename StorageType::value_type;
242 if constexpr (enablePolymer) {
243 const auto& fs = intQuants.fluidState();
246 const LhsEval surfaceVolumeWater =
247 max(Toolbox::template decay<LhsEval>(fs.saturation(waterPhaseIdx)) *
248 Toolbox::template decay<LhsEval>(fs.invB(waterPhaseIdx)) *
249 Toolbox::template decay<LhsEval>(intQuants.porosity()),
253 const LhsEval massPolymer =
255 Toolbox::template decay<LhsEval>(intQuants.polymerConcentration()) *
256 (1.0 - Toolbox::template decay<LhsEval>(intQuants.polymerDeadPoreVolume()));
259 const LhsEval adsorptionPolymer =
260 Toolbox::template decay<LhsEval>(1.0 - intQuants.porosity()) *
261 Toolbox::template decay<LhsEval>(intQuants.polymerRockDensity()) *
262 Toolbox::template decay<LhsEval>(intQuants.polymerAdsorption());
264 LhsEval accumulationPolymer = massPolymer + adsorptionPolymer;
266 storage[contiPolymerEqIdx] += accumulationPolymer;
269 if constexpr (enablePolymerMolarWeight) {
270 accumulationPolymer = max(accumulationPolymer, 1e-10);
272 storage[contiPolymerMolarWeightEqIdx] +=
273 accumulationPolymer * Toolbox::template decay<LhsEval>(intQuants.polymerMoleWeight());
278 static void computeFlux([[maybe_unused]] RateVector& flux,
279 [[maybe_unused]]
const ElementContext& elemCtx,
280 [[maybe_unused]]
unsigned scvfIdx,
281 [[maybe_unused]]
unsigned timeIdx)
283 if constexpr (enablePolymer) {
284 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
286 const unsigned upIdx = extQuants.upstreamIndex(FluidSystem::waterPhaseIdx);
287 const unsigned inIdx = extQuants.interiorIndex();
288 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
289 const unsigned contiWaterEqIdx =
290 Indices::conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(FluidSystem::waterCompIdx);
292 if (upIdx == inIdx) {
293 flux[contiPolymerEqIdx] =
294 extQuants.volumeFlux(waterPhaseIdx) *
295 up.fluidState().invB(waterPhaseIdx) *
296 up.polymerViscosityCorrection() /
297 extQuants.polymerShearFactor() *
298 up.polymerConcentration();
301 flux[contiWaterEqIdx] /= extQuants.waterShearFactor();
304 flux[contiPolymerEqIdx] =
305 extQuants.volumeFlux(waterPhaseIdx) *
306 decay<Scalar>(up.fluidState().invB(waterPhaseIdx)) *
307 decay<Scalar>(up.polymerViscosityCorrection()) /
308 decay<Scalar>(extQuants.polymerShearFactor()) *
309 decay<Scalar>(up.polymerConcentration());
312 flux[contiWaterEqIdx] /= decay<Scalar>(extQuants.waterShearFactor());
316 if constexpr (enablePolymerMolarWeight) {
317 if (upIdx == inIdx) {
318 flux[contiPolymerMolarWeightEqIdx] =
319 flux[contiPolymerEqIdx] * up.polymerMoleWeight();
322 flux[contiPolymerMolarWeightEqIdx] =
323 flux[contiPolymerEqIdx] * decay<Scalar>(up.polymerMoleWeight());
338 return static_cast<Scalar
>(0.0);
341 template <
class DofEntity>
342 static void serializeEntity(
const Model& model, std::ostream& outstream,
const DofEntity& dof)
344 if constexpr (enablePolymer) {
345 const unsigned dofIdx = model.dofMapper().index(dof);
346 const PrimaryVariables& priVars = model.solution(0)[dofIdx];
347 outstream << priVars[polymerConcentrationIdx];
348 outstream << priVars[polymerMoleWeightIdx];
352 template <
class DofEntity>
353 static void deserializeEntity(Model& model, std::istream& instream,
const DofEntity& dof)
355 if constexpr (enablePolymer) {
356 const unsigned dofIdx = model.dofMapper().index(dof);
357 PrimaryVariables& priVars0 = model.solution(0)[dofIdx];
358 PrimaryVariables& priVars1 = model.solution(1)[dofIdx];
360 instream >> priVars0[polymerConcentrationIdx];
361 instream >> priVars0[polymerMoleWeightIdx];
364 priVars1[polymerConcentrationIdx] = priVars0[polymerConcentrationIdx];
365 priVars1[polymerMoleWeightIdx] = priVars0[polymerMoleWeightIdx];
369 static Scalar plyrockDeadPoreVolume(
const ElementContext& elemCtx,
373 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
374 return params_.plyrockDeadPoreVolume_[satnumRegionIdx];
377 static Scalar plyrockResidualResistanceFactor(
const ElementContext& elemCtx,
381 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
382 return params_.plyrockResidualResistanceFactor_[satnumRegionIdx];
385 static Scalar plyrockRockDensityFactor(
const ElementContext& elemCtx,
389 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
390 return params_.plyrockRockDensityFactor_[satnumRegionIdx];
393 static Scalar plyrockAdsorbtionIndex(
const ElementContext& elemCtx,
397 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
398 return params_.plyrockAdsorbtionIndex_[satnumRegionIdx];
401 static Scalar plyrockMaxAdsorbtion(
const ElementContext& elemCtx,
405 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
406 return params_.plyrockMaxAdsorbtion_[satnumRegionIdx];
409 static const TabulatedFunction&
410 plyadsAdsorbedPolymer(
const ElementContext& elemCtx,
414 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
415 return params_.plyadsAdsorbedPolymer_[satnumRegionIdx];
418 static const TabulatedFunction&
419 plyviscViscosityMultiplierTable(
const ElementContext& elemCtx,
423 unsigned pvtnumRegionIdx =
424 elemCtx.problem().pvtRegionIndex(elemCtx, scvIdx, timeIdx);
425 return params_.plyviscViscosityMultiplierTable_[pvtnumRegionIdx];
428 static const TabulatedFunction&
429 plyviscViscosityMultiplierTable(
unsigned pvtnumRegionIdx)
430 {
return params_.plyviscViscosityMultiplierTable_[pvtnumRegionIdx]; }
432 static Scalar plymaxMaxConcentration(
const ElementContext& elemCtx,
436 const unsigned polymerMixRegionIdx =
437 elemCtx.problem().plmixnumRegionIndex(elemCtx, scvIdx, timeIdx);
438 return params_.plymaxMaxConcentration_[polymerMixRegionIdx];
441 static Scalar plymixparToddLongstaff(
const ElementContext& elemCtx,
445 const unsigned polymerMixRegionIdx =
446 elemCtx.problem().plmixnumRegionIndex(elemCtx, scvIdx, timeIdx);
447 return params_.plymixparToddLongstaff_[polymerMixRegionIdx];
450 static const typename BlackOilPolymerParams<Scalar>::PlyvmhCoefficients&
451 plyvmhCoefficients(
const ElementContext& elemCtx,
452 const unsigned scvIdx,
453 const unsigned timeIdx)
455 const unsigned polymerMixRegionIdx =
456 elemCtx.problem().plmixnumRegionIndex(elemCtx, scvIdx, timeIdx);
457 return params_.plyvmhCoefficients_[polymerMixRegionIdx];
460 static bool hasPlyshlog()
461 {
return params_.hasPlyshlog_; }
463 static bool hasShrate()
464 {
return params_.hasShrate_; }
466 static Scalar shrate(
unsigned pvtnumRegionIdx)
467 {
return params_.shrate_[pvtnumRegionIdx]; }
475 template <
class Evaluation>
477 unsigned pvtnumRegionIdx,
478 const Evaluation& v0)
480 using ToolboxLocal = MathToolbox<Evaluation>;
482 const auto& viscosityMultiplierTable = params_.plyviscViscosityMultiplierTable_[pvtnumRegionIdx];
483 const Scalar viscosityMultiplier =
484 viscosityMultiplierTable.eval(scalarValue(polymerConcentration),
true);
486 const Scalar eps = 1e-14;
488 if (std::abs((viscosityMultiplier - 1.0)) < eps) {
489 return ToolboxLocal::createConstant(v0, 1.0);
492 const std::vector<Scalar>& shearEffectRefLogVelocity =
493 params_.plyshlogShearEffectRefLogVelocity_[pvtnumRegionIdx];
494 const auto v0AbsLog = log(abs(v0));
496 if (v0AbsLog < shearEffectRefLogVelocity[0]) {
497 return ToolboxLocal::createConstant(v0, 1.0);
504 const std::vector<Scalar>& shearEffectRefMultiplier =
505 params_.plyshlogShearEffectRefMultiplier_[pvtnumRegionIdx];
506 const std::size_t numTableEntries = shearEffectRefLogVelocity.size();
507 assert(shearEffectRefMultiplier.size() == numTableEntries);
509 std::vector<Scalar> shearEffectMultiplier(numTableEntries, 1.0);
510 for (std::size_t i = 0; i < numTableEntries; ++i) {
511 shearEffectMultiplier[i] = (1.0 + (viscosityMultiplier - 1.0) *
512 shearEffectRefMultiplier[i]) / viscosityMultiplier;
513 shearEffectMultiplier[i] = log(shearEffectMultiplier[i]);
517 const TabulatedFunction logShearEffectMultiplier =
518 TabulatedFunction(numTableEntries, shearEffectRefLogVelocity,
519 shearEffectMultiplier,
false);
526 auto F = [&logShearEffectMultiplier, &v0AbsLog](
const Evaluation& u) {
527 return u + logShearEffectMultiplier.eval(u,
true) - v0AbsLog;
530 auto dF = [&logShearEffectMultiplier](
const Evaluation& u) {
531 return 1 + logShearEffectMultiplier.evalDerivative(u,
true);
537 bool converged =
false;
539 for (
int i = 0; i < 20; ++i) {
541 const auto df = dF(u);
543 if (std::abs(scalarValue(f)) < 1e-12) {
549 throw std::runtime_error(
"Not able to compute shear velocity. \n");
553 return exp(logShearEffectMultiplier.eval(u,
true));
556 Scalar molarMass()
const
560 static BlackOilPolymerParams<Scalar> params_;