cleaning up to preapre for pull request

This commit is contained in:
Kai Bao 2023-09-25 13:07:39 +02:00
parent 035d216641
commit e38e557bbc
11 changed files with 119 additions and 109 deletions

View File

@ -257,12 +257,12 @@ namespace Opm
DeferredLogger& deferred_logger) override;
virtual bool iterateWellEqWithSwitching(const Simulator& ebosSimulator,
const double dt,
const Well::InjectionControls& inj_controls,
const Well::ProductionControls& prod_controls,
WellState& well_state,
const GroupState& group_state,
DeferredLogger& deferred_logger) override;
const double dt,
const Well::InjectionControls& inj_controls,
const Well::ProductionControls& prod_controls,
WellState& well_state,
const GroupState& group_state,
DeferredLogger& deferred_logger) override;
virtual void assembleWellEqWithoutIteration(const Simulator& ebosSimulator,
const double dt,

View File

@ -523,6 +523,9 @@ getResidualMeasureValue(const WellState& well_state,
++count;
}
// if (count == 0), it should be converged.
assert(count != 0);
return sum;
}

View File

@ -140,11 +140,9 @@ segmentNumberToIndex(const int segment_number) const
template<typename Scalar>
void
MultisegmentWellGeneric<Scalar>::
detectOscillations(const std::vector<double>& measure_history,
const int it,
bool& oscillate,
bool& stagnate) const
detectOscillations(const std::vector<double>& measure_history, bool& oscillate, bool& stagnate) const
{
const auto it = measure_history.size() - 1;
if ( it < 2 ) {
oscillate = false;
stagnate = false;

View File

@ -65,7 +65,6 @@ protected:
/// Detect oscillation or stagnation based on the residual measure history
void detectOscillations(const std::vector<double>& measure_history,
const int it,
bool& oscillate,
bool& stagnate) const;

View File

@ -1339,7 +1339,7 @@ namespace Opm
bool is_oscillate = false;
bool is_stagnate = false;
this->detectOscillations(measure_history, it, is_oscillate, is_stagnate);
this->detectOscillations(measure_history, is_oscillate, is_stagnate);
// TODO: maybe we should have more sophisticated strategy to recover the relaxation factor,
// for example, to recover it to be bigger
@ -1444,13 +1444,13 @@ namespace Opm
int stagnate_count = 0;
bool relax_convergence = false;
this->regularize_ = false;
const auto& summary_state = ebosSimulator.vanguard().summaryState();
// Max status switch frequency should be 2 to avoid getting stuck in cycle
const int min_its_after_switch = 2;
int its_since_last_switch = min_its_after_switch;
int switch_count= 0;
const auto well_status = this->wellStatus_;
const auto& summary_state = ebosSimulator.vanguard().summaryState();
const bool allow_switching = !this->wellUnderZeroRateTarget(summary_state, well_state) && (this->well_ecl_.getStatus() == WellStatus::OPEN);
bool changed = false;
bool final_check = false;
@ -1490,65 +1490,67 @@ namespace Opm
its_since_last_switch = min_its_after_switch;
} else {
break;
}
}
}
// getFinteWellResiduals returns false for nan/inf residuals
{
// getFinteWellResiduals returns false for nan/inf residuals
const auto& [isFinite, residuals] = this->getFiniteWellResiduals(Base::B_avg_, deferred_logger);
if (!isFinite)
return false;
residual_history.push_back(residuals);
measure_history.push_back(this->getResidualMeasureValue(well_state,
residual_history[it],
this->param_.tolerance_wells_,
this->param_.tolerance_pressure_ms_wells_,
deferred_logger) );
}
if (!converged) {
measure_history.push_back(this->getResidualMeasureValue(well_state,
residual_history[it],
this->param_.tolerance_wells_,
this->param_.tolerance_pressure_ms_wells_,
deferred_logger));
bool is_oscillate = false;
bool is_stagnate = false;
bool is_oscillate = false;
bool is_stagnate = false;
this->detectOscillations(measure_history, it, is_oscillate, is_stagnate);
// TODO: maybe we should have more sophisticated strategy to recover the relaxation factor,
// for example, to recover it to be bigger
this->detectOscillations(measure_history, is_oscillate, is_stagnate);
// TODO: maybe we should have more sophisticated strategy to recover the relaxation factor,
// for example, to recover it to be bigger
if (is_oscillate || is_stagnate) {
// HACK!
std::ostringstream sstr;
if (relaxation_factor == min_relaxation_factor) {
// Still stagnating, terminate iterations if 5 iterations pass.
++stagnate_count;
if (false){//(stagnate_count == 6) {
sstr << " well " << this->name() << " observes severe stagnation and/or oscillation. We relax the tolerance and check for convergence. \n";
const auto reportStag = getWellConvergence(summary_state, well_state, Base::B_avg_, deferred_logger, true);
if (reportStag.converged()) {
converged = true;
sstr << " well " << this->name() << " manages to get converged with relaxed tolerances in " << it << " inner iterations";
deferred_logger.debug(sstr.str());
return converged;
if (is_oscillate || is_stagnate) {
// HACK!
std::string message;
if (relaxation_factor == min_relaxation_factor) {
++stagnate_count;
if (false) { // this disables the usage of the relaxed tolerance
fmt::format_to(std::back_inserter(message), " Well {} observes severe stagnation and/or oscillation."
" We relax the tolerance and check for convergence. \n", this->name());
const auto reportStag = getWellConvergence(summary_state, well_state, Base::B_avg_,
deferred_logger, true);
if (reportStag.converged()) {
converged = true;
fmt::format_to(std::back_inserter(message), " Well {} manages to get converged with relaxed tolerances in {} inner iterations", this->name(), it);
deferred_logger.debug(message);
return converged;
}
}
}
// a factor value to reduce the relaxation_factor
constexpr double reduction_mutliplier = 0.9;
relaxation_factor = std::max(relaxation_factor * reduction_mutliplier, min_relaxation_factor);
// debug output
if (is_stagnate) {
fmt::format_to(std::back_inserter(message), " well {} observes stagnation in inner iteration {}\n", this->name(), it);
}
if (is_oscillate) {
fmt::format_to(std::back_inserter(message), " well {} observes oscillation in inner iteration {}\n", this->name(), it);
}
fmt::format_to(std::back_inserter(message), " relaxation_factor is {} now\n", relaxation_factor);
this->regularize_ = true;
deferred_logger.debug(message);
}
// a factor value to reduce the relaxation_factor
const double reduction_mutliplier = 0.9;
relaxation_factor = std::max(relaxation_factor * reduction_mutliplier, min_relaxation_factor);
// debug output
if (is_stagnate) {
sstr << " well " << this->name() << " observes stagnation in inner iteration " << it << "\n";
}
if (is_oscillate) {
sstr << " well " << this->name() << " observes oscillation in inner iteration " << it << "\n";
}
sstr << " relaxation_factor is " << relaxation_factor << " now\n";
this->regularize_ = true;
deferred_logger.debug(sstr.str());
}
updateWellState(summary_state, dx_well, well_state, deferred_logger, relaxation_factor);
initPrimaryVariablesEvaluation();
@ -1566,16 +1568,19 @@ namespace Opm
}
// 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::ostringstream sstr;
sstr << " Well " << this->name() << " converged in " << it << " inner iterations (" << switch_count << " local control switches).";
if (relax_convergence)
sstr << " (A relaxed tolerance was used after "<< this->param_.strict_inner_iter_wells_ << " iterations)";
deferred_logger.debug(sstr.str());
this->wellStatus_ = well_status;
}
std::string message = fmt::format(" Well {} converged in {} inner iterations ("
"{} control/status switches).", this->name(), it, switch_count);
if (relax_convergence) {
message.append(fmt::format(" (A relaxed tolerance was used after {} iterations)",
this->param_.strict_inner_iter_wells_));
}
deferred_logger.debug(message);
} else {
std::ostringstream sstr;
sstr << " Well " << this->name() << " did not converge in " << it << " inner iterations (" << switch_count << " local control switches).";
const std::string message = fmt::format(" Well {} did not converged in {} inner iterations ("
"{} control/status switches).", this->name(), it, switch_count);
deferred_logger.debug(message);
}
return converged;

View File

@ -207,12 +207,12 @@ namespace Opm
// iterate well equations including control switching
bool iterateWellEqWithSwitching(const Simulator& ebosSimulator,
const double dt,
const Well::InjectionControls& inj_controls,
const Well::ProductionControls& prod_controls,
WellState& well_state,
const GroupState& group_state,
DeferredLogger& deferred_logger) override;
const double dt,
const Well::InjectionControls& inj_controls,
const Well::ProductionControls& prod_controls,
WellState& well_state,
const GroupState& group_state,
DeferredLogger& deferred_logger) override;
/// \brief Wether the Jacobian will also have well contributions in it.
virtual bool jacobianContainsWellContributions() const override

View File

@ -2175,7 +2175,7 @@ namespace Opm
const auto& summary_state = ebosSimulator.vanguard().summaryState();
// Max status switch frequency should be 2 to avoid getting stuck in cycle
const int min_its_after_switch = 2;
constexpr int min_its_after_switch = 2;
int its_since_last_switch = min_its_after_switch;
int switch_count= 0;
const auto well_status = this->wellStatus_;
@ -2236,12 +2236,13 @@ namespace Opm
}
// We reset the well status to it's original state. Status is updated
// on the outside based on operability status
this->wellStatus_ = well_status;
// TODO: this looks strange, let us check
this->wellStatus_ = well_status;
}
} else {
std::ostringstream sstr;
sstr << " Well " << this->name() << " did not converge in " << it << " inner iterations (" << switch_count << " control/status switches).";
deferred_logger.debug(sstr.str());
const std::string message = fmt::format(" Well {} did not converged in {} inner iterations ("
"{} control/status switches).", this->name(), it, switch_count);
deferred_logger.debug(message);
// add operability here as well ?
}
return converged;

View File

@ -242,12 +242,12 @@ public:
DeferredLogger& deferred_logger) /* const */;
bool updateWellControlAndStatusLocalIteration(const Simulator& ebos_simulator,
WellState& well_state,
const GroupState& group_state,
const Well::InjectionControls& inj_controls,
const Well::ProductionControls& prod_controls,
const double& WQTotal,
DeferredLogger& deferred_logger); /* const */
WellState& well_state,
const GroupState& group_state,
const Well::InjectionControls& inj_controls,
const Well::ProductionControls& prod_controls,
const double WQTotal,
DeferredLogger& deferred_logger);
virtual void updatePrimaryVariables(const SummaryState& summary_state,
const WellState& well_state,
@ -402,12 +402,12 @@ protected:
DeferredLogger& deferred_logger) = 0;
virtual bool iterateWellEqWithSwitching(const Simulator& ebosSimulator,
const double dt,
const WellInjectionControls& inj_controls,
const WellProductionControls& prod_controls,
WellState& well_state,
const GroupState& group_state,
DeferredLogger& deferred_logger) = 0;
const double dt,
const WellInjectionControls& inj_controls,
const WellProductionControls& prod_controls,
WellState& well_state,
const GroupState& group_state,
DeferredLogger& deferred_logger) = 0;
bool iterateWellEquations(const Simulator& ebosSimulator,
const double dt,

View File

@ -344,22 +344,23 @@ void WellInterfaceGeneric::setVFPProperties(const VFPProperties* vfp_properties_
vfp_properties_ = vfp_properties_arg;
}
void WellInterfaceGeneric::setPrevSurfaceRates(WellState& well_state,
void WellInterfaceGeneric::setPrevSurfaceRates(WellState& well_state,
const WellState& prev_well_state) const
{
auto& ws = well_state.well(this->index_of_well_);
auto& ws_prev = prev_well_state.well(this->index_of_well_);
// The logic here is a bit fragile:
// We need non-zero prev_surface_rates for the purpose of providing explicit fractions
// We need non-zero prev_surface_rates for the purpose of providing explicit fractions
// (if needed) for vfp interpolation.
// We assume that current surface rates either are initialized from previous step
// or (if newly opened) from updateWellStateRates. This is fine unless well was
// stopped in previous step in which case it's rates will be zero. In this case,
// or (if newly opened) from updateWellStateRates. This is fine unless well was
// stopped in previous step in which case it's rates will be zero. In this case,
// we select the previous rates of the previous well state (and hope for the best).
bool zero_rates = true;
for (const double& rate : ws.surface_rates){
zero_rates &= (rate == 0.0);
}
const bool zero_rates = std::all_of(ws.surface_rates.begin(), ws.surface_rates.end(),
[](double rate) {
return rate == 0.; // TODO: should we use a threshhold for comparison?
} );
if (zero_rates) {
ws.prev_surface_rates = ws_prev.prev_surface_rates;
} else {

View File

@ -209,9 +209,6 @@ public:
bool stopppedOrZeroRateTarget(const SummaryState& summary_state,
const WellState& well_state) const;
bool wellUnderZeroRateTarget(const SummaryState& summary_state,
const WellState& well_state) const;
double wellEfficiencyFactor() const
{ return well_efficiency_factor_; }
@ -221,7 +218,7 @@ public:
inj_fc_multiplier_ = inj_fc_multiplier;
}
void resetWellOperability();
void resetWellOperability();
protected:
bool getAllowCrossFlow() const;
@ -237,6 +234,9 @@ protected:
int polymerInjTable_() const;
int polymerWaterTable_() const;
bool wellUnderZeroRateTarget(const SummaryState& summary_state,
const WellState& well_state) const;
std::pair<bool,bool>
computeWellPotentials(std::vector<double>& well_potentials,
const WellState& well_state);

View File

@ -258,12 +258,12 @@ namespace Opm
bool
WellInterface<TypeTag>::
updateWellControlAndStatusLocalIteration(const Simulator& ebos_simulator,
WellState& well_state,
const GroupState& group_state,
const Well::InjectionControls& inj_controls,
const Well::ProductionControls& prod_controls,
const double& wqTotal,
DeferredLogger& deferred_logger) /* const */
WellState& well_state,
const GroupState& group_state,
const Well::InjectionControls& inj_controls,
const Well::ProductionControls& prod_controls,
const double wqTotal,
DeferredLogger& deferred_logger)
{
const auto& summary_state = ebos_simulator.vanguard().summaryState();
const auto& schedule = ebos_simulator.vanguard().schedule();
@ -284,9 +284,11 @@ namespace Opm
prod_controls.hasControl(Well::ProducerCMode::GRUP);
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) {
changed = this->checkGroupConstraints(well_state, group_state, schedule, summary_state, deferred_logger);
changed = this->checkGroupConstraints(well_state, group_state, schedule, summary_state,deferred_logger);
}
if (changed) {
const bool thp_controlled = this->isInjector() ? ws.injection_cmode == Well::InjectorCMode::THP :
ws.production_cmode == Well::ProducerCMode::THP;
@ -436,6 +438,7 @@ namespace Opm
const auto prod_controls = this->well_ecl_.isProducer() ? this->well_ecl_.productionControls(summary_state) : Well::ProductionControls(0);
bool converged = false;
try {
// TODO: the following two functions will be refactored to be one to reduce the code duplication
if (!this->param_.local_well_solver_control_switching_){
converged = this->iterateWellEqWithControl(ebosSimulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger);
} else {
@ -782,7 +785,7 @@ namespace Opm
DeferredLogger& deferred_logger)
{
if (this->param_.local_well_solver_control_switching_) {
bool success = updateWellOperabilityFromWellEq(ebos_simulator, well_state, deferred_logger);
const bool success = updateWellOperabilityFromWellEq(ebos_simulator, well_state, deferred_logger);
if (success) {
return;
} else {
@ -817,7 +820,7 @@ namespace Opm
const WellState& well_state,
DeferredLogger& deferred_logger)
{
// only makes sense if we're using this parameter is true
// only makes sense if we're using this parameter is true
assert(this->param_.local_well_solver_control_switching_);
this->operability_status_.resetOperability();
WellState well_state_copy = well_state;