diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index 723eae2ae..adf56e5c9 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -807,7 +807,8 @@ namespace Opm { std::vector groupTargetReductionInj(numPhases(), 0.0); wellGroupHelpers::updateGroupTargetReduction(fieldGroup, schedule(), reportStepIdx, /*isInjector*/ true, well_state_, groupTargetReductionInj); std::vector rein(numPhases(), 0.0); - wellGroupHelpers::updateREINForGroups(fieldGroup, schedule(), reportStepIdx, phase_usage_, well_state_, rein); + const auto& summaryState = ebosSimulator_.vanguard().summaryState(); + wellGroupHelpers::updateREINForGroups(fieldGroup, schedule(), reportStepIdx, phase_usage_, summaryState, well_state_, rein); double resv = 0.0; wellGroupHelpers::updateVREPForGroups(fieldGroup, schedule(), reportStepIdx, well_state_, resv); } @@ -1711,6 +1712,38 @@ namespace Opm { //OPM_THROW(std::runtime_error, "Group " + group.name() + "FLD control for injecting groups not implemented" ); } + // Handle GCONSALE + if (schedule().gConSale(reportStepIdx).has(group.name())) { + + if (controls.phase != Phase::GAS) + OPM_THROW(std::runtime_error, "Group " + group.name() + " has GCONSALE control but is not a GAS group" ); + + const auto& gconsale = schedule().gConSale(reportStepIdx).get(group.name(), summaryState); + + double sales_rate = 0.0; + int gasPos = phase_usage_.phase_pos[BlackoilPhases::Vapour]; + sales_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, gasPos, /*isInjector*/false); + sales_rate -= wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, gasPos, /*isInjector*/true); + + // add import rate and substract consumption rate for group for gas + if (schedule().gConSump(reportStepIdx).has(group.name())) { + const auto& gconsump = schedule().gConSump(reportStepIdx).get(group.name(), summaryState); + if (phase_usage_.phase_used[BlackoilPhases::Vapour]) { + sales_rate += gconsump.import_rate; + sales_rate -= gconsump.consumption_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" ); + } + 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" ); + } + 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" ); + } + } + } else if (group.isProductionGroup()) { const auto controls = group.productionControls(summaryState); diff --git a/opm/simulators/wells/MultisegmentWell_impl.hpp b/opm/simulators/wells/MultisegmentWell_impl.hpp index e37bf49a4..67967468c 100644 --- a/opm/simulators/wells/MultisegmentWell_impl.hpp +++ b/opm/simulators/wells/MultisegmentWell_impl.hpp @@ -2093,6 +2093,28 @@ namespace Opm assert(false); break; } + case Group::InjectionCMode::SALE: + { + // only for gas injectors + assert (phasePos == pu.phase_pos[BlackoilPhases::Vapour]); + + // Gas injection rate = Total gas production rate + gas import rate - gas consumption rate - sales rate; + double inj_rate = well_state.currentInjectionREINRates(group.name())[phasePos]; + if (schedule.gConSump(current_step_).has(group.name())) { + const auto& gconsump = schedule.gConSump(current_step_).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(current_step_).get(group.name(), summaryState); + inj_rate -= gconsale.sales_target; + + inj_rate /= efficiencyFactor; + double target = std::max(0.0, (inj_rate - groupTargetReduction)); + control_eq = getSegmentGTotal(0) /scaling - fraction * target; + break; + } default: OPM_DEFLOG_THROW(std::runtime_error, "Unvalid group control specified for group " + well.groupName(), deferred_logger ); diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index e2d337a7f..91eedad04 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -1089,6 +1089,28 @@ namespace Opm assert(false); break; } + case Group::InjectionCMode::SALE: + { + // only for gas injectors + assert (phasePos == pu.phase_pos[BlackoilPhases::Vapour]); + + // Gas injection rate = Total gas production rate + gas import rate - gas consumption rate - sales rate; + double inj_rate = well_state.currentInjectionREINRates(group.name())[phasePos]; + if (schedule.gConSump(current_step_).has(group.name())) { + const auto& gconsump = schedule.gConSump(current_step_).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(current_step_).get(group.name(), summaryState); + inj_rate -= gconsale.sales_target; + + inj_rate /= efficiencyFactor; + double target = std::max(0.0, (inj_rate - groupTargetReduction)); + control_eq = getWQTotal() - fraction * target; + break; + } default: OPM_DEFLOG_THROW(std::runtime_error, "Unvalid group control specified for group " + well.groupName(), deferred_logger ); } diff --git a/opm/simulators/wells/WellGroupHelpers.hpp b/opm/simulators/wells/WellGroupHelpers.hpp index 006e92b23..8ad28f346 100644 --- a/opm/simulators/wells/WellGroupHelpers.hpp +++ b/opm/simulators/wells/WellGroupHelpers.hpp @@ -29,38 +29,6 @@ namespace Opm { namespace wellGroupHelpers { - inline void setCmodeGroup(const Group& group, const Schedule& schedule, const SummaryState& summaryState, const int reportStepIdx, WellStateFullyImplicitBlackoil& wellState) { - - for (const std::string& groupName : group.groups()) { - setCmodeGroup( schedule.getGroup(groupName, reportStepIdx), schedule, summaryState, reportStepIdx, wellState); - } - - // use NONE as default control - if (!wellState.hasInjectionGroupControl(group.name())) { - wellState.setCurrentInjectionGroupControl(group.name(), Group::InjectionCMode::NONE); - } - if (!wellState.hasProductionGroupControl(group.name())) { - wellState.setCurrentProductionGroupControl(group.name(), Group::ProductionCMode::NONE); - } - - if (group.isInjectionGroup() && schedule.hasWellGroupEvent(group.name(), ScheduleEvents::GROUP_INJECTION_UPDATE, reportStepIdx)) { - const auto controls = group.injectionControls(summaryState); - wellState.setCurrentInjectionGroupControl(group.name(), controls.cmode); - } - - if (group.isProductionGroup() && schedule.hasWellGroupEvent(group.name(), ScheduleEvents::GROUP_PRODUCTION_UPDATE, reportStepIdx)) { - const auto controls = group.productionControls(summaryState); - wellState.setCurrentProductionGroupControl(group.name(), controls.cmode); - } - } - - - inline void accumulateGroupEfficiencyFactor(const Group& group, const Schedule& schedule, const int reportStepIdx, double& factor) { - factor *= group.getGroupEfficiencyFactor(); - if (group.parent() != "FIELD") - accumulateGroupEfficiencyFactor(schedule.getGroup(group.parent(), reportStepIdx), schedule, reportStepIdx, factor); - } - inline void setGroupControl(const Group& group, const Schedule& schedule, const int reportStepIdx, const bool injector, WellStateFullyImplicitBlackoil& wellState, std::ostringstream& ss) { for (const std::string& groupName : group.groups()) { @@ -107,6 +75,44 @@ namespace Opm { } } + inline void setCmodeGroup(const Group& group, const Schedule& schedule, const SummaryState& summaryState, const int reportStepIdx, WellStateFullyImplicitBlackoil& wellState) { + + for (const std::string& groupName : group.groups()) { + setCmodeGroup( schedule.getGroup(groupName, reportStepIdx), schedule, summaryState, reportStepIdx, wellState); + } + + // use NONE as default control + if (!wellState.hasInjectionGroupControl(group.name())) { + wellState.setCurrentInjectionGroupControl(group.name(), Group::InjectionCMode::NONE); + } + if (!wellState.hasProductionGroupControl(group.name())) { + wellState.setCurrentProductionGroupControl(group.name(), Group::ProductionCMode::NONE); + } + + if (group.isInjectionGroup() && schedule.hasGroupEvent(group.name(), ScheduleEvents::GROUP_INJECTION_UPDATE, reportStepIdx)) { + const auto controls = group.injectionControls(summaryState); + wellState.setCurrentInjectionGroupControl(group.name(), controls.cmode); + } + + if (group.isProductionGroup() && schedule.hasGroupEvent(group.name(), ScheduleEvents::GROUP_PRODUCTION_UPDATE, reportStepIdx)) { + const auto controls = group.productionControls(summaryState); + wellState.setCurrentProductionGroupControl(group.name(), controls.cmode); + } + + if (schedule.gConSale(reportStepIdx).has(group.name())) { + wellState.setCurrentInjectionGroupControl(group.name(), Group::InjectionCMode::SALE); + std::ostringstream ss; + setGroupControl(group, schedule, reportStepIdx, /*injector*/true, wellState, ss); + } + } + + + inline void accumulateGroupEfficiencyFactor(const Group& group, const Schedule& schedule, const int reportStepIdx, double& factor) { + factor *= group.getGroupEfficiencyFactor(); + if (group.parent() != "FIELD") + accumulateGroupEfficiencyFactor(schedule.getGroup(group.parent(), reportStepIdx), schedule, reportStepIdx, factor); + } + inline void computeGroupTargetReduction(const Group& group, const WellStateFullyImplicitBlackoil& wellState, const Schedule& schedule, const int reportStepIdx, const int phasePos, const bool isInjector, double& groupTargetReduction ) { @@ -332,12 +338,12 @@ namespace Opm { wellState.setCurrentInjectionVREPRates(group.name(), resv); } - inline void updateREINForGroups(const Group& group, const Schedule& schedule, const int reportStepIdx, const PhaseUsage& pu, WellStateFullyImplicitBlackoil& wellState, std::vector& rein) { + inline void updateREINForGroups(const Group& group, const Schedule& schedule, const int reportStepIdx, const PhaseUsage& pu, const SummaryState& st, WellStateFullyImplicitBlackoil& wellState, std::vector& rein) { const int np = wellState.numPhases(); for (const std::string& groupName : group.groups()) { const Group& groupTmp = schedule.getGroup(groupName, reportStepIdx); std::vector thisRein(np, 0.0); - updateREINForGroups(groupTmp, schedule, reportStepIdx, pu, wellState, thisRein); + updateREINForGroups(groupTmp, schedule, reportStepIdx, pu, st, wellState, thisRein); for (int phase = 0; phase < np; ++phase) { rein[phase] = thisRein[phase]; } @@ -348,10 +354,10 @@ namespace Opm { // add import rate and substract consumption rate for group for gas if (schedule.gConSump(reportStepIdx).has(group.name())) { - const auto& gconsump = schedule.gConSump(reportStepIdx).get(group.name()); + const auto& gconsump = schedule.gConSump(reportStepIdx).get(group.name(), st); if (pu.phase_used[BlackoilPhases::Vapour]) { - rein[pu.phase_pos[BlackoilPhases::Vapour]] += gconsump.import_rate.get(); - rein[pu.phase_pos[BlackoilPhases::Vapour]] -= gconsump.consumption_rate.get(); + rein[pu.phase_pos[BlackoilPhases::Vapour]] += gconsump.import_rate; + rein[pu.phase_pos[BlackoilPhases::Vapour]] -= gconsump.consumption_rate; } }