first version of the well testing for physical reason

the key difficulty is that we do not have reliable explicit information
to do the testing.

In this version, we try to obtain the explicit information by finishing
one converged solving.
This commit is contained in:
Kai Bao 2018-11-22 15:44:09 +01:00
parent 4343ae6be0
commit eaa3ad19f5
6 changed files with 181 additions and 37 deletions

View File

@ -349,6 +349,11 @@ namespace Opm
void assembleWellEqWithoutIteration(const Simulator& ebosSimulator,
const double dt,
WellState& well_state);
virtual void wellTestingPhysical(Simulator& simulator, const std::vector<double>& B_avg,
const double simulation_time, const int report_step,
const bool terminal_output,
WellState& well_state, WellTestState& welltest_state) override;
};
}

View File

@ -1648,7 +1648,7 @@ namespace Opm
checkWellOperability(const Simulator& /* ebos_simulator */,
const WellState& /* well_state */)
{
const std::string msg = "Support of well operatability checking for mutlisegment wells is not implemented "
const std::string msg = "Support of well operability checking for multisegment wells is not implemented "
"yet, checkWellOperability() for " + name() + " will do nothing";
OpmLog::warning("NO_OPERATABILITY_CHECKING_MS_WELLS", msg);
}
@ -1888,4 +1888,20 @@ namespace Opm
}
}
template<typename TypeTag>
void
MultisegmentWell<TypeTag>::
wellTestingPhysical(Simulator& simulator, const std::vector<double>& B_avg,
const double simulation_time, const int report_step, const bool terminal_output,
WellState& well_state, WellTestState& welltest_state)
{
const std::string msg = "Support of well testing for physical limits for multisegment wells is not "
"implemented yet, wellTestingPhysical() for " + name() + " will do nothing";
OpmLog::warning("NO_WELLTESTPHYSICAL_CHECKING_MS_WELLS", msg);
}
}

View File

@ -348,11 +348,16 @@ namespace Opm
// updating the inflow based on the current reservoir condition
void updateIPR(const Simulator& ebos_simulator) const;
// check whether the well is operable under the current reservoir condition
// update the operability status of the well is operable under the current reservoir condition
// mostly related to BHP limit and THP limit
virtual void checkWellOperability(const Simulator& ebos_simulator,
const WellState& well_state) override;
// check whether the well is operable under the current reservoir condition
// mostly related to BHP limit and THP limit
void updateWellOperability(const Simulator& ebos_simulator,
const WellState& well_state);
// check whether the well is operable under BHP limit with current reservoir condition
void checkOperabilityUnderBHPLimitProducer(const Simulator& ebos_simulator);
@ -398,6 +403,10 @@ namespace Opm
// calculate a relaxation factor to avoid overshoot of total rates
static double relaxationFactorRate(const std::vector<double>& primary_variables,
const BVectorWell& dwells);
virtual void wellTestingPhysical(Simulator& simulator, const std::vector<double>& B_avg,
const double simulation_time, const int report_step, const bool terminal_output,
WellState& well_state, WellTestState& welltest_state);
};
}

View File

@ -1307,6 +1307,27 @@ namespace Opm
const bool old_well_operable = this->operability_status_.isOperable();
updateWellOperability(ebos_simulator, well_state);
const bool well_operable = this->operability_status_.isOperable();
if (!well_operable && old_well_operable) {
OpmLog::info(" well " + name() + " gets SHUT during iteration ");
} else if (well_operable && !old_well_operable) {
OpmLog::info(" well " + name() + " gets REVIVED during iteration ");
}
}
template<typename TypeTag>
void
StandardWell<TypeTag>::
updateWellOperability(const Simulator& ebos_simulator,
const WellState& well_state)
{
this->operability_status_.reset();
updateIPR(ebos_simulator);
@ -1321,14 +1342,6 @@ namespace Opm
this->operability_status_.can_produce_inject_with_current_bhp =
canProduceInjectWithCurrentBhp(ebos_simulator, well_state);
}
const bool well_operable = this->operability_status_.isOperable();
if (!well_operable && old_well_operable) {
OpmLog::info(" well " + name() + " gets SHUT during iteration ");
} else if (well_operable && !old_well_operable) {
OpmLog::info(" well " + name() + " gets REVIVED during iteration ");
}
}
@ -2706,4 +2719,67 @@ namespace Opm
return relaxation_factor;
}
template<typename TypeTag>
void
StandardWell<TypeTag>::
wellTestingPhysical(Simulator& ebos_simulator, const std::vector<double>& B_avg,
const double simulation_time, const int report_step, const bool terminal_output,
WellState& well_state, WellTestState& welltest_state)
{
OpmLog::debug(" well " + name() + " is being tested for physical limits");
// some most difficult things are the explicit quantities, since there is no information
// in the WellState to do a decent initialization
// TODO: Let us assume that the simulator is updated
// Let us try to do a normal simualtion running, to keep checking the operability status
// If the well is not operable during any of the time. It means it does not pass the physical
// limit test.
// create a copy of the well_state to use. If the operability checking is sucessful, we use this one
// to replace the original one
WellState well_state_copy = well_state;
// TODO: well state for this well is kind of all zero status
// we should be able to provide a better initialization
calculateExplicitQuantities(ebos_simulator, well_state_copy);
updateWellOperability(ebos_simulator, well_state_copy);
if ( !this->isOperable() ) {
const std::string msg = " well " + name() + " is not operable during well testing for physical reason";
OpmLog::debug(msg);
return;
}
updateWellStateWithTarget(ebos_simulator, well_state_copy);
calculateExplicitQuantities(ebos_simulator, well_state_copy);
updatePrimaryVariables(well_state_copy);
initPrimaryVariablesEvaluation();
const bool converged = this->solveWellEqUntilConverged(ebos_simulator, B_avg, well_state_copy);
if (!converged) {
const std::string msg = " well " + name() + " did not get converged during well testing for physical reason";
OpmLog::debug(msg);
return;
}
if (this->isOperable() ) {
welltest_state.openWell(name() );
const std::string msg = " well " + name() + " is re-opened through well testing for physical reason";
OpmLog::info(msg);
well_state = well_state_copy;
} else {
const std::string msg = " well " + name() + " is not operable during well testing for physical reason";
OpmLog::debug(msg);
}
}
}

View File

@ -218,8 +218,8 @@ namespace Opm
// Simulator is not const is because that assembleWellEq is non-const Simulator
void wellTesting(Simulator& simulator, const std::vector<double>& B_avg,
const double simulation_time, const int report_step, const bool terminal_output,
const WellTestConfig::Reason testing_reason, const WellState& well_state,
WellTestState& welltest_state);
const WellTestConfig::Reason testing_reason,
/* const */ WellState& well_state, WellTestState& welltest_state);
void updatePerforatedCell(std::vector<bool>& is_cell_perforated);
@ -364,6 +364,10 @@ namespace Opm
const double simulation_time, const int report_step, const bool terminal_output,
const WellState& well_state, WellTestState& welltest_state);
virtual void wellTestingPhysical(Simulator& simulator, const std::vector<double>& B_avg,
const double simulation_time, const int report_step, const bool terminal_output,
WellState& well_state, WellTestState& welltest_state) = 0;
void updateWellTestStateEconomic(const WellState& well_state,
const double simulation_time,
const bool write_message_to_opmlog,
@ -374,7 +378,12 @@ namespace Opm
const bool write_message_to_opmlog,
WellTestState& well_test_state) const;
void solveWellForTesting(Simulator& ebosSimulator, WellState& well_state, const std::vector<double>& B_avg, bool terminal_output);
void solveWellForTesting(Simulator& ebosSimulator, WellState& well_state,
const std::vector<double>& B_avg, bool terminal_output);
bool solveWellEqUntilConverged(Simulator& ebosSimulator,
const std::vector<double>& B_avg,
WellState& well_state);
void scaleProductivityIndex(const int perfIdx, double& productivity_index) const;

View File

@ -923,9 +923,15 @@ namespace Opm
WellInterface<TypeTag>::
wellTesting(Simulator& simulator, const std::vector<double>& B_avg,
const double simulation_time, const int report_step, const bool terminal_output,
const WellTestConfig::Reason testing_reason, const WellState& well_state,
const WellTestConfig::Reason testing_reason,
/* const */ WellState& well_state,
WellTestState& well_test_state)
{
if (testing_reason == WellTestConfig::Reason::PHYSICAL) {
wellTestingPhysical(simulator, B_avg, simulation_time, report_step,
terminal_output, well_state, well_test_state);
}
if (testing_reason == WellTestConfig::Reason::ECONOMIC) {
wellTestingEconomic(simulator, B_avg, simulation_time, report_step,
terminal_output, well_state, well_test_state);
@ -1139,6 +1145,42 @@ namespace Opm
template<typename TypeTag>
bool
WellInterface<TypeTag>::
solveWellEqUntilConverged(Simulator& ebosSimulator,
const std::vector<double>& B_avg,
WellState& well_state)
{
const int max_iter = param_.max_welleq_iter_;
int it = 0;
const double dt = 1.0; //not used for the well tests
bool converged;
WellState well_state0 = well_state;
do {
assembleWellEq(ebosSimulator, dt, well_state);
auto report = getWellConvergence(B_avg);
converged = report.converged();
if (converged) {
break;
}
++it;
solveEqAndUpdateWellState(well_state);
wellhelpers::WellSwitchingLogger logger;
updateWellControl(ebosSimulator, well_state, logger);
initPrimaryVariablesEvaluation();
} while (it < max_iter);
return converged;
}
template<typename TypeTag>
void
WellInterface<TypeTag>::calculateReservoirRates(WellState& well_state) const
@ -1176,37 +1218,24 @@ namespace Opm
template<typename TypeTag>
void
WellInterface<TypeTag>::solveWellForTesting(Simulator& ebosSimulator, WellState& well_state, const std::vector<double>& B_avg, bool terminal_output)
WellInterface<TypeTag>::
solveWellForTesting(Simulator& ebosSimulator, WellState& well_state,
const std::vector<double>& B_avg, bool terminal_output)
{
const int max_iter = param_.max_welleq_iter_;
int it = 0;
const double dt = 1.0; //not used for the well tests
bool converged;
WellState well_state0 = well_state;
do {
assembleWellEq(ebosSimulator, dt, well_state);
// keep a copy of the original well state
const WellState well_state0 = well_state;
auto report = getWellConvergence(B_avg);
converged = report.converged();
if (converged) {
break;
}
++it;
solveEqAndUpdateWellState(well_state);
wellhelpers::WellSwitchingLogger logger;
updateWellControl(ebosSimulator, well_state, logger);
initPrimaryVariablesEvaluation();
} while (it < max_iter);
const bool converged = solveWellEqUntilConverged(ebosSimulator, B_avg, well_state);
if (converged) {
if ( terminal_output ) {
OpmLog::debug("WellTest: Well equation for well " + name() + " solution gets converged with " + std::to_string(it) + " iterations");
OpmLog::debug("WellTest: Well equation for well " + name() + " solution gets converged");
}
} else {
if ( terminal_output ) {
OpmLog::debug("WellTest: Well equation for well" +name() + " solution failed in getting converged with " + std::to_string(it) + " iterations");
const int max_iter = param_.max_welleq_iter_;
OpmLog::debug("WellTest: Well equation for well" +name() + " solution failed in getting converged with "
+ std::to_string(max_iter) + " iterations");
}
well_state = well_state0;
}