mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #3458 from joakim-hove/single-well-state
Add SingleWellState
This commit is contained in:
commit
b8567b708e
@ -70,6 +70,7 @@ list (APPEND MAIN_SOURCE_FILES
|
||||
opm/simulators/wells/ParallelWellInfo.cpp
|
||||
opm/simulators/wells/PerfData.cpp
|
||||
opm/simulators/wells/SegmentState.cpp
|
||||
opm/simulators/wells/SingleWellState.cpp
|
||||
opm/simulators/wells/StandardWellEval.cpp
|
||||
opm/simulators/wells/StandardWellGeneric.cpp
|
||||
opm/simulators/wells/TargetCalculator.cpp
|
||||
@ -307,6 +308,7 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/simulators/wells/PerforationData.hpp
|
||||
opm/simulators/wells/RateConverter.hpp
|
||||
opm/simulators/utils/readDeck.hpp
|
||||
opm/simulators/wells/SingleWellState.hpp
|
||||
opm/simulators/wells/TargetCalculator.hpp
|
||||
opm/simulators/wells/WellConnectionAuxiliaryModule.hpp
|
||||
opm/simulators/wells/WellState.hpp
|
||||
|
@ -172,15 +172,16 @@ loadRestartData(const data::Wells& rst_wells,
|
||||
for( const auto& wm : well_state.wellMap() ) {
|
||||
const auto well_index = wm.second[ 0 ];
|
||||
const auto& rst_well = rst_wells.at( wm.first );
|
||||
well_state.update_thp(well_index, rst_well.thp);
|
||||
well_state.update_bhp(well_index, rst_well.bhp);
|
||||
well_state.update_temperature(well_index, rst_well.temperature);
|
||||
auto& ws = well_state.well(well_index);
|
||||
ws.bhp = rst_well.bhp;
|
||||
ws.thp = rst_well.thp;
|
||||
ws.temperature = rst_well.temperature;
|
||||
|
||||
if (rst_well.current_control.isProducer) {
|
||||
well_state.currentProductionControl(well_index, rst_well.current_control.prod);
|
||||
ws.production_cmode = rst_well.current_control.prod;
|
||||
}
|
||||
else {
|
||||
well_state.currentInjectionControl(well_index, rst_well.current_control.inj);
|
||||
ws.injection_cmode = rst_well.current_control.inj;
|
||||
}
|
||||
|
||||
for( size_t i = 0; i < phs.size(); ++i ) {
|
||||
|
@ -612,7 +612,7 @@ namespace Opm {
|
||||
if (this->wellTestState_.hasWellClosed(well_name)) {
|
||||
// TODO: more checking here, to make sure this standard more specific and complete
|
||||
// maybe there is some WCON keywords will not open the well
|
||||
auto& events = this->wellState().events(w);
|
||||
auto& events = this->wellState().well(w).events;
|
||||
if (events.hasEvent(WellState::event_mask)) {
|
||||
if (wellTestState_.lastTestTime(well_name) == ebosSimulator_.time()) {
|
||||
// The well was shut this timestep, we are most likely retrying
|
||||
@ -1424,7 +1424,7 @@ namespace Opm {
|
||||
|
||||
if (!well->isOperable() ) continue;
|
||||
|
||||
auto& events = this->wellState().events(well->indexOfWell());
|
||||
auto& events = this->wellState().well(well->indexOfWell()).events;
|
||||
if (events.hasEvent(WellState::event_mask)) {
|
||||
well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), deferred_logger);
|
||||
// There is no new well control change input within a report step,
|
||||
@ -1732,7 +1732,7 @@ namespace Opm {
|
||||
}
|
||||
weighted_temperature = well_info.communication().sum(weighted_temperature);
|
||||
total_weight = well_info.communication().sum(total_weight);
|
||||
this->wellState().update_temperature(wellID, weighted_temperature/total_weight);
|
||||
this->wellState().well(wellID).temperature = weighted_temperature/total_weight;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,9 +202,9 @@ checkDoGasLiftOptimization_(const std::string &well_name)
|
||||
if (itr != this->ecl_wells_.end()) {
|
||||
//const Well *well = (itr->second).first;
|
||||
//assert(well); // Should never be nullptr
|
||||
const int index = (itr->second).second;
|
||||
const Well::ProducerCMode& control_mode
|
||||
= this->well_state_.currentProductionControl(index);
|
||||
const int well_index = (itr->second).second;
|
||||
const auto& ws = this->well_state_.well(well_index);
|
||||
const Well::ProducerCMode& control_mode = ws.production_cmode;
|
||||
if (control_mode != Well::ProducerCMode::THP ) {
|
||||
displayDebugMessage_("Not THP control. Skipping.", well_name);
|
||||
return false;
|
||||
|
@ -1235,9 +1235,8 @@ bool
|
||||
GasLiftSingleWellGeneric::OptimizeState::
|
||||
checkThpControl()
|
||||
{
|
||||
const int index = this->parent.well_state_.wellIndex(this->parent.well_name_);
|
||||
const Well::ProducerCMode& control_mode
|
||||
= this->parent.well_state_.currentProductionControl(index);
|
||||
const int well_index = this->parent.well_state_.wellIndex(this->parent.well_name_);
|
||||
const Well::ProducerCMode& control_mode = this->parent.well_state_.well(well_index).production_cmode;
|
||||
return control_mode == Well::ProducerCMode::THP;
|
||||
}
|
||||
|
||||
|
@ -37,10 +37,8 @@ GlobalWellInfo::GlobalWellInfo(const Schedule& sched, std::size_t report_step, c
|
||||
this->name_map.emplace( well.name(), global_well_index );
|
||||
}
|
||||
|
||||
for (const auto& well : local_wells) {
|
||||
for (const auto& well : local_wells)
|
||||
this->local_map.push_back( well.seqIndex() );
|
||||
this->is_injector.push_back( well.isInjector() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -56,23 +54,19 @@ bool GlobalWellInfo::in_producing_group(const std::string& wname) const {
|
||||
}
|
||||
|
||||
|
||||
void GlobalWellInfo::update_group(const std::vector<Well::Status>& well_status, const std::vector<Well::InjectorCMode>& injection_cmode, const std::vector<Well::ProducerCMode>& production_cmode) {
|
||||
if (well_status.size() != this->local_map.size())
|
||||
throw std::logic_error("Size mismatch");
|
||||
void GlobalWellInfo::update_injector(std::size_t well_index, Well::Status well_status, Well::InjectorCMode injection_cmode) {
|
||||
if (well_status == Well::Status::OPEN && injection_cmode == Well::InjectorCMode::GRUP)
|
||||
this->m_in_injecting_group[this->local_map[well_index]] = 1;
|
||||
}
|
||||
|
||||
void GlobalWellInfo::update_producer(std::size_t well_index, Well::Status well_status, Well::ProducerCMode production_cmode) {
|
||||
if (well_status == Well::Status::OPEN && production_cmode == Well::ProducerCMode::GRUP)
|
||||
this->m_in_producing_group[this->local_map[well_index]] = 1;
|
||||
}
|
||||
|
||||
void GlobalWellInfo::clear() {
|
||||
this->m_in_injecting_group.assign(this->name_map.size(), 0);
|
||||
this->m_in_producing_group.assign(this->name_map.size(), 0);
|
||||
for (std::size_t well_index = 0; well_index < well_status.size(); well_index++) {
|
||||
if (well_status[well_index] == Well::Status::OPEN) {
|
||||
if (this->is_injector[well_index]) {
|
||||
if (injection_cmode[well_index] == Well::InjectorCMode::GRUP)
|
||||
this->m_in_injecting_group[this->local_map[well_index]] = 1;
|
||||
} else {
|
||||
if (production_cmode[well_index] == Well::ProducerCMode::GRUP)
|
||||
this->m_in_producing_group[this->local_map[well_index]] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,13 +69,14 @@ public:
|
||||
GlobalWellInfo(const Schedule& sched, std::size_t report_step, const std::vector<Well>& local_wells);
|
||||
bool in_producing_group(const std::string& wname) const;
|
||||
bool in_injecting_group(const std::string& wname) const;
|
||||
void update_group(const std::vector<Well::Status>& well_status, const std::vector<Well::InjectorCMode>& injection_cmode, const std::vector<Well::ProducerCMode>& production_cmode);
|
||||
std::size_t well_index(const std::string& wname) const;
|
||||
const std::string& well_name(std::size_t well_index) const;
|
||||
void update_injector(std::size_t well_index, Well::Status well_status, Well::InjectorCMode injection_cmode);
|
||||
void update_producer(std::size_t well_index, Well::Status well_status, Well::ProducerCMode production_cmode);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
std::vector<std::size_t> local_map; // local_index -> global_index
|
||||
std::vector<bool> is_injector; // local_index -> bool
|
||||
|
||||
std::map<std::string, std::size_t> name_map; // string -> global_index
|
||||
std::vector<int> m_in_injecting_group; // global_index -> int/bool
|
||||
|
@ -155,9 +155,10 @@ checkConvergenceControlEq(const WellState& well_state,
|
||||
CR::WellFailure::Type ctrltype = CR::WellFailure::Type::Invalid;
|
||||
|
||||
const int well_index = baseif_.indexOfWell();
|
||||
const auto& ws = well_state.well(well_index);
|
||||
if (baseif_.isInjector() )
|
||||
{
|
||||
auto current = well_state.currentInjectionControl(well_index);
|
||||
auto current = ws.injection_cmode;
|
||||
switch(current) {
|
||||
case Well::InjectorCMode::THP:
|
||||
ctrltype = CR::WellFailure::Type::ControlTHP;
|
||||
@ -183,7 +184,7 @@ checkConvergenceControlEq(const WellState& well_state,
|
||||
|
||||
if (baseif_.isProducer() )
|
||||
{
|
||||
auto current = well_state.currentProductionControl(well_index);
|
||||
auto current = ws.production_cmode;
|
||||
switch(current) {
|
||||
case Well::ProducerCMode::THP:
|
||||
ctrltype = CR::WellFailure::Type::ControlTHP;
|
||||
@ -1474,7 +1475,8 @@ updateThp(WellState& well_state,
|
||||
|
||||
// When there is no vaild VFP table provided, we set the thp to be zero.
|
||||
if (!baseif_.isVFPActive(deferred_logger) || baseif_.wellIsStopped()) {
|
||||
well_state.update_thp(baseif_.indexOfWell(), 0.);
|
||||
auto& well = well_state.well(baseif_.indexOfWell());
|
||||
well.thp = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1492,9 +1494,9 @@ updateThp(WellState& well_state,
|
||||
rates[ Gas ] = well_state.wellRates(baseif_.indexOfWell())[pu.phase_pos[ Gas ] ];
|
||||
}
|
||||
|
||||
const double bhp = well_state.bhp(baseif_.indexOfWell());
|
||||
|
||||
well_state.update_thp(baseif_.indexOfWell(), this->calculateThpFromBhp(rates, bhp, rho, deferred_logger));
|
||||
auto& well = well_state.well(baseif_.indexOfWell());
|
||||
const double bhp = well.bhp;
|
||||
well.thp = this->calculateThpFromBhp(rates, bhp, rho, deferred_logger);
|
||||
}
|
||||
|
||||
template<typename FluidSystem, typename Indices, typename Scalar>
|
||||
@ -1614,6 +1616,7 @@ updateWellStateFromPrimaryVariables(WellState& well_state,
|
||||
assert( FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) );
|
||||
const int oil_pos = pu.phase_pos[Oil];
|
||||
|
||||
auto& well = well_state.well(baseif_.indexOfWell());
|
||||
auto& segments = well_state.segments(baseif_.indexOfWell());
|
||||
auto& segment_rates = segments.rates;
|
||||
auto& segment_pressure = segments.pressure;
|
||||
@ -1658,7 +1661,7 @@ updateWellStateFromPrimaryVariables(WellState& well_state,
|
||||
// update the segment pressure
|
||||
segment_pressure[seg] = primary_variables_[seg][SPres];
|
||||
if (seg == 0) { // top segment
|
||||
well_state.update_bhp(baseif_.indexOfWell(), segment_pressure[seg]);
|
||||
well.bhp = segment_pressure[seg];
|
||||
}
|
||||
}
|
||||
updateThp(well_state, rho, deferred_logger);
|
||||
@ -1795,9 +1798,10 @@ getControlTolerance(const WellState& well_state,
|
||||
double control_tolerance = 0.;
|
||||
|
||||
const int well_index = baseif_.indexOfWell();
|
||||
const auto& ws = well_state.well(well_index);
|
||||
if (baseif_.isInjector() )
|
||||
{
|
||||
auto current = well_state.currentInjectionControl(well_index);
|
||||
auto current = ws.injection_cmode;
|
||||
switch(current) {
|
||||
case Well::InjectorCMode::THP:
|
||||
control_tolerance = tolerance_pressure_ms_wells;
|
||||
@ -1819,7 +1823,7 @@ getControlTolerance(const WellState& well_state,
|
||||
|
||||
if (baseif_.isProducer() )
|
||||
{
|
||||
auto current = well_state.currentProductionControl(well_index);
|
||||
auto current = ws.production_cmode;
|
||||
switch(current) {
|
||||
case Well::ProducerCMode::THP:
|
||||
control_tolerance = tolerance_pressure_ms_wells; // 0.1 bar
|
||||
|
@ -136,8 +136,9 @@ void
|
||||
MultisegmentWellGeneric<Scalar>::
|
||||
scaleSegmentPressuresWithBhp(WellState& well_state) const
|
||||
{
|
||||
auto& well = well_state.well(baseif_.indexOfWell());
|
||||
auto& segments = well_state.segments(baseif_.indexOfWell());
|
||||
auto bhp = well_state.bhp(baseif_.indexOfWell());
|
||||
const auto bhp = well.bhp;
|
||||
segments.scale_pressure(bhp);
|
||||
}
|
||||
|
||||
|
@ -257,8 +257,9 @@ namespace Opm
|
||||
// If the well is pressure controlled the potential equals the rate.
|
||||
bool thp_controlled_well = false;
|
||||
bool bhp_controlled_well = false;
|
||||
const auto& ws = well_state.well(this->index_of_well_);
|
||||
if (this->isInjector()) {
|
||||
const Well::InjectorCMode& current = well_state.currentInjectionControl(index_of_well_);
|
||||
const Well::InjectorCMode& current = ws.injection_cmode;
|
||||
if (current == Well::InjectorCMode::THP) {
|
||||
thp_controlled_well = true;
|
||||
}
|
||||
@ -266,7 +267,7 @@ namespace Opm
|
||||
bhp_controlled_well = true;
|
||||
}
|
||||
} else {
|
||||
const Well::ProducerCMode& current = well_state.currentProductionControl(index_of_well_);
|
||||
const Well::ProducerCMode& current = ws.production_cmode;
|
||||
if (current == Well::ProducerCMode::THP) {
|
||||
thp_controlled_well = true;
|
||||
}
|
||||
@ -340,6 +341,7 @@ namespace Opm
|
||||
// store a copy of the well state, we don't want to update the real well state
|
||||
WellState well_state_copy = ebosSimulator.problem().wellModel().wellState();
|
||||
const auto& group_state = ebosSimulator.problem().wellModel().groupState();
|
||||
auto& ws = well_state_copy.well(this->index_of_well_);
|
||||
|
||||
// Get the current controls.
|
||||
const auto& summary_state = ebosSimulator.vanguard().summaryState();
|
||||
@ -353,12 +355,12 @@ namespace Opm
|
||||
// Set current control to bhp, and bhp value in state, modify bhp limit in control object.
|
||||
if (well_copy.well_ecl_.isInjector()) {
|
||||
inj_controls.bhp_limit = bhp;
|
||||
well_state_copy.currentInjectionControl(index_of_well_, Well::InjectorCMode::BHP);
|
||||
ws.injection_cmode = Well::InjectorCMode::BHP;
|
||||
} else {
|
||||
prod_controls.bhp_limit = bhp;
|
||||
well_state_copy.currentProductionControl(index_of_well_, Well::ProducerCMode::BHP);
|
||||
ws.production_cmode = Well::ProducerCMode::BHP;
|
||||
}
|
||||
well_state_copy.update_bhp(well_copy.index_of_well_, bhp);
|
||||
ws.bhp = bhp;
|
||||
well_copy.scaleSegmentPressuresWithBhp(well_state_copy);
|
||||
|
||||
// initialized the well rates with the potentials i.e. the well rates based on bhp
|
||||
|
60
opm/simulators/wells/SingleWellState.cpp
Normal file
60
opm/simulators/wells/SingleWellState.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2021 Equinor ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <opm/simulators/wells/SingleWellState.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
SingleWellState::SingleWellState(bool is_producer, double temp)
|
||||
: producer(is_producer)
|
||||
, temperature(temp)
|
||||
{}
|
||||
|
||||
|
||||
void SingleWellState::init_timestep(const SingleWellState& other) {
|
||||
if (this->producer != other.producer)
|
||||
return;
|
||||
|
||||
if (this->status == Well::Status::SHUT)
|
||||
return;
|
||||
|
||||
if (other.status == Well::Status::SHUT)
|
||||
return;
|
||||
|
||||
this->bhp = other.bhp;
|
||||
this->thp = other.thp;
|
||||
this->temperature = other.temperature;
|
||||
}
|
||||
|
||||
|
||||
void SingleWellState::shut() {
|
||||
this->bhp = 0;
|
||||
this->thp = 0;
|
||||
this->status = Well::Status::SHUT;
|
||||
}
|
||||
|
||||
void SingleWellState::stop() {
|
||||
this->thp = 0;
|
||||
this->status = Well::Status::STOP;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
52
opm/simulators/wells/SingleWellState.hpp
Normal file
52
opm/simulators/wells/SingleWellState.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2021 Equinor ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_SINGLE_WELL_STATE_HEADER_INCLUDED
|
||||
#define OPM_SINGLE_WELL_STATE_HEADER_INCLUDED
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Events.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class SingleWellState {
|
||||
public:
|
||||
SingleWellState(bool is_producer, double temp);
|
||||
|
||||
Well::Status status{Well::Status::OPEN};
|
||||
bool producer;
|
||||
double bhp{0};
|
||||
double thp{0};
|
||||
double temperature{};
|
||||
Events events;
|
||||
Well::InjectorCMode injection_cmode{Well::InjectorCMode::CMODE_UNDEFINED};
|
||||
Well::ProducerCMode production_cmode{Well::ProducerCMode::CMODE_UNDEFINED};
|
||||
|
||||
|
||||
void init_timestep(const SingleWellState& other);
|
||||
void shut();
|
||||
void stop();
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -255,7 +255,7 @@ updatePrimaryVariables(const WellState& well_state, DeferredLogger& deferred_log
|
||||
const int well_index = baseif_.indexOfWell();
|
||||
const int np = baseif_.numPhases();
|
||||
const auto& pu = baseif_.phaseUsage();
|
||||
|
||||
const auto& well = well_state.well(well_index);
|
||||
// the weighted total well rate
|
||||
double total_well_rate = 0.0;
|
||||
for (int p = 0; p < np; ++p) {
|
||||
@ -339,7 +339,7 @@ updatePrimaryVariables(const WellState& well_state, DeferredLogger& deferred_log
|
||||
|
||||
|
||||
// BHP
|
||||
primary_variables_[Bhp] = well_state.bhp(baseif_.indexOfWell());
|
||||
primary_variables_[Bhp] = well.bhp;
|
||||
}
|
||||
|
||||
template<class FluidSystem, class Indices, class Scalar>
|
||||
@ -553,10 +553,11 @@ updateThp(WellState& well_state,
|
||||
static constexpr int Gas = WellInterfaceIndices<FluidSystem,Indices,Scalar>::Gas;
|
||||
static constexpr int Oil = WellInterfaceIndices<FluidSystem,Indices,Scalar>::Oil;
|
||||
static constexpr int Water = WellInterfaceIndices<FluidSystem,Indices,Scalar>::Water;
|
||||
auto& well = well_state.well(baseif_.indexOfWell());
|
||||
|
||||
// When there is no vaild VFP table provided, we set the thp to be zero.
|
||||
if (!baseif_.isVFPActive(deferred_logger) || baseif_.wellIsStopped()) {
|
||||
well_state.update_thp(baseif_.indexOfWell(), 0);
|
||||
well.thp = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -574,13 +575,12 @@ updateThp(WellState& well_state,
|
||||
rates[ Gas ] = well_state.wellRates(baseif_.indexOfWell())[pu.phase_pos[ Gas ] ];
|
||||
}
|
||||
|
||||
const double bhp = well_state.bhp(baseif_.indexOfWell());
|
||||
const double bhp = well.bhp;
|
||||
|
||||
well_state.update_thp(baseif_.indexOfWell(),
|
||||
this->calculateThpFromBhp(well_state,
|
||||
rates,
|
||||
bhp,
|
||||
deferred_logger));
|
||||
well.thp = this->calculateThpFromBhp(well_state,
|
||||
rates,
|
||||
bhp,
|
||||
deferred_logger);
|
||||
}
|
||||
|
||||
template<class FluidSystem, class Indices, class Scalar>
|
||||
@ -652,7 +652,8 @@ updateWellStateFromPrimaryVariables(WellState& well_state,
|
||||
F[pu.phase_pos[Gas]] += F_solvent;
|
||||
}
|
||||
|
||||
well_state.update_bhp(baseif_.indexOfWell(), primary_variables_[Bhp]);
|
||||
auto& well = well_state.well(baseif_.indexOfWell());
|
||||
well.bhp = primary_variables_[Bhp];
|
||||
|
||||
// calculate the phase rates based on the primary variables
|
||||
// for producers, this is not a problem, while not sure for injectors here
|
||||
|
@ -265,7 +265,7 @@ doGasLiftOptimize(const WellState &well_state,
|
||||
}
|
||||
if (glift_optimize_only_thp_wells) {
|
||||
const int well_index = baseif_.indexOfWell();
|
||||
auto control_mode = well_state.currentProductionControl(well_index);
|
||||
auto control_mode = well_state.well(well_index).production_cmode;
|
||||
if (control_mode != Well::ProducerCMode::THP ) {
|
||||
gliftDebug("Not THP control", deferred_logger);
|
||||
return false;
|
||||
@ -698,13 +698,14 @@ checkConvergenceControlEq(const WellState& well_state,
|
||||
CR::WellFailure::Type ctrltype = CR::WellFailure::Type::Invalid;
|
||||
|
||||
const int well_index = baseif_.indexOfWell();
|
||||
const auto& ws = well_state.well(well_index);
|
||||
if (baseif_.wellIsStopped()) {
|
||||
ctrltype = CR::WellFailure::Type::ControlRate;
|
||||
control_tolerance = 1.e-6; // use smaller tolerance for zero control?
|
||||
}
|
||||
else if (baseif_.isInjector() )
|
||||
{
|
||||
auto current = well_state.currentInjectionControl(well_index);
|
||||
auto current = ws.injection_cmode;
|
||||
switch(current) {
|
||||
case Well::InjectorCMode::THP:
|
||||
ctrltype = CR::WellFailure::Type::ControlTHP;
|
||||
@ -729,7 +730,7 @@ checkConvergenceControlEq(const WellState& well_state,
|
||||
}
|
||||
else if (baseif_.isProducer() )
|
||||
{
|
||||
auto current = well_state.currentProductionControl(well_index);
|
||||
auto current = ws.production_cmode;
|
||||
switch(current) {
|
||||
case Well::ProducerCMode::THP:
|
||||
ctrltype = CR::WellFailure::Type::ControlTHP;
|
||||
|
@ -547,6 +547,7 @@ namespace Opm
|
||||
cq_s, perf_dis_gas_rate, perf_vap_oil_rate, deferred_logger);
|
||||
|
||||
auto& perf_data = well_state.perfData(this->index_of_well_);
|
||||
auto& ws = well_state.well(this->index_of_well_);
|
||||
if constexpr (has_polymer && Base::has_polymermw) {
|
||||
if (this->isInjector()) {
|
||||
// Store the original water flux computed from the reservoir quantities.
|
||||
@ -694,7 +695,7 @@ namespace Opm
|
||||
}
|
||||
|
||||
// Store the perforation pressure for later usage.
|
||||
perf_data.pressure[perf] = well_state.bhp(this->index_of_well_) + this->perf_pressure_diffs_[perf];
|
||||
perf_data.pressure[perf] = ws.bhp + this->perf_pressure_diffs_[perf];
|
||||
}
|
||||
|
||||
|
||||
@ -1156,7 +1157,7 @@ namespace Opm
|
||||
const WellState& well_state,
|
||||
DeferredLogger& deferred_logger)
|
||||
{
|
||||
const double bhp = well_state.bhp(index_of_well_);
|
||||
const double bhp = well_state.well(index_of_well_).bhp;
|
||||
std::vector<double> well_rates;
|
||||
computeWellRatesWithBhp(ebos_simulator, bhp, well_rates, deferred_logger);
|
||||
|
||||
@ -1211,6 +1212,7 @@ namespace Opm
|
||||
b_perf.resize(nperf * num_components_);
|
||||
surf_dens_perf.resize(nperf * num_components_);
|
||||
const int w = index_of_well_;
|
||||
const auto& ws = well_state.well(this->index_of_well_);
|
||||
|
||||
const bool waterPresent = FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx);
|
||||
const bool oilPresent = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx);
|
||||
@ -1224,7 +1226,7 @@ namespace Opm
|
||||
|
||||
// Compute the average pressure in each well block
|
||||
const auto& perf_press = well_state.perfData(w).pressure;
|
||||
auto p_above = this->parallel_well_info_.communicateAboveValues(well_state.bhp(w),
|
||||
auto p_above = this->parallel_well_info_.communicateAboveValues(ws.bhp,
|
||||
perf_press.data(),
|
||||
nperf);
|
||||
|
||||
@ -1681,14 +1683,15 @@ namespace Opm
|
||||
// to replace the original one
|
||||
WellState well_state_copy = ebosSimulator.problem().wellModel().wellState();
|
||||
const auto& group_state = ebosSimulator.problem().wellModel().groupState();
|
||||
auto& ws = well_state_copy.well(this->index_of_well_);
|
||||
|
||||
// Set current control to bhp, and bhp value in state, modify bhp limit in control object.
|
||||
if (well_ecl_.isInjector()) {
|
||||
well_state_copy.currentInjectionControl(index_of_well_, Well::InjectorCMode::BHP);
|
||||
ws.injection_cmode = Well::InjectorCMode::BHP;
|
||||
} else {
|
||||
well_state_copy.currentProductionControl(index_of_well_, Well::ProducerCMode::BHP);
|
||||
ws.production_cmode = Well::ProducerCMode::BHP;
|
||||
}
|
||||
well_state_copy.update_bhp(index_of_well_, bhp);
|
||||
ws.bhp = bhp;
|
||||
|
||||
const double dt = ebosSimulator.timeStepSize();
|
||||
bool converged = this->iterateWellEquations(ebosSimulator, dt, well_state_copy, group_state, deferred_logger);
|
||||
@ -1836,8 +1839,9 @@ namespace Opm
|
||||
// If the well is pressure controlled the potential equals the rate.
|
||||
bool thp_controlled_well = false;
|
||||
bool bhp_controlled_well = false;
|
||||
const auto& ws = well_state.well(this->index_of_well_);
|
||||
if (this->isInjector()) {
|
||||
const Well::InjectorCMode& current = well_state.currentInjectionControl(index_of_well_);
|
||||
const Well::InjectorCMode& current = ws.injection_cmode;
|
||||
if (current == Well::InjectorCMode::THP) {
|
||||
thp_controlled_well = true;
|
||||
}
|
||||
@ -1845,7 +1849,7 @@ namespace Opm
|
||||
bhp_controlled_well = true;
|
||||
}
|
||||
} else {
|
||||
const Well::ProducerCMode& current = well_state.currentProductionControl(index_of_well_);
|
||||
const Well::ProducerCMode& current = ws.production_cmode;
|
||||
if (current == Well::ProducerCMode::THP) {
|
||||
thp_controlled_well = true;
|
||||
}
|
||||
|
@ -61,20 +61,22 @@ public:
|
||||
return this->m_data.size();
|
||||
}
|
||||
|
||||
void add(const std::string& name, T&& value) {
|
||||
T& add(const std::string& name, T&& value) {
|
||||
if (index_map.count(name) != 0)
|
||||
throw std::logic_error("An object with name: " + name + " already exists in container");
|
||||
|
||||
this->index_map.emplace(name, this->m_data.size());
|
||||
this->m_data.push_back(std::forward<T>(value));
|
||||
return this->m_data.back();
|
||||
}
|
||||
|
||||
void add(const std::string& name, const T& value) {
|
||||
T& add(const std::string& name, const T& value) {
|
||||
if (index_map.count(name) != 0)
|
||||
throw std::logic_error("An object with name: " + name + " already exists in container");
|
||||
|
||||
this->index_map.emplace(name, this->m_data.size());
|
||||
this->m_data.push_back(value);
|
||||
return this->m_data.back();
|
||||
}
|
||||
|
||||
bool has(const std::string& name) const {
|
||||
|
@ -404,13 +404,14 @@ namespace WellGroupHelpers
|
||||
|
||||
const double efficiency = wellTmp.getEfficiencyFactor();
|
||||
// add contributino from wells not under group control
|
||||
const auto& ws = wellState.well(well_index);
|
||||
if (isInjector) {
|
||||
if (wellState.currentInjectionControl(well_index) != Well::InjectorCMode::GRUP)
|
||||
if (ws.injection_cmode != Well::InjectorCMode::GRUP)
|
||||
for (int phase = 0; phase < np; phase++) {
|
||||
groupTargetReduction[phase] += wellStateNupcol.wellRates(well_index)[phase] * efficiency;
|
||||
}
|
||||
} else {
|
||||
if (wellState.currentProductionControl(well_index) != Well::ProducerCMode::GRUP)
|
||||
if (ws.production_cmode != Well::ProducerCMode::GRUP)
|
||||
for (int phase = 0; phase < np; phase++) {
|
||||
groupTargetReduction[phase] -= wellStateNupcol.wellRates(well_index)[phase] * efficiency;
|
||||
}
|
||||
@ -480,13 +481,14 @@ namespace WellGroupHelpers
|
||||
}
|
||||
|
||||
// scale rates
|
||||
const auto& ws = wellState.well(well_index);
|
||||
if (isInjector) {
|
||||
if (wellState.currentInjectionControl(well_index) == Well::InjectorCMode::GRUP)
|
||||
if (ws.injection_cmode == Well::InjectorCMode::GRUP)
|
||||
for (int phase = 0; phase < np; phase++) {
|
||||
wellState.wellRates(well_index)[phase] *= scale;
|
||||
}
|
||||
} else {
|
||||
if (wellState.currentProductionControl(well_index) == Well::ProducerCMode::GRUP)
|
||||
if (ws.production_cmode == Well::ProducerCMode::GRUP)
|
||||
for (int phase = 0; phase < np; phase++) {
|
||||
wellState.wellRates(well_index)[phase] *= scale;
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ assembleControlEqProd_(const WellState& well_state,
|
||||
EvalWell& control_eq,
|
||||
DeferredLogger& deferred_logger) const
|
||||
{
|
||||
auto current = well_state.currentProductionControl(baseif_.indexOfWell());
|
||||
const auto current = well_state.well(baseif_.indexOfWell()).production_cmode;
|
||||
const auto& pu = baseif_.phaseUsage();
|
||||
const double efficiencyFactor = baseif_.wellEcl().getEfficiencyFactor();
|
||||
|
||||
@ -392,7 +392,7 @@ assembleControlEqInj_(const WellState& well_state,
|
||||
EvalWell& control_eq,
|
||||
DeferredLogger& deferred_logger) const
|
||||
{
|
||||
auto current = well_state.currentInjectionControl(baseif_.indexOfWell());
|
||||
auto current = well_state.well(baseif_.indexOfWell()).injection_cmode;
|
||||
const InjectorType injectorType = controls.injector_type;
|
||||
const auto& pu = baseif_.phaseUsage();
|
||||
const double efficiencyFactor = baseif_.wellEcl().getEfficiencyFactor();
|
||||
|
@ -90,11 +90,12 @@ activeProductionConstraint(const WellState& well_state,
|
||||
const PhaseUsage& pu = this->phaseUsage();
|
||||
const int well_index = this->index_of_well_;
|
||||
const auto controls = this->well_ecl_.productionControls(summaryState);
|
||||
auto currentControl = well_state.currentProductionControl(well_index);
|
||||
auto& ws = well_state.well(well_index);
|
||||
const auto currentControl = ws.production_cmode;
|
||||
|
||||
if (controls.hasControl(Well::ProducerCMode::BHP) && currentControl != Well::ProducerCMode::BHP) {
|
||||
const double bhp_limit = controls.bhp_limit;
|
||||
double current_bhp = well_state.bhp(well_index);
|
||||
double current_bhp = ws.bhp;
|
||||
if (bhp_limit > current_bhp)
|
||||
return Well::ProducerCMode::BHP;
|
||||
}
|
||||
@ -164,12 +165,12 @@ activeProductionConstraint(const WellState& well_state,
|
||||
|
||||
if (controls.hasControl(Well::ProducerCMode::THP) && currentControl != Well::ProducerCMode::THP) {
|
||||
const auto& thp = getTHPConstraint(summaryState);
|
||||
double current_thp = well_state.thp(well_index);
|
||||
double current_thp = ws.thp;
|
||||
if (thp > current_thp)
|
||||
return Well::ProducerCMode::THP;
|
||||
}
|
||||
|
||||
return well_state.currentProductionControl(well_index);
|
||||
return currentControl;
|
||||
}
|
||||
|
||||
|
||||
@ -181,14 +182,15 @@ activeInjectionConstraint(const WellState& well_state,
|
||||
{
|
||||
const PhaseUsage& pu = this->phaseUsage();
|
||||
const int well_index = this->index_of_well_;
|
||||
const auto& ws = well_state.well(well_index);
|
||||
|
||||
const auto controls = this->well_ecl_.injectionControls(summaryState);
|
||||
auto currentControl = well_state.currentInjectionControl(well_index);
|
||||
const auto currentControl = ws.injection_cmode;
|
||||
|
||||
if (controls.hasControl(Well::InjectorCMode::BHP) && currentControl != Well::InjectorCMode::BHP)
|
||||
{
|
||||
const auto& bhp = controls.bhp_limit;
|
||||
double current_bhp = well_state.bhp(well_index);
|
||||
double current_bhp = ws.bhp;
|
||||
if (bhp < current_bhp)
|
||||
return Well::InjectorCMode::BHP;
|
||||
}
|
||||
@ -241,12 +243,12 @@ activeInjectionConstraint(const WellState& well_state,
|
||||
if (controls.hasControl(Well::InjectorCMode::THP) && currentControl != Well::InjectorCMode::THP)
|
||||
{
|
||||
const auto& thp = getTHPConstraint(summaryState);
|
||||
double current_thp = well_state.thp(well_index);
|
||||
double current_thp = ws.thp;
|
||||
if (thp < current_thp)
|
||||
return Well::InjectorCMode::THP;
|
||||
}
|
||||
|
||||
return well_state.currentInjectionControl(well_index);
|
||||
return currentControl;
|
||||
}
|
||||
|
||||
template <typename FluidSystem>
|
||||
@ -256,18 +258,19 @@ checkIndividualConstraints(WellState& well_state,
|
||||
const SummaryState& summaryState) const
|
||||
{
|
||||
const int well_index = this->index_of_well_;
|
||||
auto& ws = well_state.well(well_index);
|
||||
if (this->well_ecl_.isProducer()) {
|
||||
auto new_cmode = this->activeProductionConstraint(well_state, summaryState);
|
||||
if (new_cmode != well_state.currentProductionControl(well_index)) {
|
||||
well_state.currentProductionControl(well_index, new_cmode);
|
||||
if (new_cmode != ws.production_cmode) {
|
||||
ws.production_cmode = new_cmode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->well_ecl_.isInjector()) {
|
||||
auto new_cmode = this->activeInjectionConstraint(well_state, summaryState);
|
||||
if (new_cmode != well_state.currentInjectionControl(well_index)) {
|
||||
well_state.currentInjectionControl(well_index, new_cmode);
|
||||
if (new_cmode != ws.injection_cmode) {
|
||||
ws.injection_cmode = new_cmode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -374,9 +377,10 @@ checkGroupConstraints(WellState& well_state,
|
||||
{
|
||||
const auto& well = well_ecl_;
|
||||
const int well_index = index_of_well_;
|
||||
auto& ws = well_state.well(well_index);
|
||||
|
||||
if (well.isInjector()) {
|
||||
auto currentControl = well_state.currentInjectionControl(well_index);
|
||||
const auto currentControl = ws.injection_cmode;
|
||||
|
||||
if (currentControl != Well::InjectorCMode::GRUP) {
|
||||
// This checks only the first encountered group limit,
|
||||
@ -393,7 +397,7 @@ checkGroupConstraints(WellState& well_state,
|
||||
// If a group constraint was broken, we set the current well control to
|
||||
// be GRUP.
|
||||
if (group_constraint.first) {
|
||||
well_state.currentInjectionControl(index_of_well_, Well::InjectorCMode::GRUP);
|
||||
ws.injection_cmode = Well::InjectorCMode::GRUP;
|
||||
const int np = well_state.numPhases();
|
||||
for (int p = 0; p<np; ++p) {
|
||||
well_state.wellRates(index_of_well_)[p] *= group_constraint.second;
|
||||
@ -404,7 +408,7 @@ checkGroupConstraints(WellState& well_state,
|
||||
}
|
||||
|
||||
if (well.isProducer( )) {
|
||||
auto currentControl = well_state.currentProductionControl(well_index);
|
||||
const auto currentControl = ws.production_cmode;
|
||||
|
||||
if (currentControl != Well::ProducerCMode::GRUP) {
|
||||
// This checks only the first encountered group limit,
|
||||
@ -421,7 +425,7 @@ checkGroupConstraints(WellState& well_state,
|
||||
// If a group constraint was broken, we set the current well control to
|
||||
// be GRUP.
|
||||
if (group_constraint.first) {
|
||||
well_state.currentProductionControl(index_of_well_, Well::ProducerCMode::GRUP);
|
||||
ws.production_cmode = Well::ProducerCMode::GRUP;
|
||||
const int np = well_state.numPhases();
|
||||
for (int p = 0; p<np; ++p) {
|
||||
well_state.wellRates(index_of_well_)[p] *= group_constraint.second;
|
||||
|
@ -165,11 +165,12 @@ namespace Opm
|
||||
const auto& summaryState = ebos_simulator.vanguard().summaryState();
|
||||
const auto& schedule = ebos_simulator.vanguard().schedule();
|
||||
const auto& well = this->well_ecl_;
|
||||
auto& ws = well_state.well(this->index_of_well_);
|
||||
std::string from;
|
||||
if (well.isInjector()) {
|
||||
from = Well::InjectorCMode2String(well_state.currentInjectionControl(this->index_of_well_));
|
||||
from = Well::InjectorCMode2String(ws.injection_cmode);
|
||||
} else {
|
||||
from = Well::ProducerCMode2String(well_state.currentProductionControl(this->index_of_well_));
|
||||
from = Well::ProducerCMode2String(ws.production_cmode);
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
@ -188,9 +189,9 @@ namespace Opm
|
||||
if (changed) {
|
||||
std::string to;
|
||||
if (well.isInjector()) {
|
||||
to = Well::InjectorCMode2String(well_state.currentInjectionControl(this->index_of_well_));
|
||||
to = Well::InjectorCMode2String(ws.injection_cmode);
|
||||
} else {
|
||||
to = Well::ProducerCMode2String(well_state.currentProductionControl(this->index_of_well_));
|
||||
to = Well::ProducerCMode2String(ws.production_cmode);
|
||||
}
|
||||
std::ostringstream ss;
|
||||
ss << " Switching control mode for well " << this->name()
|
||||
@ -573,7 +574,7 @@ namespace Opm
|
||||
{
|
||||
this->operability_status_.reset();
|
||||
|
||||
auto current_control = well_state.currentProductionControl(this->index_of_well_);
|
||||
auto current_control = well_state.well(this->index_of_well_).production_cmode;
|
||||
// Operability checking is not free
|
||||
// Only check wells under BHP and THP control
|
||||
if(current_control == Well::ProducerCMode::BHP || current_control == Well::ProducerCMode::THP) {
|
||||
@ -599,6 +600,7 @@ namespace Opm
|
||||
// only bhp and wellRates are used to initilize the primaryvariables for standard wells
|
||||
const auto& well = this->well_ecl_;
|
||||
const int well_index = this->index_of_well_;
|
||||
auto& ws = well_state.well(well_index);
|
||||
const auto& pu = this->phaseUsage();
|
||||
const int np = well_state.numPhases();
|
||||
const auto& summaryState = ebos_simulator.vanguard().summaryState();
|
||||
@ -608,7 +610,7 @@ namespace Opm
|
||||
for (int p = 0; p<np; ++p) {
|
||||
well_state.wellRates(well_index)[p] = 0.0;
|
||||
}
|
||||
well_state.update_thp(well_index, 0.0);
|
||||
ws.thp = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -638,7 +640,7 @@ namespace Opm
|
||||
OPM_DEFLOG_THROW(std::runtime_error, "Expected WATER, OIL or GAS as type for injectors " + this->name(), deferred_logger );
|
||||
}
|
||||
|
||||
auto current = well_state.currentInjectionControl(well_index);
|
||||
const auto current = ws.injection_cmode;
|
||||
|
||||
switch(current) {
|
||||
case Well::InjectorCMode::RATE:
|
||||
@ -663,7 +665,7 @@ namespace Opm
|
||||
rates[p] = well_state.wellRates(well_index)[p];
|
||||
}
|
||||
double bhp = this->calculateBhpFromThp(well_state, rates, well, summaryState, this->getRefDensity(), deferred_logger);
|
||||
well_state.update_bhp(well_index, bhp);
|
||||
ws.bhp = bhp;
|
||||
|
||||
// if the total rates are negative or zero
|
||||
// we try to provide a better intial well rate
|
||||
@ -678,7 +680,7 @@ namespace Opm
|
||||
}
|
||||
case Well::InjectorCMode::BHP:
|
||||
{
|
||||
well_state.update_bhp(well_index, controls.bhp_limit);
|
||||
ws.bhp = controls.bhp_limit;
|
||||
double total_rate = 0.0;
|
||||
for (int p = 0; p<np; ++p) {
|
||||
total_rate += well_state.wellRates(well_index)[p];
|
||||
@ -721,7 +723,7 @@ namespace Opm
|
||||
//Producer
|
||||
else
|
||||
{
|
||||
auto current = well_state.currentProductionControl(well_index);
|
||||
const auto current = ws.production_cmode;
|
||||
const auto& controls = well.productionControls(summaryState);
|
||||
switch (current) {
|
||||
case Well::ProducerCMode::ORAT:
|
||||
@ -864,7 +866,7 @@ namespace Opm
|
||||
}
|
||||
case Well::ProducerCMode::BHP:
|
||||
{
|
||||
well_state.update_bhp(well_index, controls.bhp_limit);
|
||||
ws.bhp = controls.bhp_limit;
|
||||
double total_rate = 0.0;
|
||||
for (int p = 0; p<np; ++p) {
|
||||
total_rate -= well_state.wellRates(well_index)[p];
|
||||
@ -886,7 +888,7 @@ namespace Opm
|
||||
rates[p] = well_state.wellRates(well_index)[p];
|
||||
}
|
||||
double bhp = this->calculateBhpFromThp(well_state, rates, well, summaryState, this->getRefDensity(), deferred_logger);
|
||||
well_state.update_bhp(well_index, bhp);
|
||||
ws.bhp = bhp;
|
||||
|
||||
// if the total rates are negative or zero
|
||||
// we try to provide a better intial well rate
|
||||
|
@ -41,15 +41,12 @@ void WellState::base_init(const std::vector<double>& cellPressures,
|
||||
// clear old name mapping
|
||||
this->wellMap_.clear();
|
||||
this->perfdata.clear();
|
||||
this->status_.clear();
|
||||
this->parallel_well_info_.clear();
|
||||
this->wellrates_.clear();
|
||||
this->bhp_.clear();
|
||||
this->thp_.clear();
|
||||
this->temperature_.clear();
|
||||
this->segment_state.clear();
|
||||
this->well_potentials_.clear();
|
||||
this->productivity_index_.clear();
|
||||
this->wells_.clear();
|
||||
{
|
||||
// const int nw = wells->number_of_wells;
|
||||
const int nw = wells_ecl.size();
|
||||
@ -91,21 +88,16 @@ void WellState::initSingleWell(const std::vector<double>& cellPressures,
|
||||
// May be overwritten below.
|
||||
const auto& pu = this->phase_usage_;
|
||||
const int np = pu.num_phases;
|
||||
double temp = well.isInjector() ? well.injectionControls(summary_state).temperature : 273.15 + 15.56;
|
||||
|
||||
this->status_.add(well.name(), Well::Status::OPEN);
|
||||
auto& ws = this->wells_.add(well.name(), SingleWellState{well.isProducer(), temp});
|
||||
this->parallel_well_info_.add(well.name(), well_info);
|
||||
this->wellrates_.add(well.name(), std::vector<double>(np, 0));
|
||||
this->well_potentials_.add(well.name(), std::vector<double>(np, 0));
|
||||
const int num_perf_this_well = well_info->communication().sum(well_perf_data.size());
|
||||
this->segment_state.add(well.name(), SegmentState{});
|
||||
this->perfdata.add(well.name(), PerfData{static_cast<std::size_t>(num_perf_this_well), well.isInjector(), this->phase_usage_});
|
||||
this->bhp_.add(well.name(), 0.0);
|
||||
this->thp_.add(well.name(), 0.0);
|
||||
this->productivity_index_.add(well.name(), std::vector<double>(np, 0));
|
||||
if ( well.isInjector() )
|
||||
this->temperature_.add(well.name(), well.injectionControls(summary_state).temperature);
|
||||
else
|
||||
this->temperature_.add(well.name(), 273.15 + 15.56); // standard condition temperature
|
||||
|
||||
if ( num_perf_this_well == 0 )
|
||||
return;
|
||||
@ -126,7 +118,7 @@ void WellState::initSingleWell(const std::vector<double>& cellPressures,
|
||||
const double global_pressure = well_info->broadcastFirstPerforationValue(local_pressure);
|
||||
|
||||
if (well.getStatus() == Well::Status::OPEN) {
|
||||
this->status_[w] = Well::Status::OPEN;
|
||||
ws.status = Well::Status::OPEN;
|
||||
}
|
||||
|
||||
if (well.getStatus() == Well::Status::STOP) {
|
||||
@ -136,9 +128,9 @@ void WellState::initSingleWell(const std::vector<double>& cellPressures,
|
||||
// applicable, otherwise assign equal to
|
||||
// first perforation cell pressure.
|
||||
if (is_bhp) {
|
||||
bhp_[w] = bhp_limit;
|
||||
ws.bhp = bhp_limit;
|
||||
} else {
|
||||
bhp_[w] = global_pressure;
|
||||
ws.bhp = global_pressure;
|
||||
}
|
||||
} else if (is_grup) {
|
||||
// Well under group control.
|
||||
@ -148,7 +140,7 @@ void WellState::initSingleWell(const std::vector<double>& cellPressures,
|
||||
// the well is an injector or producer)
|
||||
// pressure in first perforation cell.
|
||||
const double safety_factor = well.isInjector() ? 1.01 : 0.99;
|
||||
bhp_[w] = safety_factor * global_pressure;
|
||||
ws.bhp = safety_factor * global_pressure;
|
||||
} else {
|
||||
// Open well, under own control:
|
||||
// 1. Rates: initialize well rates to match
|
||||
@ -206,10 +198,10 @@ void WellState::initSingleWell(const std::vector<double>& cellPressures,
|
||||
// the well is an injector or producer)
|
||||
// pressure in first perforation cell.
|
||||
if (is_bhp) {
|
||||
bhp_[w] = bhp_limit;
|
||||
ws.bhp = bhp_limit;
|
||||
} else {
|
||||
const double safety_factor = well.isInjector() ? 1.01 : 0.99;
|
||||
bhp_[w] = safety_factor * global_pressure;
|
||||
ws.bhp = safety_factor * global_pressure;
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,7 +211,7 @@ void WellState::initSingleWell(const std::vector<double>& cellPressures,
|
||||
: prod_controls.hasControl(Well::ProducerCMode::THP);
|
||||
const double thp_limit = well.isInjector() ? inj_controls.thp_limit : prod_controls.thp_limit;
|
||||
if (has_thp) {
|
||||
thp_[w] = thp_limit;
|
||||
ws.thp = thp_limit;
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,15 +257,12 @@ void WellState::init(const std::vector<double>& cellPressures,
|
||||
well_dissolved_gas_rates_.clear();
|
||||
well_vaporized_oil_rates_.clear();
|
||||
|
||||
this->events_.clear();
|
||||
{
|
||||
const auto& wg_events = schedule[report_step].wellgroup_events();
|
||||
for (const auto& ecl_well : wells_ecl) {
|
||||
const auto& wname = ecl_well.name();
|
||||
if (wg_events.has(wname))
|
||||
this->events_.add( wname, wg_events.at(wname) );
|
||||
else
|
||||
this->events_.add( wname, Events() );
|
||||
this->well(wname).events = wg_events.at(wname);
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,25 +296,15 @@ void WellState::init(const std::vector<double>& cellPressures,
|
||||
this->well_vaporized_oil_rates_.add(wname, 0);
|
||||
}
|
||||
|
||||
is_producer_.clear();
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
const auto& ecl_well = wells_ecl[w];
|
||||
this->is_producer_.add( ecl_well.name(), ecl_well.isProducer());
|
||||
}
|
||||
|
||||
current_injection_controls_.clear();
|
||||
current_production_controls_.clear();
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
const auto& wname = wells_ecl[w].name();
|
||||
current_production_controls_.add(wname, Well::ProducerCMode::CMODE_UNDEFINED);
|
||||
current_injection_controls_.add(wname, Well::InjectorCMode::CMODE_UNDEFINED);
|
||||
auto& ws = this->well(w);
|
||||
if (wells_ecl[w].isProducer()) {
|
||||
const auto controls = wells_ecl[w].productionControls(summary_state);
|
||||
currentProductionControl(w, controls.cmode);
|
||||
ws.production_cmode = controls.cmode;
|
||||
}
|
||||
else {
|
||||
const auto controls = wells_ecl[w].injectionControls(summary_state);
|
||||
currentInjectionControl(w, controls.cmode);
|
||||
ws.injection_cmode = controls.cmode;
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,31 +335,30 @@ void WellState::init(const std::vector<double>& cellPressures,
|
||||
continue;
|
||||
}
|
||||
const auto& wname = well.name();
|
||||
auto& new_well = this->well(w);
|
||||
auto it = prevState->wellMap().find(well.name());
|
||||
if (it != end)
|
||||
{
|
||||
const int newIndex = w;
|
||||
const int oldIndex = it->second[ 0 ];
|
||||
if (prevState->status_[oldIndex] == Well::Status::SHUT) {
|
||||
|
||||
const auto& prev_well = prevState->well(oldIndex);
|
||||
new_well.init_timestep(prev_well);
|
||||
|
||||
|
||||
if (prev_well.status == Well::Status::SHUT) {
|
||||
// Well was shut in previous state, do not use its values.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_producer_[newIndex] != prevState->is_producer_[oldIndex]) {
|
||||
if (new_well.producer != prev_well.producer)
|
||||
// Well changed to/from injector from/to producer, do not use its privious values.
|
||||
continue;
|
||||
}
|
||||
|
||||
// bhp
|
||||
this->update_bhp( newIndex, prevState->bhp( oldIndex ));
|
||||
|
||||
// thp
|
||||
this->update_thp( newIndex, prevState->thp( oldIndex ));
|
||||
|
||||
// If new target is set using WCONPROD, WCONINJE etc. we use the new control
|
||||
if (!this->events_[w].hasEvent(WellState::event_mask)) {
|
||||
current_injection_controls_[ newIndex ] = prevState->currentInjectionControl(oldIndex);
|
||||
current_production_controls_[ newIndex ] = prevState->currentProductionControl(oldIndex);
|
||||
if (!new_well.events.hasEvent(WellState::event_mask)) {
|
||||
new_well.injection_cmode = prev_well.injection_cmode;
|
||||
new_well.production_cmode = prev_well.production_cmode;
|
||||
}
|
||||
|
||||
wellRates(w) = prevState->wellRates(oldIndex);
|
||||
@ -436,7 +414,7 @@ void WellState::init(const std::vector<double>& cellPressures,
|
||||
: well.productionControls(summary_state).hasControl(Well::ProducerCMode::THP);
|
||||
|
||||
if (!has_thp) {
|
||||
this->update_thp(w, 0.0);
|
||||
new_well.thp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -507,8 +485,8 @@ WellState::report(const int* globalCellIdxMap,
|
||||
data::Wells res;
|
||||
for( const auto& [wname, winfo]: this->wellMap() ) {
|
||||
const auto well_index = winfo[ 0 ];
|
||||
if ((this->status_[well_index] == Well::Status::SHUT) &&
|
||||
! wasDynamicallyClosed(well_index))
|
||||
const auto& ws = this->well(well_index);
|
||||
if ((ws.status == Well::Status::SHUT) && !wasDynamicallyClosed(well_index))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -519,9 +497,9 @@ WellState::report(const int* globalCellIdxMap,
|
||||
const auto& wv = this->wellRates(well_index);
|
||||
|
||||
data::Well well;
|
||||
well.bhp = this->bhp(well_index);
|
||||
well.thp = this->thp( well_index );
|
||||
well.temperature = this->temperature( well_index );
|
||||
well.bhp = ws.bhp;
|
||||
well.thp = ws.thp;
|
||||
well.temperature = ws.temperature;
|
||||
|
||||
if( pu.phase_used[BlackoilPhases::Aqua] ) {
|
||||
well.rates.set(rt::wat, wv[ pu.phase_pos[BlackoilPhases::Aqua] ] );
|
||||
@ -556,7 +534,7 @@ WellState::report(const int* globalCellIdxMap,
|
||||
well.rates.set(rt::brine, brineWellRate(well_index));
|
||||
}
|
||||
|
||||
if (is_producer_[well_index]) {
|
||||
if (ws.producer) {
|
||||
well.rates.set(rt::alq, getALQ(wname));
|
||||
}
|
||||
else {
|
||||
@ -569,9 +547,9 @@ WellState::report(const int* globalCellIdxMap,
|
||||
{
|
||||
auto& curr = well.current_control;
|
||||
|
||||
curr.isProducer = this->is_producer_[well_index];
|
||||
curr.prod = this->currentProductionControl(well_index);
|
||||
curr.inj = this->currentInjectionControl(well_index);
|
||||
curr.isProducer = ws.producer;
|
||||
curr.prod = ws.production_cmode;
|
||||
curr.inj = ws.injection_cmode;
|
||||
}
|
||||
|
||||
const auto& pwinfo = *this->parallel_well_info_[well_index];
|
||||
@ -680,6 +658,7 @@ void WellState::initWellStateMSWell(const std::vector<Well>& wells_ecl,
|
||||
// what we do here, is to set the segment rates and perforation rates
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
const auto& well_ecl = wells_ecl[w];
|
||||
auto& ws = this->well(w);
|
||||
|
||||
if ( well_ecl.isMultiSegment() ) {
|
||||
const WellSegments& segment_set = well_ecl.getSegments();
|
||||
@ -748,7 +727,7 @@ void WellState::initWellStateMSWell(const std::vector<Well>& wells_ecl,
|
||||
{
|
||||
// top segment is always the first one, and its pressure is the well bhp
|
||||
auto& segment_pressure = this->segments(w).pressure;
|
||||
segment_pressure[0] = bhp(w);
|
||||
segment_pressure[0] = ws.bhp;
|
||||
const auto& perf_press = perf_data.pressure;
|
||||
for (int seg = 1; seg < well_nseg; ++seg) {
|
||||
if ( !segment_perforations[seg].empty() ) {
|
||||
@ -777,7 +756,8 @@ void WellState::initWellStateMSWell(const std::vector<Well>& wells_ecl,
|
||||
|
||||
const auto& wname = well.name();
|
||||
if (prev_well_state->segment_state.has(wname)) {
|
||||
if (prev_well_state->status_[wname] == Well::Status::SHUT) {
|
||||
const auto& prev_ws = prev_well_state->well(wname);
|
||||
if (prev_ws.status == Well::Status::SHUT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -842,15 +822,14 @@ double WellState::brineWellRate(const int w) const
|
||||
|
||||
void WellState::stopWell(int well_index)
|
||||
{
|
||||
this->status_[well_index] = Well::Status::STOP;
|
||||
this->thp_[well_index] = 0;
|
||||
auto& ws = this->well(well_index);
|
||||
ws.stop();
|
||||
}
|
||||
|
||||
void WellState::shutWell(int well_index)
|
||||
{
|
||||
this->status_[well_index] = Well::Status::SHUT;
|
||||
this->thp_[well_index] = 0;
|
||||
this->bhp_[well_index] = 0;
|
||||
auto& ws = this->well(well_index);
|
||||
ws.shut();
|
||||
const int np = numPhases();
|
||||
this->wellrates_[well_index].assign(np, 0);
|
||||
|
||||
@ -935,7 +914,14 @@ void WellState::communicateGroupRates(const Comm& comm)
|
||||
template<class Comm>
|
||||
void WellState::updateGlobalIsGrup(const Comm& comm)
|
||||
{
|
||||
this->global_well_info.value().update_group(this->status_.data(), this->current_injection_controls_.data(), this->current_production_controls_.data());
|
||||
this->global_well_info.value().clear();
|
||||
for (std::size_t well_index = 0; well_index < this->size(); well_index++) {
|
||||
const auto& ws = this->well(well_index);
|
||||
if (ws.producer)
|
||||
this->global_well_info.value().update_producer(well_index, ws.status, ws.production_cmode);
|
||||
else
|
||||
this->global_well_info.value().update_injector(well_index, ws.status, ws.injection_cmode);
|
||||
}
|
||||
this->global_well_info.value().communicate(comm);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#define OPM_WELLSTATEFULLYIMPLICITBLACKOIL_HEADER_INCLUDED
|
||||
|
||||
#include <opm/simulators/wells/ALQState.hpp>
|
||||
#include <opm/simulators/wells/SingleWellState.hpp>
|
||||
#include <opm/simulators/wells/GlobalWellInfo.hpp>
|
||||
#include <opm/simulators/wells/SegmentState.hpp>
|
||||
#include <opm/simulators/wells/WellContainer.hpp>
|
||||
@ -107,14 +108,6 @@ public:
|
||||
const std::vector<std::vector<PerforationData>>& well_perf_data,
|
||||
const SummaryState& summary_state);
|
||||
|
||||
/// One current control per injecting well.
|
||||
Well::InjectorCMode currentInjectionControl(std::size_t well_index) const { return current_injection_controls_[well_index]; }
|
||||
void currentInjectionControl(std::size_t well_index, Well::InjectorCMode cmode) { current_injection_controls_[well_index] = cmode; }
|
||||
|
||||
/// One current control per producing well.
|
||||
Well::ProducerCMode currentProductionControl(std::size_t well_index) const { return current_production_controls_[well_index]; }
|
||||
void currentProductionControl(std::size_t well_index, Well::ProducerCMode cmode) { current_production_controls_[well_index] = cmode; }
|
||||
|
||||
void setCurrentWellRates(const std::string& wellName, const std::vector<double>& new_rates ) {
|
||||
auto& [owner, rates] = this->well_rates.at(wellName);
|
||||
if (owner)
|
||||
@ -147,10 +140,6 @@ public:
|
||||
static void calculateSegmentRates(const std::vector<std::vector<int>>& segment_inlets, const std::vector<std::vector<int>>&segment_perforations,
|
||||
const std::vector<double>& perforation_rates, const int np, const int segment, std::vector<double>& segment_rates);
|
||||
|
||||
Events& events(std::size_t well_index) {
|
||||
return this->events_[well_index];
|
||||
}
|
||||
|
||||
/// One rate pr well
|
||||
double solventWellRate(const int w) const;
|
||||
|
||||
@ -293,7 +282,7 @@ public:
|
||||
void updateStatus(int well_index, Well::Status status);
|
||||
|
||||
void openWell(int well_index) {
|
||||
this->status_[well_index] = Well::Status::OPEN;
|
||||
this->wells_[well_index].status = Well::Status::OPEN;
|
||||
}
|
||||
|
||||
void shutWell(int well_index);
|
||||
@ -309,18 +298,6 @@ public:
|
||||
return this->phase_usage_;
|
||||
}
|
||||
|
||||
/// One bhp pressure per well.
|
||||
void update_bhp(std::size_t well_index, double value) { bhp_[well_index] = value; }
|
||||
double bhp(std::size_t well_index) const { return bhp_[well_index]; }
|
||||
|
||||
/// One thp pressure per well.
|
||||
void update_thp(std::size_t well_index, double value) { thp_[well_index] = value; }
|
||||
double thp(std::size_t well_index) const { return thp_[well_index]; }
|
||||
|
||||
/// One temperature per well.
|
||||
void update_temperature(std::size_t well_index, double value) { temperature_[well_index] = value; }
|
||||
double temperature(std::size_t well_index) const { return temperature_[well_index]; }
|
||||
|
||||
/// One rate per well and phase.
|
||||
const WellContainer<std::vector<double>>& wellRates() const { return wellrates_; }
|
||||
std::vector<double>& wellRates(std::size_t well_index) { return wellrates_[well_index]; }
|
||||
@ -345,13 +322,26 @@ public:
|
||||
}
|
||||
|
||||
const std::string& name(std::size_t well_index) const {
|
||||
return this->status_.well_name(well_index);
|
||||
return this->wells_.well_name(well_index);
|
||||
}
|
||||
|
||||
bool producer(std::size_t well_index) const {
|
||||
return this->is_producer_[well_index];
|
||||
const SingleWellState& well(std::size_t well_index) const {
|
||||
return this->wells_[well_index];
|
||||
}
|
||||
|
||||
const SingleWellState& well(const std::string& well_name) const {
|
||||
return this->wells_[well_name];
|
||||
}
|
||||
|
||||
SingleWellState& well(std::size_t well_index) {
|
||||
return this->wells_[well_index];
|
||||
}
|
||||
|
||||
SingleWellState& well(const std::string& well_name) {
|
||||
return this->wells_[well_name];
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
WellMapType wellMap_;
|
||||
@ -362,23 +352,12 @@ private:
|
||||
ALQState alq_state;
|
||||
bool do_glift_optimization_;
|
||||
|
||||
WellContainer<Well::Status> status_;
|
||||
WellContainer<SingleWellState> wells_;
|
||||
WellContainer<const ParallelWellInfo*> parallel_well_info_;
|
||||
WellContainer<double> bhp_;
|
||||
WellContainer<double> thp_;
|
||||
WellContainer<double> temperature_;
|
||||
WellContainer<std::vector<double>> wellrates_;
|
||||
PhaseUsage phase_usage_;
|
||||
WellContainer<PerfData> perfdata;
|
||||
|
||||
WellContainer<int> is_producer_; // Size equal to number of local wells.
|
||||
|
||||
// vector with size number of wells +1.
|
||||
// iterate over all perforations of a given well
|
||||
// for (int perf = first_perf_index_[well_index]; perf < first_perf_index_[well_index] + num_perf_[well_index]; ++perf)
|
||||
WellContainer<Opm::Well::InjectorCMode> current_injection_controls_;
|
||||
WellContainer<Well::ProducerCMode> current_production_controls_;
|
||||
|
||||
// The well_rates variable is defined for all wells on all processors. The
|
||||
// bool in the value pair is whether the current process owns the well or
|
||||
// not.
|
||||
@ -396,11 +375,6 @@ private:
|
||||
// should be zero for injection wells
|
||||
WellContainer<double> well_vaporized_oil_rates_;
|
||||
|
||||
// some events happens to the well, like this well is a new well
|
||||
// or new well control keywords happens
|
||||
// \Note: for now, only WCON* keywords, and well status change is considered
|
||||
WellContainer<Events> events_;
|
||||
|
||||
WellContainer<SegmentState> segment_state;
|
||||
|
||||
// Productivity Index
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <opm/simulators/wells/GlobalWellInfo.hpp>
|
||||
#include <opm/simulators/wells/ParallelWellInfo.hpp>
|
||||
#include <opm/simulators/wells/WellState.hpp>
|
||||
#include <opm/simulators/wells/SingleWellState.hpp>
|
||||
#include <opm/simulators/wells/SegmentState.hpp>
|
||||
#include <opm/simulators/wells/WellContainer.hpp>
|
||||
#include <opm/simulators/wells/PerfData.hpp>
|
||||
@ -575,5 +576,27 @@ GAS
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TestSingleWellState) {
|
||||
Opm::SingleWellState ws1(true, 1);
|
||||
Opm::SingleWellState ws2(true, 2);
|
||||
Opm::SingleWellState ws3(false, 3);
|
||||
|
||||
ws1.bhp = 100;
|
||||
ws1.thp = 200;
|
||||
|
||||
ws2.init_timestep(ws1);
|
||||
BOOST_CHECK_EQUAL(ws2.bhp, ws1.bhp);
|
||||
BOOST_CHECK_EQUAL(ws2.thp, ws1.thp);
|
||||
|
||||
ws3.bhp = ws1.bhp * 2;
|
||||
ws3.thp = ws1.thp * 2;
|
||||
ws3.init_timestep(ws1);
|
||||
BOOST_CHECK(ws3.bhp != ws1.bhp);
|
||||
BOOST_CHECK(ws3.thp != ws1.thp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
Loading…
Reference in New Issue
Block a user