Merge pull request #2851 from osae/extboSimulators

Alternative solvent extension for the black oil model.
This commit is contained in:
Tor Harald Sandve
2020-11-18 14:01:36 +01:00
committed by GitHub
29 changed files with 438 additions and 20 deletions

View File

@@ -29,6 +29,7 @@
# include <flow/flow_ebos_oilwater.hpp>
# include <flow/flow_ebos_solvent.hpp>
# include <flow/flow_ebos_polymer.hpp>
# include <flow/flow_ebos_extbo.hpp>
# include <flow/flow_ebos_foam.hpp>
# include <flow/flow_ebos_brine.hpp>
# include <flow/flow_ebos_oilwater_brine.hpp>
@@ -292,6 +293,14 @@ namespace Opm
std::move(summaryConfig_));
return Opm::flowEbosSolventMain(argc_, argv_, outputCout_, outputFiles_);
}
// Extended BO case
else if ( phases.active( Opm::Phase::ZFRACTION ) ) {
Opm::flowEbosExtboSetDeck(setupTime_, std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
std::move(summaryConfig_));
return Opm::flowEbosExtboMain(argc_, argv_, outputCout_, outputFiles_);
}
// Energy case
else if (eclipseState_->getSimulationConfig().isThermal()) {
Opm::flowEbosEnergySetDeck(setupTime_, std::move(deck_),

View File

@@ -296,6 +296,7 @@ namespace Opm {
const ModelParameters param_;
bool terminal_output_;
bool has_solvent_;
bool has_zFraction_;
bool has_polymer_;
std::vector<int> pvt_region_idx_;
PhaseUsage phase_usage_;

View File

@@ -33,6 +33,7 @@ namespace Opm {
BlackoilWellModel(Simulator& ebosSimulator)
: ebosSimulator_(ebosSimulator)
, has_solvent_(getPropValue<TypeTag, Properties::EnableSolvent>())
, has_zFraction_(getPropValue<TypeTag, Properties::EnableExtbo>())
, has_polymer_(getPropValue<TypeTag, Properties::EnablePolymer>())
{
terminal_output_ = false;

View File

@@ -33,6 +33,7 @@
#include <opm/models/blackoil/blackoilpolymermodules.hh>
#include <opm/models/blackoil/blackoilsolventmodules.hh>
#include <opm/models/blackoil/blackoilextbomodules.hh>
#include <opm/models/blackoil/blackoilfoammodules.hh>
#include <opm/models/blackoil/blackoilbrinemodules.hh>
@@ -74,6 +75,7 @@ namespace Opm
using Base::numEq;
using Base::has_solvent;
using Base::has_zFraction;
using Base::has_polymer;
using Base::has_foam;
using Base::has_brine;
@@ -89,9 +91,10 @@ namespace Opm
static const int numEnergyEq = Indices::numEnergy;
static const int numFoamEq = Indices::numFoam;
static const int numBrineEq = Indices::numBrine;
static const int numExtbos = Indices::numExtbos;
// number of the conservation equations
static const int numWellConservationEq = numEq - numPolymerEq - numEnergyEq - numFoamEq - numBrineEq;
static const int numWellConservationEq = numEq - numPolymerEq - numEnergyEq - numFoamEq - numBrineEq - numExtbos;
// number of the well control equations
static const int numWellControlEq = 1;
// number of the well equations that will always be used
@@ -147,6 +150,7 @@ namespace Opm
typedef DenseAd::DynamicEvaluation<Scalar, numStaticWellEq + numEq + 1> EvalWell;
using Base::contiSolventEqIdx;
using Base::contiZfracEqIdx;
using Base::contiPolymerEqIdx;
using Base::contiFoamEqIdx;
using Base::contiBrineEqIdx;
@@ -523,6 +527,7 @@ namespace Opm
std::vector<RateVector>& connectionRates,
std::vector<EvalWell>& cq_s,
EvalWell& water_flux_s,
EvalWell& cq_s_zfrac_effective,
Opm::DeferredLogger& deferred_logger) const;
// check whether the well is operable under the current reservoir condition

View File

@@ -388,6 +388,12 @@ namespace Opm
b_perfcells_dense[contiSolventEqIdx] = extendEval(intQuants.solventInverseFormationVolumeFactor());
}
if (has_zFraction && this->isInjector()) {
const unsigned gasCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::gasCompIdx);
b_perfcells_dense[gasCompIdx] *= (1.0 - wsolvent());
b_perfcells_dense[gasCompIdx] += wsolvent()*intQuants.zPureInvFormationVolumeFactor().value();
}
// Pressure drawdown (also used to determine direction of flow)
const EvalWell well_pressure = bhp + perf_pressure_diffs_[perf];
EvalWell drawdown = pressure - well_pressure;
@@ -605,7 +611,8 @@ namespace Opm
// Calculate perforation quantities.
std::vector<EvalWell> cq_s(num_components_, {numWellEq_ + numEq, 0.0});
EvalWell water_flux_s{numWellEq_ + numEq, 0.0};
calculateSinglePerf(ebosSimulator, perf, well_state, connectionRates, cq_s, water_flux_s, deferred_logger);
EvalWell cq_s_zfrac_effective{numWellEq_ + numEq, 0.0};
calculateSinglePerf(ebosSimulator, perf, well_state, connectionRates, cq_s, water_flux_s, cq_s_zfrac_effective, deferred_logger);
// Equation assembly for this perforation.
if (has_polymer && this->has_polymermw && this->isInjector()) {
@@ -639,6 +646,12 @@ namespace Opm
well_state.perfPhaseRates()[(first_perf_ + perf) * np + ebosCompIdxToFlowCompIdx(componentIdx)] = cq_s[componentIdx].value();
}
}
if (has_zFraction) {
for (int pvIdx = 0; pvIdx < numWellEq_; ++pvIdx) {
duneC_[0][cell_idx][pvIdx][contiZfracEqIdx] -= cq_s_zfrac_effective.derivative(pvIdx+numEq);
}
}
}
// Update the connection
connectionRates_ = connectionRates;
@@ -686,6 +699,7 @@ namespace Opm
std::vector<RateVector>& connectionRates,
std::vector<EvalWell>& cq_s,
EvalWell& water_flux_s,
EvalWell& cq_s_zfrac_effective,
Opm::DeferredLogger& deferred_logger) const
{
const bool allow_cf = getAllowCrossFlow() || openCrossFlowAvoidSingularity(ebosSimulator);
@@ -812,6 +826,22 @@ namespace Opm
connectionRates[perf][contiFoamEqIdx] = Base::restrictEval(cq_s_foam);
}
if (has_zFraction) {
// TODO: the application of well efficiency factor has not been tested with an example yet
const unsigned gasCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::gasCompIdx);
cq_s_zfrac_effective = cq_s[gasCompIdx];
if (this->isInjector()) {
cq_s_zfrac_effective *= wsolvent();
} else if (cq_s_zfrac_effective.value() != 0.0) {
const double dis_gas_frac = perf_dis_gas_rate / cq_s_zfrac_effective.value();
cq_s_zfrac_effective *= extendEval(dis_gas_frac*intQuants.xVolume() + (1.0-dis_gas_frac)*intQuants.yVolume());
}
well_state.perfRateSolvent()[first_perf_ + perf] = cq_s_zfrac_effective.value();
cq_s_zfrac_effective *= well_efficiency_factor_;
connectionRates[perf][contiZfracEqIdx] = Base::restrictEval(cq_s_zfrac_effective);
}
if (has_brine) {
// TODO: the application of well efficiency factor has not been tested with an example yet
const unsigned waterCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::waterCompIdx);
@@ -1978,7 +2008,7 @@ namespace Opm
const double oilrate = std::abs(well_state.wellRates()[oilpos_well]); //in order to handle negative rates in producers
rvmax_perf[perf] = FluidSystem::gasPvt().saturatedOilVaporizationFactor(fs.pvtRegionIndex(), temperature, p_avg);
if (oilrate > 0) {
const double gasrate = std::abs(well_state.wellRates()[gaspos_well]) - well_state.solventWellRate(w);
const double gasrate = std::abs(well_state.wellRates()[gaspos_well]) - (has_solvent ? well_state.solventWellRate(w) : 0.0);
double rv = 0.0;
if (gasrate > 0) {
rv = oilrate / gasrate;
@@ -2003,7 +2033,7 @@ namespace Opm
if (gasPresent) {
rsmax_perf[perf] = FluidSystem::oilPvt().saturatedGasDissolutionFactor(fs.pvtRegionIndex(), temperature, p_avg);
const int gaspos_well = pu.phase_pos[Gas] + w * pu.num_phases;
const double gasrate = std::abs(well_state.wellRates()[gaspos_well]) - well_state.solventWellRate(w);
const double gasrate = std::abs(well_state.wellRates()[gaspos_well]) - (has_solvent ? well_state.solventWellRate(w) : 0.0);
if (gasrate > 0) {
const double oilrate = std::abs(well_state.wellRates()[oilpos_well]);
double rs = 0.0;
@@ -2224,7 +2254,7 @@ namespace Opm
{
// the following implementation assume that the polymer is always after the w-o-g phases
// For the polymer, energy and foam cases, there is one more mass balance equations of reservoir than wells
assert((int(B_avg.size()) == num_components_) || has_polymer || has_energy || has_foam || has_brine);
assert((int(B_avg.size()) == num_components_) || has_polymer || has_energy || has_foam || has_brine || has_zFraction);
const double tol_wells = param_.tolerance_wells_;
const double maxResidualAllowed = param_.max_residual_allowed_;
@@ -2900,7 +2930,8 @@ namespace Opm
primary_variables_[WFrac] = scalingFactor(pu.phase_pos[Water]) * well_state.wellRates()[np*well_index + pu.phase_pos[Water]] / total_well_rate;
}
if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
primary_variables_[GFrac] = scalingFactor(pu.phase_pos[Gas]) * (well_state.wellRates()[np*well_index + pu.phase_pos[Gas]] - well_state.solventWellRate(well_index)) / total_well_rate ;
primary_variables_[GFrac] = scalingFactor(pu.phase_pos[Gas]) * (well_state.wellRates()[np*well_index + pu.phase_pos[Gas]]
- (has_solvent ? well_state.solventWellRate(well_index) : 0.0) ) / total_well_rate ;
}
if (has_solvent) {
primary_variables_[SFrac] = scalingFactor(pu.phase_pos[Gas]) * well_state.solventWellRate(well_index) / total_well_rate ;
@@ -2919,8 +2950,9 @@ namespace Opm
if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
if (phase == InjectorType::GAS) {
primary_variables_[GFrac] = 1.0 - wsolvent();
primary_variables_[GFrac] = 1.0;
if (has_solvent) {
primary_variables_[GFrac] = 1.0 - wsolvent();
primary_variables_[SFrac] = wsolvent();
}
} else {

View File

@@ -92,6 +92,7 @@ namespace Opm
typedef DenseAd::Evaluation<double, /*size=*/numEq> Eval;
static const bool has_solvent = getPropValue<TypeTag, Properties::EnableSolvent>();
static const bool has_zFraction = getPropValue<TypeTag, Properties::EnableExtbo>();
static const bool has_polymer = getPropValue<TypeTag, Properties::EnablePolymer>();
static const bool has_energy = getPropValue<TypeTag, Properties::EnableEnergy>();
static const bool has_temperature = getPropValue<TypeTag, Properties::EnableTemperature>();
@@ -100,6 +101,7 @@ namespace Opm
static const bool has_foam = getPropValue<TypeTag, Properties::EnableFoam>();
static const bool has_brine = getPropValue<TypeTag, Properties::EnableBrine>();
static const int contiSolventEqIdx = Indices::contiSolventEqIdx;
static const int contiZfracEqIdx = Indices::contiZfracEqIdx;
static const int contiPolymerEqIdx = Indices::contiPolymerEqIdx;
// index for the polymer molecular weight continuity equation
static const int contiPolymerMWEqIdx = Indices::contiPolymerMWEqIdx;

View File

@@ -94,7 +94,7 @@ namespace Opm
wsolvent_ = 0.0;
if (has_solvent && well.isInjector()) {
if ((has_solvent || has_zFraction) && well.isInjector()) {
auto injectorType = well_ecl_.injectorType();
if (injectorType == InjectorType::GAS) {
wsolvent_ = well_ecl_.getSolventFraction();

View File

@@ -163,7 +163,6 @@ namespace Opm
perfRateBrine_.clear();
perfRateBrine_.resize(nperf, 0.0);
// intialize wells that have been there before
// order may change so the mapping is based on the well name
if (prevState && !prevState->wellMap().empty()) {
@@ -576,7 +575,7 @@ namespace Opm
well.rates.set( rt::well_potential_gas, this->well_potentials_[well_rate_index + pu.phase_pos[Gas]] );
}
if ( pu.has_solvent ) {
if ( pu.has_solvent || pu.has_zFraction) {
well.rates.set( rt::solvent, solventWellRate(w) );
}
@@ -621,7 +620,7 @@ namespace Opm
if ( pu.has_brine ) {
comp.rates.set( rt::brine, this->perfRateBrine()[wt.second[1] + local_comp_index]);
}
if ( pu.has_solvent ) {
if ( pu.has_solvent || pu.has_zFraction) {
comp.rates.set( rt::solvent, this->perfRateSolvent()[wt.second[1] + local_comp_index]);
}