This commit is contained in:
Stein Krogstad 2023-11-08 21:58:26 +01:00
parent 5083052a3f
commit 2121373e4f
7 changed files with 14 additions and 87 deletions

View File

@ -1327,7 +1327,7 @@ namespace Opm
const auto msg = fmt::format("updateIPRImplicit: Well {} has zero rate, IPRs might be problematic", this->name()); const auto msg = fmt::format("updateIPRImplicit: Well {} has zero rate, IPRs might be problematic", this->name());
deferred_logger.debug(msg); deferred_logger.debug(msg);
/* /*
// could revert to standard approach here // could revert to standard approach here:
updateIPR(ebos_simulator, deferred_logger); updateIPR(ebos_simulator, deferred_logger);
for (int comp_idx = 0; comp_idx < this->num_components_; ++comp_idx){ for (int comp_idx = 0; comp_idx < this->num_components_; ++comp_idx){
const int idx = this->ebosCompIdxToFlowCompIdx(comp_idx); const int idx = this->ebosCompIdxToFlowCompIdx(comp_idx);
@ -1589,8 +1589,6 @@ namespace Opm
const bool fixed_control /*false*/, const bool fixed_control /*false*/,
const bool fixed_status /*false*/) const bool fixed_status /*false*/)
{ {
//if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return true;
const int max_iter_number = this->param_.max_inner_iter_ms_wells_; const int max_iter_number = this->param_.max_inner_iter_ms_wells_;
{ {
@ -1741,9 +1739,6 @@ namespace Opm
} else { } else {
this->operability_status_.operable_under_only_bhp_limit = !is_stopped; this->operability_status_.operable_under_only_bhp_limit = !is_stopped;
} }
// We reset the well status to it's original state. Status is updated
// on the outside based on operability status
// this->wellStatus_ = well_status;
} }
std::string message = fmt::format(" Well {} converged in {} inner iterations (" std::string message = fmt::format(" Well {} converged in {} inner iterations ("
"{} control/status switches).", this->name(), it, switch_count); "{} control/status switches).", this->name(), it, switch_count);

View File

@ -856,7 +856,7 @@ namespace Opm
const auto msg = fmt::format("updateIPRImplicit: Well {} has zero rate, IPRs might be probelmatic", this->name()); const auto msg = fmt::format("updateIPRImplicit: Well {} has zero rate, IPRs might be probelmatic", this->name());
deferred_logger.debug(msg); deferred_logger.debug(msg);
/* /*
// could revert to standard approach here // could revert to standard approach here:
updateIPR(ebos_simulator, deferred_logger); updateIPR(ebos_simulator, deferred_logger);
for (int comp_idx = 0; comp_idx < this->num_components_; ++comp_idx){ for (int comp_idx = 0; comp_idx < this->num_components_; ++comp_idx){
const int idx = this->ebosCompIdxToFlowCompIdx(comp_idx); const int idx = this->ebosCompIdxToFlowCompIdx(comp_idx);
@ -2341,14 +2341,7 @@ namespace Opm
allow_switching = allow_switching && (!fixed_control || !fixed_status); allow_switching = allow_switching && (!fixed_control || !fixed_status);
bool changed = false; bool changed = false;
bool final_check = false; bool final_check = false;
/*
if (allow_switching) {
// ??????????????????????????????????????????
this->operability_status_.can_obtain_bhp_with_thp_limit = true;
this->operability_status_.obey_thp_limit_under_bhp_limit = true;
this->operability_status_.operable_under_only_bhp_limit = true;
}
*/
do { do {
its_since_last_switch++; its_since_last_switch++;
if (allow_switching && its_since_last_switch >= min_its_after_switch){ if (allow_switching && its_since_last_switch >= min_its_after_switch){
@ -2411,14 +2404,6 @@ namespace Opm
} else { } else {
this->operability_status_.operable_under_only_bhp_limit = !is_stopped; this->operability_status_.operable_under_only_bhp_limit = !is_stopped;
} }
// We reset the well status to its original state. Status is updated
// on the outside based on operability status
// \Note for future reference: For the well to update its status to stop/shut,
// the flag changed_to_stopped_this_step_ in prepareWellBeforeAssembling needs to be set to true.
// For this to happen, isOperableAndSolvable() must change from true to false,
// and (until the most recent commit) the well needs to be open for this to trigger.
// Hence, the resetting of status.
//this->wellStatus_ = well_status;
} }
} else { } else {
this->wellStatus_ = well_status_orig; this->wellStatus_ = well_status_orig;

View File

@ -90,8 +90,7 @@ double VFPProdProperties::bhp(int table_id,
const double& alq, const double& alq,
const double& explicit_wfr, const double& explicit_wfr,
const double& explicit_gfr, const double& explicit_gfr,
const bool use_expvfp, const bool use_expvfp) const {
const double ipr_slope) const {
const VFPProdTable& table = detail::getTable(m_tables, table_id); const VFPProdTable& table = detail::getTable(m_tables, table_id);
detail::VFPEvaluation retval = detail::bhp(table, aqua, liquid, vapour, thp_arg, alq, explicit_wfr,explicit_gfr, use_expvfp); detail::VFPEvaluation retval = detail::bhp(table, aqua, liquid, vapour, thp_arg, alq, explicit_wfr,explicit_gfr, use_expvfp);
@ -168,8 +167,7 @@ EvalWell VFPProdProperties::bhp(const int table_id,
const double& alq, const double& alq,
const double& explicit_wfr, const double& explicit_wfr,
const double& explicit_gfr, const double& explicit_gfr,
const bool use_expvfp, const bool use_expvfp) const
const double ipr_slope /*=0*/) const
{ {
//Get the table //Get the table
const VFPProdTable& table = detail::getTable(m_tables, table_id); const VFPProdTable& table = detail::getTable(m_tables, table_id);
@ -202,7 +200,7 @@ EvalWell VFPProdProperties::bhp(const int table_id,
#define INSTANCE(...) \ #define INSTANCE(...) \
template __VA_ARGS__ VFPProdProperties::bhp<__VA_ARGS__>(const int, \ template __VA_ARGS__ VFPProdProperties::bhp<__VA_ARGS__>(const int, \
const __VA_ARGS__&, const __VA_ARGS__&, const __VA_ARGS__&, \ const __VA_ARGS__&, const __VA_ARGS__&, const __VA_ARGS__&, \
const double&, const double&, const double&, const double&, const bool, const double) const; const double&, const double&, const double&, const double&, const bool) const;
INSTANCE(DenseAd::Evaluation<double, -1, 4u>) INSTANCE(DenseAd::Evaluation<double, -1, 4u>)
INSTANCE(DenseAd::Evaluation<double, -1, 5u>) INSTANCE(DenseAd::Evaluation<double, -1, 5u>)

View File

@ -68,8 +68,7 @@ public:
const double& alq, const double& alq,
const double& explicit_wfr, const double& explicit_wfr,
const double& explicit_gfr, const double& explicit_gfr,
const bool use_expvfp, const bool use_expvfp) const;
const double ipr_slope = 0.0) const;
/** /**
* Linear interpolation of bhp as a function of the input parameters * Linear interpolation of bhp as a function of the input parameters
@ -91,8 +90,7 @@ public:
const double& alq, const double& alq,
const double& explicit_wfr, const double& explicit_wfr,
const double& explicit_gfr, const double& explicit_gfr,
const bool use_expvfp, const bool use_expvfp) const;
const double ipr_slope = 0.0) const;
/** /**
* Linear interpolation of thp as a function of the input parameters * Linear interpolation of thp as a function of the input parameters

View File

@ -365,16 +365,12 @@ calculateBhpFromThp(const WellState& well_state,
const auto& wfr = well_.vfpProperties()->getExplicitWFR(controls.vfp_table_number, well_.indexOfWell()); const auto& wfr = well_.vfpProperties()->getExplicitWFR(controls.vfp_table_number, well_.indexOfWell());
const auto& gfr = well_.vfpProperties()->getExplicitGFR(controls.vfp_table_number, well_.indexOfWell()); const auto& gfr = well_.vfpProperties()->getExplicitGFR(controls.vfp_table_number, well_.indexOfWell());
const bool use_vfpexplicit = well_.useVfpExplicit(); const bool use_vfpexplicit = well_.useVfpExplicit();
double ipr_slope = 0.0;
if (use_vfpexplicit) {
const auto ipr = getFloIPR(well_state, well, summaryState);
ipr_slope = -1/ipr.second;
}
bhp_tab = well_.vfpProperties()->getProd()->bhp(controls.vfp_table_number, bhp_tab = well_.vfpProperties()->getProd()->bhp(controls.vfp_table_number,
aqua, liquid, vapour, aqua, liquid, vapour,
thp_limit, thp_limit,
well_.getALQ(well_state), well_.getALQ(well_state),
wfr, gfr, use_vfpexplicit, ipr_slope); wfr, gfr, use_vfpexplicit);
} }
else { else {
OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER for well " + well_.name(), deferred_logger); OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER for well " + well_.name(), deferred_logger);
@ -896,11 +892,6 @@ isStableSolution(const WellState& well_state,
const auto& table = well_.vfpProperties()->getProd()->getTable(controls.vfp_table_number); const auto& table = well_.vfpProperties()->getProd()->getTable(controls.vfp_table_number);
const bool use_vfpexplicit = well_.useVfpExplicit(); const bool use_vfpexplicit = well_.useVfpExplicit();
//const double vfp_ref_depth = well_.vfpProperties()->getProd()->getTable(controls.vfp_table_number).getDatumDepth();
//const auto bhp_adjustment = getVfpBhpAdjustment(well_state.well(well_.indexOfWell()).bhp, thp);
// XXX this needs to be fixed
//assert(bhp_adjustment == 0.0);
detail::VFPEvaluation bhp = detail::bhp(table, aqua, liquid, vapour, thp, well_.getALQ(well_state), wfr, gfr, use_vfpexplicit); detail::VFPEvaluation bhp = detail::bhp(table, aqua, liquid, vapour, thp, well_.getALQ(well_state), wfr, gfr, use_vfpexplicit);
bhp.value = bhp.value + getVfpBhpAdjustment(bhp.value, thp); bhp.value = bhp.value + getVfpBhpAdjustment(bhp.value, thp);
@ -953,7 +944,6 @@ estimateStableBhp(const WellState& well_state,
auto bhp_adjusted = [this, &thp, &dp_hydro](const double bhp) { auto bhp_adjusted = [this, &thp, &dp_hydro](const double bhp) {
return bhp - dp_hydro + getVfpBhpAdjustment(bhp, thp); return bhp - dp_hydro + getVfpBhpAdjustment(bhp, thp);
}; };
//const auto retval = detail::intersectWithIPR(table, thp, wfr, gfr, well_.getALQ(well_state), ipr.first+ipr.second*dp_hydro, ipr.second);
const auto retval = detail::intersectWithIPR(table, thp, wfr, gfr, well_.getALQ(well_state), ipr.first, ipr.second, bhp_adjusted); const auto retval = detail::intersectWithIPR(table, thp, wfr, gfr, well_.getALQ(well_state), ipr.first, ipr.second, bhp_adjusted);
if (retval.has_value()) { if (retval.has_value()) {
// returned pair is (flo, bhp) // returned pair is (flo, bhp)

View File

@ -441,7 +441,6 @@ protected:
std::optional<double> estimateOperableBhp(const Simulator& ebos_simulator, std::optional<double> estimateOperableBhp(const Simulator& ebos_simulator,
const double dt, const double dt,
WellState& well_state, WellState& well_state,
const GroupState& group_state,
const SummaryState& summary_state, const SummaryState& summary_state,
DeferredLogger& deferred_logger); DeferredLogger& deferred_logger);

View File

@ -289,7 +289,6 @@ namespace Opm
prod_controls.hasControl(Well::ProducerCMode::GRUP); prod_controls.hasControl(Well::ProducerCMode::GRUP);
changed = this->checkIndividualConstraints(ws, summary_state, deferred_logger, inj_controls, prod_controls); changed = this->checkIndividualConstraints(ws, summary_state, deferred_logger, inj_controls, prod_controls);
// TODO: with current way, the checkGroupConstraints might overwrite the result from checkIndividualConstraints, which remains to be investigated
if (hasGroupControl) { if (hasGroupControl) {
changed = changed || this->checkGroupConstraints(well_state, group_state, schedule, summary_state,deferred_logger); changed = changed || this->checkGroupConstraints(well_state, group_state, schedule, summary_state,deferred_logger);
} }
@ -315,16 +314,12 @@ namespace Opm
double inj_limit = inj_controls.bhp_limit; double inj_limit = inj_controls.bhp_limit;
const bool has_thp = this->wellHasTHPConstraints(summary_state); const bool has_thp = this->wellHasTHPConstraints(summary_state);
if (has_thp){ if (has_thp){
// calculate bhp from thp-limit (using explicit fractions zince zero rate)
// TODO: this will often be too strict condition for re-opening, a better
// option is probably minimum bhp on current vfp-curve, but some more functionality
// is needed for this option to be robustly implemented.
std::vector<double> rates(this->num_components_); std::vector<double> rates(this->num_components_);
//const double bhp_thp = WellBhpThpCalculator(*this).calculateBhpFromThp(well_state, rates, this->well_ecl_, summary_state, this->getRefDensity(), deferred_logger);
if (this->isInjector()){ if (this->isInjector()){
const double bhp_thp = WellBhpThpCalculator(*this).calculateBhpFromThp(well_state, rates, this->well_ecl_, summary_state, this->getRefDensity(), deferred_logger); const double bhp_thp = WellBhpThpCalculator(*this).calculateBhpFromThp(well_state, rates, this->well_ecl_, summary_state, this->getRefDensity(), deferred_logger);
inj_limit = std::min(bhp_thp, inj_controls.bhp_limit); inj_limit = std::min(bhp_thp, inj_controls.bhp_limit);
} else { } else {
// if the well can operate, it must at least be able to produce at the lowest bhp of the bhp-curve (explicit fractions)
const double bhp_min = WellBhpThpCalculator(*this).calculateMinimumBhpFromThp(well_state, this->well_ecl_, summary_state, this->getRefDensity()); const double bhp_min = WellBhpThpCalculator(*this).calculateMinimumBhpFromThp(well_state, this->well_ecl_, summary_state, this->getRefDensity());
prod_limit = std::max(bhp_min, prod_controls.bhp_limit); prod_limit = std::max(bhp_min, prod_controls.bhp_limit);
//auto prates = well_state.well(this->index_of_well_).prev_surface_rates; //auto prates = well_state.well(this->index_of_well_).prev_surface_rates;
@ -494,7 +489,7 @@ namespace Opm
// if well is stopped, check if we can reopen // if well is stopped, check if we can reopen
if (this->wellIsStopped()) { if (this->wellIsStopped()) {
this->openWell(); this->openWell();
auto bhp_target = estimateOperableBhp(ebos_simulator, dt, well_state, group_state, summary_state, deferred_logger); auto bhp_target = estimateOperableBhp(ebos_simulator, dt, well_state, summary_state, deferred_logger);
if (!bhp_target.has_value()) { if (!bhp_target.has_value()) {
// no intersection with ipr // no intersection with ipr
const auto msg = fmt::format("estimateOperableBhp: Did not find operable BHP for well {}", this->name()); const auto msg = fmt::format("estimateOperableBhp: Did not find operable BHP for well {}", this->name());
@ -547,7 +542,7 @@ namespace Opm
// Well did not converge, switch to explicit fractions // Well did not converge, switch to explicit fractions
this->operability_status_.use_vfpexplicit = true; this->operability_status_.use_vfpexplicit = true;
this->openWell(); this->openWell();
auto bhp_target = estimateOperableBhp(ebos_simulator, dt, well_state, group_state, summary_state, deferred_logger); auto bhp_target = estimateOperableBhp(ebos_simulator, dt, well_state, summary_state, deferred_logger);
if (!bhp_target.has_value()) { if (!bhp_target.has_value()) {
// well can't operate using explicit fractions // well can't operate using explicit fractions
is_operable = false; is_operable = false;
@ -557,19 +552,9 @@ namespace Opm
} else { } else {
// solve well with the estimated target bhp (or limit) // solve well with the estimated target bhp (or limit)
const double bhp = std::max(bhp_target.value(), prod_controls.bhp_limit); const double bhp = std::max(bhp_target.value(), prod_controls.bhp_limit);
const bool converged_bhp = solveWellWithBhp(ebos_simulator, dt, bhp, well_state, deferred_logger); solveWellWithBhp(ebos_simulator, dt, bhp, well_state, deferred_logger);
ws.thp = this->getTHPConstraint(summary_state); ws.thp = this->getTHPConstraint(summary_state);
converged = this->iterateWellEqWithSwitching(ebos_simulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger); converged = this->iterateWellEqWithSwitching(ebos_simulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger);
/*
if (!converged) {
// debug
} else {
// re-solve well equations
// XXX reset thp
well_state.well(this->index_of_well_).thp = this->getTHPConstraint(summary_state);
}
*/
} }
} }
// update operability // update operability
@ -585,7 +570,6 @@ namespace Opm
estimateOperableBhp(const Simulator& ebos_simulator, estimateOperableBhp(const Simulator& ebos_simulator,
const double dt, const double dt,
WellState& well_state, WellState& well_state,
const GroupState& group_state,
const SummaryState& summary_state, const SummaryState& summary_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
@ -654,30 +638,8 @@ namespace Opm
auto group_state = GroupState(); // empty group auto group_state = GroupState(); // empty group
auto inj_controls = Well::InjectionControls(0); auto inj_controls = Well::InjectionControls(0);
auto prod_controls = Well::ProductionControls(0); auto prod_controls = Well::ProductionControls(0);
/*
auto& ws = well_state.well(this->index_of_well_);
auto cmode_inj = ws.injection_cmode;
auto cmode_prod = ws.production_cmode;
if (this->isInjector()) {
assert(false);
//inj_controls.addControl(Well::InjectorCMode::BHP);
//inj_controls.bhp_limit = bhp;
//inj_controls.cmode = Well::InjectorCMode::BHP;
//ws.injection_cmode = Well::InjectorCMode::BHP;
} else {
prod_controls.addControl(Well::ProducerCMode::ORAT);
prod_controls.oil_rate = 0.0;
prod_controls.cmode = Well::ProducerCMode::ORAT;
ws.production_cmode = Well::ProducerCMode::ORAT;
}
*/
// update well-state
//ws.bhp = bhp;
// solve
const bool converged = this->iterateWellEqWithSwitching(ebos_simulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger, /*fixed_control*/true, /*fixed_status*/ true); const bool converged = this->iterateWellEqWithSwitching(ebos_simulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger, /*fixed_control*/true, /*fixed_status*/ true);
this->wellStatus_ = well_status_orig; this->wellStatus_ = well_status_orig;
//ws.injection_cmode = cmode_inj;
//ws.production_cmode = cmode_prod;
return converged; return converged;
} }