mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #2588 from totto82/addMinMaxSupportGCONSALE
Implement min/max for GCONSALE
This commit is contained in:
commit
7dbbc0f2e5
@ -39,6 +39,7 @@
|
|||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellTestState.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellTestState.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GuideRate.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GuideRate.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
|
||||||
|
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GConSale.hpp>
|
||||||
|
|
||||||
#include <opm/simulators/timestepping/SimulatorReport.hpp>
|
#include <opm/simulators/timestepping/SimulatorReport.hpp>
|
||||||
#include <opm/simulators/wells/PerforationData.hpp>
|
#include <opm/simulators/wells/PerforationData.hpp>
|
||||||
@ -428,7 +429,7 @@ namespace Opm {
|
|||||||
bool checkGroupConstraints(const Group& group, Opm::DeferredLogger& deferred_logger) const;
|
bool checkGroupConstraints(const Group& group, Opm::DeferredLogger& deferred_logger) const;
|
||||||
Group::ProductionCMode checkGroupProductionConstraints(const Group& group, Opm::DeferredLogger& deferred_logger) const;
|
Group::ProductionCMode checkGroupProductionConstraints(const Group& group, Opm::DeferredLogger& deferred_logger) const;
|
||||||
Group::InjectionCMode checkGroupInjectionConstraints(const Group& group, const Phase& phase) const;
|
Group::InjectionCMode checkGroupInjectionConstraints(const Group& group, const Phase& phase) const;
|
||||||
void checkGconsaleLimits(const Group& group) const;
|
void checkGconsaleLimits(const Group& group, WellState& well_state, Opm::DeferredLogger& deferred_logger ) const;
|
||||||
|
|
||||||
void updateGroupHigherControls(Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups);
|
void updateGroupHigherControls(Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups);
|
||||||
void checkGroupHigherConstraints(const Group& group, Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups);
|
void checkGroupHigherConstraints(const Group& group, Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups);
|
||||||
|
@ -464,16 +464,17 @@ namespace Opm {
|
|||||||
const std::string msg = "A zero well potential is returned for output purposes. ";
|
const std::string msg = "A zero well potential is returned for output purposes. ";
|
||||||
local_deferredLogger.warning("WELL_POTENTIAL_CALCULATION_FAILED", msg);
|
local_deferredLogger.warning("WELL_POTENTIAL_CALCULATION_FAILED", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check group sales limits at the end of the timestep
|
||||||
|
const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx);
|
||||||
|
checkGconsaleLimits(fieldGroup, well_state_, local_deferredLogger);
|
||||||
|
|
||||||
previous_well_state_ = well_state_;
|
previous_well_state_ = well_state_;
|
||||||
|
|
||||||
Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(local_deferredLogger);
|
Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(local_deferredLogger);
|
||||||
if (terminal_output_) {
|
if (terminal_output_) {
|
||||||
global_deferredLogger.logMessages();
|
global_deferredLogger.logMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check group sales limits at the end of the timestep
|
|
||||||
const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx);
|
|
||||||
checkGconsaleLimits(fieldGroup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2046,12 +2047,12 @@ namespace Opm {
|
|||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
void
|
void
|
||||||
BlackoilWellModel<TypeTag>::
|
BlackoilWellModel<TypeTag>::
|
||||||
checkGconsaleLimits(const Group& group) const
|
checkGconsaleLimits(const Group& group, WellState& well_state, Opm::DeferredLogger& deferred_logger) const
|
||||||
{
|
{
|
||||||
const int reportStepIdx = ebosSimulator_.episodeIndex();
|
const int reportStepIdx = ebosSimulator_.episodeIndex();
|
||||||
// call recursively down the group hiearchy
|
// call recursively down the group hiearchy
|
||||||
for (const std::string& groupName : group.groups()) {
|
for (const std::string& groupName : group.groups()) {
|
||||||
checkGconsaleLimits( schedule().getGroup(groupName, reportStepIdx));
|
checkGconsaleLimits( schedule().getGroup(groupName, reportStepIdx), well_state, deferred_logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// only for groups with gas injection controls
|
// only for groups with gas injection controls
|
||||||
@ -2063,20 +2064,26 @@ namespace Opm {
|
|||||||
if (!schedule().gConSale(reportStepIdx).has(group.name()))
|
if (!schedule().gConSale(reportStepIdx).has(group.name()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
std::ostringstream ss;
|
||||||
|
|
||||||
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
|
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
|
||||||
const auto& comm = ebosSimulator_.vanguard().grid().comm();
|
const auto& comm = ebosSimulator_.vanguard().grid().comm();
|
||||||
const auto& well_state = well_state_;
|
|
||||||
|
|
||||||
const auto& controls = group.injectionControls(Phase::GAS, summaryState);
|
const auto& inj_controls = group.injectionControls(Phase::GAS, summaryState);
|
||||||
const auto& gconsale = schedule().gConSale(reportStepIdx).get(group.name(), summaryState);
|
const auto& gconsale = schedule().gConSale(reportStepIdx).get(group.name(), summaryState);
|
||||||
|
const Group::ProductionCMode& oldProductionControl = well_state.currentProductionGroupControl(group.name());
|
||||||
|
|
||||||
|
|
||||||
double sales_rate = 0.0;
|
|
||||||
int gasPos = phase_usage_.phase_pos[BlackoilPhases::Vapour];
|
int gasPos = phase_usage_.phase_pos[BlackoilPhases::Vapour];
|
||||||
sales_rate += WellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, gasPos, /*isInjector*/false);
|
double production_rate = WellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, gasPos, /*isInjector*/false);
|
||||||
sales_rate -= WellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, gasPos, /*isInjector*/true);
|
double injection_rate = WellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, gasPos, /*isInjector*/true);
|
||||||
|
|
||||||
// sum over all nodes
|
// sum over all nodes
|
||||||
sales_rate = comm.sum(sales_rate);
|
injection_rate = comm.sum(injection_rate);
|
||||||
|
production_rate = comm.sum(production_rate);
|
||||||
|
|
||||||
|
double sales_rate = production_rate - injection_rate;
|
||||||
|
double production_target = gconsale.sales_target + injection_rate;
|
||||||
|
|
||||||
// add import rate and substract consumption rate for group for gas
|
// add import rate and substract consumption rate for group for gas
|
||||||
if (schedule().gConSump(reportStepIdx).has(group.name())) {
|
if (schedule().gConSump(reportStepIdx).has(group.name())) {
|
||||||
@ -2084,18 +2091,80 @@ namespace Opm {
|
|||||||
if (phase_usage_.phase_used[BlackoilPhases::Vapour]) {
|
if (phase_usage_.phase_used[BlackoilPhases::Vapour]) {
|
||||||
sales_rate += gconsump.import_rate;
|
sales_rate += gconsump.import_rate;
|
||||||
sales_rate -= gconsump.consumption_rate;
|
sales_rate -= gconsump.consumption_rate;
|
||||||
|
production_target -= gconsump.import_rate;
|
||||||
|
production_target += gconsump.consumption_rate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sales_rate > gconsale.max_sales_rate) {
|
if (sales_rate > gconsale.max_sales_rate) {
|
||||||
OPM_THROW(std::runtime_error, "Group " + group.name() + " has sale rate more then the maximum permitted value. Not implemented in Flow" );
|
|
||||||
|
switch(gconsale.max_proc) {
|
||||||
|
case GConSale::MaxProcedure::NONE: {
|
||||||
|
if (oldProductionControl != Group::ProductionCMode::GRAT && oldProductionControl != Group::ProductionCMode::NONE) {
|
||||||
|
ss << "Group sales exceed maximum limit, but the action is NONE for " + group.name() + ". Nothing happens";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GConSale::MaxProcedure::CON: {
|
||||||
|
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "GCONSALE exceed limit CON not implemented", deferred_logger);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GConSale::MaxProcedure::CON_P: {
|
||||||
|
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "GCONSALE exceed limit CON_P not implemented", deferred_logger);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GConSale::MaxProcedure::WELL: {
|
||||||
|
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "GCONSALE exceed limit WELL not implemented", deferred_logger);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GConSale::MaxProcedure::PLUG: {
|
||||||
|
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "GCONSALE exceed limit PLUG not implemented", deferred_logger);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GConSale::MaxProcedure::MAXR: {
|
||||||
|
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "GCONSALE exceed limit MAXR not implemented", deferred_logger);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GConSale::MaxProcedure::END: {
|
||||||
|
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "GCONSALE exceed limit END not implemented", deferred_logger);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GConSale::MaxProcedure::RATE: {
|
||||||
|
well_state.setCurrentProductionGroupControl(group.name(), Group::ProductionCMode::GRAT);
|
||||||
|
ss << "Maximum GCONSALE limit violated for " << group.name() << ". The group is switched from ";
|
||||||
|
ss << Group::ProductionCMode2String(oldProductionControl) << " to " << Group::ProductionCMode2String(Group::ProductionCMode::GRAT);
|
||||||
|
ss << " and limited by the maximum sales rate after consumption and import are considered" ;
|
||||||
|
well_state.setCurrentGroupGratTargetFromSales(group.name(), production_target);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw("Invalid procedure for maximum rate limit selected for group" + group.name());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (sales_rate < gconsale.min_sales_rate) {
|
if (sales_rate < gconsale.min_sales_rate) {
|
||||||
OPM_THROW(std::runtime_error, "Group " + group.name() + " has sale rate less then minimum permitted value. Not implemented in Flow" );
|
const Group::ProductionCMode& currentProductionControl = well_state.currentProductionGroupControl(group.name());
|
||||||
|
if ( currentProductionControl == Group::ProductionCMode::GRAT ) {
|
||||||
|
ss << "Group " + group.name() + " has sale rate less then minimum permitted value and is under GRAT control. \n";
|
||||||
|
ss << "The GRAT is increased to meet the sales minimum rate. \n";
|
||||||
|
well_state.setCurrentGroupGratTargetFromSales(group.name(), production_target);
|
||||||
|
//} else if () {//TODO add action for WGASPROD
|
||||||
|
//} else if () {//TODO add action for drilling queue
|
||||||
|
} else {
|
||||||
|
ss << "Group " + group.name() + " has sale rate less then minimum permitted value but cannot increase the group production rate \n";
|
||||||
|
ss << "or adjust gas production using WGASPROD or drill new wells to meet the sales target. \n";
|
||||||
|
ss << "Note that WGASPROD and drilling queues are not implemented in Flow. No action is taken. \n ";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (gconsale.sales_target < 0.0) {
|
if (gconsale.sales_target < 0.0) {
|
||||||
OPM_THROW(std::runtime_error, "Group " + group.name() + " has sale rate target less then zero. Not implemented in Flow" );
|
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + " has sale rate target less then zero. Not implemented in Flow" , deferred_logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto cc = Dune::MPIHelper::getCollectiveCommunication();
|
||||||
|
if (cc.size() > 1) {
|
||||||
|
ss << " on rank " << cc.rank();
|
||||||
|
}
|
||||||
|
if (!ss.str().empty())
|
||||||
|
deferred_logger.info(ss.str());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,11 +46,14 @@ namespace WellGroupHelpers
|
|||||||
public:
|
public:
|
||||||
TargetCalculator(const Group::ProductionCMode cmode,
|
TargetCalculator(const Group::ProductionCMode cmode,
|
||||||
const PhaseUsage& pu,
|
const PhaseUsage& pu,
|
||||||
const std::vector<double>& resv_coeff)
|
const std::vector<double>& resv_coeff,
|
||||||
|
const double group_grat_target_from_sales)
|
||||||
: cmode_(cmode)
|
: cmode_(cmode)
|
||||||
, pu_(pu)
|
, pu_(pu)
|
||||||
, resv_coeff_(resv_coeff)
|
, resv_coeff_(resv_coeff)
|
||||||
|
, group_grat_target_from_sales_(group_grat_target_from_sales)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename RateVec>
|
template <typename RateVec>
|
||||||
@ -107,7 +110,13 @@ namespace WellGroupHelpers
|
|||||||
case Group::ProductionCMode::WRAT:
|
case Group::ProductionCMode::WRAT:
|
||||||
return ctrl.water_target;
|
return ctrl.water_target;
|
||||||
case Group::ProductionCMode::GRAT:
|
case Group::ProductionCMode::GRAT:
|
||||||
|
{
|
||||||
|
// gas target may have been adjusted by GCONSALE
|
||||||
|
if ( group_grat_target_from_sales_ > 0)
|
||||||
|
return group_grat_target_from_sales_;
|
||||||
|
|
||||||
return ctrl.gas_target;
|
return ctrl.gas_target;
|
||||||
|
}
|
||||||
case Group::ProductionCMode::LRAT:
|
case Group::ProductionCMode::LRAT:
|
||||||
return ctrl.liquid_target;
|
return ctrl.liquid_target;
|
||||||
case Group::ProductionCMode::RESV:
|
case Group::ProductionCMode::RESV:
|
||||||
@ -151,6 +160,7 @@ namespace WellGroupHelpers
|
|||||||
Group::ProductionCMode cmode_;
|
Group::ProductionCMode cmode_;
|
||||||
const PhaseUsage& pu_;
|
const PhaseUsage& pu_;
|
||||||
const std::vector<double>& resv_coeff_;
|
const std::vector<double>& resv_coeff_;
|
||||||
|
const double group_grat_target_from_sales_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace WellGroupHelpers
|
} // namespace WellGroupHelpers
|
||||||
|
@ -1008,14 +1008,8 @@ namespace WellGroupHelpers
|
|||||||
assert(phasePos == pu.phase_pos[BlackoilPhases::Vapour]);
|
assert(phasePos == pu.phase_pos[BlackoilPhases::Vapour]);
|
||||||
|
|
||||||
// Gas injection rate = Total gas production rate + gas import rate - gas consumption rate - sales rate;
|
// Gas injection rate = Total gas production rate + gas import rate - gas consumption rate - sales rate;
|
||||||
|
// Gas import and consumption is already included in the REIN rates
|
||||||
double inj_rate = wellState.currentInjectionREINRates(group.name())[phasePos];
|
double inj_rate = wellState.currentInjectionREINRates(group.name())[phasePos];
|
||||||
if (schedule.gConSump(reportStepIdx).has(group.name())) {
|
|
||||||
const auto& gconsump = schedule.gConSump(reportStepIdx).get(group.name(), summaryState);
|
|
||||||
if (pu.phase_used[BlackoilPhases::Vapour]) {
|
|
||||||
inj_rate += gconsump.import_rate;
|
|
||||||
inj_rate -= gconsump.consumption_rate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const auto& gconsale = schedule.gConSale(reportStepIdx).get(group.name(), summaryState);
|
const auto& gconsale = schedule.gConSale(reportStepIdx).get(group.name(), summaryState);
|
||||||
inj_rate -= gconsale.sales_target;
|
inj_rate -= gconsale.sales_target;
|
||||||
|
|
||||||
@ -1125,7 +1119,14 @@ namespace WellGroupHelpers
|
|||||||
|
|
||||||
// If we are here, we are at the topmost group to be visited in the recursion.
|
// If we are here, we are at the topmost group to be visited in the recursion.
|
||||||
// This is the group containing the control we will check against.
|
// This is the group containing the control we will check against.
|
||||||
TargetCalculator tcalc(currentGroupControl, pu, resv_coeff);
|
|
||||||
|
// gconsale may adjust the grat target.
|
||||||
|
// the adjusted rates is send to the targetCalculator
|
||||||
|
double gratTargetFromSales = 0.0;
|
||||||
|
if (wellState.hasGroupGratTargetFromSales(group.name()))
|
||||||
|
gratTargetFromSales = wellState.currentGroupGratTargetFromSales(group.name());
|
||||||
|
|
||||||
|
TargetCalculator tcalc(currentGroupControl, pu, resv_coeff, gratTargetFromSales);
|
||||||
FractionCalculator fcalc(schedule, wellState, reportStepIdx, guideRate, tcalc.guideTargetMode(), pu);
|
FractionCalculator fcalc(schedule, wellState, reportStepIdx, guideRate, tcalc.guideTargetMode(), pu);
|
||||||
|
|
||||||
auto localFraction = [&](const std::string& child) { return fcalc.localFraction(child, name); };
|
auto localFraction = [&](const std::string& child) { return fcalc.localFraction(child, name); };
|
||||||
|
@ -2246,7 +2246,13 @@ namespace Opm
|
|||||||
std::vector<double> resv_coeff(phaseUsage().num_phases, 1.0);
|
std::vector<double> resv_coeff(phaseUsage().num_phases, 1.0);
|
||||||
rateConverter_.calcCoeff(0, pvtRegionIdx_, resv_coeff); // FIPNUM region 0 here, should use FIPNUM from WELSPECS.
|
rateConverter_.calcCoeff(0, pvtRegionIdx_, resv_coeff); // FIPNUM region 0 here, should use FIPNUM from WELSPECS.
|
||||||
|
|
||||||
WellGroupHelpers::TargetCalculator tcalc(currentGroupControl, pu, resv_coeff);
|
// gconsale may adjust the grat target.
|
||||||
|
// the adjusted rates is send to the targetCalculator
|
||||||
|
double gratTargetFromSales = 0.0;
|
||||||
|
if (well_state.hasGroupGratTargetFromSales(group.name()))
|
||||||
|
gratTargetFromSales = well_state.currentGroupGratTargetFromSales(group.name());
|
||||||
|
|
||||||
|
WellGroupHelpers::TargetCalculator tcalc(currentGroupControl, pu, resv_coeff, gratTargetFromSales);
|
||||||
WellGroupHelpers::FractionCalculator fcalc(schedule, well_state, current_step_, guide_rate_, tcalc.guideTargetMode(), pu);
|
WellGroupHelpers::FractionCalculator fcalc(schedule, well_state, current_step_, guide_rate_, tcalc.guideTargetMode(), pu);
|
||||||
|
|
||||||
auto localFraction = [&](const std::string& child) {
|
auto localFraction = [&](const std::string& child) {
|
||||||
|
@ -447,6 +447,24 @@ namespace Opm
|
|||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setCurrentGroupGratTargetFromSales(const std::string& groupName, const double& target ) {
|
||||||
|
group_grat_target_from_sales[groupName] = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasGroupGratTargetFromSales(const std::string& groupName) const {
|
||||||
|
auto it = group_grat_target_from_sales.find(groupName);
|
||||||
|
return it != group_grat_target_from_sales.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const double& currentGroupGratTargetFromSales(const std::string& groupName) const {
|
||||||
|
auto it = group_grat_target_from_sales.find(groupName);
|
||||||
|
|
||||||
|
if (it == group_grat_target_from_sales.end())
|
||||||
|
OPM_THROW(std::logic_error, "Could not find any grat target from sales for group " << groupName);
|
||||||
|
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
void setCurrentGroupInjectionPotentials(const std::string& groupName, const std::vector<double>& pot ) {
|
void setCurrentGroupInjectionPotentials(const std::string& groupName, const std::vector<double>& pot ) {
|
||||||
injection_group_potentials[groupName] = pot;
|
injection_group_potentials[groupName] = pot;
|
||||||
}
|
}
|
||||||
@ -1042,6 +1060,7 @@ namespace Opm
|
|||||||
std::map<std::string, std::vector<double>> injection_group_potentials;
|
std::map<std::string, std::vector<double>> injection_group_potentials;
|
||||||
std::map<std::string, double> injection_group_vrep_rates;
|
std::map<std::string, double> injection_group_vrep_rates;
|
||||||
std::map<std::string, std::vector<double>> injection_group_rein_rates;
|
std::map<std::string, std::vector<double>> injection_group_rein_rates;
|
||||||
|
std::map<std::string, double> group_grat_target_from_sales;
|
||||||
|
|
||||||
std::vector<double> perfRateSolvent_;
|
std::vector<double> perfRateSolvent_;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user