mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #2125 from totto82/mswThp
add support for thp control in MSW
This commit is contained in:
commit
bc71341462
@ -173,6 +173,8 @@ namespace Opm
|
||||
|
||||
// protected member variables from the Base class
|
||||
using Base::well_ecl_;
|
||||
using Base::vfp_properties_;
|
||||
using Base::ref_depth_;
|
||||
using Base::number_of_perforations_; // TODO: can use well_ecl_?
|
||||
using Base::current_step_;
|
||||
using Base::index_of_well_;
|
||||
@ -279,6 +281,7 @@ namespace Opm
|
||||
// updating the well_state based on well solution dwells
|
||||
void updateWellState(const BVectorWell& dwells,
|
||||
WellState& well_state,
|
||||
Opm::DeferredLogger& deferred_logger,
|
||||
const double relaxation_factor=1.0) const;
|
||||
|
||||
|
||||
@ -318,6 +321,13 @@ namespace Opm
|
||||
// convert a Eval from reservoir to contain the derivative related to wells
|
||||
EvalWell extendEval(const Eval& in) const;
|
||||
|
||||
|
||||
template <class ValueType>
|
||||
ValueType calculateBhpFromThp(const std::vector<ValueType>& rates, const Well2& well, const SummaryState& summaryState, Opm::DeferredLogger& deferred_logger) const;
|
||||
|
||||
double calculateThpFromBhp(const std::vector<double>& rates, const double bhp, Opm::DeferredLogger& deferred_logger) const;
|
||||
void updateThp(WellState& well_state, Opm::DeferredLogger& deferred_logger) const;
|
||||
|
||||
// compute the fluid properties, such as densities, viscosities, and so on, in the segments
|
||||
// They will be treated implicitly, so they need to be of Evaluation type
|
||||
void computeSegmentFluidProperties(const Simulator& ebosSimulator);
|
||||
@ -365,7 +375,7 @@ namespace Opm
|
||||
const WellState& well_state,
|
||||
Opm::DeferredLogger& deferred_logger) override;
|
||||
|
||||
void updateWellStateFromPrimaryVariables(WellState& well_state) const;
|
||||
void updateWellStateFromPrimaryVariables(WellState& well_state, Opm::DeferredLogger& deferred_logger) const;
|
||||
|
||||
bool frictionalPressureLossConsidered() const;
|
||||
|
||||
|
@ -329,7 +329,12 @@ namespace Opm
|
||||
|
||||
case Well2::InjectorCMode::THP:
|
||||
{
|
||||
OPM_DEFLOG_THROW(std::runtime_error, "THP not supported for MSW wells " + name(), deferred_logger );
|
||||
std::vector<double> rates(3, 0.0);
|
||||
for (int p = 0; p<np; ++p) {
|
||||
rates[p] = well_state.wellRates()[well_index*np + p];
|
||||
}
|
||||
double bhp = calculateBhpFromThp(rates, well, summaryState, deferred_logger);
|
||||
well_state.bhp()[well_index] = bhp;
|
||||
break;
|
||||
}
|
||||
case Well2::InjectorCMode::BHP:
|
||||
@ -453,7 +458,12 @@ namespace Opm
|
||||
}
|
||||
case Well2::ProducerCMode::THP:
|
||||
{
|
||||
OPM_DEFLOG_THROW(std::runtime_error, "THP not supported for MSW wells " + name(), deferred_logger );
|
||||
std::vector<double> rates(3, 0.0);
|
||||
for (int p = 0; p<np; ++p) {
|
||||
rates[p] = well_state.wellRates()[well_index*np + p];
|
||||
}
|
||||
double bhp = calculateBhpFromThp(rates, well, summaryState, deferred_logger);
|
||||
well_state.bhp()[well_index] = bhp;
|
||||
break;
|
||||
}
|
||||
case Well2::ProducerCMode::GRUP:
|
||||
@ -622,11 +632,11 @@ namespace Opm
|
||||
MultisegmentWell<TypeTag>::
|
||||
recoverWellSolutionAndUpdateWellState(const BVector& x,
|
||||
WellState& well_state,
|
||||
Opm::DeferredLogger& /* deferred_logger*/) const
|
||||
Opm::DeferredLogger& deferred_logger) const
|
||||
{
|
||||
BVectorWell xw(1);
|
||||
recoverSolutionWell(x, xw);
|
||||
updateWellState(xw, well_state);
|
||||
updateWellState(xw, well_state, deferred_logger);
|
||||
}
|
||||
|
||||
|
||||
@ -802,13 +812,13 @@ namespace Opm
|
||||
template <typename TypeTag>
|
||||
void
|
||||
MultisegmentWell<TypeTag>::
|
||||
solveEqAndUpdateWellState(WellState& well_state, Opm::DeferredLogger& /* deferred_logger */)
|
||||
solveEqAndUpdateWellState(WellState& well_state, Opm::DeferredLogger& deferred_logger)
|
||||
{
|
||||
// We assemble the well equations, then we check the convergence,
|
||||
// which is why we do not put the assembleWellEq here.
|
||||
const BVectorWell dx_well = mswellhelpers::invDXDirect(duneD_, resWell_);
|
||||
|
||||
updateWellState(dx_well, well_state);
|
||||
updateWellState(dx_well, well_state, deferred_logger);
|
||||
}
|
||||
|
||||
|
||||
@ -893,6 +903,7 @@ namespace Opm
|
||||
MultisegmentWell<TypeTag>::
|
||||
updateWellState(const BVectorWell& dwells,
|
||||
WellState& well_state,
|
||||
Opm::DeferredLogger& deferred_logger,
|
||||
const double relaxation_factor) const
|
||||
{
|
||||
const double dFLimit = param_.dwell_fraction_max_;
|
||||
@ -941,7 +952,7 @@ namespace Opm
|
||||
|
||||
}
|
||||
|
||||
updateWellStateFromPrimaryVariables(well_state);
|
||||
updateWellStateFromPrimaryVariables(well_state, deferred_logger);
|
||||
}
|
||||
|
||||
|
||||
@ -1688,8 +1699,18 @@ namespace Opm
|
||||
|
||||
case Well2::InjectorCMode::THP:
|
||||
{
|
||||
OPM_DEFLOG_THROW(std::runtime_error, "Not handling THP control for Multisegment wells for now", deferred_logger);
|
||||
}
|
||||
std::vector<EvalWell> rates(3, 0.);
|
||||
if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) {
|
||||
rates[ Water ] = getSegmentRate(0, Indices::canonicalToActiveComponentIndex(FluidSystem::waterCompIdx));
|
||||
}
|
||||
if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
|
||||
rates[ Oil ] = getSegmentRate(0, Indices::canonicalToActiveComponentIndex(FluidSystem::oilCompIdx));
|
||||
}
|
||||
if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
|
||||
rates[ Gas ] = getSegmentRate(0, Indices::canonicalToActiveComponentIndex(FluidSystem::gasCompIdx));
|
||||
}
|
||||
control_eq = getSegmentPressure(0) - calculateBhpFromThp(rates, well, summaryState, deferred_logger);
|
||||
break; }
|
||||
case Well2::InjectorCMode::BHP:
|
||||
{
|
||||
const auto& bhp = controls.bhp_limit;
|
||||
@ -1790,8 +1811,18 @@ namespace Opm
|
||||
}
|
||||
case Well2::ProducerCMode::THP:
|
||||
{
|
||||
OPM_DEFLOG_THROW(std::runtime_error, "Not handling THP control for Multisegment wells for now", deferred_logger);
|
||||
}
|
||||
std::vector<EvalWell> rates(3, 0.);
|
||||
if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) {
|
||||
rates[ Water ] = getSegmentRate(0, Indices::canonicalToActiveComponentIndex(FluidSystem::waterCompIdx));
|
||||
}
|
||||
if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
|
||||
rates[ Oil ] = getSegmentRate(0, Indices::canonicalToActiveComponentIndex(FluidSystem::oilCompIdx));
|
||||
}
|
||||
if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
|
||||
rates[ Gas ] = getSegmentRate(0, Indices::canonicalToActiveComponentIndex(FluidSystem::gasCompIdx));
|
||||
}
|
||||
control_eq = getSegmentPressure(0) - calculateBhpFromThp(rates, well, summaryState, deferred_logger);
|
||||
break; }
|
||||
case Well2::ProducerCMode::GRUP:
|
||||
{
|
||||
assert(well.isAvailableForGroupControl());
|
||||
@ -1820,6 +1851,126 @@ namespace Opm
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
void
|
||||
MultisegmentWell<TypeTag>::
|
||||
updateThp(WellState& well_state, Opm::DeferredLogger& deferred_logger) const
|
||||
{
|
||||
// When there is no vaild VFP table provided, we set the thp to be zero.
|
||||
if (!this->isVFPActive(deferred_logger) || this->wellIsStopped()) {
|
||||
well_state.thp()[index_of_well_] = 0.;
|
||||
return;
|
||||
}
|
||||
|
||||
// the well is under other control types, we calculate the thp based on bhp and rates
|
||||
std::vector<double> rates(3, 0.0);
|
||||
|
||||
const Opm::PhaseUsage& pu = phaseUsage();
|
||||
if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) {
|
||||
rates[ Water ] = well_state.wellRates()[index_of_well_ * number_of_phases_ + pu.phase_pos[ Water ] ];
|
||||
}
|
||||
if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
|
||||
rates[ Oil ] = well_state.wellRates()[index_of_well_ * number_of_phases_ + pu.phase_pos[ Oil ] ];
|
||||
}
|
||||
if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
|
||||
rates[ Gas ] = well_state.wellRates()[index_of_well_ * number_of_phases_ + pu.phase_pos[ Gas ] ];
|
||||
}
|
||||
|
||||
const double bhp = well_state.bhp()[index_of_well_];
|
||||
|
||||
well_state.thp()[index_of_well_] = calculateThpFromBhp(rates, bhp, deferred_logger);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
double
|
||||
MultisegmentWell<TypeTag>::
|
||||
calculateThpFromBhp(const std::vector<double>& rates,
|
||||
const double bhp,
|
||||
Opm::DeferredLogger& deferred_logger) const
|
||||
{
|
||||
assert(int(rates.size()) == 3); // the vfp related only supports three phases now.
|
||||
|
||||
const double aqua = rates[Water];
|
||||
const double liquid = rates[Oil];
|
||||
const double vapour = rates[Gas];
|
||||
|
||||
// pick the density in the top segment
|
||||
const double rho = segment_densities_[0].value();
|
||||
|
||||
double thp = 0.0;
|
||||
if (well_type_ == INJECTOR) {
|
||||
const int table_id = well_ecl_.vfp_table_number();
|
||||
const double vfp_ref_depth = vfp_properties_->getInj()->getTable(table_id)->getDatumDepth();
|
||||
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
|
||||
|
||||
thp = vfp_properties_->getInj()->thp(table_id, aqua, liquid, vapour, bhp + dp);
|
||||
}
|
||||
else if (well_type_ == PRODUCER) {
|
||||
const int table_id = well_ecl_.vfp_table_number();
|
||||
const double alq = well_ecl_.alq_value();
|
||||
const double vfp_ref_depth = vfp_properties_->getProd()->getTable(table_id)->getDatumDepth();
|
||||
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
|
||||
|
||||
thp = vfp_properties_->getProd()->thp(table_id, aqua, liquid, vapour, bhp + dp, alq);
|
||||
}
|
||||
else {
|
||||
OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well", deferred_logger);
|
||||
}
|
||||
|
||||
return thp;
|
||||
}
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
template<class ValueType>
|
||||
ValueType
|
||||
MultisegmentWell<TypeTag>::
|
||||
calculateBhpFromThp(const std::vector<ValueType>& rates,
|
||||
const Well2& well,
|
||||
const SummaryState& summaryState,
|
||||
Opm::DeferredLogger& deferred_logger) const
|
||||
{
|
||||
// TODO: when well is under THP control, the BHP is dependent on the rates,
|
||||
// the well rates is also dependent on the BHP, so it might need to do some iteration.
|
||||
// However, when group control is involved, change of the rates might impacts other wells
|
||||
// so iterations on a higher level will be required. Some investigation might be needed when
|
||||
// we face problems under THP control.
|
||||
|
||||
assert(int(rates.size()) == 3); // the vfp related only supports three phases now.
|
||||
|
||||
const ValueType aqua = rates[Water];
|
||||
const ValueType liquid = rates[Oil];
|
||||
const ValueType vapour = rates[Gas];
|
||||
|
||||
// pick the density in the top layer
|
||||
// TODO: it is possible it should be a Evaluation
|
||||
const double rho = segment_densities_[0].value();
|
||||
|
||||
if (well.isInjector() )
|
||||
{
|
||||
const auto& controls = well.injectionControls(summaryState);
|
||||
const double vfp_ref_depth = vfp_properties_->getInj()->getTable(controls.vfp_table_number)->getDatumDepth();
|
||||
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
|
||||
return vfp_properties_->getInj()->bhp(controls.vfp_table_number, aqua, liquid, vapour, controls.thp_limit) - dp;
|
||||
}
|
||||
else if (well.isProducer()) {
|
||||
const auto& controls = well.productionControls(summaryState);
|
||||
const double vfp_ref_depth = vfp_properties_->getProd()->getTable(controls.vfp_table_number)->getDatumDepth();
|
||||
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
|
||||
return vfp_properties_->getProd()->bhp(controls.vfp_table_number, aqua, liquid, vapour, controls.thp_limit, controls.alq_value) - dp;
|
||||
}
|
||||
else {
|
||||
OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well", deferred_logger);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
template <typename TypeTag>
|
||||
void
|
||||
MultisegmentWell<TypeTag>::
|
||||
@ -2261,7 +2412,7 @@ namespace Opm
|
||||
template <typename TypeTag>
|
||||
void
|
||||
MultisegmentWell<TypeTag>::
|
||||
updateWellStateFromPrimaryVariables(WellState& well_state) const
|
||||
updateWellStateFromPrimaryVariables(WellState& well_state, Opm::DeferredLogger& deferred_logger) const
|
||||
{
|
||||
const PhaseUsage& pu = phaseUsage();
|
||||
assert( FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) );
|
||||
@ -2311,7 +2462,8 @@ namespace Opm
|
||||
if (seg == 0) { // top segment
|
||||
well_state.bhp()[index_of_well_] = well_state.segPress()[seg + top_segment_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
updateThp(well_state, deferred_logger);
|
||||
}
|
||||
|
||||
|
||||
@ -2398,7 +2550,7 @@ namespace Opm
|
||||
sstr << " relaxation_factor is " << relaxation_factor << " now\n";
|
||||
deferred_logger.debug(sstr.str());
|
||||
}
|
||||
updateWellState(dx_well, well_state, relaxation_factor);
|
||||
updateWellState(dx_well, well_state, deferred_logger, relaxation_factor);
|
||||
initPrimaryVariablesEvaluation();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user