mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
@@ -317,11 +317,14 @@ public:
|
|||||||
// \Note: The report steps are met in any case
|
// \Note: The report steps are met in any case
|
||||||
// \Note: The sub stepping will require a copy of the state variables
|
// \Note: The sub stepping will require a copy of the state variables
|
||||||
if (adaptiveTimeStepping_) {
|
if (adaptiveTimeStepping_) {
|
||||||
auto tuningUpdater = [enableTUNING, this, reportStep = timer.currentStepNum()]()
|
auto tuningUpdater = [enableTUNING, this,
|
||||||
|
reportStep = timer.currentStepNum()](const double curr_time,
|
||||||
|
double dt, const int timeStep)
|
||||||
{
|
{
|
||||||
auto& schedule = this->simulator_.vanguard().schedule();
|
auto& schedule = this->simulator_.vanguard().schedule();
|
||||||
auto& events = this->schedule()[reportStep].events();
|
auto& events = this->schedule()[reportStep].events();
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) {
|
if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) {
|
||||||
// Unset the event to not trigger it again on the next sub step
|
// Unset the event to not trigger it again on the next sub step
|
||||||
schedule.clear_event(ScheduleEvents::TUNING_CHANGE, reportStep);
|
schedule.clear_event(ScheduleEvents::TUNING_CHANGE, reportStep);
|
||||||
@@ -335,14 +338,46 @@ public:
|
|||||||
// \Note: Need to update both solver (model) and simulator since solver is re-created each report step.
|
// \Note: Need to update both solver (model) and simulator since solver is re-created each report step.
|
||||||
solver_->model().updateTUNING(tuning);
|
solver_->model().updateTUNING(tuning);
|
||||||
this->updateTUNING(tuning);
|
this->updateTUNING(tuning);
|
||||||
|
dt = this->adaptiveTimeStepping_->suggestedNextStep();
|
||||||
} else {
|
} else {
|
||||||
|
dt = max_next_tstep;
|
||||||
this->adaptiveTimeStepping_->updateNEXTSTEP(max_next_tstep);
|
this->adaptiveTimeStepping_->updateNEXTSTEP(max_next_tstep);
|
||||||
}
|
}
|
||||||
return max_next_tstep >0;
|
result = max_next_tstep > 0;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
const auto& wcycle = schedule[reportStep].wcycle.get();
|
||||||
|
if (wcycle.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& wmatcher = schedule.wellMatcher(reportStep);
|
||||||
|
double wcycle_time_step =
|
||||||
|
wcycle.nextTimeStep(curr_time,
|
||||||
|
dt,
|
||||||
|
wmatcher,
|
||||||
|
this->wellModel_().wellOpenTimes(),
|
||||||
|
this->wellModel_().wellCloseTimes(),
|
||||||
|
[this, reportStep, schedule, timeStep](const std::string& name)
|
||||||
|
{
|
||||||
|
if (timeStep != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto& wg_events = schedule[reportStep].wellgroup_events();
|
||||||
|
return wg_events.hasEvent(name, ScheduleEvents::REQUEST_OPEN_WELL);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dt != wcycle_time_step) {
|
||||||
|
this->adaptiveTimeStepping_->updateNEXTSTEP(wcycle_time_step);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
tuningUpdater();
|
|
||||||
|
tuningUpdater(timer.simulationTimeElapsed(),
|
||||||
|
this->adaptiveTimeStepping_->suggestedNextStep(), 0);
|
||||||
|
|
||||||
const auto& events = schedule()[timer.currentStepNum()].events();
|
const auto& events = schedule()[timer.currentStepNum()].events();
|
||||||
bool event = events.hasEvent(ScheduleEvents::NEW_WELL) ||
|
bool event = events.hasEvent(ScheduleEvents::NEW_WELL) ||
|
||||||
events.hasEvent(ScheduleEvents::INJECTION_TYPE_CHANGED) ||
|
events.hasEvent(ScheduleEvents::INJECTION_TYPE_CHANGED) ||
|
||||||
|
|||||||
@@ -180,10 +180,10 @@ void registerAdaptiveParameters();
|
|||||||
SimulatorReport step(const SimulatorTimer& simulatorTimer,
|
SimulatorReport step(const SimulatorTimer& simulatorTimer,
|
||||||
Solver& solver,
|
Solver& solver,
|
||||||
const bool isEvent,
|
const bool isEvent,
|
||||||
const std::function<bool()> tuningUpdater)
|
const std::function<bool(const double, const double, const int)> tuningUpdater)
|
||||||
{
|
{
|
||||||
// Maybe update tuning
|
// Maybe update tuning
|
||||||
tuningUpdater();
|
tuningUpdater(simulatorTimer.simulationTimeElapsed(), suggestedNextTimestep_, 0);
|
||||||
SimulatorReport report;
|
SimulatorReport report;
|
||||||
const double timestep = simulatorTimer.currentStepLength();
|
const double timestep = simulatorTimer.currentStepLength();
|
||||||
|
|
||||||
@@ -215,7 +215,9 @@ void registerAdaptiveParameters();
|
|||||||
// Maybe update tuning
|
// Maybe update tuning
|
||||||
// get current delta t
|
// get current delta t
|
||||||
auto oldValue = suggestedNextTimestep_;
|
auto oldValue = suggestedNextTimestep_;
|
||||||
if (tuningUpdater()) {
|
if (tuningUpdater(substepTimer.simulationTimeElapsed(),
|
||||||
|
substepTimer.currentStepLength(),
|
||||||
|
substepTimer.currentStepNum())) {
|
||||||
// Use provideTimeStepEstimate to make we sure don't simulate longer than the report step is.
|
// Use provideTimeStepEstimate to make we sure don't simulate longer than the report step is.
|
||||||
substepTimer.provideTimeStepEstimate(suggestedNextTimestep_);
|
substepTimer.provideTimeStepEstimate(suggestedNextTimestep_);
|
||||||
suggestedNextTimestep_ = oldValue;
|
suggestedNextTimestep_ = oldValue;
|
||||||
|
|||||||
@@ -672,7 +672,6 @@ const KeywordValidation::UnsupportedKeywords& unsupportedKeywords()
|
|||||||
{"WCONINJP", {true, std::nullopt}},
|
{"WCONINJP", {true, std::nullopt}},
|
||||||
{"WCUTBACK", {true, std::nullopt}},
|
{"WCUTBACK", {true, std::nullopt}},
|
||||||
{"WCUTBACT", {true, std::nullopt}},
|
{"WCUTBACT", {true, std::nullopt}},
|
||||||
{"WCYCLE", {true, std::nullopt}},
|
|
||||||
{"WDRILTIM", {true, std::nullopt}},
|
{"WDRILTIM", {true, std::nullopt}},
|
||||||
{"WDRILPRI", {true, std::nullopt}},
|
{"WDRILPRI", {true, std::nullopt}},
|
||||||
{"WDRILRES", {true, std::nullopt}},
|
{"WDRILRES", {true, std::nullopt}},
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ template<class Scalar> class WellContributions;
|
|||||||
// Keep track of the domain of each well, if using subdomains.
|
// Keep track of the domain of each well, if using subdomains.
|
||||||
std::map<std::string, int> well_domain_;
|
std::map<std::string, int> well_domain_;
|
||||||
|
|
||||||
// Store the local index of the wells perforated cells in the domain, if using sumdomains
|
// Store the local index of the wells perforated cells in the domain, if using subdomains
|
||||||
SparseTable<int> well_local_cells_;
|
SparseTable<int> well_local_cells_;
|
||||||
|
|
||||||
const Grid& grid() const
|
const Grid& grid() const
|
||||||
|
|||||||
@@ -1575,7 +1575,8 @@ calculateEfficiencyFactors(const int reportStepIdx)
|
|||||||
{
|
{
|
||||||
for (auto& well : well_container_generic_) {
|
for (auto& well : well_container_generic_) {
|
||||||
const Well& wellEcl = well->wellEcl();
|
const Well& wellEcl = well->wellEcl();
|
||||||
Scalar well_efficiency_factor = wellEcl.getEfficiencyFactor();
|
Scalar well_efficiency_factor = wellEcl.getEfficiencyFactor() *
|
||||||
|
wellState()[well->name()].efficiency_scaling_factor;
|
||||||
WellGroupHelpers<Scalar>::accumulateGroupEfficiencyFactor(schedule().getGroup(wellEcl.groupName(),
|
WellGroupHelpers<Scalar>::accumulateGroupEfficiencyFactor(schedule().getGroup(wellEcl.groupName(),
|
||||||
reportStepIdx),
|
reportStepIdx),
|
||||||
schedule(),
|
schedule(),
|
||||||
|
|||||||
@@ -205,6 +205,9 @@ public:
|
|||||||
|
|
||||||
const GuideRate& guideRate() const { return guideRate_; }
|
const GuideRate& guideRate() const { return guideRate_; }
|
||||||
|
|
||||||
|
const std::map<std::string, double>& wellOpenTimes() const { return well_open_times_; }
|
||||||
|
const std::map<std::string, double>& wellCloseTimes() const { return well_close_times_; }
|
||||||
|
|
||||||
bool reportStepStarts() const { return report_step_starts_; }
|
bool reportStepStarts() const { return report_step_starts_; }
|
||||||
|
|
||||||
bool shouldBalanceNetwork(const int reportStepIndex,
|
bool shouldBalanceNetwork(const int reportStepIndex,
|
||||||
@@ -468,6 +471,12 @@ protected:
|
|||||||
std::vector<Well> wells_ecl_;
|
std::vector<Well> wells_ecl_;
|
||||||
std::vector<std::vector<PerforationData<Scalar>>> well_perf_data_;
|
std::vector<std::vector<PerforationData<Scalar>>> well_perf_data_;
|
||||||
|
|
||||||
|
// Times at which wells were opened (for WCYCLE)
|
||||||
|
std::map<std::string, double> well_open_times_;
|
||||||
|
|
||||||
|
// Times at which wells were shut (for WCYCLE)
|
||||||
|
std::map<std::string, double> well_close_times_;
|
||||||
|
|
||||||
/// Connection index mappings
|
/// Connection index mappings
|
||||||
class ConnectionIndexMap
|
class ConnectionIndexMap
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include <opm/input/eclipse/Schedule/Network/Balance.hpp>
|
#include <opm/input/eclipse/Schedule/Network/Balance.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
|
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Well/PAvgDynamicSourceData.hpp>
|
#include <opm/input/eclipse/Schedule/Well/PAvgDynamicSourceData.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/Well/WellMatcher.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Well/WellTestConfig.hpp>
|
#include <opm/input/eclipse/Schedule/Well/WellTestConfig.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||||
@@ -177,6 +178,11 @@ namespace Opm {
|
|||||||
const auto& events = this->schedule()[reportStepIdx].wellgroup_events();
|
const auto& events = this->schedule()[reportStepIdx].wellgroup_events();
|
||||||
for (auto& wellPtr : this->well_container_) {
|
for (auto& wellPtr : this->well_container_) {
|
||||||
const bool well_opened_this_step = this->report_step_starts_ && events.hasEvent(wellPtr->name(), effective_events_mask);
|
const bool well_opened_this_step = this->report_step_starts_ && events.hasEvent(wellPtr->name(), effective_events_mask);
|
||||||
|
if (well_opened_this_step && this->wellState().well(wellPtr->name()).status == Well::Status::OPEN) {
|
||||||
|
this->well_open_times_.insert_or_assign(wellPtr->name(), this->simulator_.time());
|
||||||
|
this->well_close_times_.erase(wellPtr->name());
|
||||||
|
}
|
||||||
|
|
||||||
wellPtr->init(&this->phase_usage_, this->depth_, this->gravity_, this->B_avg_, well_opened_this_step);
|
wellPtr->init(&this->phase_usage_, this->depth_, this->gravity_, this->B_avg_, well_opened_this_step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -648,7 +654,8 @@ namespace Opm {
|
|||||||
// some preparation before the well can be used
|
// some preparation before the well can be used
|
||||||
well->init(&this->phase_usage_, depth_, gravity_, B_avg_, true);
|
well->init(&this->phase_usage_, depth_, gravity_, B_avg_, true);
|
||||||
|
|
||||||
Scalar well_efficiency_factor = wellEcl.getEfficiencyFactor();
|
Scalar well_efficiency_factor = wellEcl.getEfficiencyFactor() *
|
||||||
|
this->wellState()[well_name].efficiency_scaling_factor;
|
||||||
WellGroupHelpers<Scalar>::accumulateGroupEfficiencyFactor(this->schedule().getGroup(wellEcl.groupName(),
|
WellGroupHelpers<Scalar>::accumulateGroupEfficiencyFactor(this->schedule().getGroup(wellEcl.groupName(),
|
||||||
timeStepIdx),
|
timeStepIdx),
|
||||||
this->schedule(),
|
this->schedule(),
|
||||||
@@ -671,8 +678,8 @@ namespace Opm {
|
|||||||
GLiftEclWells ecl_well_map;
|
GLiftEclWells ecl_well_map;
|
||||||
initGliftEclWellMap(ecl_well_map);
|
initGliftEclWellMap(ecl_well_map);
|
||||||
well->wellTesting(simulator_, simulationTime, this->wellState(),
|
well->wellTesting(simulator_, simulationTime, this->wellState(),
|
||||||
this->groupState(), this->wellTestState(), this->phase_usage_,
|
this->groupState(), this->wellTestState(), this->phase_usage_,
|
||||||
ecl_well_map, deferred_logger);
|
ecl_well_map, this->well_open_times_, deferred_logger);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
const std::string msg = fmt::format("Exception during testing of well: {}. The well will not open.\n Exception message: {}", wellEcl.name(), e.what());
|
const std::string msg = fmt::format("Exception during testing of well: {}. The well will not open.\n Exception message: {}", wellEcl.name(), e.what());
|
||||||
deferred_logger.warning("WELL_TESTING_FAILED", msg);
|
deferred_logger.warning("WELL_TESTING_FAILED", msg);
|
||||||
@@ -918,6 +925,13 @@ namespace Opm {
|
|||||||
if (nw > 0) {
|
if (nw > 0) {
|
||||||
well_container_.reserve(nw);
|
well_container_.reserve(nw);
|
||||||
|
|
||||||
|
const auto& wmatcher = this->schedule().wellMatcher(report_step);
|
||||||
|
const auto& wcycle = this->schedule()[report_step].wcycle.get();
|
||||||
|
const auto cycle_states = wcycle.wellStatus(this->simulator_.time(),
|
||||||
|
wmatcher,
|
||||||
|
this->well_open_times_,
|
||||||
|
this->well_close_times_);
|
||||||
|
|
||||||
for (int w = 0; w < nw; ++w) {
|
for (int w = 0; w < nw; ++w) {
|
||||||
const Well& well_ecl = this->wells_ecl_[w];
|
const Well& well_ecl = this->wells_ecl_[w];
|
||||||
|
|
||||||
@@ -939,6 +953,8 @@ namespace Opm {
|
|||||||
this->wellState().shutWell(w);
|
this->wellState().shutWell(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->well_open_times_.erase(well_name);
|
||||||
|
this->well_close_times_.erase(well_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -956,6 +972,9 @@ namespace Opm {
|
|||||||
if (!closed_this_step) {
|
if (!closed_this_step) {
|
||||||
this->wellTestState().open_well(well_name);
|
this->wellTestState().open_well(well_name);
|
||||||
this->wellTestState().open_completions(well_name);
|
this->wellTestState().open_completions(well_name);
|
||||||
|
this->well_open_times_.insert_or_assign(well_name,
|
||||||
|
this->simulator_.time());
|
||||||
|
this->well_close_times_.erase(well_name);
|
||||||
}
|
}
|
||||||
events.clearEvent(ScheduleEvents::REQUEST_OPEN_WELL);
|
events.clearEvent(ScheduleEvents::REQUEST_OPEN_WELL);
|
||||||
}
|
}
|
||||||
@@ -969,12 +988,16 @@ namespace Opm {
|
|||||||
if (well_ecl.getAutomaticShutIn()) {
|
if (well_ecl.getAutomaticShutIn()) {
|
||||||
// shut wells are not added to the well container
|
// shut wells are not added to the well container
|
||||||
this->wellState().shutWell(w);
|
this->wellState().shutWell(w);
|
||||||
|
this->well_close_times_.erase(well_name);
|
||||||
|
this->well_open_times_.erase(well_name);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if (!well_ecl.getAllowCrossFlow()) {
|
if (!well_ecl.getAllowCrossFlow()) {
|
||||||
// stopped wells where cross flow is not allowed
|
// stopped wells where cross flow is not allowed
|
||||||
// are not added to the well container
|
// are not added to the well container
|
||||||
this->wellState().shutWell(w);
|
this->wellState().shutWell(w);
|
||||||
|
this->well_close_times_.erase(well_name);
|
||||||
|
this->well_open_times_.erase(well_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// stopped wells are added to the container but marked as stopped
|
// stopped wells are added to the container but marked as stopped
|
||||||
@@ -992,19 +1015,55 @@ namespace Opm {
|
|||||||
// Treat as shut, do not add to container.
|
// Treat as shut, do not add to container.
|
||||||
local_deferredLogger.debug(fmt::format(" Well {} gets shut due to having zero rate constraint and disallowing crossflow ", well_ecl.name()) );
|
local_deferredLogger.debug(fmt::format(" Well {} gets shut due to having zero rate constraint and disallowing crossflow ", well_ecl.name()) );
|
||||||
this->wellState().shutWell(w);
|
this->wellState().shutWell(w);
|
||||||
|
this->well_close_times_.erase(well_name);
|
||||||
|
this->well_open_times_.erase(well_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (well_status == Well::Status::STOP) {
|
if (well_status == Well::Status::STOP) {
|
||||||
this->wellState().stopWell(w);
|
this->wellState().stopWell(w);
|
||||||
|
this->well_close_times_.erase(well_name);
|
||||||
|
this->well_open_times_.erase(well_name);
|
||||||
wellIsStopped = true;
|
wellIsStopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wcycle.empty()) {
|
||||||
|
const auto it = cycle_states.find(well_name);
|
||||||
|
if (it != cycle_states.end()) {
|
||||||
|
if (!it->second) {
|
||||||
|
this->wellState().shutWell(w);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
this->wellState().openWell(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
well_container_.emplace_back(this->createWellPointer(w, report_step));
|
well_container_.emplace_back(this->createWellPointer(w, report_step));
|
||||||
|
|
||||||
if (wellIsStopped)
|
if (wellIsStopped) {
|
||||||
well_container_.back()->stopWell();
|
well_container_.back()->stopWell();
|
||||||
|
this->well_close_times_.erase(well_name);
|
||||||
|
this->well_open_times_.erase(well_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wcycle.empty()) {
|
||||||
|
auto schedule_open = [this, report_step](const std::string& name)
|
||||||
|
{
|
||||||
|
const auto& wg_events = this->schedule()[report_step].wellgroup_events();
|
||||||
|
return wg_events.hasEvent(name, ScheduleEvents::REQUEST_OPEN_WELL);
|
||||||
|
};
|
||||||
|
for (const auto& [wname, wscale] : wcycle.efficiencyScale(this->simulator_.time(),
|
||||||
|
this->simulator_.timeStepSize(),
|
||||||
|
wmatcher,
|
||||||
|
this->well_open_times_,
|
||||||
|
schedule_open))
|
||||||
|
{
|
||||||
|
this->wellState()[wname].efficiency_scaling_factor = wscale;
|
||||||
|
this->schedule_.add_event(ScheduleEvents::WELLGROUP_EFFICIENCY_UPDATE, report_step);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -584,7 +584,8 @@ initializeGroupRatesRecursive_(const Group& group)
|
|||||||
if (well->isProducer()) {
|
if (well->isProducer()) {
|
||||||
auto [sw_oil_rate, sw_gas_rate, sw_water_rate, sw_oil_pot, sw_gas_pot, sw_water_pot] = getProducerWellRates_(well, index);
|
auto [sw_oil_rate, sw_gas_rate, sw_water_rate, sw_oil_pot, sw_gas_pot, sw_water_pot] = getProducerWellRates_(well, index);
|
||||||
auto sw_alq = this->well_state_.getALQ(well_name);
|
auto sw_alq = this->well_state_.getALQ(well_name);
|
||||||
Scalar factor = well->getEfficiencyFactor();
|
const Scalar factor = well->getEfficiencyFactor() *
|
||||||
|
this->well_state_[well_name].efficiency_scaling_factor;
|
||||||
oil_rate += (factor * sw_oil_rate);
|
oil_rate += (factor * sw_oil_rate);
|
||||||
gas_rate += (factor * sw_gas_rate);
|
gas_rate += (factor * sw_gas_rate);
|
||||||
water_rate += (factor * sw_water_rate);
|
water_rate += (factor * sw_water_rate);
|
||||||
@@ -705,7 +706,8 @@ initializeWell2GroupMapRecursive_(const Group& group,
|
|||||||
if (checkDoGasLift) {
|
if (checkDoGasLift) {
|
||||||
const auto &well = this->schedule_.getWell(
|
const auto &well = this->schedule_.getWell(
|
||||||
well_name, this->report_step_idx_);
|
well_name, this->report_step_idx_);
|
||||||
Scalar wfac = well.getEfficiencyFactor();
|
const Scalar wfac = well.getEfficiencyFactor() *
|
||||||
|
this->well_state_[well_name].efficiency_scaling_factor;
|
||||||
auto [itr, success] = this->well_group_map_.insert(
|
auto [itr, success] = this->well_group_map_.insert(
|
||||||
{well_name, /*empty vector*/ {}});
|
{well_name, /*empty vector*/ {}});
|
||||||
assert(success);
|
assert(success);
|
||||||
|
|||||||
@@ -658,13 +658,13 @@ removeSurplusALQ_(const Group& group,
|
|||||||
alq, max_glift_str);
|
alq, max_glift_str);
|
||||||
displayDebugMessage_(msg);
|
displayDebugMessage_(msg);
|
||||||
}
|
}
|
||||||
SurplusState state {*this, group, oil_rate, gas_rate, water_rate, alq,
|
SurplusState state {*this, group, this->well_state_, oil_rate, gas_rate, water_rate, alq,
|
||||||
static_cast<Scalar>(min_eco_grad),
|
static_cast<Scalar>(min_eco_grad),
|
||||||
static_cast<Scalar>(controls.oil_target),
|
static_cast<Scalar>(controls.oil_target),
|
||||||
static_cast<Scalar>(controls.gas_target),
|
static_cast<Scalar>(controls.gas_target),
|
||||||
static_cast<Scalar>(controls.water_target),
|
static_cast<Scalar>(controls.water_target),
|
||||||
static_cast<Scalar>(controls.liquid_target),
|
static_cast<Scalar>(controls.liquid_target),
|
||||||
max_glift, max_totalgas };
|
max_glift, max_totalgas};
|
||||||
|
|
||||||
while (!stop_iteration) {
|
while (!stop_iteration) {
|
||||||
if (dec_grads.size() >= 2) {
|
if (dec_grads.size() >= 2) {
|
||||||
@@ -831,7 +831,8 @@ computeDelta(const std::string& well_name, bool add)
|
|||||||
// only get deltas for wells owned by this rank
|
// only get deltas for wells owned by this rank
|
||||||
if (this->well_state_.wellIsOwned(well.indexOfWell(), well_name)) {
|
if (this->well_state_.wellIsOwned(well.indexOfWell(), well_name)) {
|
||||||
const auto& well_ecl = well.wellEcl();
|
const auto& well_ecl = well.wellEcl();
|
||||||
Scalar factor = well_ecl.getEfficiencyFactor();
|
Scalar factor = well_ecl.getEfficiencyFactor() *
|
||||||
|
this->well_state_[well_name].efficiency_scaling_factor;
|
||||||
auto& [delta_oil, delta_gas, delta_water, delta_alq] = delta;
|
auto& [delta_oil, delta_gas, delta_water, delta_alq] = delta;
|
||||||
delta_oil = factor * (gi.new_oil_rate - state.oilRate());
|
delta_oil = factor * (gi.new_oil_rate - state.oilRate());
|
||||||
delta_gas = factor * (gi.new_gas_rate - state.gasRate());
|
delta_gas = factor * (gi.new_gas_rate - state.gasRate());
|
||||||
@@ -1081,7 +1082,7 @@ checkGasTarget(Scalar delta_gas)
|
|||||||
// the change in gas rate is added to the gas rate to make sure the
|
// the change in gas rate is added to the gas rate to make sure the
|
||||||
// group still can produce its target
|
// group still can produce its target
|
||||||
// i.e. we want to find the solution that optimize gas lift while still
|
// i.e. we want to find the solution that optimize gas lift while still
|
||||||
// producing the given group limit
|
// producing the given group limit
|
||||||
if (this->gas_target < (this->gas_rate + delta_gas) ) {
|
if (this->gas_target < (this->gas_rate + delta_gas) ) {
|
||||||
if (this->parent.debug) {
|
if (this->parent.debug) {
|
||||||
const std::string msg = fmt::format("group: {} : "
|
const std::string msg = fmt::format("group: {} : "
|
||||||
@@ -1177,7 +1178,8 @@ computeDelta(const std::string& well_name)
|
|||||||
// only get deltas for wells owned by this rank
|
// only get deltas for wells owned by this rank
|
||||||
if (this->parent.well_state_.wellIsOwned(well.indexOfWell(), well_name)) {
|
if (this->parent.well_state_.wellIsOwned(well.indexOfWell(), well_name)) {
|
||||||
const auto& well_ecl = well.wellEcl();
|
const auto& well_ecl = well.wellEcl();
|
||||||
Scalar factor = well_ecl.getEfficiencyFactor();
|
Scalar factor = well_ecl.getEfficiencyFactor() *
|
||||||
|
this->well_state[well_name].efficiency_scaling_factor;
|
||||||
auto& [delta_oil, delta_gas, delta_water, delta_alq] = delta;
|
auto& [delta_oil, delta_gas, delta_water, delta_alq] = delta;
|
||||||
delta_oil = factor * (gi.new_oil_rate - state.oilRate());
|
delta_oil = factor * (gi.new_oil_rate - state.oilRate());
|
||||||
delta_gas = factor * (gi.new_gas_rate - state.gasRate());
|
delta_gas = factor * (gi.new_gas_rate - state.gasRate());
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ protected:
|
|||||||
{
|
{
|
||||||
SurplusState(GasLiftStage2& parent_,
|
SurplusState(GasLiftStage2& parent_,
|
||||||
const Group& group_,
|
const Group& group_,
|
||||||
|
const WellState<Scalar>& well_state_,
|
||||||
Scalar oil_rate_,
|
Scalar oil_rate_,
|
||||||
Scalar gas_rate_,
|
Scalar gas_rate_,
|
||||||
Scalar water_rate_,
|
Scalar water_rate_,
|
||||||
@@ -222,6 +223,7 @@ protected:
|
|||||||
std::optional<Scalar> max_total_gas_)
|
std::optional<Scalar> max_total_gas_)
|
||||||
: parent{parent_}
|
: parent{parent_}
|
||||||
, group{group_}
|
, group{group_}
|
||||||
|
, well_state(well_state_)
|
||||||
, oil_rate{oil_rate_}
|
, oil_rate{oil_rate_}
|
||||||
, gas_rate{gas_rate_}
|
, gas_rate{gas_rate_}
|
||||||
, water_rate{water_rate_}
|
, water_rate{water_rate_}
|
||||||
@@ -238,6 +240,7 @@ protected:
|
|||||||
|
|
||||||
GasLiftStage2 &parent;
|
GasLiftStage2 &parent;
|
||||||
const Group &group;
|
const Group &group;
|
||||||
|
const WellState<Scalar>& well_state;
|
||||||
Scalar oil_rate;
|
Scalar oil_rate;
|
||||||
Scalar gas_rate;
|
Scalar gas_rate;
|
||||||
Scalar water_rate;
|
Scalar water_rate;
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ public:
|
|||||||
serializer(bhp);
|
serializer(bhp);
|
||||||
serializer(thp);
|
serializer(thp);
|
||||||
serializer(temperature);
|
serializer(temperature);
|
||||||
|
serializer(efficiency_scaling_factor);
|
||||||
serializer(phase_mixing_rates);
|
serializer(phase_mixing_rates);
|
||||||
serializer(well_potentials);
|
serializer(well_potentials);
|
||||||
serializer(productivity_index);
|
serializer(productivity_index);
|
||||||
@@ -88,6 +89,7 @@ public:
|
|||||||
Scalar bhp{0};
|
Scalar bhp{0};
|
||||||
Scalar thp{0};
|
Scalar thp{0};
|
||||||
Scalar temperature{0};
|
Scalar temperature{0};
|
||||||
|
Scalar efficiency_scaling_factor{1.0};
|
||||||
|
|
||||||
// filtration injection concentration
|
// filtration injection concentration
|
||||||
Scalar filtrate_conc{0};
|
Scalar filtrate_conc{0};
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ assembleControlEqProd(const WellState<Scalar>& well_state,
|
|||||||
{
|
{
|
||||||
const auto current = well_state.well(well_.indexOfWell()).production_cmode;
|
const auto current = well_state.well(well_.indexOfWell()).production_cmode;
|
||||||
const auto& pu = well_.phaseUsage();
|
const auto& pu = well_.phaseUsage();
|
||||||
const Scalar efficiencyFactor = well_.wellEcl().getEfficiencyFactor();
|
const Scalar efficiencyFactor = well_.wellEcl().getEfficiencyFactor() *
|
||||||
|
well_state[well_.name()].efficiency_scaling_factor;
|
||||||
|
|
||||||
switch (current) {
|
switch (current) {
|
||||||
case Well::ProducerCMode::ORAT: {
|
case Well::ProducerCMode::ORAT: {
|
||||||
@@ -208,7 +209,8 @@ assembleControlEqInj(const WellState<Scalar>& well_state,
|
|||||||
auto current = well_state.well(well_.indexOfWell()).injection_cmode;
|
auto current = well_state.well(well_.indexOfWell()).injection_cmode;
|
||||||
const InjectorType injectorType = controls.injector_type;
|
const InjectorType injectorType = controls.injector_type;
|
||||||
const auto& pu = well_.phaseUsage();
|
const auto& pu = well_.phaseUsage();
|
||||||
const Scalar efficiencyFactor = well_.wellEcl().getEfficiencyFactor();
|
const Scalar efficiencyFactor = well_.wellEcl().getEfficiencyFactor() *
|
||||||
|
well_state[well_.name()].efficiency_scaling_factor;
|
||||||
|
|
||||||
switch (current) {
|
switch (current) {
|
||||||
case Well::InjectorCMode::RATE: {
|
case Well::InjectorCMode::RATE: {
|
||||||
|
|||||||
@@ -150,7 +150,8 @@ checkGroupConstraints(WellState<Scalar>& well_state,
|
|||||||
// check, skipping over only the single group parent whose
|
// check, skipping over only the single group parent whose
|
||||||
// control is the active one for the well (if any).
|
// control is the active one for the well (if any).
|
||||||
const auto& group = schedule.getGroup(well.groupName(), well_.currentStep());
|
const auto& group = schedule.getGroup(well.groupName(), well_.currentStep());
|
||||||
const Scalar efficiencyFactor = well.getEfficiencyFactor();
|
const Scalar efficiencyFactor = well.getEfficiencyFactor() *
|
||||||
|
well_state[well.name()].efficiency_scaling_factor;
|
||||||
const std::pair<bool, Scalar> group_constraint =
|
const std::pair<bool, Scalar> group_constraint =
|
||||||
this->checkGroupConstraintsInj(group, well_state,
|
this->checkGroupConstraintsInj(group, well_state,
|
||||||
group_state, efficiencyFactor,
|
group_state, efficiencyFactor,
|
||||||
@@ -181,7 +182,8 @@ checkGroupConstraints(WellState<Scalar>& well_state,
|
|||||||
// check, skipping over only the single group parent whose
|
// check, skipping over only the single group parent whose
|
||||||
// control is the active one for the well (if any).
|
// control is the active one for the well (if any).
|
||||||
const auto& group = schedule.getGroup(well.groupName(), well_.currentStep());
|
const auto& group = schedule.getGroup(well.groupName(), well_.currentStep());
|
||||||
const Scalar efficiencyFactor = well.getEfficiencyFactor();
|
const Scalar efficiencyFactor = well.getEfficiencyFactor() *
|
||||||
|
well_state[well.name()].efficiency_scaling_factor;
|
||||||
const std::pair<bool, Scalar> group_constraint =
|
const std::pair<bool, Scalar> group_constraint =
|
||||||
this->checkGroupConstraintsProd(group, well_state,
|
this->checkGroupConstraintsProd(group, well_state,
|
||||||
group_state, efficiencyFactor,
|
group_state, efficiencyFactor,
|
||||||
|
|||||||
@@ -115,7 +115,8 @@ namespace Opm {
|
|||||||
if (wellEcl.getStatus() == Opm::Well::Status::SHUT)
|
if (wellEcl.getStatus() == Opm::Well::Status::SHUT)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Scalar factor = wellEcl.getEfficiencyFactor();
|
const Scalar factor = wellEcl.getEfficiencyFactor() *
|
||||||
|
wellState[wellEcl.name()].efficiency_scaling_factor;
|
||||||
const auto& ws = wellState.well(well_index.value());
|
const auto& ws = wellState.well(well_index.value());
|
||||||
if (res_rates) {
|
if (res_rates) {
|
||||||
const auto& well_rates = ws.reservoir_rates;
|
const auto& well_rates = ws.reservoir_rates;
|
||||||
@@ -265,7 +266,8 @@ sumSolventRates(const Group& group,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto& ws = wellState.well(well_index.value());
|
const auto& ws = wellState.well(well_index.value());
|
||||||
const Scalar factor = wellEcl.getEfficiencyFactor();
|
const Scalar factor = wellEcl.getEfficiencyFactor() *
|
||||||
|
wellState[wellEcl.name()].efficiency_scaling_factor;
|
||||||
if (injector)
|
if (injector)
|
||||||
rate += factor * ws.sum_solvent_rates();
|
rate += factor * ws.sum_solvent_rates();
|
||||||
else
|
else
|
||||||
@@ -455,8 +457,10 @@ updateGroupTargetReduction(const Group& group,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Scalar efficiency = wellTmp.getEfficiencyFactor();
|
const Scalar efficiency = wellTmp.getEfficiencyFactor() *
|
||||||
// add contributino from wells not under group control
|
wellState[wellTmp.name()].efficiency_scaling_factor;
|
||||||
|
|
||||||
|
// add contribution from wells not under group control
|
||||||
const auto& ws = wellState.well(well_index.value());
|
const auto& ws = wellState.well(well_index.value());
|
||||||
if (isInjector) {
|
if (isInjector) {
|
||||||
if (ws.injection_cmode != Well::InjectorCMode::GRUP)
|
if (ws.injection_cmode != Well::InjectorCMode::GRUP)
|
||||||
@@ -868,7 +872,8 @@ computeNetworkPressures(const Network::ExtNetwork& network,
|
|||||||
// - Making the wells' maximum flows (i.e. not time-averaged by using a efficiency factor)
|
// - Making the wells' maximum flows (i.e. not time-averaged by using a efficiency factor)
|
||||||
// available and using those (for wells with WEFAC(3) true only) when accumulating group
|
// available and using those (for wells with WEFAC(3) true only) when accumulating group
|
||||||
// rates, but ONLY for network calculations.
|
// rates, but ONLY for network calculations.
|
||||||
const Scalar efficiency = well.getEfficiencyFactor();
|
const Scalar efficiency = well.getEfficiencyFactor() *
|
||||||
|
well_state[well.name()].efficiency_scaling_factor;
|
||||||
node_inflows[node][BlackoilPhases::Vapour] += well_state.getALQ(wellname) * efficiency;
|
node_inflows[node][BlackoilPhases::Vapour] += well_state.getALQ(wellname) * efficiency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ public:
|
|||||||
WellTestState& welltest_state,
|
WellTestState& welltest_state,
|
||||||
const PhaseUsage& phase_usage,
|
const PhaseUsage& phase_usage,
|
||||||
GLiftEclWells& ecl_well_map,
|
GLiftEclWells& ecl_well_map,
|
||||||
|
std::map<std::string, double>& open_times,
|
||||||
DeferredLogger& deferred_logger);
|
DeferredLogger& deferred_logger);
|
||||||
|
|
||||||
void checkWellOperability(const Simulator& simulator,
|
void checkWellOperability(const Simulator& simulator,
|
||||||
|
|||||||
@@ -318,7 +318,8 @@ zeroGroupRateTarget(const SummaryState& summary_state,
|
|||||||
{
|
{
|
||||||
const auto& well = this->well_ecl_;
|
const auto& well = this->well_ecl_;
|
||||||
const auto& group = schedule.getGroup(well.groupName(), this->currentStep());
|
const auto& group = schedule.getGroup(well.groupName(), this->currentStep());
|
||||||
const Scalar efficiencyFactor = well.getEfficiencyFactor();
|
const Scalar efficiencyFactor = well.getEfficiencyFactor() *
|
||||||
|
well_state[well.name()].efficiency_scaling_factor;
|
||||||
if (this->isInjector()) {
|
if (this->isInjector()) {
|
||||||
// Check injector under group control
|
// Check injector under group control
|
||||||
const auto& controls = well.injectionControls(summary_state);
|
const auto& controls = well.injectionControls(summary_state);
|
||||||
|
|||||||
@@ -384,6 +384,7 @@ namespace Opm
|
|||||||
WellTestState& well_test_state,
|
WellTestState& well_test_state,
|
||||||
const PhaseUsage& phase_usage,
|
const PhaseUsage& phase_usage,
|
||||||
GLiftEclWells& ecl_well_map,
|
GLiftEclWells& ecl_well_map,
|
||||||
|
std::map<std::string, double>& open_times,
|
||||||
DeferredLogger& deferred_logger)
|
DeferredLogger& deferred_logger)
|
||||||
{
|
{
|
||||||
deferred_logger.info(" well " + this->name() + " is being tested");
|
deferred_logger.info(" well " + this->name() + " is being tested");
|
||||||
@@ -480,6 +481,7 @@ namespace Opm
|
|||||||
// set the status of the well_state to open
|
// set the status of the well_state to open
|
||||||
ws.open();
|
ws.open();
|
||||||
well_state = well_state_copy;
|
well_state = well_state_copy;
|
||||||
|
open_times.try_emplace(this->name(), well_test_state.lastTestTime(this->name()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1240,7 +1242,8 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
assert(well.isAvailableForGroupControl());
|
assert(well.isAvailableForGroupControl());
|
||||||
const auto& group = schedule.getGroup(well.groupName(), this->currentStep());
|
const auto& group = schedule.getGroup(well.groupName(), this->currentStep());
|
||||||
const Scalar efficiencyFactor = well.getEfficiencyFactor();
|
const Scalar efficiencyFactor = well.getEfficiencyFactor() *
|
||||||
|
well_state[well.name()].efficiency_scaling_factor;
|
||||||
std::optional<Scalar> target =
|
std::optional<Scalar> target =
|
||||||
this->getGroupInjectionTargetRate(group,
|
this->getGroupInjectionTargetRate(group,
|
||||||
well_state,
|
well_state,
|
||||||
@@ -1464,7 +1467,8 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
assert(well.isAvailableForGroupControl());
|
assert(well.isAvailableForGroupControl());
|
||||||
const auto& group = schedule.getGroup(well.groupName(), this->currentStep());
|
const auto& group = schedule.getGroup(well.groupName(), this->currentStep());
|
||||||
const Scalar efficiencyFactor = well.getEfficiencyFactor();
|
const Scalar efficiencyFactor = well.getEfficiencyFactor() *
|
||||||
|
well_state[well.name()].efficiency_scaling_factor;
|
||||||
Scalar scale = this->getGroupProductionTargetRate(group,
|
Scalar scale = this->getGroupProductionTargetRate(group,
|
||||||
well_state,
|
well_state,
|
||||||
group_state,
|
group_state,
|
||||||
|
|||||||
@@ -519,6 +519,7 @@ WellState<Scalar>::report(const int* globalCellIdxMap,
|
|||||||
well.bhp = ws.bhp;
|
well.bhp = ws.bhp;
|
||||||
well.thp = ws.thp;
|
well.thp = ws.thp;
|
||||||
well.temperature = ws.temperature;
|
well.temperature = ws.temperature;
|
||||||
|
well.efficiency_scaling_factor = ws.efficiency_scaling_factor;
|
||||||
well.filtrate.rate = ws.sum_filtrate_rate();
|
well.filtrate.rate = ws.sum_filtrate_rate();
|
||||||
well.filtrate.total = ws.sum_filtrate_total();
|
well.filtrate.total = ws.sum_filtrate_total();
|
||||||
well.filtrate.concentration = ws.filtrate_conc;
|
well.filtrate.concentration = ws.filtrate_conc;
|
||||||
|
|||||||
@@ -583,6 +583,17 @@ foreach(templ_case RANGE 1 6)
|
|||||||
)
|
)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
foreach(wcycle_case RANGE 0 7)
|
||||||
|
add_test_compareECLFiles(CASENAME WCYCLE-${wcycle_case}
|
||||||
|
FILENAME WCYCLE-${wcycle_case}
|
||||||
|
SIMULATOR flow
|
||||||
|
ABS_TOL ${abs_tol}
|
||||||
|
REL_TOL ${rel_tol}
|
||||||
|
DIR wcycle
|
||||||
|
TEST_ARGS --enable-tuning=true
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
add_test_compareECLFiles(CASENAME udq_uadd
|
add_test_compareECLFiles(CASENAME udq_uadd
|
||||||
FILENAME UDQ_M1
|
FILENAME UDQ_M1
|
||||||
SIMULATOR flow
|
SIMULATOR flow
|
||||||
|
|||||||
Reference in New Issue
Block a user