20#ifndef OPM_BLACKOILWELLMODEL_RESCOUP_IMPL_HEADER_INCLUDED
21#define OPM_BLACKOILWELLMODEL_RESCOUP_IMPL_HEADER_INCLUDED
24#ifndef OPM_BLACKOILWELLMODEL_RESCOUP_HEADER_INCLUDED
29#ifdef RESERVOIR_COUPLING_ENABLED
31#include <opm/common/TimingMacros.hpp>
33#include <opm/input/eclipse/EclipseState/Grid/RegionSetMatcher.hpp>
34#include <opm/input/eclipse/Schedule/ResCoup/ReservoirCouplingInfo.hpp>
35#include <opm/input/eclipse/Schedule/Schedule.hpp>
36#include <opm/input/eclipse/Schedule/SummaryState.hpp>
37#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
38#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
39#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
40#include <opm/input/eclipse/Schedule/Well/WellMatcher.hpp>
41#include <opm/input/eclipse/Units/UnitSystem.hpp>
64template<
typename TypeTag>
65BlackoilWellModelRescoup<TypeTag>::
66BlackoilWellModelRescoup(BlackoilWellModel<TypeTag>& well_model)
67 : well_model_{well_model}
68 , network_{well_model.network()}
69 , simulator_{well_model.simulator()}
70 , param_{well_model.param()}
76template<
typename TypeTag>
78BlackoilWellModelRescoup<TypeTag>::
79evalGroupAndFieldUDQs()
81 const int reportStepIdx = this->groupStateHelper().reportStepIdx();
82 auto& deferred_logger = this->groupStateHelper().deferredLogger();
91 const auto select = [](
const UDQDefine& def) {
92 const auto var_type = def.var_type();
93 return ((var_type == UDQVarType::GROUP_VAR) || (var_type == UDQVarType::FIELD_VAR))
94 && (def.status().first != UDQUpdate::NEXT);
96 const auto& schedule = this->schedule();
99 schedule[reportStepIdx].udq().eval(
101 schedule.wellMatcher(reportStepIdx),
102 schedule[reportStepIdx].group_order(),
103 schedule.segmentMatcherFactory(reportStepIdx),
104 [es = std::cref(this->simulator_.vanguard().eclState())]() {
105 return std::make_unique<RegionSetMatcher>(es.get().fipRegionStatistics());
107 this->simulator_.vanguard().summaryState(),
108 this->simulator_.vanguard().udqState(),
112 "Failed to evaluate UDQs for reservoir coupling slave: ",
113 this->well_model_.terminalOutput(),
114 this->simulator_.vanguard().grid().comm())
117template<
typename TypeTag>
119BlackoilWellModelRescoup<TypeTag>::
120masterIsInCoupledNetworkIteration()
const
122 return this->isReservoirCouplingMaster()
123 && this->reservoirCouplingMaster().isFirstSubstepOfSyncTimestep()
124 && this->masterNetworkHasMasterGroupLeaves()
125 && !this->lastSentMasterGroupNodePressuresIsFinal();
129template<
typename TypeTag>
131BlackoilWellModelRescoup<TypeTag>::
132masterNetworkHasMasterGroupLeaves()
const
137 if (!this->isReservoirCouplingMaster())
return false;
138 const auto& rcm = this->reservoirCouplingMaster();
139 const auto num_slaves = rcm.numSlaves();
140 for (std::size_t s = 0; s < num_slaves; ++s) {
141 if (!rcm.slaveIsCoupled(s))
continue;
142 if (this->masterNetworkHasMasterGroupLeavesForSlave_(s)) {
149template<
typename TypeTag>
151BlackoilWellModelRescoup<TypeTag>::
152maybeExchangeNetworkOuterIterationWithSlaves(
bool more_network_update)
154 if (!this->masterIsInCoupledNetworkIteration()) {
157 const bool is_final = !more_network_update;
166 if (is_final || !this->well_model_.useTightRcNetworkCoupling()) {
168 this->sendMasterGroupNodePressuresToSlaves(is_final);
171 this->receiveSlaveGroupData();
172 this->refreshAndSendGroupConstraints();
177template<
typename TypeTag>
179BlackoilWellModelRescoup<TypeTag>::
180maybeExchangeNetworkSubIterationWithSlaves()
200 if (!this->well_model_.useTightRcNetworkCoupling()) {
203 if (!this->masterIsInCoupledNetworkIteration()) {
206 this->sendMasterGroupNodePressuresToSlaves(
false);
207 this->receiveSlaveGroupData();
208 this->refreshAndSendGroupConstraints();
211template<
typename TypeTag>
213BlackoilWellModelRescoup<TypeTag>::
214receiveCoupledNetworkActiveStatus()
217 assert(this->isReservoirCouplingSlave());
218 this->reservoirCouplingSlave().receiveCoupledNetworkActiveStatusFromMaster();
219 if (!this->reservoirCouplingSlave().connectedToMasterCoupledNetwork()) {
221 this->network_.setNodePressureOverrides({});
222 for (
auto& well : this->wellContainer()) {
223 well->setLogAllControlSwitches(
false);
228template<
typename TypeTag>
230BlackoilWellModelRescoup<TypeTag>::
231receiveGroupConstraintsFromMaster()
234 RescoupReceiveGroupConstraints<Scalar, IndexTraits> constraint_receiver{
235 this->well_model_.guideRateHandler(),
236 this->groupStateHelper()
238 constraint_receiver.receiveGroupConstraintsFromMaster();
241template<
typename TypeTag>
243BlackoilWellModelRescoup<TypeTag>::
244receiveMasterGroupNodePressuresFromMaster()
247 assert(this->isReservoirCouplingSlave());
248 auto& rescoup_slave = this->reservoirCouplingSlave();
249 const auto [num_pressures, is_final] =
250 rescoup_slave.receiveNumMasterGroupNodePressuresFromMaster();
251 if (num_pressures > 0) {
252 rescoup_slave.receiveMasterGroupNodePressuresFromMaster(num_pressures);
281 const auto& pressures = rescoup_slave.masterGroupNodePressures();
282 std::map<std::string, Scalar> overrides;
283 for (
const auto& [group_name, pressure] : pressures) {
284 if (this->slaveGroupIsFixedPressureNodeInOwnNetwork_(group_name)) {
285 overrides[group_name] = pressure;
288 this->network_.setNodePressureOverrides(overrides);
297 for (
auto& well : this->wellContainer()) {
298 well->setLogAllControlSwitches(
false);
300 if (pressures.empty())
return;
301 const auto& summary_state = this->well_model_.summaryState();
302 auto& well_state = this->wellState();
303 for (
auto& well : this->wellContainer()) {
304 if (!well->isProducer() || !well->wellEcl().predictionMode())
continue;
305 const auto& group_name = well->wellEcl().groupName();
306 if (this->wellIsBelowOverriddenNode_(group_name, overrides)) {
307 well->setLogAllControlSwitches(!is_final);
309 const auto it = pressures.find(group_name);
310 if (it == pressures.end())
continue;
311 if (!this->slaveGroupIsFixedPressureNodeInOwnNetwork_(group_name))
continue;
312 well->setDynamicThpLimit(it->second);
313 auto& ws = well_state[well->indexOfWell()];
318 ws.network_thp_limit = it->second;
319 if (ws.production_cmode == Well::ProducerCMode::THP) {
320 ws.thp = well->getTHPConstraint(summary_state);
325template<
typename TypeTag>
327BlackoilWellModelRescoup<TypeTag>::
328receiveRefreshedGroupConstraintsFromMaster()
334 this->receiveGroupConstraintsFromMaster();
335 this->groupStateHelper().updateSlaveGroupCmodesFromMaster();
336 this->refreshSlaveGroupTargets();
339template<
typename TypeTag>
341BlackoilWellModelRescoup<TypeTag>::
342receiveSlaveGroupData()
345 assert(this->isReservoirCouplingMaster());
346 RescoupReceiveSlaveGroupData<Scalar, IndexTraits> slave_group_data_receiver{
347 this->groupStateHelper(),
349 slave_group_data_receiver.receiveSlaveGroupData();
352template<
typename TypeTag>
354BlackoilWellModelRescoup<TypeTag>::
355refreshAndSendGroupConstraints()
371 const int report_step_idx = this->well_model_.simulator().episodeIndex();
372 this->well_model_.updateAndCommunicateGroupData(
373 report_step_idx,
false);
374 this->sendMasterGroupConstraintsToSlaves();
377template<
typename TypeTag>
379BlackoilWellModelRescoup<TypeTag>::
380refreshSlaveGroupTargets()
388 this->storeSlaveGroupInjectionTargets();
389 this->storeSlaveGroupProductionTargets();
390 this->evalGroupAndFieldUDQs();
391 this->storeSlaveGroupInjectionTargets();
392 this->storeSlaveGroupProductionTargets();
395template<
typename TypeTag>
397BlackoilWellModelRescoup<TypeTag>::
398rescoupSyncSummaryData()
418 if (this->isReservoirCouplingMaster()) {
419 if (this->reservoirCouplingMaster().needsSlaveDataReceive()) {
425 this->reservoirCouplingMaster().saveGroupFlowsAtStartOfSyncStep();
426 this->receiveSlaveGroupData();
427 this->reservoirCouplingMaster().updateFlowChangeTimeStepLimit();
428 this->reservoirCouplingMaster().setNeedsSlaveDataReceive(
false);
431 if (this->isReservoirCouplingSlave()) {
432 if (this->reservoirCouplingSlave().isLastSubstepOfSyncTimestep()) {
433 this->well_model_.updateGroupRatesFromWellState(
434 this->well_model_.simulator().episodeIndex());
435 this->sendSlaveGroupDataToMaster();
440template<
typename TypeTag>
442BlackoilWellModelRescoup<TypeTag>::
443sendCoupledNetworkActiveStatus()
446 assert(this->isReservoirCouplingMaster());
455 auto& rescoup_master = this->reservoirCouplingMaster();
456 const auto num_slaves = rescoup_master.numSlaves();
457 bool any_connected =
false;
458 for (std::size_t slave_idx = 0; slave_idx < num_slaves; ++slave_idx) {
459 if (rescoup_master.slaveIsCoupled(slave_idx)) {
460 const bool connected =
461 this->masterNetworkHasMasterGroupLeavesForSlave_(slave_idx);
462 any_connected = any_connected || connected;
463 rescoup_master.sendCoupledNetworkActiveStatusToSlave(slave_idx, connected);
470 this->last_sent_master_group_node_pressures_is_final_ = !any_connected;
473template<
typename TypeTag>
475BlackoilWellModelRescoup<TypeTag>::
476sendMasterGroupConstraintsToSlaves()
482 RescoupConstraintsCalculator<Scalar, IndexTraits> constraints_calculator{
483 this->well_model_.guideRateHandler(),
484 this->groupStateHelper()
486 constraints_calculator.calculateMasterGroupConstraintsAndSendToSlaves();
489template<
typename TypeTag>
491BlackoilWellModelRescoup<TypeTag>::
492sendMasterGroupNodePressuresToSlaves(
bool is_final)
495 assert(this->isReservoirCouplingMaster());
496 auto& rescoup_master = this->reservoirCouplingMaster();
497 const auto& node_pressures = this->network_.nodePressures();
498 const auto num_slaves = rescoup_master.numSlaves();
499 for (std::size_t slave_idx = 0; slave_idx < num_slaves; ++slave_idx) {
500 if (!rescoup_master.slaveIsCoupled(slave_idx))
continue;
501 std::vector<typename ReservoirCoupling::MasterGroupNodePressure<Scalar>> pressures;
502 const auto& master_groups = rescoup_master.getMasterGroupNamesForSlave(slave_idx);
503 for (std::size_t i = 0; i < master_groups.size(); ++i) {
504 const auto it = node_pressures.find(master_groups[i]);
505 if (it != node_pressures.end()) {
506 pressures.push_back({i, it->second});
509 rescoup_master.sendNumMasterGroupNodePressuresToSlave(
510 slave_idx, pressures.size(), is_final);
511 if (!pressures.empty()) {
512 rescoup_master.sendMasterGroupNodePressuresToSlave(slave_idx, pressures);
515 this->last_sent_master_group_node_pressures_is_final_ = is_final;
518template<
typename TypeTag>
520BlackoilWellModelRescoup<TypeTag>::
521sendSlaveGroupDataToMaster()
524 assert(this->isReservoirCouplingSlave());
525 RescoupSendSlaveGroupData<Scalar, IndexTraits> slave_group_data_sender{
526 this->groupStateHelper(), this->well_model_.nupcolWellState()};
527 slave_group_data_sender.sendSlaveGroupDataToMaster();
539template<
typename TypeTag>
540std::optional<ReservoirCoupling::ScopedLoggerGuard>
541BlackoilWellModelRescoup<TypeTag>::
542setupScopedLogger(DeferredLogger& local_logger)
544 if (this->isReservoirCouplingMaster()) {
545 return ReservoirCoupling::ScopedLoggerGuard{
546 this->reservoirCouplingMaster().logger(),
549 }
else if (this->isReservoirCouplingSlave()) {
550 return ReservoirCoupling::ScopedLoggerGuard{
551 this->reservoirCouplingSlave().logger(),
558template<
typename TypeTag>
560BlackoilWellModelRescoup<TypeTag>::
561storeSlaveGroupInjectionTargets()
563 const int reportStepIdx = this->groupStateHelper().reportStepIdx();
579 using M = UnitSystem::measure;
580 auto& summary_state = this->simulator_.vanguard().summaryState();
581 const auto& units = this->simulator_.vanguard().eclState().getUnits();
582 auto& slave = this->reservoirCouplingSlave();
583 const auto& rescoup = this->schedule()[reportStepIdx].rescoup();
593 const auto targets = std::array {
594 std::tuple { Phase::GAS, std::string{
"GGIRT"}, M::gas_surface_rate },
595 std::tuple { Phase::WATER, std::string{
"GWIRT"}, M::liquid_surface_rate },
597 auto& in_force = slave.effectiveInjectionTargets();
599 for (std::size_t i = 0; i < slave.numSlaveGroups(); ++i) {
600 const auto& gname = slave.slaveGroupIdxToGroupName(i);
601 for (
const auto& [phase, keyword, unit] : targets) {
602 const auto effective = this->effectiveSlaveGroupInjectionTarget_(
603 gname, phase, reportStepIdx, rescoup, summary_state);
604 if (effective.has_value()) {
605 in_force[gname][phase] = *effective;
606 summary_state.update_group_var(gname, keyword, units.from_si(unit, *effective));
609 summary_state.update_group_var(
611 units.from_si(unit, this->scheduleInjectionTarget_(gname, phase, reportStepIdx, summary_state)));
617template<
typename TypeTag>
619BlackoilWellModelRescoup<TypeTag>::
620storeSlaveGroupProductionTargets()
622 const int reportStepIdx = this->groupStateHelper().reportStepIdx();
635 using M = UnitSystem::measure;
636 using CMode = Group::ProductionCMode;
637 auto& summary_state = this->simulator_.vanguard().summaryState();
638 const auto& units = this->simulator_.vanguard().eclState().getUnits();
639 auto& slave = this->reservoirCouplingSlave();
640 const auto& rescoup = this->schedule()[reportStepIdx].rescoup();
641 const auto targets = std::array {
642 std::tuple { CMode::ORAT, std::string{
"GOPRT"}, M::rate },
643 std::tuple { CMode::WRAT, std::string{
"GWPRT"}, M::rate },
644 std::tuple { CMode::GRAT, std::string{
"GGPRT"}, M::gas_surface_rate },
645 std::tuple { CMode::LRAT, std::string{
"GLPRT"}, M::rate },
647 auto& in_force = slave.effectiveProductionTargets();
649 for (std::size_t i = 0; i < slave.numSlaveGroups(); ++i) {
650 const auto& gname = slave.slaveGroupIdxToGroupName(i);
651 for (
const auto& [cmode, keyword, unit] : targets) {
652 const auto effective = this->effectiveSlaveGroupProductionTarget_(
653 gname, cmode, reportStepIdx, rescoup, summary_state);
654 if (effective.has_value()) {
655 in_force[gname][cmode] = *effective;
656 summary_state.update_group_var(gname, keyword, units.from_si(unit, *effective));
659 summary_state.update_group_var(
661 units.from_si(unit, this->scheduleProductionTarget_(gname, cmode, reportStepIdx, summary_state)));
670template<
typename TypeTag>
671std::optional<typename BlackoilWellModelRescoup<TypeTag>::Scalar>
672BlackoilWellModelRescoup<TypeTag>::
673effectiveSlaveGroupInjectionTarget_(
const std::string& gname,
675 const int reportStepIdx,
676 const ReservoirCoupling::CouplingInfo& rescoup,
677 const SummaryState& summary_state)
const
679 using FilterFlag = ReservoirCoupling::GrupSlav::FilterFlag;
680 const auto& slave = this->reservoirCouplingSlave();
681 if (! slave.hasMasterInjectionTarget(gname, phase)) {
684 const auto [master_target, cmode] = slave.masterInjectionTarget(gname, phase);
685 if (cmode != Group::InjectionCMode::RATE) {
691 auto filter = FilterFlag::MAST;
692 if (rescoup.hasGrupSlav(gname)) {
693 const auto& grup_slav = rescoup.grupSlav(gname);
694 filter = (phase == Phase::GAS) ? grup_slav.gasInjFlag()
695 : (phase == Phase::WATER) ? grup_slav.waterInjFlag()
696 : grup_slav.oilInjFlag();
698 if (filter == FilterFlag::SLAV) {
703 if (filter == FilterFlag::BOTH) {
704 const auto& group = this->schedule().getGroup(gname, reportStepIdx);
705 if (group.hasInjectionControl(phase)) {
706 return std::min(master_target,
707 this->scheduleInjectionTarget_(gname, phase, reportStepIdx, summary_state));
710 return master_target;
713template<
typename TypeTag>
714std::optional<typename BlackoilWellModelRescoup<TypeTag>::Scalar>
715BlackoilWellModelRescoup<TypeTag>::
716effectiveSlaveGroupProductionTarget_(
const std::string& gname,
717 const Group::ProductionCMode cmode,
718 const int reportStepIdx,
719 const ReservoirCoupling::CouplingInfo& rescoup,
720 const SummaryState& summary_state)
const
727 using CMode = Group::ProductionCMode;
728 using FilterFlag = ReservoirCoupling::GrupSlav::FilterFlag;
729 const auto& slave = this->reservoirCouplingSlave();
730 if (! slave.hasMasterProductionLimits(gname)) {
733 const auto& limits = slave.masterProductionLimits(gname);
734 const Scalar master_limit = (cmode == CMode::ORAT) ? limits.oil_limit
735 : (cmode == CMode::WRAT) ? limits.water_limit
736 : (cmode == CMode::GRAT) ? limits.gas_limit
737 : limits.liquid_limit;
738 if (master_limit < 0) {
747 auto filter = FilterFlag::MAST;
748 if (rescoup.hasGrupSlav(gname)) {
749 const auto& grup_slav = rescoup.grupSlav(gname);
750 filter = (cmode == CMode::ORAT) ? grup_slav.oilProdFlag()
751 : (cmode == CMode::GRAT) ? grup_slav.gasProdFlag()
752 : grup_slav.liquidProdFlag();
754 if (filter == FilterFlag::SLAV) {
757 if (filter == FilterFlag::BOTH) {
758 const auto& group = this->schedule().getGroup(gname, reportStepIdx);
759 if (group.has_control(cmode)) {
760 return std::min(master_limit,
761 this->scheduleProductionTarget_(gname, cmode, reportStepIdx, summary_state));
767template<
typename TypeTag>
769BlackoilWellModelRescoup<TypeTag>::
770masterNetworkHasMasterGroupLeavesForSlave_(std::size_t slave_idx)
const
774 if (!this->isReservoirCouplingMaster())
return false;
775 const int episodeIdx = this->simulator_.episodeIndex();
776 const auto& network = this->schedule()[episodeIdx].network();
777 if (!network.active())
return false;
778 const auto& rcm = this->reservoirCouplingMaster();
779 for (
const auto& mg : rcm.getMasterGroupNamesForSlave(slave_idx)) {
780 if (network.has_node(mg)) {
787template<
typename TypeTag>
788typename BlackoilWellModelRescoup<TypeTag>::Scalar
789BlackoilWellModelRescoup<TypeTag>::
790scheduleInjectionTarget_(
const std::string& gname,
792 const int reportStepIdx,
793 const SummaryState& summary_state)
const
795 const auto& group = this->schedule().getGroup(gname, reportStepIdx);
796 if (! group.hasInjectionControl(phase)) {
799 return static_cast<Scalar
>(group.injectionControls(phase, summary_state).surface_max_rate);
802template<
typename TypeTag>
803typename BlackoilWellModelRescoup<TypeTag>::Scalar
804BlackoilWellModelRescoup<TypeTag>::
805scheduleProductionTarget_(
const std::string& gname,
806 const Group::ProductionCMode cmode,
807 const int reportStepIdx,
808 const SummaryState& summary_state)
const
810 using CMode = Group::ProductionCMode;
811 const auto controls = this->schedule().getGroup(gname, reportStepIdx)
812 .productionControls(summary_state);
814 case CMode::ORAT:
return static_cast<Scalar
>(controls.oil_target);
815 case CMode::WRAT:
return static_cast<Scalar
>(controls.water_target);
816 case CMode::GRAT:
return static_cast<Scalar
>(controls.gas_target);
817 case CMode::LRAT:
return static_cast<Scalar
>(controls.liquid_target);
818 default:
return Scalar{0};
822template<
typename TypeTag>
824BlackoilWellModelRescoup<TypeTag>::
825slaveGroupIsFixedPressureNodeInOwnNetwork_(
const std::string& group_name)
const
827 const int episodeIdx = this->simulator_.episodeIndex();
828 const auto& network = this->schedule()[episodeIdx].network();
829 if (!network.active())
return false;
830 if (!network.has_node(group_name))
return false;
831 return network.node(group_name).terminal_pressure().has_value();
834template<
typename TypeTag>
836BlackoilWellModelRescoup<TypeTag>::
837wellIsBelowOverriddenNode_(
const std::string& group_name,
838 const std::map<std::string, Scalar>& overrides)
const
840 if (overrides.empty())
return false;
841 const int episodeIdx = this->simulator_.episodeIndex();
842 const auto& network = this->schedule()[episodeIdx].network();
843 if (!network.active() || !network.has_node(group_name))
return false;
#define OPM_END_PARALLEL_TRY_CATCH_LOG(obptc_logger, obptc_prefix, obptc_output, comm)
Catch exception, log, and throw in a parallel try-catch clause.
Definition: DeferredLoggingErrorHelpers.hpp:207
#define OPM_BEGIN_PARALLEL_TRY_CATCH()
Macro to setup the try of a parallel try-catch.
Definition: DeferredLoggingErrorHelpers.hpp:160
if(!linsolver_)
Definition: FlexibleSolver_impl.hpp:336
Phase
Phase indices for reservoir coupling, we currently only support black-oil phases (oil,...
Definition: ReservoirCoupling.hpp:183
Definition: blackoilbioeffectsmodules.hh:45
bool nodeFollowsOverriddenNode(const Network::ExtNetwork &network, std::string node, const std::map< std::string, Scalar > &overrides)
Whether the pressure of a node follows from one of the overridden nodes (see the terminal pressure ov...
Definition: BlackoilWellModelNetworkPressureComputation.hpp:304