77 using Toolbox = MathToolbox<Evaluation>;
79 using TabulatedFunction =
typename BlackOilPolymerParams<Scalar>::TabulatedFunction;
80 using TabulatedTwoDFunction =
typename BlackOilPolymerParams<Scalar>::TabulatedTwoDFunction;
82 static constexpr unsigned polymerConcentrationIdx = Indices::polymerConcentrationIdx;
83 static constexpr unsigned polymerMoleWeightIdx = Indices::polymerMoleWeightIdx;
84 static constexpr unsigned contiPolymerEqIdx = Indices::contiPolymerEqIdx;
85 static constexpr unsigned contiPolymerMolarWeightEqIdx = Indices::contiPolymerMWEqIdx;
86 static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
88 static constexpr unsigned enablePolymer = enablePolymerV;
105 const auto iterTable = params_.plymwinjTables_.find(tableNumber);
106 if (iterTable != params_.plymwinjTables_.end()) {
107 return iterTable->second;
110 throw std::runtime_error(
" the PLYMWINJ table " + std::to_string(tableNumber) +
" does not exist\n");
119 const auto iterTable = params_.skprwatTables_.find(tableNumber);
120 if (iterTable != params_.skprwatTables_.end()) {
121 return iterTable->second;
124 throw std::runtime_error(
" the SKPRWAT table " + std::to_string(tableNumber) +
" does not exist\n");
134 const auto iterTable = params_.skprpolyTables_.find(tableNumber);
135 if (iterTable != params_.skprpolyTables_.end()) {
136 return iterTable->second;
139 throw std::runtime_error(
" the SKPRPOLY table " + std::to_string(tableNumber) +
" does not exist\n");
148 if constexpr (enablePolymer) {
157 Simulator& simulator)
159 if constexpr (enablePolymer) {
164 static bool primaryVarApplies(
unsigned pvIdx)
166 if constexpr (enablePolymer) {
167 if constexpr (enablePolymerMolarWeight) {
168 return pvIdx == polymerConcentrationIdx || pvIdx == polymerMoleWeightIdx;
171 return pvIdx == polymerConcentrationIdx;
179 static std::string primaryVarName(
unsigned pvIdx)
181 assert(primaryVarApplies(pvIdx));
183 if (pvIdx == polymerConcentrationIdx) {
184 return "polymer_waterconcentration";
187 return "polymer_molecularweight";
191 static Scalar primaryVarWeight([[maybe_unused]]
unsigned pvIdx)
193 assert(primaryVarApplies(pvIdx));
196 return static_cast<Scalar
>(1.0);
199 static bool eqApplies(
unsigned eqIdx)
201 if constexpr (enablePolymer) {
202 if constexpr (enablePolymerMolarWeight) {
203 return eqIdx == contiPolymerEqIdx || eqIdx == contiPolymerMolarWeightEqIdx;
206 return eqIdx == contiPolymerEqIdx;
214 static std::string eqName(
unsigned eqIdx)
216 assert(eqApplies(eqIdx));
218 if (eqIdx == contiPolymerEqIdx) {
219 return "conti^polymer";
222 return "conti^polymer_molecularweight";
226 static Scalar eqWeight([[maybe_unused]]
unsigned eqIdx)
228 assert(eqApplies(eqIdx));
231 return static_cast<Scalar
>(1.0);
235 template <
class LhsEval>
236 static void addStorage(Dune::FieldVector<LhsEval, numEq>& storage,
237 const IntensiveQuantities& intQuants)
239 if constexpr (enablePolymer) {
240 const auto& fs = intQuants.fluidState();
243 const LhsEval surfaceVolumeWater =
244 max(Toolbox::template decay<LhsEval>(fs.saturation(waterPhaseIdx)) *
245 Toolbox::template decay<LhsEval>(fs.invB(waterPhaseIdx)) *
246 Toolbox::template decay<LhsEval>(intQuants.porosity()),
250 const LhsEval massPolymer =
252 Toolbox::template decay<LhsEval>(intQuants.polymerConcentration()) *
253 (1.0 - Toolbox::template decay<LhsEval>(intQuants.polymerDeadPoreVolume()));
256 const LhsEval adsorptionPolymer =
257 Toolbox::template decay<LhsEval>(1.0 - intQuants.porosity()) *
258 Toolbox::template decay<LhsEval>(intQuants.polymerRockDensity()) *
259 Toolbox::template decay<LhsEval>(intQuants.polymerAdsorption());
261 LhsEval accumulationPolymer = massPolymer + adsorptionPolymer;
263 storage[contiPolymerEqIdx] += accumulationPolymer;
266 if constexpr (enablePolymerMolarWeight) {
267 accumulationPolymer = max(accumulationPolymer, 1e-10);
269 storage[contiPolymerMolarWeightEqIdx] +=
270 accumulationPolymer * Toolbox::template decay<LhsEval>(intQuants.polymerMoleWeight());
275 static void computeFlux([[maybe_unused]] RateVector& flux,
276 [[maybe_unused]]
const ElementContext& elemCtx,
277 [[maybe_unused]]
unsigned scvfIdx,
278 [[maybe_unused]]
unsigned timeIdx)
280 if constexpr (enablePolymer) {
281 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
283 const unsigned upIdx = extQuants.upstreamIndex(FluidSystem::waterPhaseIdx);
284 const unsigned inIdx = extQuants.interiorIndex();
285 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
286 const unsigned contiWaterEqIdx =
287 Indices::conti0EqIdx + FluidSystem::canonicalToActiveCompIdx(FluidSystem::waterCompIdx);
289 if (upIdx == inIdx) {
290 flux[contiPolymerEqIdx] =
291 extQuants.volumeFlux(waterPhaseIdx) *
292 up.fluidState().invB(waterPhaseIdx) *
293 up.polymerViscosityCorrection() /
294 extQuants.polymerShearFactor() *
295 up.polymerConcentration();
298 flux[contiWaterEqIdx] /= extQuants.waterShearFactor();
301 flux[contiPolymerEqIdx] =
302 extQuants.volumeFlux(waterPhaseIdx) *
303 decay<Scalar>(up.fluidState().invB(waterPhaseIdx)) *
304 decay<Scalar>(up.polymerViscosityCorrection()) /
305 decay<Scalar>(extQuants.polymerShearFactor()) *
306 decay<Scalar>(up.polymerConcentration());
309 flux[contiWaterEqIdx] /= decay<Scalar>(extQuants.waterShearFactor());
313 if constexpr (enablePolymerMolarWeight) {
314 if (upIdx == inIdx) {
315 flux[contiPolymerMolarWeightEqIdx] =
316 flux[contiPolymerEqIdx] * up.polymerMoleWeight();
319 flux[contiPolymerMolarWeightEqIdx] =
320 flux[contiPolymerEqIdx] * decay<Scalar>(up.polymerMoleWeight());
335 return static_cast<Scalar
>(0.0);
338 template <
class DofEntity>
339 static void serializeEntity(
const Model& model, std::ostream& outstream,
const DofEntity& dof)
341 if constexpr (enablePolymer) {
342 const unsigned dofIdx = model.dofMapper().index(dof);
343 const PrimaryVariables& priVars = model.solution(0)[dofIdx];
344 outstream << priVars[polymerConcentrationIdx];
345 outstream << priVars[polymerMoleWeightIdx];
349 template <
class DofEntity>
350 static void deserializeEntity(Model& model, std::istream& instream,
const DofEntity& dof)
352 if constexpr (enablePolymer) {
353 const unsigned dofIdx = model.dofMapper().index(dof);
354 PrimaryVariables& priVars0 = model.solution(0)[dofIdx];
355 PrimaryVariables& priVars1 = model.solution(1)[dofIdx];
357 instream >> priVars0[polymerConcentrationIdx];
358 instream >> priVars0[polymerMoleWeightIdx];
361 priVars1[polymerConcentrationIdx] = priVars0[polymerConcentrationIdx];
362 priVars1[polymerMoleWeightIdx] = priVars0[polymerMoleWeightIdx];
366 static Scalar plyrockDeadPoreVolume(
const ElementContext& elemCtx,
370 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
371 return params_.plyrockDeadPoreVolume_[satnumRegionIdx];
374 static Scalar plyrockResidualResistanceFactor(
const ElementContext& elemCtx,
378 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
379 return params_.plyrockResidualResistanceFactor_[satnumRegionIdx];
382 static Scalar plyrockRockDensityFactor(
const ElementContext& elemCtx,
386 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
387 return params_.plyrockRockDensityFactor_[satnumRegionIdx];
390 static Scalar plyrockAdsorbtionIndex(
const ElementContext& elemCtx,
394 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
395 return params_.plyrockAdsorbtionIndex_[satnumRegionIdx];
398 static Scalar plyrockMaxAdsorbtion(
const ElementContext& elemCtx,
402 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
403 return params_.plyrockMaxAdsorbtion_[satnumRegionIdx];
406 static const TabulatedFunction&
407 plyadsAdsorbedPolymer(
const ElementContext& elemCtx,
411 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
412 return params_.plyadsAdsorbedPolymer_[satnumRegionIdx];
415 static const TabulatedFunction&
416 plyviscViscosityMultiplierTable(
const ElementContext& elemCtx,
420 unsigned pvtnumRegionIdx =
421 elemCtx.problem().pvtRegionIndex(elemCtx, scvIdx, timeIdx);
422 return params_.plyviscViscosityMultiplierTable_[pvtnumRegionIdx];
425 static const TabulatedFunction&
426 plyviscViscosityMultiplierTable(
unsigned pvtnumRegionIdx)
427 {
return params_.plyviscViscosityMultiplierTable_[pvtnumRegionIdx]; }
429 static Scalar plymaxMaxConcentration(
const ElementContext& elemCtx,
433 const unsigned polymerMixRegionIdx =
434 elemCtx.problem().plmixnumRegionIndex(elemCtx, scvIdx, timeIdx);
435 return params_.plymaxMaxConcentration_[polymerMixRegionIdx];
438 static Scalar plymixparToddLongstaff(
const ElementContext& elemCtx,
442 const unsigned polymerMixRegionIdx =
443 elemCtx.problem().plmixnumRegionIndex(elemCtx, scvIdx, timeIdx);
444 return params_.plymixparToddLongstaff_[polymerMixRegionIdx];
447 static const typename BlackOilPolymerParams<Scalar>::PlyvmhCoefficients&
448 plyvmhCoefficients(
const ElementContext& elemCtx,
449 const unsigned scvIdx,
450 const unsigned timeIdx)
452 const unsigned polymerMixRegionIdx =
453 elemCtx.problem().plmixnumRegionIndex(elemCtx, scvIdx, timeIdx);
454 return params_.plyvmhCoefficients_[polymerMixRegionIdx];
457 static bool hasPlyshlog()
458 {
return params_.hasPlyshlog_; }
460 static bool hasShrate()
461 {
return params_.hasShrate_; }
463 static Scalar shrate(
unsigned pvtnumRegionIdx)
464 {
return params_.shrate_[pvtnumRegionIdx]; }
472 template <
class Evaluation>
474 unsigned pvtnumRegionIdx,
475 const Evaluation& v0)
477 using ToolboxLocal = MathToolbox<Evaluation>;
479 const auto& viscosityMultiplierTable = params_.plyviscViscosityMultiplierTable_[pvtnumRegionIdx];
480 const Scalar viscosityMultiplier =
481 viscosityMultiplierTable.eval(scalarValue(polymerConcentration),
true);
483 const Scalar eps = 1e-14;
485 if (std::abs((viscosityMultiplier - 1.0)) < eps) {
486 return ToolboxLocal::createConstant(v0, 1.0);
489 const std::vector<Scalar>& shearEffectRefLogVelocity =
490 params_.plyshlogShearEffectRefLogVelocity_[pvtnumRegionIdx];
491 const auto v0AbsLog = log(abs(v0));
493 if (v0AbsLog < shearEffectRefLogVelocity[0]) {
494 return ToolboxLocal::createConstant(v0, 1.0);
501 const std::vector<Scalar>& shearEffectRefMultiplier =
502 params_.plyshlogShearEffectRefMultiplier_[pvtnumRegionIdx];
503 const std::size_t numTableEntries = shearEffectRefLogVelocity.size();
504 assert(shearEffectRefMultiplier.size() == numTableEntries);
506 std::vector<Scalar> shearEffectMultiplier(numTableEntries, 1.0);
507 for (std::size_t i = 0; i < numTableEntries; ++i) {
508 shearEffectMultiplier[i] = (1.0 + (viscosityMultiplier - 1.0) *
509 shearEffectRefMultiplier[i]) / viscosityMultiplier;
510 shearEffectMultiplier[i] = log(shearEffectMultiplier[i]);
514 const TabulatedFunction logShearEffectMultiplier =
515 TabulatedFunction(numTableEntries, shearEffectRefLogVelocity,
516 shearEffectMultiplier,
false);
523 auto F = [&logShearEffectMultiplier, &v0AbsLog](
const Evaluation& u) {
524 return u + logShearEffectMultiplier.eval(u,
true) - v0AbsLog;
527 auto dF = [&logShearEffectMultiplier](
const Evaluation& u) {
528 return 1 + logShearEffectMultiplier.evalDerivative(u,
true);
534 bool converged =
false;
536 for (
int i = 0; i < 20; ++i) {
538 const auto df = dF(u);
540 if (std::abs(scalarValue(f)) < 1e-12) {
546 throw std::runtime_error(
"Not able to compute shear velocity. \n");
550 return exp(logShearEffectMultiplier.eval(u,
true));
553 Scalar molarMass()
const
557 static BlackOilPolymerParams<Scalar> params_;