Updating MICP

This commit is contained in:
David Landa Marban committed 2025-04-02 22:19:01 +02:00
1 parent 292f571d22
commit ccc452f4d4
39 files changed
+1119 -550

No files matched your search

+13
View File
@@ -24,6 +24,8 @@
#include <opm/grid/CpGrid.hpp>
#include <opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp>
#include <opm/simulators/flow/Main.hpp>
#include <opm/models/blackoil/blackoillocalresidualtpfa.hh>
#include <opm/models/discretization/common/tpfalinearizer.hh>
namespace Opm {
namespace Properties {
@@ -36,6 +38,10 @@ template<class TypeTag>
struct EnableMICP<TypeTag, TTag::FlowMICPProblem> {
static constexpr bool value = true;
};
template<class TypeTag>
struct Linearizer<TypeTag, TTag::FlowMICPProblem> { using type = TpfaLinearizer<TypeTag>; };
template<class TypeTag>
struct LocalResidual<TypeTag, TTag::FlowMICPProblem> { using type = BlackOilLocalResidualTPFA<TypeTag>; };
//! The indices required by the model
template<class TypeTag>
struct Indices<TypeTag, TTag::FlowMICPProblem>
@@ -58,6 +64,13 @@ public:
/*enabledCompIdx=*/FluidSystem::waterCompIdx,
5>; //Five MICP components
};
template<class TypeTag>
struct EnableDiffusion<TypeTag, TTag::FlowMICPProblem> { static constexpr bool value = true; };
template<class TypeTag>
struct EnableDispersion<TypeTag, TTag::FlowMICPProblem> { static constexpr bool value = true; };
}}
namespace Opm {
@@ -512,6 +512,11 @@ public:
Scalar referencePorosity() const
{ return referencePorosity_; }
const Evaluation& permFactor() const
{
throw std::logic_error("permFactor() is not yet implemented for compositional modeling");
}
private:
friend BlackOilSolventIntensiveQuantities<TypeTag>;
friend BlackOilExtboIntensiveQuantities<TypeTag>;
+1 -1
View File
@@ -486,6 +486,6 @@ public:
};
} // namespace Ewoms
} // namespace Opm
#endif
+164 -106
View File
@@ -28,6 +28,7 @@
#ifndef OPM_BLACKOIL_DIFFUSION_MODULE_HH
#define OPM_BLACKOIL_DIFFUSION_MODULE_HH
#include <opm/models/blackoil/blackoilmicpmodules.hh>
#include <opm/models/discretization/common/fvbaseproperties.hh>
#include <opm/material/common/Valgrind.hpp>
@@ -100,11 +101,19 @@ class BlackOilDiffusionModule<TypeTag, /*enableDiffusion=*/true>
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Indices = GetPropType<TypeTag, Properties::Indices>;
using IntensiveQuantities = GetPropType<TypeTag, Properties::IntensiveQuantities>;
enum { numPhases = FluidSystem::numPhases };
enum { numComponents = FluidSystem::numComponents };
enum { conti0EqIdx = Indices::conti0EqIdx };
enum { enableMICP = getPropValue<TypeTag, Properties::EnableMICP>() };
static constexpr unsigned contiMicrobialEqIdx = Indices::contiMicrobialEqIdx;
static constexpr unsigned contiOxygenEqIdx = Indices::contiOxygenEqIdx;
static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
static constexpr unsigned contiUreaEqIdx = Indices::contiUreaEqIdx;
using Toolbox = MathToolbox<Evaluation>;
public:
@@ -157,86 +166,113 @@ public:
if(!FluidSystem::enableDiffusion())
return;
const auto& extQuants = context.extensiveQuantities(spaceIdx, timeIdx);
const auto& fluidStateI = context.intensiveQuantities(extQuants.interiorIndex(), timeIdx).fluidState();
const auto& fluidStateJ = context.intensiveQuantities(extQuants.exteriorIndex(), timeIdx).fluidState();
const auto& inIq = context.intensiveQuantities(extQuants.interiorIndex(), timeIdx);
const auto& exIq = context.intensiveQuantities(extQuants.exteriorIndex(), timeIdx);
const auto& diffusivity = extQuants.diffusivity();
const auto& effectiveDiffusionCoefficient = extQuants.effectiveDiffusionCoefficient();
addDiffusiveFlux(flux, fluidStateI, fluidStateJ, diffusivity, effectiveDiffusionCoefficient);
addDiffusiveFlux(flux, inIq, exIq, diffusivity, effectiveDiffusionCoefficient);
}
template<class FluidState,class EvaluationArray>
template<class IntensiveQuantities,class EvaluationArray>
static void addDiffusiveFlux(RateVector& flux,
const FluidState& fluidStateI,
const FluidState& fluidStateJ,
const IntensiveQuantities& inIq,
const IntensiveQuantities& exIq,
const Evaluation& diffusivity,
const EvaluationArray& effectiveDiffusionCoefficient)
{
unsigned pvtRegionIndex = fluidStateI.pvtRegionIndex();
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx)) {
continue;
}
const auto& inFs = inIq.fluidState();
const auto& exFs = exIq.fluidState();
Evaluation diffR = 0.0;
if constexpr(enableMICP) {
// The diffusion coefficients are given for mass concentrations (urea scaled by a factor of 10)
Evaluation bAvg = (inFs.invB(waterPhaseIdx) + Toolbox::value(exFs.invB(waterPhaseIdx))) / 2;
diffR = inIq.microbialConcentration() - Toolbox::value(exIq.microbialConcentration());
flux[contiMicrobialEqIdx] +=
bAvg
* diffR
* diffusivity
* effectiveDiffusionCoefficient[waterPhaseIdx][0];
diffR = inIq.oxygenConcentration() - Toolbox::value(exIq.oxygenConcentration());
flux[contiOxygenEqIdx] +=
bAvg
* diffR
* diffusivity
* effectiveDiffusionCoefficient[waterPhaseIdx][1];
diffR = inIq.ureaConcentration() - Toolbox::value(exIq.ureaConcentration());
// dividing by scaling factor 10 (see WellInterfaceGeneric.cpp)
flux[contiUreaEqIdx] +=
bAvg
* diffR
* diffusivity
* effectiveDiffusionCoefficient[waterPhaseIdx][2] / 10;
}
else {
unsigned pvtRegionIndex = inFs.pvtRegionIndex();
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx)) {
continue;
}
// no diffusion in water for blackoil models
if (!FluidSystem::enableDissolvedGasInWater() && FluidSystem::waterPhaseIdx == phaseIdx) {
continue;
}
// no diffusion in water for blackoil models
if (!FluidSystem::enableDissolvedGasInWater() && FluidSystem::waterPhaseIdx == phaseIdx) {
continue;
}
// no diffusion in gas phase in water + gas system.
if (FluidSystem::gasPhaseIdx == phaseIdx && !FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
continue;
}
// no diffusion in gas phase in water + gas system.
if (FluidSystem::gasPhaseIdx == phaseIdx && !FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
continue;
}
// arithmetic mean of the phase's b factor weighed by saturation
Evaluation bSAvg = fluidStateI.saturation(phaseIdx) * fluidStateI.invB(phaseIdx);
bSAvg += Toolbox::value(fluidStateJ.saturation(phaseIdx)) * Toolbox::value(fluidStateJ.invB(phaseIdx));
bSAvg /= 2;
// arithmetic mean of the phase's b factor weighed by saturation
Evaluation bSAvg = inFs.saturation(phaseIdx) * inFs.invB(phaseIdx);
bSAvg += Toolbox::value(exFs.saturation(phaseIdx)) * Toolbox::value(exFs.invB(phaseIdx));
bSAvg /= 2;
// phase not present, skip
if(bSAvg < 1.0e-6)
continue;
Evaluation convFactor = 1.0;
Evaluation diffR = 0.0;
if (FluidSystem::enableDissolvedGas() && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx) && phaseIdx == FluidSystem::oilPhaseIdx) {
Evaluation rsAvg = (fluidStateI.Rs() + Toolbox::value(fluidStateJ.Rs())) / 2;
convFactor = 1.0 / (toFractionGasOil(pvtRegionIndex) + rsAvg);
diffR = fluidStateI.Rs() - Toolbox::value(fluidStateJ.Rs());
}
if (FluidSystem::enableVaporizedOil() && FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) && phaseIdx == FluidSystem::gasPhaseIdx) {
Evaluation rvAvg = (fluidStateI.Rv() + Toolbox::value(fluidStateJ.Rv())) / 2;
convFactor = toFractionGasOil(pvtRegionIndex) / (1.0 + rvAvg*toFractionGasOil(pvtRegionIndex));
diffR = fluidStateI.Rv() - Toolbox::value(fluidStateJ.Rv());
}
if (FluidSystem::enableDissolvedGasInWater() && phaseIdx == FluidSystem::waterPhaseIdx) {
Evaluation rsAvg = (fluidStateI.Rsw() + Toolbox::value(fluidStateJ.Rsw())) / 2;
convFactor = 1.0 / (toFractionGasWater(pvtRegionIndex) + rsAvg);
diffR = fluidStateI.Rsw() - Toolbox::value(fluidStateJ.Rsw());
}
if (FluidSystem::enableVaporizedWater() && phaseIdx == FluidSystem::gasPhaseIdx) {
Evaluation rvAvg = (fluidStateI.Rvw() + Toolbox::value(fluidStateJ.Rvw())) / 2;
convFactor = toFractionGasWater(pvtRegionIndex)/ (1.0 + rvAvg*toFractionGasWater(pvtRegionIndex));
diffR = fluidStateI.Rvw() - Toolbox::value(fluidStateJ.Rvw());
}
// phase not present, skip
if(bSAvg < 1.0e-6)
continue;
Evaluation convFactor = 1.0;
if (FluidSystem::enableDissolvedGas() && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx) && phaseIdx == FluidSystem::oilPhaseIdx) {
Evaluation rsAvg = (inFs.Rs() + Toolbox::value(exFs.Rs())) / 2;
convFactor = 1.0 / (toFractionGasOil(pvtRegionIndex) + rsAvg);
diffR = inFs.Rs() - Toolbox::value(exFs.Rs());
}
if (FluidSystem::enableVaporizedOil() && FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) && phaseIdx == FluidSystem::gasPhaseIdx) {
Evaluation rvAvg = (inFs.Rv() + Toolbox::value(exFs.Rv())) / 2;
convFactor = toFractionGasOil(pvtRegionIndex) / (1.0 + rvAvg*toFractionGasOil(pvtRegionIndex));
diffR = inFs.Rv() - Toolbox::value(exFs.Rv());
}
if (FluidSystem::enableDissolvedGasInWater() && phaseIdx == FluidSystem::waterPhaseIdx) {
Evaluation rsAvg = (inFs.Rsw() + Toolbox::value(exFs.Rsw())) / 2;
convFactor = 1.0 / (toFractionGasWater(pvtRegionIndex) + rsAvg);
diffR = inFs.Rsw() - Toolbox::value(exFs.Rsw());
}
if (FluidSystem::enableVaporizedWater() && phaseIdx == FluidSystem::gasPhaseIdx) {
Evaluation rvAvg = (inFs.Rvw() + Toolbox::value(exFs.Rvw())) / 2;
convFactor = toFractionGasWater(pvtRegionIndex)/ (1.0 + rvAvg*toFractionGasWater(pvtRegionIndex));
diffR = inFs.Rvw() - Toolbox::value(exFs.Rvw());
}
// mass flux of solvent component (oil in oil or gas in gas)
unsigned solventCompIdx = FluidSystem::solventComponentIndex(phaseIdx);
unsigned activeSolventCompIdx = Indices::canonicalToActiveComponentIndex(solventCompIdx);
flux[conti0EqIdx + activeSolventCompIdx] +=
- bSAvg
* convFactor
* diffR
* diffusivity
* effectiveDiffusionCoefficient[phaseIdx][solventCompIdx];
// mass flux of solvent component (oil in oil or gas in gas)
unsigned solventCompIdx = FluidSystem::solventComponentIndex(phaseIdx);
unsigned activeSolventCompIdx = Indices::canonicalToActiveComponentIndex(solventCompIdx);
flux[conti0EqIdx + activeSolventCompIdx] +=
- bSAvg
* convFactor
* diffR
* diffusivity
* effectiveDiffusionCoefficient[phaseIdx][solventCompIdx];
// mass flux of solute component (gas in oil or oil in gas)
unsigned soluteCompIdx = FluidSystem::soluteComponentIndex(phaseIdx);
unsigned activeSoluteCompIdx = Indices::canonicalToActiveComponentIndex(soluteCompIdx);
flux[conti0EqIdx + activeSoluteCompIdx] +=
bSAvg
* diffR
* convFactor
* diffusivity
* effectiveDiffusionCoefficient[phaseIdx][soluteCompIdx];
// mass flux of solute component (gas in oil or oil in gas)
unsigned soluteCompIdx = FluidSystem::soluteComponentIndex(phaseIdx);
unsigned activeSoluteCompIdx = Indices::canonicalToActiveComponentIndex(soluteCompIdx);
flux[conti0EqIdx + activeSoluteCompIdx] +=
bSAvg
* diffR
* convFactor
* diffusivity
* effectiveDiffusionCoefficient[phaseIdx][soluteCompIdx];
}
}
}
@@ -339,8 +375,11 @@ class BlackOilDiffusionIntensiveQuantities<TypeTag, /*enableDiffusion=*/true>
using ElementContext = GetPropType<TypeTag, Properties::ElementContext>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using IntensiveQuantities = GetPropType<TypeTag, Properties::IntensiveQuantities>;
using MICPModule = BlackOilMICPModule<TypeTag>;
enum { numPhases = FluidSystem::numPhases };
enum { numComponents = FluidSystem::numComponents };
enum { enableMICP = getPropValue<TypeTag, Properties::EnableMICP>() };
static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
public:
BlackOilDiffusionIntensiveQuantities() = default;
@@ -418,34 +457,42 @@ protected:
const IntensiveQuantities& intQuants) {
using Toolbox = MathToolbox<Evaluation>;
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx)) {
continue;
}
if constexpr(enableMICP) {
unsigned pvtRegionIndex = intQuants.fluidState().pvtRegionIndex();
diffusionCoefficient_[waterPhaseIdx][0] = MICPModule::microbialDiffusion(pvtRegionIndex);
diffusionCoefficient_[waterPhaseIdx][1] = MICPModule::oxygenDiffusion(pvtRegionIndex);
diffusionCoefficient_[waterPhaseIdx][2] = MICPModule::ureaDiffusion(pvtRegionIndex);
}
else {
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx)) {
continue;
}
// no diffusion in water for blackoil models
if (!FluidSystem::enableDissolvedGasInWater() && FluidSystem::waterPhaseIdx == phaseIdx) {
continue;
}
// no diffusion in water for blackoil models
if (!FluidSystem::enableDissolvedGasInWater() && FluidSystem::waterPhaseIdx == phaseIdx) {
continue;
}
// Based on Millington, R. J., & Quirk, J. P. (1961).
// \Note: it is possible to use NumericalConstants later
// constexpr auto& numconst = GetPropValue<TypeTag, Properties::NumericalConstants>;
constexpr double myeps = 0.0001; //numconst.blackoildiffusionmoduleeps;
const Evaluation& base =
Toolbox::max(myeps, //0.0001,
intQuants.porosity()
* intQuants.fluidState().saturation(phaseIdx));
tortuosity_[phaseIdx] =
1.0 / (intQuants.porosity() * intQuants.porosity())
* Toolbox::pow(base, 10.0/3.0);
// Based on Millington, R. J., & Quirk, J. P. (1961).
// \Note: it is possible to use NumericalConstants later
// constexpr auto& numconst = GetPropValue<TypeTag, Properties::NumericalConstants>;
constexpr double myeps = 0.0001; //numconst.blackoildiffusionmoduleeps;
const Evaluation& base =
Toolbox::max(myeps, //0.0001,
intQuants.porosity()
* intQuants.fluidState().saturation(phaseIdx));
tortuosity_[phaseIdx] =
1.0 / (intQuants.porosity() * intQuants.porosity())
* Toolbox::pow(base, 10.0/3.0);
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
diffusionCoefficient_[phaseIdx][compIdx] =
FluidSystem::diffusionCoefficient(fluidState,
paramCache,
phaseIdx,
compIdx);
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
diffusionCoefficient_[phaseIdx][compIdx] =
FluidSystem::diffusionCoefficient(fluidState,
paramCache,
phaseIdx,
compIdx);
}
}
}
}
@@ -535,6 +582,8 @@ class BlackOilDiffusionExtensiveQuantities<TypeTag, /*enableDiffusion=*/true>
enum { dimWorld = GridView::dimensionworld };
enum { numPhases = getPropValue<TypeTag, Properties::NumPhases>() };
enum { numComponents = getPropValue<TypeTag, Properties::NumComponents>() };
enum { enableMICP = getPropValue<TypeTag, Properties::EnableMICP>() };
static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
using DimVector = Dune::FieldVector<Scalar, dimWorld>;
using DimEvalVector = Dune::FieldVector<Evaluation, dimWorld>;
@@ -569,21 +618,30 @@ public:
const IntensiveQuantities& intQuantsInside,
const IntensiveQuantities& intQuantsOutside) {
// opm-models expects per area flux
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx)) {
continue;
}
// no diffusion in water for blackoil models
if (!FluidSystem::enableDissolvedGasInWater() && FluidSystem::waterPhaseIdx == phaseIdx) {
continue;
}
// use the arithmetic average for the effective
// diffusion coefficients.
if constexpr(enableMICP) {
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
// use the arithmetic average for the effective
// diffusion coefficients.
effectiveDiffusionCoefficient[phaseIdx][compIdx] = 0.5 *
( intQuantsInside.effectiveDiffusionCoefficient(phaseIdx, compIdx) +
intQuantsOutside.effectiveDiffusionCoefficient(phaseIdx, compIdx) );
Valgrind::CheckDefined(effectiveDiffusionCoefficient[phaseIdx][compIdx]);
effectiveDiffusionCoefficient[waterPhaseIdx][compIdx] = 0.5 *
( intQuantsInside.effectiveDiffusionCoefficient(waterPhaseIdx, compIdx) +
intQuantsOutside.effectiveDiffusionCoefficient(waterPhaseIdx, compIdx) );
}
}
else {
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx)) {
continue;
}
// no diffusion in water for blackoil models
if (!FluidSystem::enableDissolvedGasInWater() && FluidSystem::waterPhaseIdx == phaseIdx) {
continue;
}
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
effectiveDiffusionCoefficient[phaseIdx][compIdx] = 0.5 *
( intQuantsInside.effectiveDiffusionCoefficient(phaseIdx, compIdx) +
intQuantsOutside.effectiveDiffusionCoefficient(phaseIdx, compIdx) );
Valgrind::CheckDefined(effectiveDiffusionCoefficient[phaseIdx][compIdx]);
}
}
}
}
@@ -608,7 +666,7 @@ public:
{ return diffusivity_; }
/*!
* \brief The effective diffusion coeffcient of a component in a
* \brief The effective diffusion coefficient of a component in a
* fluid phase at the face's integration point
*
* \copydoc Doxygen::phaseIdxParam
+106 -78
View File
@@ -62,6 +62,7 @@ class BlackOilDispersionModule<TypeTag, /*enableDispersion=*/false>
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Evaluation = GetPropType<TypeTag, Properties::Evaluation>;
using IntensiveQuantities = GetPropType<TypeTag, Properties::IntensiveQuantities>;
enum { numPhases = FluidSystem::numPhases };
@@ -85,10 +86,10 @@ public:
unsigned)
{}
template<class FluidState, class Scalar>
template<class IntensiveQuantities, class Scalar>
static void addDispersiveFlux(RateVector&,
const FluidState&,
const FluidState&,
const IntensiveQuantities&,
const IntensiveQuantities&,
const Evaluation&,
const Scalar&)
{}
@@ -116,6 +117,12 @@ class BlackOilDispersionModule<TypeTag, /*enableDispersion=*/true>
enum { numComponents = FluidSystem::numComponents };
enum { conti0EqIdx = Indices::conti0EqIdx };
enum { enableDispersion = getPropValue<TypeTag, Properties::EnableDispersion>() };
enum { enableMICP = getPropValue<TypeTag, Properties::EnableMICP>() };
static constexpr unsigned contiMicrobialEqIdx = Indices::contiMicrobialEqIdx;
static constexpr unsigned contiOxygenEqIdx = Indices::contiOxygenEqIdx;
static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
static constexpr unsigned contiUreaEqIdx = Indices::contiUreaEqIdx;
using Toolbox = MathToolbox<Evaluation>;
@@ -148,11 +155,11 @@ public:
return;
}
const auto& extQuants = context.extensiveQuantities(spaceIdx, timeIdx);
const auto& fluidStateI = context.intensiveQuantities(extQuants.interiorIndex(), timeIdx).fluidState();
const auto& fluidStateJ = context.intensiveQuantities(extQuants.exteriorIndex(), timeIdx).fluidState();
const auto& inIq = context.intensiveQuantities(extQuants.interiorIndex(), timeIdx);
const auto& exIq = context.intensiveQuantities(extQuants.exteriorIndex(), timeIdx);
const auto& dispersivity = extQuants.dispersivity();
const auto& normVelocityAvg = extQuants.normVelocityAvg();
addDispersiveFlux(flux, fluidStateI, fluidStateJ, dispersivity, normVelocityAvg);
addDispersiveFlux(flux, inIq, exIq, dispersivity, normVelocityAvg);
}
/*!
@@ -175,86 +182,105 @@ public:
* \f$D_{ij}\f$ is computed in ecltransmissibility_impl.hh, using the dispersion coefficients \f$E_i\f$
* and \f$E_j\f$.
*/
template<class FluidState, class Scalar>
template<class IntensiveQuantities, class Scalar>
static void addDispersiveFlux(RateVector& flux,
const FluidState& fluidStateI,
const FluidState& fluidStateJ,
const IntensiveQuantities& inIq,
const IntensiveQuantities& exIq,
const Evaluation& dispersivity,
const Scalar& normVelocityAvg)
{
unsigned pvtRegionIndex = fluidStateI.pvtRegionIndex();
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx)) {
continue;
}
const auto& inFs = inIq.fluidState();
const auto& exFs = exIq.fluidState();
Evaluation diffR = 0.0;
if constexpr(enableMICP) {
// The dispersion coefficients are given for mass concentrations
Evaluation bAvg = (inFs.invB(waterPhaseIdx) + Toolbox::value(exFs.invB(waterPhaseIdx))) / 2;
diffR = inIq.microbialConcentration()- Toolbox::value(exIq.microbialConcentration());
flux[contiMicrobialEqIdx] +=
bAvg
* normVelocityAvg[waterPhaseIdx]
* dispersivity
* diffR;
diffR = inIq.oxygenConcentration()- Toolbox::value(exIq.oxygenConcentration());
flux[contiOxygenEqIdx] +=
bAvg
* normVelocityAvg[waterPhaseIdx]
* dispersivity
* diffR;
diffR = inIq.ureaConcentration()- Toolbox::value(exIq.ureaConcentration());
// dividing by scaling factor 10 (see WellInterfaceGeneric.cpp)
flux[contiUreaEqIdx] +=
bAvg
* normVelocityAvg[waterPhaseIdx]
* dispersivity
* diffR / 10;
}
else {
unsigned pvtRegionIndex = inFs.pvtRegionIndex();
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx)) {
continue;
}
// no dispersion in water for blackoil models unless water can contain dissolved gas
if (!FluidSystem::enableDissolvedGasInWater() && FluidSystem::waterPhaseIdx == phaseIdx) {
continue;
}
// no dispersion in water for blackoil models unless water can contain dissolved gas
if (!FluidSystem::enableDissolvedGasInWater() && FluidSystem::waterPhaseIdx == phaseIdx) {
continue;
}
// Adding dispersion in the gas phase leads to
// convergence issues and unphysical results.
// We disable dispersion in the gas phase for now
// See comment below
if (FluidSystem::gasPhaseIdx == phaseIdx) {
continue;
}
// adding dispersion in the gas phase leads to
// convergence issues and unphysical results.
// we disable dispersion in the gas phase for now
if (FluidSystem::gasPhaseIdx == phaseIdx) {
continue;
}
// no dispersion in gas for blackoil models unless gas can contain evaporated water or oil
// phase check disabled due to if above, reenable when removing unconditional gas phase disablement
if ((!FluidSystem::enableVaporizedWater() && !FluidSystem::enableVaporizedOil())
/*&& FluidSystem::gasPhaseIdx == phaseIdx*/) {
continue;
}
// arithmetic mean of the phase's b factor
Evaluation bAvg = inFs.invB(phaseIdx);
bAvg += Toolbox::value(exFs.invB(phaseIdx));
bAvg /= 2;
// arithmetic mean of the phase's b factor
Evaluation bAvg = fluidStateI.invB(phaseIdx);
bAvg += Toolbox::value(fluidStateJ.invB(phaseIdx));
bAvg /= 2;
Evaluation convFactor = 1.0;
if (FluidSystem::enableDissolvedGas() && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx) && phaseIdx == FluidSystem::oilPhaseIdx) {
Evaluation rsAvg = (inFs.Rs() + Toolbox::value(exFs.Rs())) / 2;
convFactor = 1.0 / (toMassFractionGasOil(pvtRegionIndex) + rsAvg);
diffR = inFs.Rs() - Toolbox::value(exFs.Rs());
}
if (FluidSystem::enableVaporizedOil() && FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) && phaseIdx == FluidSystem::gasPhaseIdx) {
Evaluation rvAvg = (inFs.Rv() + Toolbox::value(exFs.Rv())) / 2;
convFactor = toMassFractionGasOil(pvtRegionIndex) / (1.0 + rvAvg*toMassFractionGasOil(pvtRegionIndex));
diffR = inFs.Rv() - Toolbox::value(exFs.Rv());
}
if (FluidSystem::enableDissolvedGasInWater() && phaseIdx == FluidSystem::waterPhaseIdx) {
Evaluation rsAvg = (inFs.Rsw() + Toolbox::value(exFs.Rsw())) / 2;
convFactor = 1.0 / (toMassFractionGasWater(pvtRegionIndex) + rsAvg);
diffR = inFs.Rsw() - Toolbox::value(exFs.Rsw());
}
if (FluidSystem::enableVaporizedWater() && phaseIdx == FluidSystem::gasPhaseIdx) {
Evaluation rvAvg = (inFs.Rvw() + Toolbox::value(exFs.Rvw())) / 2;
convFactor = toMassFractionGasWater(pvtRegionIndex)/ (1.0 + rvAvg*toMassFractionGasWater(pvtRegionIndex));
diffR = inFs.Rvw() - Toolbox::value(exFs.Rvw());
}
Evaluation convFactor = 1.0;
Evaluation diffR = 0.0;
if (FluidSystem::enableDissolvedGas() && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx) && phaseIdx == FluidSystem::oilPhaseIdx) {
Evaluation rsAvg = (fluidStateI.Rs() + Toolbox::value(fluidStateJ.Rs())) / 2;
convFactor = 1.0 / (toMassFractionGasOil(pvtRegionIndex) + rsAvg);
diffR = fluidStateI.Rs() - Toolbox::value(fluidStateJ.Rs());
}
if (FluidSystem::enableVaporizedOil() && FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) && phaseIdx == FluidSystem::gasPhaseIdx) {
Evaluation rvAvg = (fluidStateI.Rv() + Toolbox::value(fluidStateJ.Rv())) / 2;
convFactor = toMassFractionGasOil(pvtRegionIndex) / (1.0 + rvAvg*toMassFractionGasOil(pvtRegionIndex));
diffR = fluidStateI.Rv() - Toolbox::value(fluidStateJ.Rv());
}
if (FluidSystem::enableDissolvedGasInWater() && phaseIdx == FluidSystem::waterPhaseIdx) {
Evaluation rsAvg = (fluidStateI.Rsw() + Toolbox::value(fluidStateJ.Rsw())) / 2;
convFactor = 1.0 / (toMassFractionGasWater(pvtRegionIndex) + rsAvg);
diffR = fluidStateI.Rsw() - Toolbox::value(fluidStateJ.Rsw());
}
if (FluidSystem::enableVaporizedWater() && phaseIdx == FluidSystem::gasPhaseIdx) {
Evaluation rvAvg = (fluidStateI.Rvw() + Toolbox::value(fluidStateJ.Rvw())) / 2;
convFactor = toMassFractionGasWater(pvtRegionIndex)/ (1.0 + rvAvg*toMassFractionGasWater(pvtRegionIndex));
diffR = fluidStateI.Rvw() - Toolbox::value(fluidStateJ.Rvw());
}
// mass flux of solvent component
unsigned solventCompIdx = FluidSystem::solventComponentIndex(phaseIdx);
unsigned activeSolventCompIdx = Indices::canonicalToActiveComponentIndex(solventCompIdx);
flux[conti0EqIdx + activeSolventCompIdx] +=
- bAvg
* normVelocityAvg[phaseIdx]
* convFactor
* dispersivity
* diffR;
// mass flux of solvent component
unsigned solventCompIdx = FluidSystem::solventComponentIndex(phaseIdx);
unsigned activeSolventCompIdx = Indices::canonicalToActiveComponentIndex(solventCompIdx);
flux[conti0EqIdx + activeSolventCompIdx] +=
- bAvg
* normVelocityAvg[phaseIdx]
* convFactor
* dispersivity
* diffR;
// mass flux of solute component
unsigned soluteCompIdx = FluidSystem::soluteComponentIndex(phaseIdx);
unsigned activeSoluteCompIdx = Indices::canonicalToActiveComponentIndex(soluteCompIdx);
flux[conti0EqIdx + activeSoluteCompIdx] +=
bAvg
* normVelocityAvg[phaseIdx]
* convFactor
* dispersivity
* diffR;
// mass flux of solute component
unsigned soluteCompIdx = FluidSystem::soluteComponentIndex(phaseIdx);
unsigned activeSoluteCompIdx = Indices::canonicalToActiveComponentIndex(soluteCompIdx);
flux[conti0EqIdx + activeSoluteCompIdx] +=
bAvg
* normVelocityAvg[phaseIdx]
* convFactor
* dispersivity
* diffR;
}
}
}
@@ -498,8 +524,10 @@ public:
if (!FluidSystem::enableDissolvedGasInWater() && FluidSystem::waterPhaseIdx == phaseIdx) {
continue;
}
// no dispersion in gas for blackoil models unless gas can contain evaporated water or oil
if ((!FluidSystem::enableVaporizedWater() && !FluidSystem::enableVaporizedOil()) && FluidSystem::gasPhaseIdx == phaseIdx) {
// adding dispersion in the gas phase leads to
// convergence issues and unphysical results.
// we disable dispersion in the gas phase for now
if (FluidSystem::gasPhaseIdx == phaseIdx) {
continue;
}
// use the arithmetic average for the effective
+16 -16
View File
@@ -147,24 +147,24 @@ struct BlackOilIndices
numPolymers > 1 ? polymerConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the first MICP component
static constexpr int microbialConcentrationIdx =
static constexpr int biofilmConcentrationIdx =
enableMICP ? PVOffset + numPhases + numSolvents : -1000;
//! Index of the primary variable for the second MICP component
static constexpr int oxygenConcentrationIdx =
numMICPs > 1 ? microbialConcentrationIdx + 1 : -1000;
static constexpr int microbialConcentrationIdx =
numMICPs > 1 ? biofilmConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the third MICP component
static constexpr int ureaConcentrationIdx =
numMICPs > 2 ? oxygenConcentrationIdx + 1 : -1000;
static constexpr int oxygenConcentrationIdx =
numMICPs > 2 ? microbialConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the fourth MICP component
static constexpr int biofilmConcentrationIdx =
numMICPs > 3 ? ureaConcentrationIdx + 1 : -1000;
static constexpr int ureaConcentrationIdx =
numMICPs > 3 ? oxygenConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the fifth MICP component
static constexpr int calciteConcentrationIdx =
numMICPs > 4 ? biofilmConcentrationIdx + 1 : -1000;
numMICPs > 4 ? ureaConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the foam
static constexpr int foamConcentrationIdx =
@@ -204,24 +204,24 @@ struct BlackOilIndices
numPolymers > 1 ? contiPolymerEqIdx + 1 : -1000;
//! Index of the continuity equation for the first MICP component
static constexpr int contiMicrobialEqIdx =
static constexpr int contiBiofilmEqIdx =
enableMICP ? PVOffset + numPhases + numSolvents + numExtbos : -1000;
//! Index of the continuity equation for the second MICP component
static constexpr int contiOxygenEqIdx =
numMICPs > 1 ? contiMicrobialEqIdx + 1 : -1000;
static constexpr int contiMicrobialEqIdx =
numMICPs > 1 ? contiBiofilmEqIdx + 1 : -1000;
//! Index of the continuity equation for the third MICP component
static constexpr int contiUreaEqIdx =
numMICPs > 2 ? contiOxygenEqIdx + 1 : -1000;
static constexpr int contiOxygenEqIdx =
numMICPs > 2 ? contiMicrobialEqIdx + 1 : -1000;
//! Index of the continuity equation for the fourth MICP component
static constexpr int contiBiofilmEqIdx =
numMICPs > 3 ? contiUreaEqIdx + 1 : -1000;
static constexpr int contiUreaEqIdx =
numMICPs > 3 ? contiOxygenEqIdx + 1 : -1000;
//! Index of the continuity equation for the fifth MICP component
static constexpr int contiCalciteEqIdx =
numMICPs > 4 ? contiBiofilmEqIdx + 1 : -1000;
numMICPs > 4 ? contiUreaEqIdx + 1 : -1000;
//! Index of the continuity equation for the foam component
static constexpr int contiFoamEqIdx =
@@ -129,6 +129,8 @@ class BlackOilIntensiveQuantities
using DirectionalMobilityPtr = Opm::Utility::CopyablePtr<DirectionalMobility<TypeTag, Evaluation>>;
using BrineModule = BlackOilBrineModule<TypeTag>;
using BrineIntQua = BlackOilBrineIntensiveQuantities<TypeTag, enableSaltPrecipitation>;
using MICPIntQua = BlackOilMICPIntensiveQuantities<TypeTag, enableMICP>;
public:
@@ -506,11 +508,11 @@ public:
// deal with water induced rock compaction
porosity_ *= problem.template rockCompPoroMultiplier<Evaluation>(*this, globalSpaceIdx);
// the MICP processes change the porosity
// deal with MICP
if constexpr (enableMICP){
Evaluation biofilm_ = priVars.makeEvaluation(Indices::biofilmConcentrationIdx, timeIdx, linearizationType);
Evaluation calcite_ = priVars.makeEvaluation(Indices::calciteConcentrationIdx, timeIdx, linearizationType);
porosity_ += - biofilm_ - calcite_;
Evaluation biofilm_ = priVars.makeEvaluation(Indices::biofilmConcentrationIdx, timeIdx, linearizationType);
Evaluation calcite_ = priVars.makeEvaluation(Indices::calciteConcentrationIdx, timeIdx, linearizationType);
porosity_ += max(- biofilm_ - calcite_, -referencePorosity_+1e-8);
}
// deal with salt-precipitation
@@ -692,6 +694,15 @@ public:
Scalar referencePorosity() const
{ return referencePorosity_; }
const Evaluation& permFactor() const
{
if constexpr (enableMICP)
return MICPIntQua::permFactor();
if constexpr (enableSaltPrecipitation)
return BrineIntQua::permFactor();
throw std::logic_error("permFactor() called but salt precipitation or MICP are disabled");
}
private:
friend BlackOilSolventIntensiveQuantities<TypeTag>;
friend BlackOilExtboIntensiveQuantities<TypeTag>;
@@ -372,7 +372,10 @@ public:
const IntensiveQuantities& up = (upIdx == interiorDofIdx) ? intQuantsIn : intQuantsEx;
unsigned globalUpIndex = (upIdx == interiorDofIdx) ? globalIndexIn : globalIndexEx;
// Use arithmetic average (more accurate with harmonic, but that requires recomputing the transmissbility)
const Evaluation transMult = (intQuantsIn.rockCompTransMultiplier() + Toolbox::value(intQuantsEx.rockCompTransMultiplier()))/2;
Evaluation transMult = (intQuantsIn.rockCompTransMultiplier() + Toolbox::value(intQuantsEx.rockCompTransMultiplier()))/2;
if constexpr (enableMICP) {
transMult *= (intQuantsIn.permFactor() + Toolbox::value(intQuantsEx.permFactor()))/2;
}
Evaluation darcyFlux;
if (globalUpIndex == globalIndexIn) {
darcyFlux = pressureDifference * up.mobility(phaseIdx, facedir) * transMult * (-trans / faceArea);
@@ -396,6 +399,10 @@ public:
EnergyModule::template addPhaseEnthalpyFluxes_<Evaluation, Evaluation, FluidState>(
flux, phaseIdx, darcyFlux, up.fluidState());
}
if constexpr (enableMICP) {
MICPModule::template addMICPFluxes_<Evaluation, Evaluation, IntensiveQuantities>(
flux, darcyFlux, intQuantsIn);
}
} else {
const auto& invB = getInvB_<FluidSystem, FluidState, Scalar>(up.fluidState(), phaseIdx, pvtRegionIdx);
const auto& surfaceVolumeFlux = invB * darcyFlux;
@@ -406,6 +413,11 @@ public:
addPhaseEnthalpyFluxes_<Scalar, Evaluation, FluidState>
(flux,phaseIdx,darcyFlux, up.fluidState());
}
if constexpr (enableMICP) {
MICPModule::template
addMICPFluxes_<Scalar, Evaluation, IntensiveQuantities>
(flux, darcyFlux, intQuantsEx);
}
}
}
@@ -478,8 +490,8 @@ public:
const Scalar diffusivity = nbInfo.diffusivity;
const Scalar tmpdiffusivity = diffusivity / faceArea;
DiffusionModule::addDiffusiveFlux(flux,
intQuantsIn.fluidState(),
intQuantsEx.fluidState(),
intQuantsIn,
intQuantsEx,
tmpdiffusivity,
effectiveDiffusionCoefficient);
@@ -491,16 +503,12 @@ public:
const Scalar dispersivity = nbInfo.dispersivity;
const Scalar tmpdispersivity = dispersivity / faceArea;
DispersionModule::addDispersiveFlux(flux,
intQuantsIn.fluidState(),
intQuantsEx.fluidState(),
intQuantsIn,
intQuantsEx,
tmpdispersivity,
normVelocityAvg);
}
// deal with micp (if present)
static_assert(!enableMICP, "Relevant computeFlux() method must be implemented for this module before enabling.");
// MICPModule::computeFlux(flux, elemCtx, scvfIdx, timeIdx);
}
template <class BoundaryConditionData>
@@ -612,7 +620,7 @@ public:
// conductive heat flux from boundary
if constexpr(enableEnergy){
Evaluation heatFlux;
// avoid overload of functions with same numeber of elements in eclproblem
// avoid overload of functions with same number of elements in eclproblem
Scalar alpha = problem.eclTransmissibilities().thermalHalfTransBoundary(globalSpaceIdx, bdyInfo.boundaryFaceIndex);
unsigned inIdx = 0;//dummy
// always calculated with derivatives of this cell
@@ -627,7 +635,7 @@ public:
static_assert(!enableSolvent, "Relevant treatment of boundary conditions must be implemented before enabling.");
static_assert(!enablePolymer, "Relevant treatment of boundary conditions must be implemented before enabling.");
static_assert(!enableMICP, "Relevant treatment of boundary conditions must be implemented before enabling.");
//static_assert(!enableMICP, "Relevant treatment of boundary conditions must be implemented before enabling.");
// make sure that the right mass conservation quantities are used
adaptMassConservationQuantities_(bdyFlux, insideIntQuants.pvtRegionIndex());
@@ -677,6 +685,7 @@ public:
static void computeSource(RateVector& source,
const Problem& problem,
const IntensiveQuantities& insideIntQuants,
unsigned globalSpaceIdex,
unsigned timeIdx)
{
@@ -685,9 +694,7 @@ public:
problem.source(source, globalSpaceIdex, timeIdx);
// deal with MICP (if present)
// deal with micp (if present)
static_assert(!enableMICP, "Relevant addSource() method must be implemented for this module before enabling.");
// MICPModule::addSource(source, elemCtx, dofIdx, timeIdx);
MICPModule::addSource(source, problem, insideIntQuants, globalSpaceIdex);
// scale the source term of the energy equation
if (enableEnergy)
@@ -696,6 +703,7 @@ public:
static void computeSourceDense(RateVector& source,
const Problem& problem,
const IntensiveQuantities& insideIntQuants,
unsigned globalSpaceIdex,
unsigned timeIdx)
{
@@ -703,9 +711,7 @@ public:
problem.addToSourceDense(source, globalSpaceIdex, timeIdx);
// deal with MICP (if present)
// deal with micp (if present)
static_assert(!enableMICP, "Relevant addSource() method must be implemented for this module before enabling.");
// MICPModule::addSource(source, elemCtx, dofIdx, timeIdx);
MICPModule::addSource(source, problem, insideIntQuants, globalSpaceIdex);
// scale the source term of the energy equation
if (enableEnergy)
+212 -184
View File
@@ -25,8 +25,8 @@
*
* \brief Contains the classes required to extend the black-oil model by MICP.
*/
#ifndef EWOMS_BLACK_OIL_MICP_MODULE_HH
#define EWOMS_BLACK_OIL_MICP_MODULE_HH
#ifndef OPM_BLACK_OIL_MICP_MODULE_HH
#define OPM_BLACK_OIL_MICP_MODULE_HH
#include <dune/common/fvector.hh>
@@ -59,9 +59,14 @@ class BlackOilMICPModule
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using Indices = GetPropType<TypeTag, Properties::Indices>;
using Problem = GetPropType<TypeTag, Properties::Problem>;
using Toolbox = MathToolbox<Evaluation>;
using TabulatedFunction = typename BlackOilMICPParams<Scalar>::TabulatedFunction;
enum { waterCompIdx = FluidSystem::waterCompIdx };
static constexpr unsigned microbialConcentrationIdx = Indices::microbialConcentrationIdx;
static constexpr unsigned oxygenConcentrationIdx = Indices::oxygenConcentrationIdx;
static constexpr unsigned ureaConcentrationIdx = Indices::ureaConcentrationIdx;
@@ -85,30 +90,13 @@ public:
params_ = params;
}
/*!
* \brief The simulator stops if "clogging" has been (almost) reached in any of the cells.
*
* I.e., porosity - biofilm - calcite < tol_clgg, where tol_clgg is a given tolerance. In the
* implemented model a permebaility-porosity relatonship is used where a minimum
* permeability value is reached if porosity - biofilm - calcite < phi_crit.
*/
static void checkCloggingMICP(const Model& model, const Scalar phi, unsigned dofIdx)
{
const PrimaryVariables& priVars = model.solution(/*timeIdx=*/1)[dofIdx];
if (phi - priVars[biofilmConcentrationIdx] - priVars[calciteConcentrationIdx] < toleranceBeforeClogging())
throw std::logic_error("Clogging has been (almost) reached in at least one cell\n");
}
/*!
* \brief Register all run-time parameters for the black-oil MICP module.
*/
static void registerParameters()
{
if (!enableMICP)
// MICP has been disabled at compile time
return;
VtkBlackOilMICPModule<TypeTag>::registerParameters();
if constexpr (enableMICP)
VtkBlackOilMICPModule<TypeTag>::registerParameters();
}
/*!
@@ -117,20 +105,17 @@ public:
static void registerOutputModules(Model& model,
Simulator& simulator)
{
if (!enableMICP)
// MICP has been disabled at compile time
return;
model.addOutputModule(new VtkBlackOilMICPModule<TypeTag>(simulator));
if constexpr (enableMICP)
model.addOutputModule(new VtkBlackOilMICPModule<TypeTag>(simulator));
}
static bool eqApplies(unsigned eqIdx)
{
if (!enableMICP)
if constexpr (enableMICP)
return eqIdx == contiMicrobialEqIdx || eqIdx == contiOxygenEqIdx || eqIdx == contiUreaEqIdx
|| eqIdx == contiBiofilmEqIdx || eqIdx == contiCalciteEqIdx;
else
return false;
// All MICP components are true here
return eqIdx == contiMicrobialEqIdx || eqIdx == contiOxygenEqIdx || eqIdx == contiUreaEqIdx || eqIdx == contiBiofilmEqIdx || eqIdx == contiCalciteEqIdx;
}
static Scalar eqWeight([[maybe_unused]] unsigned eqIdx)
@@ -146,208 +131,240 @@ public:
static void addStorage(Dune::FieldVector<LhsEval, numEq>& storage,
const IntensiveQuantities& intQuants)
{
if (!enableMICP)
return;
LhsEval surfaceVolumeWater = Toolbox::template decay<LhsEval>(intQuants.porosity());
// avoid singular matrix if no water is present.
surfaceVolumeWater = max(surfaceVolumeWater, 1e-10);
// Suspended microbes in water phase
const LhsEval massMicrobes = surfaceVolumeWater * Toolbox::template decay<LhsEval>(intQuants.microbialConcentration());
LhsEval accumulationMicrobes = massMicrobes;
storage[contiMicrobialEqIdx] += accumulationMicrobes;
// Oxygen in water phase
const LhsEval massOxygen = surfaceVolumeWater * Toolbox::template decay<LhsEval>(intQuants.oxygenConcentration());
LhsEval accumulationOxygen = massOxygen;
storage[contiOxygenEqIdx] += accumulationOxygen;
// Urea in water phase
const LhsEval massUrea = surfaceVolumeWater * Toolbox::template decay<LhsEval>(intQuants.ureaConcentration());
LhsEval accumulationUrea = massUrea;
storage[contiUreaEqIdx] += accumulationUrea;
// Biofilm
const LhsEval massBiofilm = Toolbox::template decay<LhsEval>(intQuants.biofilmConcentration());
LhsEval accumulationBiofilm = massBiofilm;
storage[contiBiofilmEqIdx] += accumulationBiofilm;
// Calcite
const LhsEval massCalcite = Toolbox::template decay<LhsEval>(intQuants.calciteConcentration());
LhsEval accumulationCalcite = massCalcite;
storage[contiCalciteEqIdx] += accumulationCalcite;
if constexpr (enableMICP) {
const auto& fs = intQuants.fluidState();
LhsEval surfaceVolumeWater = Toolbox::template decay<LhsEval>(fs.invB(waterPhaseIdx))
* Toolbox::template decay<LhsEval>(intQuants.porosity());
// avoid singular matrix if no water is present.
surfaceVolumeWater = max(surfaceVolumeWater, 1e-10);
// suspended microbes in water phase
const LhsEval massMicrobes = surfaceVolumeWater * Toolbox::template decay<LhsEval>(intQuants.microbialConcentration());
LhsEval accumulationMicrobes = massMicrobes;
storage[contiMicrobialEqIdx] += accumulationMicrobes;
// oxygen in water phase
const LhsEval massOxygen = surfaceVolumeWater * Toolbox::template decay<LhsEval>(intQuants.oxygenConcentration());
LhsEval accumulationOxygen = massOxygen;
storage[contiOxygenEqIdx] += accumulationOxygen;
// urea in water phase
const LhsEval massUrea = surfaceVolumeWater * Toolbox::template decay<LhsEval>(intQuants.ureaConcentration());
LhsEval accumulationUrea = massUrea;
storage[contiUreaEqIdx] += accumulationUrea;
// biofilm
const LhsEval massBiofilm = Toolbox::template decay<LhsEval>(intQuants.biofilmConcentration());
LhsEval accumulationBiofilm = massBiofilm;
storage[contiBiofilmEqIdx] += accumulationBiofilm;
// calcite
const LhsEval massCalcite = Toolbox::template decay<LhsEval>(intQuants.calciteConcentration());
LhsEval accumulationCalcite = massCalcite;
storage[contiCalciteEqIdx] += accumulationCalcite;
}
}
static void computeFlux(RateVector& flux,
const ElementContext& elemCtx,
unsigned scvfIdx,
unsigned timeIdx)
template <class UpEval, class Eval, class IntensiveQuantities>
static void addMICPFluxes_(RateVector& flux,
const Eval& volumeFlux,
const IntensiveQuantities& upFs)
{
if constexpr (enableMICP) {
flux[contiMicrobialEqIdx] +=
decay<UpEval>(upFs.microbialConcentration())
* volumeFlux;
flux[contiOxygenEqIdx] +=
decay<UpEval>(upFs.oxygenConcentration())
* volumeFlux;
flux[contiUreaEqIdx] +=
decay<UpEval>(upFs.ureaConcentration())
* volumeFlux;
}
}
static void computeFlux([[maybe_unused]] RateVector& flux,
[[maybe_unused]] const ElementContext& elemCtx,
[[maybe_unused]] unsigned scvfIdx,
[[maybe_unused]] unsigned timeIdx)
{
if (!enableMICP)
return;
if constexpr (enableMICP) {
flux[contiMicrobialEqIdx] = 0.0;
flux[contiOxygenEqIdx] = 0.0;
flux[contiUreaEqIdx] = 0.0;
const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
unsigned focusIdx = elemCtx.focusDofIndex();
unsigned upIdx = extQuants.upstreamIndex(waterPhaseIdx);
if (upIdx == focusIdx)
addMICPFluxes_<Evaluation>(flux, elemCtx, scvfIdx, timeIdx);
else
addMICPFluxes_<Scalar>(flux, elemCtx, scvfIdx, timeIdx);
}
}
template <class UpstreamEval>
static void addMICPFluxes_(RateVector& flux,
const ElementContext& elemCtx,
unsigned scvfIdx,
unsigned timeIdx)
{
const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
const unsigned upIdx = extQuants.upstreamIndex(waterPhaseIdx);
const unsigned inIdx = extQuants.interiorIndex();
unsigned upIdx = extQuants.upstreamIndex(waterPhaseIdx);
const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
if (upIdx == inIdx) {
flux[contiMicrobialEqIdx] = extQuants.volumeFlux(waterPhaseIdx) * up.microbialConcentration();
flux[contiOxygenEqIdx] = extQuants.volumeFlux(waterPhaseIdx) * up.oxygenConcentration();
flux[contiUreaEqIdx] = extQuants.volumeFlux(waterPhaseIdx) * up.ureaConcentration();
}
else {
flux[contiMicrobialEqIdx] = extQuants.volumeFlux(waterPhaseIdx) * decay<Scalar>(up.microbialConcentration());
flux[contiOxygenEqIdx] = extQuants.volumeFlux(waterPhaseIdx) * decay<Scalar>(up.oxygenConcentration());
flux[contiUreaEqIdx] = extQuants.volumeFlux(waterPhaseIdx) * decay<Scalar>(up.ureaConcentration());
}
const auto& fs = up.fluidState();
const auto& volFlux = extQuants.volumeFlux(waterPhaseIdx);
addMICPFluxes_<UpstreamEval>(flux, volFlux, fs);
}
// See https://doi.org/10.1016/j.ijggc.2021.103256 for the micp processes in the model.
// see https://doi.org/10.1016/j.ijggc.2021.103256 for the MICP processes in the model
static void addSource(RateVector& source,
const ElementContext& elemCtx,
unsigned dofIdx,
unsigned timeIdx)
const Problem& problem,
const IntensiveQuantities& intQuants,
unsigned globalSpaceIdex)
{
if (!enableMICP)
return;
if constexpr (enableMICP) {
const auto& velocityInf = problem.model().linearizer().getVelocityInfo();
auto velocityInfos = velocityInf[globalSpaceIdex];
Scalar normVelocityCell = 0.0;
for (const auto& velocityInfo : velocityInfos) {
normVelocityCell = max(normVelocityCell, std::abs(velocityInfo.velocity[waterPhaseIdx]));
}
// compute dpW (max norm of the pressure gradient in the cell center)
const IntensiveQuantities& intQuants = elemCtx.intensiveQuantities(dofIdx, timeIdx);
const auto& K = elemCtx.problem().intrinsicPermeability(elemCtx, dofIdx, 0);
size_t numInteriorFaces = elemCtx.numInteriorFaces(timeIdx);
Evaluation dpW = 0;
for (unsigned scvfIdx = 0; scvfIdx < numInteriorFaces; scvfIdx++) {
const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
unsigned upIdx = extQuants.upstreamIndex(waterPhaseIdx);
const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
const Evaluation& mobWater = up.mobility(waterPhaseIdx);
// get the model parameters
const auto b = intQuants.fluidState().invB(waterPhaseIdx);
unsigned satnumIdx = problem.satnumRegionIndex(globalSpaceIdex);
Scalar k_a = microbialAttachmentRate(satnumIdx);
Scalar k_d = microbialDeathRate(satnumIdx);
Scalar rho_b = densityBiofilm(satnumIdx);
Scalar rho_c = densityCalcite(satnumIdx);
Scalar k_str = detachmentRate(satnumIdx);
Scalar eta = detachmentExponent(satnumIdx);
Scalar k_o = halfVelocityOxygen(satnumIdx);
Scalar k_u = halfVelocityUrea(satnumIdx) / 10;// dividing by scaling factor 10 (see WellInterfaceGeneric.cpp)
Scalar mu = maximumGrowthRate(satnumIdx);
Scalar mu_u = maximumUreaUtilization(satnumIdx) / 10;// dividing by scaling factor 10
Scalar Y_sb = yieldGrowthCoefficient(satnumIdx);
Scalar F = oxygenConsumptionFactor(satnumIdx);
Scalar Y_uc = yieldUreaToCalciteCoefficient(satnumIdx) * 10;// multiplying by scaling factor 10
// compute water velocity from flux
Evaluation waterVolumeVelocity = extQuants.volumeFlux(waterPhaseIdx) / (K[0][0] * mobWater);
dpW = std::max(dpW, abs(waterVolumeVelocity));
// compute the processes
source[Indices::contiMicrobialEqIdx] += intQuants.microbialConcentration() * intQuants.porosity() * b *
(Y_sb * mu * intQuants.oxygenConcentration() / (k_o + intQuants.oxygenConcentration()) - k_d - k_a)
+ rho_b * intQuants.biofilmConcentration() * k_str * pow(normVelocityCell, eta);
source[Indices::contiOxygenEqIdx] -= (intQuants.microbialConcentration() * intQuants.porosity() * b + rho_b * intQuants.biofilmConcentration()) *
F * mu * intQuants.oxygenConcentration() / (k_o + intQuants.oxygenConcentration());
source[Indices::contiUreaEqIdx] -= rho_b * intQuants.biofilmConcentration() * mu_u * intQuants.ureaConcentration() / (k_u + intQuants.ureaConcentration());
source[Indices::contiBiofilmEqIdx] += intQuants.biofilmConcentration() * (Y_sb * mu * intQuants.oxygenConcentration() / (k_o + intQuants.oxygenConcentration()) - k_d
- k_str * pow(normVelocityCell, eta) - Y_uc * (rho_b / rho_c) * intQuants.biofilmConcentration() * mu_u *
(intQuants.ureaConcentration() / (k_u + intQuants.ureaConcentration())) / (intQuants.porosity() + intQuants.biofilmConcentration()))
+ k_a * intQuants.microbialConcentration() * intQuants.porosity() * b / rho_b;
source[Indices::contiCalciteEqIdx] += (rho_b / rho_c) * intQuants.biofilmConcentration() * Y_uc * mu_u * intQuants.ureaConcentration() / (k_u + intQuants.ureaConcentration());
}
// get the model parameters
Scalar k_a = microbialAttachmentRate();
Scalar k_d = microbialDeathRate();
Scalar rho_b = densityBiofilm();
Scalar rho_c = densityCalcite();
Scalar k_str = detachmentRate();
Scalar k_o = halfVelocityOxygen();
Scalar k_u = halfVelocityUrea() / 10.0;//Dividing by scaling factor 10 (see WellInterface_impl.hpp)
Scalar mu = maximumGrowthRate();
Scalar mu_u = maximumUreaUtilization() / 10.0;//Dividing by scaling factor 10 (see WellInterface_impl.hpp)
Scalar Y_sb = yieldGrowthCoefficient();
Scalar F = oxygenConsumptionFactor();
Scalar Y_uc = 1.67 * 10; //Multiplying by scaling factor 10 (see WellInterface_impl.hpp)
// compute the processes
source[Indices::contiMicrobialEqIdx] += intQuants.microbialConcentration() * intQuants.porosity() *
(Y_sb * mu * intQuants.oxygenConcentration() / (k_o + intQuants.oxygenConcentration()) - k_d - k_a)
+ rho_b * intQuants.biofilmConcentration() * k_str * pow(intQuants.porosity() * dpW, 0.58);
source[Indices::contiOxygenEqIdx] -= (intQuants.microbialConcentration() * intQuants.porosity() + rho_b * intQuants.biofilmConcentration()) *
F * mu * intQuants.oxygenConcentration() / (k_o + intQuants.oxygenConcentration());
source[Indices::contiUreaEqIdx] -= rho_b * intQuants.biofilmConcentration() * mu_u * intQuants.ureaConcentration() / (k_u + intQuants.ureaConcentration());
source[Indices::contiBiofilmEqIdx] += intQuants.biofilmConcentration() * (Y_sb * mu * intQuants.oxygenConcentration() / (k_o + intQuants.oxygenConcentration()) - k_d
- k_str * pow(intQuants.porosity() * dpW, 0.58) - Y_uc * (rho_b / rho_c) * intQuants.biofilmConcentration() * mu_u *
(intQuants.ureaConcentration() / (k_u + intQuants.ureaConcentration())) / (intQuants.porosity() + intQuants.biofilmConcentration()))
+ k_a * intQuants.microbialConcentration() * intQuants.porosity() / rho_b;
source[Indices::contiCalciteEqIdx] += (rho_b / rho_c) * intQuants.biofilmConcentration() * Y_uc * mu_u * intQuants.ureaConcentration() / (k_u + intQuants.ureaConcentration());
}
static const Scalar densityBiofilm()
static void addSource([[maybe_unused]] RateVector& source,
[[maybe_unused]] const ElementContext& elemCtx,
[[maybe_unused]] unsigned dofIdx,
[[maybe_unused]] unsigned timeIdx)
{
return params_.densityBiofilm_;
if constexpr (enableMICP) {
const auto& problem = elemCtx.problem();
const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, timeIdx);
addSource(source, problem, intQuants, dofIdx);
}
}
static const Scalar densityCalcite()
static const Scalar densityBiofilm(unsigned satnumRegionIdx)
{
return params_.densityCalcite_;
return params_.densityBiofilm_[satnumRegionIdx];
}
static const Scalar detachmentRate()
static const Scalar densityCalcite(unsigned satnumRegionIdx)
{
return params_.detachmentRate_;
return params_.densityCalcite_[satnumRegionIdx];
}
static const Scalar criticalPorosity()
static const Scalar detachmentRate(unsigned satnumRegionIdx)
{
return params_.criticalPorosity_;
return params_.detachmentRate_[satnumRegionIdx];
}
static const Scalar fittingFactor()
static const Scalar detachmentExponent(unsigned satnumRegionIdx)
{
return params_.fittingFactor_;
return params_.detachmentExponent_[satnumRegionIdx];
}
static const Scalar halfVelocityOxygen()
static const Scalar halfVelocityOxygen(unsigned satnumRegionIdx)
{
return params_.halfVelocityOxygen_;
return params_.halfVelocityOxygen_[satnumRegionIdx];
}
static const Scalar halfVelocityUrea()
static const Scalar halfVelocityUrea(unsigned satnumRegionIdx)
{
return params_.halfVelocityUrea_;
return params_.halfVelocityUrea_[satnumRegionIdx];
}
static const Scalar maximumGrowthRate()
static const Scalar maximumGrowthRate(unsigned satnumRegionIdx)
{
return params_.maximumGrowthRate_;
return params_.maximumGrowthRate_[satnumRegionIdx];
}
static const Scalar maximumOxygenConcentration()
static const Scalar maximumUreaUtilization(unsigned satnumRegionIdx)
{
return params_.maximumOxygenConcentration_;
return params_.maximumUreaUtilization_[satnumRegionIdx];
}
static const Scalar maximumUreaConcentration()
static const Scalar microbialAttachmentRate(unsigned satnumRegionIdx)
{
return params_.maximumUreaConcentration_ / 10.0;//Dividing by scaling factor 10 (see WellInterface_impl.hpp);
return params_.microbialAttachmentRate_[satnumRegionIdx];
}
static const Scalar maximumUreaUtilization()
static const Scalar microbialDeathRate(unsigned satnumRegionIdx)
{
return params_.maximumUreaUtilization_;
return params_.microbialDeathRate_[satnumRegionIdx];
}
static const Scalar microbialAttachmentRate()
static const Scalar oxygenConsumptionFactor(unsigned satnumRegionIdx)
{
return params_.microbialAttachmentRate_;
return params_.oxygenConsumptionFactor_[satnumRegionIdx];
}
static const Scalar microbialDeathRate()
static const Scalar yieldGrowthCoefficient(unsigned satnumRegionIdx)
{
return params_.microbialDeathRate_;
return params_.yieldGrowthCoefficient_[satnumRegionIdx];
}
static const Scalar minimumPermeability()
static const Scalar yieldUreaToCalciteCoefficient(unsigned satnumRegionIdx)
{
return params_.minimumPermeability_;
return params_.yieldUreaToCalciteCoefficient_[satnumRegionIdx];
}
static const Scalar oxygenConsumptionFactor()
static const Scalar microbialDiffusion(unsigned pvtRegionIdx)
{
return params_.oxygenConsumptionFactor_;
return params_.microbialDiffusion_[pvtRegionIdx];
}
static const Scalar toleranceBeforeClogging()
static const Scalar oxygenDiffusion(unsigned pvtRegionIdx)
{
return params_.toleranceBeforeClogging_;
return params_.oxygenDiffusion_[pvtRegionIdx];
}
static const Scalar yieldGrowthCoefficient()
static const Scalar ureaDiffusion(unsigned pvtRegionIdx)
{
return params_.yieldGrowthCoefficient_;
return params_.ureaDiffusion_[pvtRegionIdx];
}
static const std::vector<Scalar> phi()
static const TabulatedFunction& permfactTable(const ElementContext& elemCtx,
unsigned scvIdx,
unsigned timeIdx)
{
return params_.phi_;
unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
return params_.permfactTable_[satnumRegionIdx];
}
static const TabulatedFunction& permfactTable(unsigned satnumRegionIdx)
{
return params_.permfactTable_[satnumRegionIdx];
}
private:
@@ -396,17 +413,12 @@ public:
*
*/
void MICPPropertiesUpdate_(const ElementContext& elemCtx,
unsigned dofIdx,
unsigned timeIdx)
unsigned dofIdx,
unsigned timeIdx)
{
const auto linearizationType = elemCtx.linearizationType();
const PrimaryVariables& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, timeIdx);
const auto& K = elemCtx.problem().intrinsicPermeability(elemCtx, dofIdx, timeIdx);
Scalar referencePorosity_ = elemCtx.problem().porosity(elemCtx, dofIdx, timeIdx);
Scalar eta = MICPModule::fittingFactor();
Scalar k_min = MICPModule::minimumPermeability();
Scalar phi_crit = MICPModule::criticalPorosity();
const Scalar referencePorosity_ = elemCtx.problem().referencePorosity(dofIdx, timeIdx);
microbialConcentration_ = priVars.makeEvaluation(microbialConcentrationIdx, timeIdx, linearizationType);
oxygenConcentration_ = priVars.makeEvaluation(oxygenConcentrationIdx, timeIdx, linearizationType);
@@ -414,9 +426,13 @@ public:
biofilmConcentration_ = priVars.makeEvaluation(biofilmConcentrationIdx, timeIdx, linearizationType);
calciteConcentration_ = priVars.makeEvaluation(calciteConcentrationIdx, timeIdx, linearizationType);
// Permeability reduction due to MICP, by adjusting the water mobility
asImp_().mobility_[waterPhaseIdx] *= max((pow((intQuants.porosity() - phi_crit) / (referencePorosity_ - phi_crit), eta) + k_min / K[0][0])/(1. + k_min / K[0][0]), k_min / K[0][0]);
const Evaluation porosityFactor = min(1.0 - (biofilmConcentration_+calciteConcentration_)/(referencePorosity_+1e-8), 1.0); //phi/phi_0
unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, dofIdx, timeIdx);
const auto& permfactTable = MICPModule::permfactTable(satnumRegionIdx);
permFactor_ = permfactTable.eval(porosityFactor, /*extrapolation=*/true);
biofilmMass_ = referencePorosity_*biofilmConcentration_*MICPModule::densityBiofilm(satnumRegionIdx);
calciteMass_ = referencePorosity_*calciteConcentration_*MICPModule::densityCalcite(satnumRegionIdx);
}
const Evaluation& microbialConcentration() const
@@ -434,16 +450,24 @@ public:
const Evaluation& calciteConcentration() const
{ return calciteConcentration_; }
const Evaluation biofilmMass() const
{ return biofilmMass_; }
const Evaluation calciteMass() const
{ return calciteMass_; }
const Evaluation& permFactor() const
{ return permFactor_; }
protected:
Implementation& asImp_()
{ return *static_cast<Implementation*>(this); }
Evaluation microbialConcentration_;
Evaluation oxygenConcentration_;
Evaluation ureaConcentration_;
Evaluation biofilmConcentration_;
Evaluation calciteConcentration_;
Evaluation biofilmMass_;
Evaluation calciteMass_;
Evaluation permFactor_;
};
@@ -456,8 +480,8 @@ class BlackOilMICPIntensiveQuantities<TypeTag, false>
public:
void MICPPropertiesUpdate_(const ElementContext&,
unsigned,
unsigned)
unsigned,
unsigned)
{ }
const Evaluation& microbialConcentration() const
@@ -474,6 +498,15 @@ public:
const Evaluation& calciteConcentration() const
{ throw std::logic_error("calciteConcentration() called but MICP is disabled"); }
const Evaluation& biofilmMass() const
{ throw std::logic_error("biofilmMass() called but MICP is disabled"); }
const Evaluation& calciteMass() const
{ throw std::logic_error("calciteMass() called but MICP is disabled"); }
const Evaluation& permFactor() const
{ throw std::logic_error("permFactor() called but MICP is disabled"); }
};
/*!
@@ -487,11 +520,6 @@ template <class TypeTag, bool enableMICPV = getPropValue<TypeTag, Properties::En
class BlackOilMICPExtensiveQuantities
{
using Implementation = GetPropType<TypeTag, Properties::ExtensiveQuantities>;
private:
Implementation& asImp_()
{ return *static_cast<Implementation*>(this); }
};
template <class TypeTag>
+69 -27
View File
@@ -26,7 +26,11 @@
#if HAVE_ECL_INPUT
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/input/eclipse/EclipseState/MICPpara.hpp>
#include <opm/input/eclipse/EclipseState/Tables/BiofilmTable.hpp>
#include <opm/input/eclipse/EclipseState/Tables/DiffMICPTable.hpp>
#include <opm/input/eclipse/EclipseState/Tables/PermfactTable.hpp>
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
#include <opm/input/eclipse/EclipseState/Tables/SimpleTable.hpp>
#endif
#include <algorithm>
@@ -59,33 +63,71 @@ initFromState(const EclipseState& eclState)
if (!eclState.runspec().micp())
return; // MICP treatment is supposed to be disabled*/
// initialize the objects which deal with the MICPpara keyword
const auto& MICPpara = eclState.getMICPpara();
densityBiofilm_ = MICPpara.getDensityBiofilm();
densityCalcite_ = MICPpara.getDensityCalcite();
detachmentRate_ = MICPpara.getDetachmentRate();
criticalPorosity_ = MICPpara.getCriticalPorosity();
fittingFactor_ = MICPpara.getFittingFactor();
halfVelocityOxygen_ = MICPpara.getHalfVelocityOxygen();
halfVelocityUrea_ = MICPpara.getHalfVelocityUrea();
maximumGrowthRate_ = MICPpara.getMaximumGrowthRate();
maximumUreaUtilization_ = MICPpara.getMaximumUreaUtilization();
microbialAttachmentRate_ = MICPpara.getMicrobialAttachmentRate();
microbialDeathRate_ = MICPpara.getMicrobialDeathRate();
minimumPermeability_ = MICPpara.getMinimumPermeability();
oxygenConsumptionFactor_ = MICPpara.getOxygenConsumptionFactor();
yieldGrowthCoefficient_ = MICPpara.getYieldGrowthCoefficient();
maximumOxygenConcentration_ = MICPpara.getMaximumOxygenConcentration();
maximumUreaConcentration_ = MICPpara.getMaximumUreaConcentration();
toleranceBeforeClogging_ = MICPpara.getToleranceBeforeClogging();
const auto& tableManager = eclState.getTableManager();
unsigned numSatRegions = tableManager.getTabdims().getNumSatTables();
unsigned numPvtRegions = tableManager.getTabdims().getNumPVTTables();
// obtain the porosity for the clamp in the blackoilnewtonmethod
if constexpr (std::is_same_v<Scalar, float>) {
const auto phi = eclState.fieldProps().get_double("PORO");
phi_.resize(phi.size());
std::copy(phi.begin(), phi.end(), phi_.begin());
} else {
phi_ = eclState.fieldProps().get_double("PORO");
// initialize the objects which deal with the MICP parameters
const TableContainer& biofilmTables = tableManager.getBiofilmTables();
if (biofilmTables.empty()) {
throw std::runtime_error("MICP requires the BIOFPARA keyword");
}
densityBiofilm_.resize(numSatRegions);
densityCalcite_.resize(numSatRegions);
detachmentRate_.resize(numSatRegions);
detachmentExponent_.resize(numSatRegions);
halfVelocityOxygen_.resize(numSatRegions);
halfVelocityUrea_.resize(numSatRegions);
maximumGrowthRate_.resize(numSatRegions);
maximumUreaUtilization_.resize(numSatRegions);
microbialAttachmentRate_.resize(numSatRegions);
microbialDeathRate_.resize(numSatRegions);
oxygenConsumptionFactor_.resize(numSatRegions);
yieldGrowthCoefficient_.resize(numSatRegions);
yieldUreaToCalciteCoefficient_.resize(numSatRegions);
for (unsigned stnRegionIdx = 0; stnRegionIdx < numSatRegions; ++stnRegionIdx) {
const BiofilmTable& biofilmTable = biofilmTables.getTable<BiofilmTable>(stnRegionIdx);
densityBiofilm_[stnRegionIdx] = biofilmTable.getDensityBiofilm().front();
densityCalcite_[stnRegionIdx] = biofilmTable.getDensityCalcite().front();
detachmentRate_[stnRegionIdx] = biofilmTable.getDetachmentRate().front();
detachmentExponent_[stnRegionIdx] = biofilmTable.getDetachmentExponent().front();
halfVelocityOxygen_[stnRegionIdx] = biofilmTable.getHalfVelocityOxygen().front();
halfVelocityUrea_[stnRegionIdx] = biofilmTable.getHalfVelocityUrea().front();
maximumGrowthRate_[stnRegionIdx] = biofilmTable.getMaximumGrowthRate().front();
maximumUreaUtilization_[stnRegionIdx] = biofilmTable.getMaximumUreaUtilization().front();
microbialAttachmentRate_[stnRegionIdx] = biofilmTable.getMicrobialAttachmentRate().front();
microbialDeathRate_[stnRegionIdx] = biofilmTable.getMicrobialDeathRate().front();
oxygenConsumptionFactor_[stnRegionIdx] = biofilmTable.getOxygenConsumptionFactor().front();
yieldGrowthCoefficient_[stnRegionIdx] = biofilmTable.getYieldGrowthCoefficient().front();
yieldUreaToCalciteCoefficient_[stnRegionIdx] = biofilmTable.getYieldUreaToCalciteCoefficient().front();
}
const TableContainer& diffMICPTables = tableManager.getDiffMICPTables();
microbialDiffusion_.resize(numPvtRegions);
oxygenDiffusion_.resize(numPvtRegions);
ureaDiffusion_.resize(numPvtRegions);
for (unsigned pvtRegionIdx = 0; pvtRegionIdx < numPvtRegions; ++pvtRegionIdx) {
if (!diffMICPTables.empty()) {
const DiffMICPTable& diffMICPTable = diffMICPTables.getTable<DiffMICPTable>(pvtRegionIdx);
microbialDiffusion_[pvtRegionIdx] = diffMICPTable.getMicrobialDiffusion().front();
oxygenDiffusion_[pvtRegionIdx] = diffMICPTable.getOxygenDiffusion().front();
ureaDiffusion_[pvtRegionIdx] = diffMICPTable.getUreaDiffusion().front();
}
else {
microbialDiffusion_[pvtRegionIdx] = 0.0;
oxygenDiffusion_[pvtRegionIdx] = 0.0;
ureaDiffusion_[pvtRegionIdx] = 0.0;
}
}
const TableContainer& permfactTables = tableManager.getPermfactTables();
if (permfactTables.empty()) {
throw std::runtime_error("MICP requires the PERMFACT keyword");
}
permfactTable_.resize(numSatRegions);
for (std::size_t i = 0; i < permfactTables.size(); ++i) {
const PermfactTable& permfactTable = permfactTables.getTable<PermfactTable>(i);
permfactTable_[i].setXYContainers(permfactTable.getPorosityChangeColumn(), permfactTable.getPermeabilityMultiplierColumn());
}
}
#endif
+22 -18
View File
@@ -28,6 +28,8 @@
#ifndef OPM_BLACK_OIL_MICP_PARAMS_HPP
#define OPM_BLACK_OIL_MICP_PARAMS_HPP
#include <opm/material/common/Tabulated1DFunction.hpp>
#include <vector>
namespace Opm {
@@ -45,24 +47,26 @@ struct BlackOilMICPParams
void initFromState(const EclipseState& eclState);
#endif
Scalar densityBiofilm_;
Scalar densityCalcite_;
Scalar detachmentRate_;
Scalar criticalPorosity_;
Scalar fittingFactor_;
Scalar halfVelocityOxygen_;
Scalar halfVelocityUrea_;
Scalar maximumGrowthRate_;
Scalar maximumUreaUtilization_;
Scalar microbialAttachmentRate_;
Scalar microbialDeathRate_;
Scalar minimumPermeability_;
Scalar oxygenConsumptionFactor_;
Scalar yieldGrowthCoefficient_;
Scalar maximumOxygenConcentration_;
Scalar maximumUreaConcentration_;
Scalar toleranceBeforeClogging_;
std::vector<Scalar> phi_;
using TabulatedFunction = Tabulated1DFunction<Scalar>;
std::vector<TabulatedFunction> permfactTable_;
std::vector<Scalar> densityBiofilm_;
std::vector<Scalar> densityCalcite_;
std::vector<Scalar> detachmentRate_;
std::vector<Scalar> detachmentExponent_;
std::vector<Scalar> halfVelocityOxygen_;
std::vector<Scalar> halfVelocityUrea_;
std::vector<Scalar> maximumGrowthRate_;
std::vector<Scalar> maximumUreaUtilization_;
std::vector<Scalar> microbialAttachmentRate_;
std::vector<Scalar> microbialDeathRate_;
std::vector<Scalar> oxygenConsumptionFactor_;
std::vector<Scalar> yieldGrowthCoefficient_;
std::vector<Scalar> yieldUreaToCalciteCoefficient_;
std::vector<Scalar> microbialDiffusion_;
std::vector<Scalar> oxygenDiffusion_;
std::vector<Scalar> ureaDiffusion_;
};
} // namespace Opm
+18 -19
View File
@@ -373,25 +373,24 @@ protected:
}
// Limit the variables to [0, cmax] values to improve the convergence.
// For the microorganisms we set this value equal to the biomass density value.
// For the oxygen and urea we set this value to the maximum injected
// concentration (the urea concentration has been scaled by 10). For
// the biofilm and calcite, we set this value equal to the porosity minus the clogging tolerance.
if (enableMICP && pvIdx == Indices::microbialConcentrationIdx) {
nextValue[pvIdx] = std::clamp(nextValue[pvIdx], Scalar{0.0}, MICPModule::densityBiofilm());
}
if (enableMICP && pvIdx == Indices::oxygenConcentrationIdx) {
nextValue[pvIdx] = std::clamp(nextValue[pvIdx], Scalar{0.0}, MICPModule::maximumOxygenConcentration());
}
if (enableMICP && pvIdx == Indices::ureaConcentrationIdx) {
nextValue[pvIdx] = std::clamp(nextValue[pvIdx], Scalar{0.0}, MICPModule::maximumUreaConcentration());
}
if (enableMICP && pvIdx == Indices::biofilmConcentrationIdx) {
nextValue[pvIdx] = std::clamp(nextValue[pvIdx], Scalar{0.0}, MICPModule::phi()[globalDofIdx] - MICPModule::toleranceBeforeClogging());
}
if (enableMICP && pvIdx == Indices::calciteConcentrationIdx) {
nextValue[pvIdx] = std::clamp(nextValue[pvIdx], Scalar{0.0}, MICPModule::phi()[globalDofIdx] - MICPModule::toleranceBeforeClogging());
// keep the values above 0
// for the biofilm and calcite, we set an upper limit
if constexpr (enableMICP) {
if (pvIdx == Indices::microbialConcentrationIdx) {
nextValue[pvIdx] = std::max(nextValue[pvIdx], Scalar{0.0});
}
if (pvIdx == Indices::oxygenConcentrationIdx) {
nextValue[pvIdx] = std::max(nextValue[pvIdx], Scalar{0.0});
}
if (pvIdx == Indices::ureaConcentrationIdx) {
nextValue[pvIdx] = std::max(nextValue[pvIdx], Scalar{0.0});
}
if (pvIdx == Indices::biofilmConcentrationIdx) {
nextValue[pvIdx] = std::clamp(nextValue[pvIdx], Scalar{0.0}, this->problem().referencePorosity(globalDofIdx, 0) - 1.e-8);
}
if (pvIdx == Indices::calciteConcentrationIdx) {
nextValue[pvIdx] = std::clamp(nextValue[pvIdx], Scalar{0.0}, this->problem().referencePorosity(globalDofIdx, 0) - 1.e-8);
}
}
}
+16 -16
View File
@@ -145,24 +145,24 @@ struct BlackOilOnePhaseIndices
numPolymers > 1 ? polymerConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the first MICP component
static constexpr int microbialConcentrationIdx =
static constexpr int biofilmConcentrationIdx =
enableMICP ? PVOffset + numPhases + numSolvents : -1000;
//! Index of the primary variable for the second MICP component
static constexpr int oxygenConcentrationIdx =
numMICPs > 1 ? microbialConcentrationIdx + 1 : -1000;
static constexpr int microbialConcentrationIdx =
numMICPs > 1 ? biofilmConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the third MICP component
static constexpr int ureaConcentrationIdx =
numMICPs > 2 ? oxygenConcentrationIdx + 1 : -1000;
static constexpr int oxygenConcentrationIdx =
numMICPs > 2 ? microbialConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the fourth MICP component
static constexpr int biofilmConcentrationIdx =
numMICPs > 3 ? ureaConcentrationIdx + 1 : -1000;
static constexpr int ureaConcentrationIdx =
numMICPs > 3 ? oxygenConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the fifth MICP component
static constexpr int calciteConcentrationIdx =
numMICPs > 4 ? biofilmConcentrationIdx + 1 : -1000;
numMICPs > 4 ? ureaConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the foam
static constexpr int foamConcentrationIdx =
@@ -221,24 +221,24 @@ struct BlackOilOnePhaseIndices
numPolymers > 1 ? contiPolymerEqIdx + 1 : -1000;
//! Index of the continuity equation for the first MICP component
static constexpr int contiMicrobialEqIdx =
static constexpr int contiBiofilmEqIdx =
enableMICP ? PVOffset + numPhases + numSolvents : -1000;
//! Index of the continuity equation for the second MICP component
static constexpr int contiOxygenEqIdx =
numMICPs > 1 ? contiMicrobialEqIdx + 1 : -1000;
static constexpr int contiMicrobialEqIdx =
numMICPs > 1 ? contiBiofilmEqIdx + 1 : -1000;
//! Index of the continuity equation for the third MICP component
static constexpr int contiUreaEqIdx =
numMICPs > 2 ? contiOxygenEqIdx + 1 : -1000;
static constexpr int contiOxygenEqIdx =
numMICPs > 2 ? contiMicrobialEqIdx + 1 : -1000;
//! Index of the continuity equation for the fourth MICP component
static constexpr int contiBiofilmEqIdx =
numMICPs > 3 ? contiUreaEqIdx + 1 : -1000;
static constexpr int contiUreaEqIdx =
numMICPs > 3 ? contiOxygenEqIdx + 1 : -1000;
//! Index of the continuity equation for the fifth MICP component
static constexpr int contiCalciteEqIdx =
numMICPs > 4 ? contiBiofilmEqIdx + 1 : -1000;
numMICPs > 4 ? contiUreaEqIdx + 1 : -1000;
//! Index of the continuity equation for the foam component
static constexpr int contiFoamEqIdx =
+16 -16
View File
@@ -145,24 +145,24 @@ struct BlackOilTwoPhaseIndices
numPolymers > 1 ? polymerConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the first MICP component
static constexpr int microbialConcentrationIdx =
static constexpr int biofilmConcentrationIdx =
enableMICP ? PVOffset + numPhases + numSolvents : -1000;
//! Index of the primary variable for the second MICP component
static constexpr int oxygenConcentrationIdx =
numMICPs > 1 ? microbialConcentrationIdx + 1 : -1000;
static constexpr int microbialConcentrationIdx =
numMICPs > 1 ? biofilmConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the third MICP component
static constexpr int ureaConcentrationIdx =
numMICPs > 2 ? oxygenConcentrationIdx + 1 : -1000;
static constexpr int oxygenConcentrationIdx =
numMICPs > 2 ? microbialConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the fourth MICP component
static constexpr int biofilmConcentrationIdx =
numMICPs > 3 ? ureaConcentrationIdx + 1 : -1000;
static constexpr int ureaConcentrationIdx =
numMICPs > 3 ? oxygenConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the fifth MICP component
static constexpr int calciteConcentrationIdx =
numMICPs > 4 ? biofilmConcentrationIdx + 1 : -1000;
numMICPs > 4 ? ureaConcentrationIdx + 1 : -1000;
//! Index of the primary variable for the foam
static constexpr int foamConcentrationIdx =
@@ -240,24 +240,24 @@ struct BlackOilTwoPhaseIndices
numPolymers > 1 ? contiPolymerEqIdx + 1 : -1000;
//! Index of the continuity equation for the first MICP component
static constexpr int contiMicrobialEqIdx =
static constexpr int contiBiofilmEqIdx =
enableMICP ? PVOffset + numPhases + numSolvents : -1000;
//! Index of the continuity equation for the second MICP component
static constexpr int contiOxygenEqIdx =
numMICPs > 1 ? contiMicrobialEqIdx + 1 : -1000;
static constexpr int contiMicrobialEqIdx =
numMICPs > 1 ? contiBiofilmEqIdx + 1 : -1000;
//! Index of the continuity equation for the third MICP component
static constexpr int contiUreaEqIdx =
numMICPs > 2 ? contiOxygenEqIdx + 1 : -1000;
static constexpr int contiOxygenEqIdx =
numMICPs > 2 ? contiMicrobialEqIdx + 1 : -1000;
//! Index of the continuity equation for the fourth MICP component
static constexpr int contiBiofilmEqIdx =
numMICPs > 3 ? contiUreaEqIdx + 1 : -1000;
static constexpr int contiUreaEqIdx =
numMICPs > 3 ? contiOxygenEqIdx + 1 : -1000;
//! Index of the continuity equation for the fifth MICP component
static constexpr int contiCalciteEqIdx =
numMICPs > 4 ? contiBiofilmEqIdx + 1 : -1000;
numMICPs > 4 ? contiUreaEqIdx + 1 : -1000;
//! Index of the continuity equation for the foam component
static constexpr int contiFoamEqIdx =
@@ -108,6 +108,7 @@ class TpfaLinearizer
static const bool linearizeNonLocalElements = getPropValue<TypeTag, Properties::LinearizeNonLocalElements>();
static const bool enableEnergy = getPropValue<TypeTag, Properties::EnableEnergy>();
static const bool enableDiffusion = getPropValue<TypeTag, Properties::EnableDiffusion>();
static const bool enableMICP = getPropValue<TypeTag, Properties::EnableMICP>();
// copying the linearizer is not a good idea
TpfaLinearizer(const TpfaLinearizer&) = delete;
@@ -543,7 +544,7 @@ private:
simulator_().problem().eclWriter().outputModule().getFlows().hasBlockFlows();
const bool anyFlores = simulator_().problem().eclWriter().outputModule().getFlows().anyFlores();
const bool enableDispersion = simulator_().vanguard().eclState().getSimulationConfig().rock_config().dispersion();
if (((!anyFlows || !flowsInfo_.empty()) && (!anyFlores || !floresInfo_.empty())) && !enableDispersion) {
if (((!anyFlows || !flowsInfo_.empty()) && (!anyFlores || !floresInfo_.empty())) && (!enableDispersion && !enableMICP)) {
return;
}
const auto& model = model_();
@@ -569,7 +570,7 @@ private:
if (anyFlores) {
floresInfo_.reserve(numCells, 6 * numCells);
}
if (enableDispersion) {
if (enableDispersion || enableMICP) {
velocityInfo_.reserve(numCells, 6 * numCells);
}
@@ -616,7 +617,7 @@ private:
if (anyFlores) {
floresInfo_.appendRow(loc_flinfo.begin(), loc_flinfo.end());
}
if (enableDispersion) {
if (enableDispersion || enableMICP) {
velocityInfo_.appendRow(loc_vlinfo.begin(), loc_vlinfo.end());
}
}
@@ -757,7 +758,7 @@ private:
const IntensiveQuantities& intQuantsEx = model_().intensiveQuantities(globJ, /*timeIdx*/ 0);
LocalResidual::computeFlux(adres,darcyFlux, globI, globJ, intQuantsIn, intQuantsEx, nbInfo.res_nbinfo, problem_().moduleParams());
adres *= nbInfo.res_nbinfo.faceArea;
if (enableDispersion) {
if (enableDispersion || enableMICP) {
for (unsigned phaseIdx = 0; phaseIdx < numEq; ++ phaseIdx) {
velocityInfo_[globI][loc].velocity[phaseIdx] = darcyFlux[phaseIdx].value() / nbInfo.res_nbinfo.faceArea;
}
@@ -831,9 +832,9 @@ private:
bMat = 0.0;
adres = 0.0;
if (separateSparseSourceTerms_) {
LocalResidual::computeSourceDense(adres, problem_(), globI, 0);
LocalResidual::computeSourceDense(adres, problem_(), intQuantsIn, globI, 0);
} else {
LocalResidual::computeSource(adres, problem_(), globI, 0);
LocalResidual::computeSource(adres, problem_(), intQuantsIn, globI, 0);
}
adres *= -volume;
setResAndJacobi(res, bMat, adres);
+2 -1
View File
@@ -141,8 +141,9 @@ public:
}
if (params_.ureaConcentrationOutput_) {
// multypliging by scaling factor 10 (see WellInterfaceGeneric.cpp)
ureaConcentration_[globalDofIdx] =
10 * scalarValue(intQuants.ureaConcentration());//Multypliging by scaling factor 10 (see WellInterface_impl.hpp)
10 * scalarValue(intQuants.ureaConcentration());
}
if (params_.biofilmConcentrationOutput_) {
+85
View File
@@ -337,6 +337,91 @@ assignCo2InWater(const unsigned globalDofIdx,
}
}
template<class FluidSystem>
bool
FIPContainer<FluidSystem>::
hasMicrobialMass() const
{
return has(Inplace::Phase::MicrobialMass);
}
template<class FluidSystem>
void
FIPContainer<FluidSystem>::
assignMicrobialMass(const unsigned globalDofIdx,
const Scalar microbialMass)
{
this->fip_[Inplace::Phase::MicrobialMass][globalDofIdx] = microbialMass;
}
template<class FluidSystem>
bool
FIPContainer<FluidSystem>::
hasOxygenMass() const
{
return has(Inplace::Phase::OxygenMass);
}
template<class FluidSystem>
void
FIPContainer<FluidSystem>::
assignOxygenMass(const unsigned globalDofIdx,
const Scalar oxygenMass)
{
this->fip_[Inplace::Phase::OxygenMass][globalDofIdx] = oxygenMass;
}
template<class FluidSystem>
bool
FIPContainer<FluidSystem>::
hasUreaMass() const
{
return has(Inplace::Phase::UreaMass);
}
template<class FluidSystem>
void
FIPContainer<FluidSystem>::
assignUreaMass(const unsigned globalDofIdx,
const Scalar ureaMass)
{
this->fip_[Inplace::Phase::UreaMass][globalDofIdx] = ureaMass;
}
template<class FluidSystem>
bool
FIPContainer<FluidSystem>::
hasBiofilmMass() const
{
return has(Inplace::Phase::BiofilmMass);
}
template<class FluidSystem>
void
FIPContainer<FluidSystem>::
assignBiofilmMass(const unsigned globalDofIdx,
const Scalar biofilmMass)
{
this->fip_[Inplace::Phase::BiofilmMass][globalDofIdx] = biofilmMass;
}
template<class FluidSystem>
bool
FIPContainer<FluidSystem>::
hasCalciteMass() const
{
return has(Inplace::Phase::CalciteMass);
}
template<class FluidSystem>
void
FIPContainer<FluidSystem>::
assignCalciteMass(const unsigned globalDofIdx,
const Scalar calciteMass)
{
this->fip_[Inplace::Phase::CalciteMass][globalDofIdx] = calciteMass;
}
template<class FluidSystem>
void
FIPContainer<FluidSystem>::
+20
View File
@@ -86,6 +86,26 @@ public:
const Scalar co2InWater,
const Scalar mM);
bool hasMicrobialMass() const;
void assignMicrobialMass(const unsigned globalDofIdx,
const Scalar microbialMass);
bool hasOxygenMass() const;
void assignOxygenMass(const unsigned globalDofIdx,
const Scalar oxygenMass);
bool hasUreaMass() const;
void assignUreaMass(const unsigned globalDofIdx,
const Scalar ureaMass);
bool hasBiofilmMass() const;
void assignBiofilmMass(const unsigned globalDofIdx,
const Scalar biofilmMass);
bool hasCalciteMass() const;
void assignCalciteMass(const unsigned globalDofIdx,
const Scalar calciteMass);
void assignGasWater(const unsigned globalDofIdx,
const std::array<Scalar, numPhases>& fip,
const Scalar gasInPlaceWater,
+6 -6
View File
@@ -173,7 +173,7 @@ public:
/*!
* \brief Returns the initial polymer concentration for a given a cell index
*/
Scalar polymerConcentration(unsigned elemIdx) const;
Scalar polymerConcentration(unsigned elemIdx) const;
/*!
* \brief Returns the polymer molecule weight for a given cell index
@@ -184,27 +184,27 @@ public:
/*!
* \brief Returns the initial microbial concentration for a given a cell index
*/
Scalar microbialConcentration(unsigned elemIdx) const;
Scalar microbialConcentration(unsigned elemIdx) const;
/*!
* \brief Returns the initial oxygen concentration for a given a cell index
*/
Scalar oxygenConcentration(unsigned elemIdx) const;
Scalar oxygenConcentration(unsigned elemIdx) const;
/*!
* \brief Returns the initial urea concentration for a given a cell index
*/
Scalar ureaConcentration(unsigned elemIdx) const;
Scalar ureaConcentration(unsigned elemIdx) const;
/*!
* \brief Returns the initial biofilm concentration for a given a cell index
*/
Scalar biofilmConcentration(unsigned elemIdx) const;
Scalar biofilmConcentration(unsigned elemIdx) const;
/*!
* \brief Returns the initial calcite concentration for a given a cell index
*/
Scalar calciteConcentration(unsigned elemIdx) const;
Scalar calciteConcentration(unsigned elemIdx) const;
/*!
* \brief Returns the index the relevant PVT region given a cell index
+16 -1
View File
@@ -1102,7 +1102,7 @@ public:
/*!
* \brief Return the well transmissibility multiplier due to rock changues.
* \brief Return the well transmissibility multiplier due to rock changes.
*/
template <class LhsEval>
LhsEval wellTransMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx) const
@@ -1153,6 +1153,15 @@ public:
case BCComponent::POLYMER:
this->handlePolymerBC(bc, rate);
break;
case BCComponent::MICR:
this->handleMicrBC(bc, rate);
break;
case BCComponent::OXYG:
this->handleOxygBC(bc, rate);
break;
case BCComponent::UREA:
this->handleUreaBC(bc, rate);
break;
case BCComponent::NONE:
throw std::logic_error("you need to specify the component when RATE type is set in BC");
break;
@@ -1701,6 +1710,12 @@ protected:
virtual void handlePolymerBC(const BCProp::BCFace&, RateVector&) const = 0;
virtual void handleMicrBC(const BCProp::BCFace&, RateVector&) const = 0;
virtual void handleOxygBC(const BCProp::BCFace&, RateVector&) const = 0;
virtual void handleUreaBC(const BCProp::BCFace&, RateVector&) const = 0;
BCData<int> bcindex_;
bool nonTrivialBoundaryConditions_ = false;
bool first_step_ = true;
+44 -14
View File
@@ -486,17 +486,6 @@ public:
});
});
}
// Deal with "clogging" for the MICP model
if constexpr (enableMICP) {
auto& model = this->model();
const auto& residual = model.linearizer().residual();
for (unsigned globalDofIdx = 0; globalDofIdx < residual.size(); ++globalDofIdx) {
auto& phi = this->referencePorosity_[/*timeIdx=*/1][globalDofIdx];
MICPModule::checkCloggingMICP(model, phi, globalDofIdx);
}
}
}
/*!
@@ -629,6 +618,12 @@ public:
if constexpr (enablePolymer) {
rate[Indices::polymerConcentrationIdx] += source.rate({ijk, SourceComponent::POLYMER}) / this->model().dofTotalVolume(globalDofIdx);
}
if constexpr (enableMICP) {
rate[Indices::microbialConcentrationIdx] += source.rate({ijk, SourceComponent::MICR}) / this->model().dofTotalVolume(globalDofIdx);
rate[Indices::oxygenConcentrationIdx] += source.rate({ijk, SourceComponent::OXYG}) / this->model().dofTotalVolume(globalDofIdx);
// dividing by scaling factor 10 (see WellInterfaceGeneric.cpp)
rate[Indices::ureaConcentrationIdx] += source.rate({ijk, SourceComponent::UREA}) / (this->model().dofTotalVolume(globalDofIdx) * 10);
}
if constexpr (enableEnergy) {
for (unsigned i = 0; i < phidx_map.size(); ++i) {
const auto phaseIdx = phidx_map[i];
@@ -692,7 +687,7 @@ public:
LhsEval permFactTransMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx) const
{
OPM_TIMEBLOCK_LOCAL(permFactTransMultiplier);
if (!enableSaltPrecipitation)
if (!enableSaltPrecipitation && !enableMICP)
return 1.0;
const auto& fs = intQuants.fluidState();
@@ -700,8 +695,15 @@ public:
LhsEval porosityFactor = decay<LhsEval>(1. - fs.saltSaturation());
porosityFactor = min(porosityFactor, 1.0);
const auto& permfactTable = BrineModule::permfactTable(tableIdx);
return permfactTable.eval(porosityFactor, /*extrapolation=*/true);
if constexpr (enableSaltPrecipitation) {
const auto& permfactTable = BrineModule::permfactTable(tableIdx);
return permfactTable.eval(porosityFactor, /*extrapolation=*/true);
}
if constexpr (enableMICP){
const auto& permfactTable = MICPModule::permfactTable(tableIdx);
return permfactTable.eval(porosityFactor, /*extrapolation=*/true);
}
return 1.0;
}
// temporary solution to facilitate output of initial state from flow
@@ -763,6 +765,9 @@ public:
break;
case BCComponent::SOLVENT:
case BCComponent::POLYMER:
case BCComponent::MICR:
case BCComponent::OXYG:
case BCComponent::UREA:
case BCComponent::NONE:
throw std::logic_error("you need to specify a valid component (OIL, WATER or GAS) when DIRICHLET type is set in BC");
}
@@ -1516,6 +1521,31 @@ protected:
rate[Indices::polymerConcentrationIdx] = bc.rate;
}
void handleMicrBC(const BCProp::BCFace& bc, RateVector& rate) const override
{
if constexpr (!enableMICP)
throw std::logic_error("MICP is disabled and you're trying to add microbes to BC");
rate[Indices::microbialConcentrationIdx] = bc.rate;
}
void handleOxygBC(const BCProp::BCFace& bc, RateVector& rate) const override
{
if constexpr (!enableMICP)
throw std::logic_error("MICP is disabled and you're trying to add oxygen to BC");
rate[Indices::oxygenConcentrationIdx] = bc.rate;
}
void handleUreaBC(const BCProp::BCFace& bc, RateVector& rate) const override
{
if constexpr (!enableMICP)
throw std::logic_error("MICP is disabled and you're trying to add urea to BC");
// dividing by scaling factor 10 (see WellInterfaceGeneric.cpp)
rate[Indices::ureaConcentrationIdx] = bc.rate / 10;
}
void updateExplicitQuantities_(const bool first_step_after_restart)
{
OPM_TIMEBLOCK(updateExplicitQuantities);
+15
View File
@@ -607,6 +607,21 @@ private:
throw std::logic_error("polymer is disabled for compositional modeling and you're trying to add polymer to BC");
}
void handleMicrBC(const BCProp::BCFace& /* bc */, RateVector& /* rate */) const override
{
throw std::logic_error("MICP is disabled for compositional modeling and you're trying to add microbes to BC");
}
void handleOxygBC(const BCProp::BCFace& /* bc */, RateVector& /* rate */) const override
{
throw std::logic_error("MICP is disabled for compositional modeling and you're trying to add oxygen to BC");
}
void handleUreaBC(const BCProp::BCFace& /* bc */, RateVector& /* rate */) const override
{
throw std::logic_error("MICP is disabled for compositional modeling and you're trying to add urea to BC");
}
FlowThresholdPressure<TypeTag> thresholdPressures_;
std::vector<InitialFluidState> initialFluidStates_;
@@ -708,7 +708,7 @@ doAllocBuffers(const unsigned bufferSize,
Entry{&cFoam_, "", enableFoam_},
Entry{&cSalt_, "", enableBrine_},
Entry{&pSalt_, "", enableSaltPrecipitation_},
Entry{&permFact_, "", enableSaltPrecipitation_},
Entry{&permFact_, "", enableSaltPrecipitation_ || enableMICP_},
Entry{&soMax_, "", oilvap.getType() == OilVapP::VAPPARS},
Entry{&soMax_, "", hysteresisConfig &&
hysteresisConfig->enableNonWettingHysteresis() &&
+116 -1
View File
@@ -114,6 +114,7 @@ class OutputBlackOilModule : public GenericOutputBlackoilModule<GetPropType<Type
static constexpr int oilCompIdx = FluidSystem::oilCompIdx;
static constexpr int waterCompIdx = FluidSystem::waterCompIdx;
enum { enableEnergy = getPropValue<TypeTag, Properties::EnableEnergy>() };
enum { enableMICP = getPropValue<TypeTag, Properties::EnableMICP>() };
template<int idx, class VectorType>
static Scalar value_or_zero(const VectorType& v)
@@ -873,6 +874,25 @@ private:
{
this->updateCO2InWater(globalDofIdx, pv, fs);
}
if constexpr(enableMICP) {
const auto surfVolWat = pv * getValue(fs.invB(waterPhaseIdx));
if (this->fipC_.hasMicrobialMass()) {
this->updateMicrobialMass(globalDofIdx, intQuants, surfVolWat);
}
if (this->fipC_.hasOxygenMass()) {
this->updateOxygenMass(globalDofIdx, intQuants, surfVolWat);
}
if (this->fipC_.hasUreaMass()) {
this->updateUreaMass(globalDofIdx, intQuants, surfVolWat);
}
if (this->fipC_.hasBiofilmMass()) {
this->updateBiofilmMass(globalDofIdx, intQuants, totVolume);
}
if (this->fipC_.hasCalciteMass()) {
this->updateCalciteMass(globalDofIdx, intQuants, totVolume);
}
}
}
template <typename FluidState, typename FIPArray>
@@ -991,6 +1011,57 @@ private:
return xoG * pv * rhoo * so / mM;
}
template <typename IntensiveQuantities>
void updateMicrobialMass(const unsigned globalDofIdx,
const IntensiveQuantities& intQuants,
const double surfVolWat)
{
const Scalar mass = surfVolWat * intQuants.microbialConcentration().value();
this->fipC_.assignMicrobialMass(globalDofIdx, mass);
}
template <typename IntensiveQuantities>
void updateOxygenMass(const unsigned globalDofIdx,
const IntensiveQuantities& intQuants,
const double surfVolWat)
{
const Scalar mass = surfVolWat * intQuants.oxygenConcentration().value();
this->fipC_.assignOxygenMass(globalDofIdx, mass);
}
template <typename IntensiveQuantities>
void updateUreaMass(const unsigned globalDofIdx,
const IntensiveQuantities& intQuants,
const double surfVolWat)
{
// rescaling back the urea concentration (see WellInterfaceGeneric.cpp)
const Scalar mass = surfVolWat * intQuants.ureaConcentration().value() * 10;
this->fipC_.assignUreaMass(globalDofIdx, mass);
}
template <typename IntensiveQuantities>
void updateBiofilmMass(const unsigned globalDofIdx,
const IntensiveQuantities& intQuants,
const double totVolume)
{
const Scalar mass = totVolume * intQuants.biofilmMass().value();
this->fipC_.assignBiofilmMass(globalDofIdx, mass);
}
template <typename IntensiveQuantities>
void updateCalciteMass(const unsigned globalDofIdx,
const IntensiveQuantities& intQuants,
const double totVolume)
{
const Scalar mass = totVolume * intQuants.calciteMass().value();
this->fipC_.assignCalciteMass(globalDofIdx, mass);
}
//! \brief Setup extractors for element-level data.
void setupElementExtractors_()
{
@@ -1441,7 +1512,7 @@ private:
micpC.assign(ectx.globalDofIdx,
ectx.intQuants.microbialConcentration().value(),
ectx.intQuants.oxygenConcentration().value(),
// Rescaling back the urea concentration (see WellInterface_impl.hpp)
// rescaling back the urea concentration (see WellInterfaceGeneric.cpp)
10 * ectx.intQuants.ureaConcentration().value(),
ectx.intQuants.biofilmConcentration().value(),
ectx.intQuants.calciteConcentration().value());
@@ -1958,6 +2029,50 @@ private:
}
}
},
Entry{ScalarEntry{"BMMIP",
[&model = this->simulator_.model()](const Context& ectx)
{
return getValue(ectx.intQuants.microbialConcentration()) *
getValue(ectx.intQuants.porosity()) *
model.dofTotalVolume(ectx.globalDofIdx);
}
}
},
Entry{ScalarEntry{"BMOIP",
[&model = this->simulator_.model()](const Context& ectx)
{
return getValue(ectx.intQuants.oxygenConcentration()) *
getValue(ectx.intQuants.porosity()) *
model.dofTotalVolume(ectx.globalDofIdx);
}
}
},
Entry{ScalarEntry{"BMUIP",
[&model = this->simulator_.model()](const Context& ectx)
{
// rescaling back the urea concentration (see WellInterfaceGeneric.cpp)
return getValue(ectx.intQuants.ureaConcentration()) *
getValue(ectx.intQuants.porosity()) *
model.dofTotalVolume(ectx.globalDofIdx) * 10;
}
}
},
Entry{ScalarEntry{"BMBIP",
[&model = this->simulator_.model()](const Context& ectx)
{
return model.dofTotalVolume(ectx.globalDofIdx) *
getValue(ectx.intQuants.biofilmMass());
}
}
},
Entry{ScalarEntry{"BMCIP",
[&model = this->simulator_.model()](const Context& ectx)
{
return model.dofTotalVolume(ectx.globalDofIdx) *
getValue(ectx.intQuants.calciteMass());
}
}
},
};
this->blockExtractors_ = BlockExtractor::setupExecMap(this->blockData_, handlers);
+1
View File
@@ -55,4 +55,5 @@ Opm::PhaseUsage::PhaseUsage(std::vector<BlackoilPhases::PhaseIndex> phases)
this->has_foam = this->phase_used[BlackoilPhases::Foam];
this->has_brine = this->phase_used[BlackoilPhases::Brine];
this->has_zFraction = this->phase_used[BlackoilPhases::ZFraction];
this->has_micp = this->phase_used[BlackoilPhases::MICP];
}
+3 -2
View File
@@ -36,10 +36,10 @@ namespace Opm
// to and from active ones. That said, they are not considered by num_phases or
// MaxNumPhases. The crypto phases which are currently implemented are solvent,
// polymer, energy, polymer molecular weight, foam and brine.
static const int NumCryptoPhases = 7;
static const int NumCryptoPhases = 8;
// enum ComponentIndex { Water = 0, Oil = 1, Gas = 2 };
enum PhaseIndex { Aqua = 0, Liquid = 1, Vapour = 2, Solvent = 3, Polymer = 4, Energy = 5, PolymerMW = 6, Foam = 7, Brine = 8, ZFraction = 9 };
enum PhaseIndex { Aqua = 0, Liquid = 1, Vapour = 2, Solvent = 3, Polymer = 4, Energy = 5, PolymerMW = 6, Foam = 7, Brine = 8, ZFraction = 9, MICP = 10 };
};
struct PhaseUsage : public BlackoilPhases
@@ -60,6 +60,7 @@ namespace Opm
bool has_foam{};
bool has_brine{};
bool has_zFraction{};
bool has_micp{};
};
@@ -134,10 +134,32 @@ PhaseUsage phaseUsage(const Phases& phases)
return pu;
}
PhaseUsage phaseUsageMICP()
{
PhaseUsage pu;
pu.phase_used.fill(0);
for (int phaseIdx = 0; phaseIdx < BlackoilPhases::MaxNumPhases + BlackoilPhases::NumCryptoPhases; ++phaseIdx) {
pu.phase_used[phaseIdx] = 0;
pu.phase_pos[phaseIdx] = -1;
}
pu.phase_used[BlackoilPhases::Aqua] = 1;
pu.phase_used[BlackoilPhases::MICP] = 1;
pu.phase_pos[BlackoilPhases::Aqua] = 0;
pu.phase_pos[BlackoilPhases::MICP] = 1;
pu.num_phases = 1;
pu.has_micp = true;
return pu;
}
PhaseUsage phaseUsageFromDeck(const EclipseState& eclipseState)
{
const auto& phases = eclipseState.runspec().phases();
if (eclipseState.runspec().micp()) {
return phaseUsageMICP();
}
return phaseUsage(phases);
}
@@ -39,6 +39,9 @@ namespace Opm
/// Looks at presence of WATER, OIL and GAS keywords in deck
/// to determine active phases.
PhaseUsage phaseUsageFromDeck(const Deck& deck);
/// Handels MICP
PhaseUsage phaseUsageMICP(const Phases& phases);
}
#endif // OPM_PHASEUSAGEFROMDECK_HEADER_INCLUDED
@@ -98,6 +98,10 @@ namespace Opm
OPM_THROW(std::runtime_error, "water evaporation is not supported by multisegment well yet");
}
if constexpr (Base::has_micp) {
OPM_THROW(std::runtime_error, "MICP is not supported by multisegment well yet");
}
if(this->rsRvInj() > 0) {
OPM_THROW(std::runtime_error,
"dissolved gas/ vapporized oil in injected oil/gas not supported by multisegment well yet."
+12 -4
View File
@@ -42,7 +42,9 @@ PerfData<Scalar>::PerfData(const std::size_t num_perf,
, polymer_rates(num_perf)
, brine_rates(num_perf)
, prod_index(num_perf * num_phases)
, micp_rates(num_perf)
, microbial_rates(num_perf)
, oxygen_rates(num_perf)
, urea_rates(num_perf)
, cell_index(num_perf)
, connection_transmissibility_factor(num_perf)
, connection_d_factor(num_perf)
@@ -79,7 +81,9 @@ PerfData<Scalar> PerfData<Scalar>::serializationTestObject()
result.polymer_rates = {10.0, 11.0, 12.0};
result.brine_rates = {13.0};
result.prod_index = {14.0, 15.0};
result.micp_rates = {16.0};
result.microbial_rates = {16.0};
result.oxygen_rates = {16.0};
result.urea_rates = {16.0};
result.cell_index = {17, 18, 19, 20};
result.connection_transmissibility_factor = {21.0};
result.connection_d_factor = {21.5};
@@ -127,7 +131,9 @@ bool PerfData<Scalar>::try_assign(const PerfData& other)
this->polymer_rates = other.polymer_rates;
this->brine_rates = other.brine_rates;
this->prod_index = other.prod_index;
this->micp_rates = other.micp_rates;
this->microbial_rates = other.microbial_rates;
this->oxygen_rates = other.oxygen_rates;
this->urea_rates = other.urea_rates;
this->water_throughput = other.water_throughput;
this->skin_pressure = other.skin_pressure;
this->water_velocity = other.water_velocity;
@@ -150,7 +156,9 @@ bool PerfData<Scalar>::operator==(const PerfData& rhs) const
&& (this->polymer_rates == rhs.polymer_rates)
&& (this->brine_rates == rhs.brine_rates)
&& (this->prod_index == rhs.prod_index)
&& (this->micp_rates == rhs.micp_rates)
&& (this->microbial_rates == rhs.microbial_rates)
&& (this->oxygen_rates == rhs.oxygen_rates)
&& (this->urea_rates == rhs.urea_rates)
&& (this->cell_index == rhs.cell_index)
&& (this->connection_transmissibility_factor == rhs.connection_transmissibility_factor)
&& (this->connection_d_factor == rhs.connection_d_factor)
+6 -2
View File
@@ -66,7 +66,9 @@ public:
serializer(polymer_rates);
serializer(brine_rates);
serializer(prod_index);
serializer(micp_rates);
serializer(microbial_rates);
serializer(oxygen_rates);
serializer(urea_rates);
serializer(cell_index);
serializer(connection_transmissibility_factor);
serializer(connection_d_factor);
@@ -97,7 +99,9 @@ public:
std::vector<Scalar> polymer_rates{};
std::vector<Scalar> brine_rates{};
std::vector<Scalar> prod_index{};
std::vector<Scalar> micp_rates{};
std::vector<Scalar> microbial_rates{};
std::vector<Scalar> oxygen_rates{};
std::vector<Scalar> urea_rates{};
std::vector<std::size_t> cell_index{};
std::vector<Scalar> connection_transmissibility_factor{};
std::vector<Scalar> connection_d_factor{};
+18
View File
@@ -193,6 +193,24 @@ Scalar SingleWellState<Scalar>::sum_solvent_rates() const
return this->sum_connection_rates(this->perf_data.solvent_rates);
}
template<class Scalar>
Scalar SingleWellState<Scalar>::sum_microbial_rates() const
{
return this->sum_connection_rates(this->perf_data.microbial_rates);
}
template<class Scalar>
Scalar SingleWellState<Scalar>::sum_oxygen_rates() const
{
return this->sum_connection_rates(this->perf_data.oxygen_rates);
}
template<class Scalar>
Scalar SingleWellState<Scalar>::sum_urea_rates() const
{
return this->sum_connection_rates(this->perf_data.urea_rates);
}
template<class Scalar>
Scalar SingleWellState<Scalar>::sum_filtrate_rate() const
{
+3
View File
@@ -144,6 +144,9 @@ public:
Scalar sum_solvent_rates() const;
Scalar sum_polymer_rates() const;
Scalar sum_brine_rates() const;
Scalar sum_microbial_rates() const;
Scalar sum_oxygen_rates() const;
Scalar sum_urea_rates() const;
Scalar sum_filtrate_rate() const;
Scalar sum_filtrate_total() const;
@@ -756,7 +756,10 @@ std::tuple<typename StandardWellConnections<FluidSystem,Indices>::Eval,
typename StandardWellConnections<FluidSystem,Indices>::Eval,
typename StandardWellConnections<FluidSystem,Indices>::Eval>
StandardWellConnections<FluidSystem,Indices>::
connectionRatesMICP(const std::vector<EvalWell>& cq_s,
connectionRatesMICP(Scalar& rate_m,
Scalar& rate_o,
Scalar& rate_u,
const std::vector<EvalWell>& cq_s,
const std::variant<Scalar,EvalWell>& microbialConcentration,
const std::variant<Scalar,EvalWell>& oxygenConcentration,
const std::variant<Scalar,EvalWell>& ureaConcentration) const
@@ -769,6 +772,8 @@ connectionRatesMICP(const std::vector<EvalWell>& cq_s,
cq_s_microbe *= std::get<EvalWell>(microbialConcentration);
}
rate_m = cq_s_microbe.value();
EvalWell cq_s_oxygen = cq_s[waterCompIdx];
if (well_.isInjector()) {
cq_s_oxygen *= std::get<Scalar>(oxygenConcentration);
@@ -776,6 +781,8 @@ connectionRatesMICP(const std::vector<EvalWell>& cq_s,
cq_s_oxygen *= std::get<EvalWell>(oxygenConcentration);
}
rate_o = cq_s_oxygen.value();
EvalWell cq_s_urea = cq_s[waterCompIdx];
if (well_.isInjector()) {
cq_s_urea *= std::get<Scalar>(ureaConcentration);
@@ -783,6 +790,9 @@ connectionRatesMICP(const std::vector<EvalWell>& cq_s,
cq_s_urea *= std::get<EvalWell>(ureaConcentration);
}
// rescaling back the urea concentration (see WellInterfaceGeneric.cpp)
rate_u = cq_s_urea.value() * 10;
return {well_.restrictEval(cq_s_microbe),
well_.restrictEval(cq_s_oxygen),
well_.restrictEval(cq_s_urea)};
@@ -124,7 +124,10 @@ public:
const std::variant<Scalar,EvalWell>& polymerConcentration) const;
std::tuple<Eval,Eval,Eval>
connectionRatesMICP(const std::vector<EvalWell>& cq_s,
connectionRatesMICP(Scalar& rate_m,
Scalar& rate_o,
Scalar& rate_u,
const std::vector<EvalWell>& cq_s,
const std::variant<Scalar,EvalWell>& microbialConcentration,
const std::variant<Scalar,EvalWell>& oxygenConcentration,
const std::variant<Scalar,EvalWell>& ureaConcentration) const;
+4 -1
View File
@@ -623,7 +623,10 @@ namespace Opm
std::tie(connectionRates[perf][Indices::contiMicrobialEqIdx],
connectionRates[perf][Indices::contiOxygenEqIdx],
connectionRates[perf][Indices::contiUreaEqIdx]) =
this->connections_.connectionRatesMICP(cq_s,
this->connections_.connectionRatesMICP(perf_data.microbial_rates[perf],
perf_data.oxygen_rates[perf],
perf_data.urea_rates[perf],
cq_s,
microbialConcentration,
oxygenConcentration,
ureaConcentration);
@@ -785,6 +785,11 @@ Scalar WellInterfaceGeneric<Scalar>::wpolymer_() const
}
}
// The urea injection concentration is scaled down by a factor of 10, since its value
// can be much bigger than 1 (not doing this slows the simulations). The corresponding
// values are scaled accordingly when computing the reactions and also when writing
// the output files.
template<class Scalar>
Scalar WellInterfaceGeneric<Scalar>::wurea_() const
{
@@ -792,7 +797,7 @@ Scalar WellInterfaceGeneric<Scalar>::wurea_() const
if (injectorType == InjectorType::WATER) {
WellMICPProperties urea = this->well_ecl_.getMICPProperties();
const Scalar urea_injection_concentration = urea.m_ureaConcentration / 10.; //Dividing by scaling factor 10
const Scalar urea_injection_concentration = urea.m_ureaConcentration / 10;//Dividing by scaling factor 10
return urea_injection_concentration;
} else {
// Not a water injection well => no urea.
@@ -173,12 +173,6 @@ namespace Opm
return 0.0;
}
// The urea injection concentration is scaled down by a factor of 10, since its value
// can be much bigger than 1 (not doing this slows the simulations). The
// corresponding values are scaled accordingly in blackoilmicpmodules.hh when computing
// the reactions and also when writing the output files (vtk and eclipse format, i.e.,
// vtkblackoilmicpmodule.hh and ecloutputblackoilmodel.hh respectively).
template<typename TypeTag>
typename WellInterface<TypeTag>::Scalar
WellInterface<TypeTag>::
+14
View File
@@ -577,6 +577,12 @@ WellState<Scalar>::report(const int* globalCellIdxMap,
well.rates.set(rt::brine, ws.sum_brine_rates());
}
if (pu.has_micp) {
well.rates.set(rt::microbial, ws.sum_microbial_rates());
well.rates.set(rt::oxygen, ws.sum_oxygen_rates());
well.rates.set(rt::urea, ws.sum_urea_rates());
}
if (ws.producer) {
well.rates.set(rt::alq, getALQ(wname));
}
@@ -1123,6 +1129,14 @@ reportConnectionPressuresAndRates(const std::size_t well_index,
connections[i].rates.set(rt::solvent, perf_data.solvent_rates[i]);
}
}
if (pu.has_micp) {
for (auto i = 0*num_perf_well; i < num_perf_well; ++i) {
connections[i].rates.set(rt::microbial, perf_data.microbial_rates[i]);
connections[i].rates.set(rt::oxygen, perf_data.oxygen_rates[i]);
connections[i].rates.set(rt::urea, perf_data.urea_rates[i]);
}
}
}
template <class Scalar>