From f79fe1f7ad93b893cd66875a6016325b3c32adde Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 22 Sep 2016 16:16:32 +0200 Subject: [PATCH 01/37] adding support for the FLD for the control type of group control. And also adding support for the liquid rate type of guide rate type. --- opm/core/wells/ProductionSpecification.hpp | 2 +- opm/core/wells/WellsManager.cpp | 31 +++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/opm/core/wells/ProductionSpecification.hpp b/opm/core/wells/ProductionSpecification.hpp index 4bae4cae..104b3a32 100644 --- a/opm/core/wells/ProductionSpecification.hpp +++ b/opm/core/wells/ProductionSpecification.hpp @@ -22,7 +22,7 @@ namespace Opm enum GuideRateType { - OIL, GAS, WATER, NONE_GRT + OIL, GAS, WATER, LIQ, NONE_GRT }; ProductionSpecification(); diff --git a/opm/core/wells/WellsManager.cpp b/opm/core/wells/WellsManager.cpp index 746a6ec2..760324a4 100644 --- a/opm/core/wells/WellsManager.cpp +++ b/opm/core/wells/WellsManager.cpp @@ -783,7 +783,17 @@ namespace Opm if ( well->isProducer(timeStep) ) { // The guide rates is calculated based on the group control // Currently only supporting WRAT, ORAT and GRAT. - switch (group.prodSpec().control_mode_) { + ProductionSpecification::ControlMode control_mode = group.prodSpec().control_mode_; + if (control_mode == ProductionSpecification::FLD) { + if (group.getParent() != nullptr) { + const WellsGroupInterface& higher_group = *(group.getParent()); + control_mode = higher_group.prodSpec().control_mode_; + } else { + OPM_THROW(std::runtime_error, "Group " << group.name() << " is under FLD control while no higher level of group is specified."); + } + } + + switch (control_mode) { case ProductionSpecification::WRAT: { if (!phaseUsage.phase_used[BlackoilPhases::Aqua]) { OPM_THROW(std::runtime_error, "Water phase not used, yet found water rate controlled well."); @@ -811,6 +821,25 @@ namespace Opm wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::GAS; break; } + case ProductionSpecification::FLD: { + OPM_THROW(std::logic_error, "Not support more than one continous level of FLD control"); + } + case ProductionSpecification::LRAT: { + double guide_rate = 0; + if (phaseUsage.phase_used[BlackoilPhases::Liquid]) { + const int oil_index = phaseUsage.phase_pos[BlackoilPhases::Liquid]; + const double potential_oil = well_potentials[np*wix + oil_index]; + guide_rate += potential_oil; + } + if (phaseUsage.phase_used[BlackoilPhases::Aqua]) { + const int water_index = phaseUsage.phase_pos[BlackoilPhases::Aqua]; + const double potential_water = well_potentials[np*wix + water_index]; + guide_rate += potential_water; + } + // not sure if no water and no oil, what will happen here, zero guide_rate? + wellnode.prodSpec().guide_rate_ = guide_rate; + wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::LIQ; + } case ProductionSpecification::NONE: { // Group control is not in use for this group. break; From a0d3ceff628f967ba61d8ba6010204a45cd9892e Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 23 Sep 2016 14:16:37 +0200 Subject: [PATCH 02/37] group can be both injection group and production group. Change if else to two ifs. --- opm/core/wells/WellsGroup.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index e9267dde..15bbbfd5 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -1087,7 +1087,8 @@ namespace Opm injection_specification.reinjection_fraction_target_ = group.getTargetReinjectFraction(timeStep); injection_specification.voidage_replacment_fraction_ = group.getTargetVoidReplacementFraction(timeStep); } - else if (group.isProductionGroup(timeStep)) { + + if (group.isProductionGroup(timeStep)) { production_specification.oil_max_rate_ = group.getOilTargetRate(timeStep); production_specification.control_mode_ = toProductionControlMode(GroupProduction::ControlEnum2String(group.getProductionControlMode(timeStep))); production_specification.water_max_rate_ = group.getWaterTargetRate(timeStep); From c5958da6c924fcf28176afe1533797bc5ac3d2ab Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 23 Sep 2016 16:57:14 +0200 Subject: [PATCH 03/37] To make the injection well be able to receive the target. Very hacky way here. The logic of the code is that only a well is specified under GRUP control, it is under group control. Which is not the case observed from the result. From the result, if we specify group control with GCONPROD and WCONPROD for a well, it looks like the well will be under group control. TODO: make the logic correct here instead of using `false` here. --- opm/core/wells/WellsGroup.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 15bbbfd5..2df2a505 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -487,14 +487,24 @@ namespace Opm InjectionSpecification::ControlMode inj_mode = injSpec().control_mode_; switch (inj_mode) { case InjectionSpecification::RATE: + // need to be careful in the future. + // pay attention to the phase under control and the phase for the guide rate + // they can be different, and more delicate situatioin can happen here. case InjectionSpecification::RESV: { - const double my_guide_rate = injectionGuideRate(true); + // very hacky way here. + // The logic of the code is that only a well is specified under GRUP control, it is under group control. + // Which is not the case observed from the result. + // From the result, if we specify group control with GCONPROD and WCONPROD for a well, it looks like + // the well will be under group control. + // TODO: make the logic correct here instead of using `false here`. + const double my_guide_rate = injectionGuideRate(false); + for (size_t i = 0; i < children_.size(); ++i) { // Apply for all children. // Note, we do _not_ want to call the applyProdGroupControl in this object, // as that would check if we're under group control, something we're not. - const double children_guide_rate = children_[i]->injectionGuideRate(true); + const double children_guide_rate = children_[i]->injectionGuideRate(false); children_[i]->applyInjGroupControl(inj_mode, (children_guide_rate / my_guide_rate) * getTarget(inj_mode), false); From 3bdf0eae110984097aa54d0c68135ca7bdad4d33 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 28 Sep 2016 13:29:54 +0200 Subject: [PATCH 04/37] Not return from the WellNode:applyInjGroupControl unless we prevent the well from group control with keyword WGRUPCON. --- opm/core/wells/WellsGroup.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 2df2a505..53fa801f 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -813,10 +813,13 @@ namespace Opm const bool forced) { // Not changing if we're not forced to change - if (!forced - && (injSpec().control_mode_ != InjectionSpecification::GRUP && injSpec().control_mode_ != InjectionSpecification::NONE)) { - return; - } + // It should be the well will under group control, if we prevent the well from group control + // with keyword WGRUPCON. + // It is just current undertstanding, while further change in the understanding will be possible. + // if (!forced + // && (injSpec().control_mode_ != InjectionSpecification::GRUP && injSpec().control_mode_ != InjectionSpecification::NONE)) { + // return; + // } if (wells_->type[self_index_] != INJECTOR) { assert(target == 0.0); return; From 36bedfcf67dcf0941e7634b0cdfe7bef7a5d1c52 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 28 Sep 2016 13:49:58 +0200 Subject: [PATCH 05/37] not returning zero from double WellNode::productionGuideRate Current understanding. Two ways might prevent to return the guide_rate here 1. preventing the well from group control with keyword WGRUPCON 2. the well violating some limits and working under limits. We do not have strategy to handle this situation yet. --- opm/core/wells/WellsGroup.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 53fa801f..ec29e71d 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -981,10 +981,14 @@ namespace Opm /// wells under group control double WellNode::productionGuideRate(bool only_group) { - if (!only_group || prodSpec().control_mode_ == ProductionSpecification::GRUP) { - return prodSpec().guide_rate_; - } - return 0.0; + // Current understanding. Two ways might prevent to return the guide_rate here + // 1. preventing the well from group control with keyword WGRUPCON + // 2. the well violating some limits and working under limits. We do not have strategy + // to handle this situation yet. + // if (!only_group || prodSpec().control_mode_ == ProductionSpecification::GRUP) { + return prodSpec().guide_rate_; + // } + // return 0.0; } /// Calculates the injection guide rate for the group. From 4214cfec833a24d93682d7f53f70ac9285a94cea Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 30 Sep 2016 12:59:10 +0200 Subject: [PATCH 06/37] adding a non-const wellCollection() in WellsManager. For the WellModel from the simulator to use. Not decided totally, well_collection might need to be updated during the simualtion due to the update the target of wells. --- opm/core/wells/WellsManager.cpp | 6 ++++++ opm/core/wells/WellsManager.hpp | 1 + 2 files changed, 7 insertions(+) diff --git a/opm/core/wells/WellsManager.cpp b/opm/core/wells/WellsManager.cpp index 760324a4..94700cce 100644 --- a/opm/core/wells/WellsManager.cpp +++ b/opm/core/wells/WellsManager.cpp @@ -373,6 +373,12 @@ namespace Opm return well_collection_; } + WellCollection& WellsManager::wellCollection() { + return well_collection_; + + } + + bool WellsManager::conditionsMet(const std::vector& well_bhp, const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase) diff --git a/opm/core/wells/WellsManager.hpp b/opm/core/wells/WellsManager.hpp index 4db577c4..e9075862 100644 --- a/opm/core/wells/WellsManager.hpp +++ b/opm/core/wells/WellsManager.hpp @@ -114,6 +114,7 @@ namespace Opm /// Access the well group hierarchy. const WellCollection& wellCollection() const; + WellCollection& wellCollection(); /// Checks if each condition is met, applies well controls where needed /// (that is, it either changes the active control of violating wells, or shuts From f62806488402b69d38367425ac00fb2c9841d851 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 30 Sep 2016 17:54:49 +0200 Subject: [PATCH 07/37] keeping putting group controlling in. --- opm/core/wells/WellCollection.cpp | 26 +++++++++++++++ opm/core/wells/WellCollection.hpp | 16 +++++++++ opm/core/wells/WellCollection_impl.hpp | 45 ++++++++++++++++++++++++++ opm/core/wells/WellsGroup.cpp | 37 ++++++++++++++++++++- opm/core/wells/WellsGroup.hpp | 27 ++++++++++++++++ opm/core/wells/WellsGroup_impl.hpp | 41 +++++++++++++++++++++++ 6 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 opm/core/wells/WellCollection_impl.hpp create mode 100644 opm/core/wells/WellsGroup_impl.hpp diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index c901c8ab..618042b1 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -189,4 +189,30 @@ namespace Opm roots_[i]->applyExplicitReinjectionControls(well_reservoirrates_phase, well_surfacerates_phase); } } + + + //TODO: later, it should be extended to update group targets + bool WellCollection::needUpdateWellTargets() const + { + for (size_t i = 0; i < leaf_nodes_.size(); ++i) { + if (leaf_nodes_[i]->shouldUpdateWellTargets() && !leaf_nodes_[i]->individualControl()) { + return true; + } + } + return false; + } + + + const size_t WellCollection::numNode() const + { + return leaf_nodes_.size(); + } + + + WellNode* WellCollection::getNode(size_t i) const + { + assert( i< numNode()); + return leaf_nodes_[i]; + } + } diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index a05142ae..ee51313a 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -110,6 +110,20 @@ namespace Opm void applyExplicitReinjectionControls(const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase); + /// Checking whehter need to update the targets of the wells / or the groups later + /// True need to update well targets within this iteration, no switching control within this iteration. + /// False no need to update well targets within this iteration, continuing as usual. + /// TODO: currently return true whenever a wellNode needs to be updated. Later some more sophiscated + /// strategy might be required. + bool needUpdateWellTargets() const; + + const size_t numNode() const; + + WellNode* getNode(size_t i) const; + + template + void updateWellTargets(const WellState& well_state); + private: // To account for the possibility of a forest std::vector > roots_; @@ -121,5 +135,7 @@ namespace Opm }; } // namespace Opm + +#include "WellCollection_impl.hpp" #endif /* OPM_WELLCOLLECTION_HPP */ diff --git a/opm/core/wells/WellCollection_impl.hpp b/opm/core/wells/WellCollection_impl.hpp new file mode 100644 index 00000000..5ef4c183 --- /dev/null +++ b/opm/core/wells/WellCollection_impl.hpp @@ -0,0 +1,45 @@ +/* + Copyright 2016 SINTEF ICT, Applied Mathematics. + Copyright 2016 Statoil 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 . +*/ + +#include + + +namespace Opm +{ + + + template + void WellCollection::updateWellTargets(const WellState& well_state) + { + // TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells + // We believe the relations between groups are similar to the relations between different wells inside the same group. + // While there will be somre more complication invloved for sure. + for (size_t i = 0; i < leaf_nodes_.size(); ++i) { + // find a node needs to update targets, then update targets inside the group. + if (leaf_nodes_[i]->shouldUpdateWellTargets() && !leaf_nodes_[i]->individualControl()) { + // TODO: will remove dynamic_cast with interface revision. + WellsGroup* parent_node = dynamic_cast(leaf_nodes_[i]->getParent()); + // update the target within this group. + parent_node->updateWellTargets(well_state); + } + } + } + +} diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index ec29e71d..c5cda8d3 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -68,7 +68,9 @@ namespace Opm name_(myname), production_specification_(prod_spec), injection_specification_(inje_spec), - phase_usage_(phase_usage) + phase_usage_(phase_usage), + individual_control_(true), // always begin with individual control + should_update_well_targets_(false) { } @@ -80,6 +82,12 @@ namespace Opm { return parent_; } + + WellsGroupInterface* WellsGroupInterface::getParent() + { + return parent_; + } + const std::string& WellsGroupInterface::name() const { return name_; @@ -229,8 +237,15 @@ namespace Opm } + bool WellsGroupInterface::shouldUpdateWellTargets() const { + return should_update_well_targets_; + } + bool WellsGroupInterface::setShouldUpdateWellTargets(const bool should_update_well_targets) { + should_update_well_targets_ = should_update_well_targets; + } + // ============== WellsGroup members ============= @@ -638,6 +653,16 @@ namespace Opm } } + + bool WellsGroupInterface::individualControl() const { + return individual_control_; + } + + void WellsGroupInterface::setIndividualControl(const bool individual_control) { + individual_control_ = individual_control; + } + + // ============== WellNode members ============ @@ -851,6 +876,8 @@ namespace Opm well_controls_iset_distr(wells_->ctrls[self_index_] , group_control_index_ , distr); } set_current_control(self_index_, group_control_index_, wells_); + // TODO: it might always be the case + setIndividualControl(false); } @@ -1003,6 +1030,14 @@ namespace Opm } + + /// Returning the group control index + int WellNode::groupControlIndex() const + { + return group_control_index_; + } + + namespace { diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 81e7e63e..4d7de15c 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -92,6 +92,8 @@ namespace Opm /// Gets the parent of the group, NULL if no parent. const WellsGroupInterface* getParent() const; + WellsGroupInterface* getParent(); + /// Calculates the number of leaf nodes in the given group. /// A leaf node is defined to have one leaf node in its group. virtual int numberOfLeafNodes() = 0; @@ -202,6 +204,18 @@ namespace Opm virtual void applyExplicitReinjectionControls(const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase) = 0; + /// Return whether the well is running under group control target + /// or under their own limit. + /// True under their own limit. + /// False running under group control target + bool individualControl() const; + + /// Update the status for individual contrl + void setIndividualControl(const bool); + + virtual bool shouldUpdateWellTargets() const; + + virtual bool setShouldUpdateWellTargets(const bool); protected: /// Calculates the correct rate for the given ProductionSpecification::ControlMode @@ -221,6 +235,13 @@ namespace Opm ProductionSpecification production_specification_; InjectionSpecification injection_specification_; PhaseUsage phase_usage_; + // when some well (mabye group also later), change status from group control + // to individual control, or the other way, the targets for the wells in the group need to be redistributed. + bool should_update_well_targets_; + // Whether well is running under the group control target. + // Current only consider one level of control. + // So not putting it in the WellsGroupInterface yet. + bool individual_control_; }; @@ -303,6 +324,9 @@ namespace Opm virtual void applyExplicitReinjectionControls(const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase); + template + void updateWellTargets(const WellState& well_state); + private: std::vector > children_; }; @@ -394,6 +418,7 @@ namespace Opm /// with all phase rates of a single well adjacent in the array. virtual void applyExplicitReinjectionControls(const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase); + int groupControlIndex() const; private: Wells* wells_; @@ -416,5 +441,7 @@ namespace Opm std::shared_ptr createGroupWellsGroup(const Group& group, size_t timeStep, const PhaseUsage& phase_usage ); } + +#include "WellsGroup_impl.hpp" #endif /* OPM_WELLSGROUP_HPP */ diff --git a/opm/core/wells/WellsGroup_impl.hpp b/opm/core/wells/WellsGroup_impl.hpp new file mode 100644 index 00000000..567e99bd --- /dev/null +++ b/opm/core/wells/WellsGroup_impl.hpp @@ -0,0 +1,41 @@ +/* + Copyright 2016 SINTEF ICT, Applied Mathematics. + Copyright 2016 Statoil 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 . +*/ + +#include + + +namespace Opm +{ + + + template + void WellsGroup::updateWellTargets(const WellState& well_state) + { + // TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells + // We believe the relations between groups are similar to the relations between different wells inside the same group. + // While there will be somre more complication invloved for sure. + // Basically, we need to update the target rates for the wells still under group control. + + // What facility need to be put in? + // update the production control + // update the injectioin control + } + +} From 0d5a86cc71c4627e7e75b2e5fdf5fbbf0167a0c2 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 5 Oct 2016 17:03:47 +0200 Subject: [PATCH 08/37] keeping adding group control related in. --- opm/core/wells/ProductionSpecification.hpp | 1 - opm/core/wells/WellsGroup.cpp | 18 ++++++-- opm/core/wells/WellsGroup_impl.hpp | 52 ++++++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/opm/core/wells/ProductionSpecification.hpp b/opm/core/wells/ProductionSpecification.hpp index 104b3a32..ef64c4c0 100644 --- a/opm/core/wells/ProductionSpecification.hpp +++ b/opm/core/wells/ProductionSpecification.hpp @@ -46,4 +46,3 @@ namespace Opm } #endif /* OPM_PRODUCTIONSPECIFICATION_HPP */ - diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index c5cda8d3..4e9ebaa5 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -310,7 +310,10 @@ namespace Opm { if (forced || (prodSpec().control_mode_ == ProductionSpecification::FLD || prodSpec().control_mode_ == ProductionSpecification::NONE)) { - const double my_guide_rate = productionGuideRate(!forced); + const double my_guide_rate = productionGuideRate(false); + std::cout << " forced " << forced << std::endl; + std::cout << " name " << name () << std::endl; + std::cout << " my_guide_rate is " << my_guide_rate << std::endl; if (my_guide_rate == 0.0) { // Nothing to do here std::cout << "returning" << std::endl; @@ -470,7 +473,9 @@ namespace Opm case ProductionSpecification::LRAT: case ProductionSpecification::RESV: { - const double my_guide_rate = productionGuideRate(true); + // const double my_guide_rate = productionGuideRate(true); + const double my_guide_rate = productionGuideRate(false); + std::cout << "my_guide_rate of group " << name() << " is " << my_guide_rate << std::endl; if (my_guide_rate == 0) { OPM_THROW(std::runtime_error, "Can't apply group control for group " << name() << " as the sum of guide rates for all group controlled wells is zero."); } @@ -549,7 +554,13 @@ namespace Opm { double sum = 0.0; for (size_t i = 0; i < children_.size(); ++i) { - sum += children_[i]->productionGuideRate(only_group); + if (only_group) { + if (!children_[i]->individualControl()) { + sum += children_[i]->productionGuideRate(only_group); + } + } else { + sum += children_[i]->productionGuideRate(only_group); + } } return sum; } @@ -1013,6 +1024,7 @@ namespace Opm // 2. the well violating some limits and working under limits. We do not have strategy // to handle this situation yet. // if (!only_group || prodSpec().control_mode_ == ProductionSpecification::GRUP) { + std::cout << "guide_rate for well " << name() << " is " << prodSpec().guide_rate_ << std::endl; return prodSpec().guide_rate_; // } // return 0.0; diff --git a/opm/core/wells/WellsGroup_impl.hpp b/opm/core/wells/WellsGroup_impl.hpp index 567e99bd..c3414296 100644 --- a/opm/core/wells/WellsGroup_impl.hpp +++ b/opm/core/wells/WellsGroup_impl.hpp @@ -19,6 +19,7 @@ */ #include +#include namespace Opm @@ -35,6 +36,57 @@ namespace Opm // What facility need to be put in? // update the production control + // What we need there? 1. The target. 2. The control mode. 3. The share produced by the wells under individual control + // 4. The guide rate. + // control mode + ProductionSpecification::ControlMode control_mode = prodSpec().control_mode_; + double target_rate = prodSpec().liquid_max_rate_; + std::cout << " control mode is " << ProductionSpecification::toString(control_mode); + std::cout << " rate is " << target_rate << std::endl; + + if (ProductionSpecification::toString(control_mode) == "FLD") { + auto* parent_node = getParent(); + control_mode = parent_node->prodSpec().control_mode_; + target_rate = parent_node->prodSpec().liquid_max_rate_; + std::cout << " control mode is " << ProductionSpecification::toString(control_mode); + std::cout << " rate is " << target_rate << std::endl; + } + + double rate_individual_control = 0; + + for (size_t i = 0; i < children_.size(); ++i) { + if (children_[i]->individualControl()) { + // get the rate here. + const std::string well_name = children_[i]->name(); + std::cout << "well_name " << well_name; + typedef typename WellState::WellMapType::const_iterator const_iterator; + const_iterator it = well_state.wellMap().find(well_name); + const int well_index = (*it).second[0]; + const int np = well_state.numPhases(); + + const double oil_rate = well_state.wellRates()[np * well_index + 1]; + const double water_rate = well_state.wellRates()[np * well_index]; + std::cout << " oil_rate is " << oil_rate << " water_rate is " << water_rate << " liquid rate is " << oil_rate + water_rate << std::endl; + rate_individual_control -= std::abs(oil_rate + water_rate); + } + } + + const double rate_for_group_control = target_rate - rate_individual_control; + + const double my_guide_rate = productionGuideRate(true); + if (my_guide_rate == 0) { + std::cout << " something wrong with the my_guide_rate, need to check, it should have come here " << std::endl; + std::cin.ignore(); + } + + for (size_t i = 0; i < children_.size(); ++i) { + const double children_guide_rate = children_[i]->productionGuideRate(true); + children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, false); + children_[i]->setShouldUpdateWellTargets(false); + } + std::cin.ignore(); + // liquid_max_rate + // update the injectioin control } From a438680fb083252733163766f20b304b6e9b5fc3 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 6 Oct 2016 18:00:08 +0200 Subject: [PATCH 09/37] putting more things in the prototyping test. --- opm/core/wells/WellCollection.cpp | 21 ++++++++++++++++++--- opm/core/wells/WellCollection.hpp | 6 ++++++ opm/core/wells/WellCollection_impl.hpp | 7 +++++-- opm/core/wells/WellsGroup.cpp | 14 ++++++++++---- opm/core/wells/WellsGroup_impl.hpp | 16 ++++++++++++---- opm/core/wells/WellsManager_impl.hpp | 1 + 6 files changed, 52 insertions(+), 13 deletions(-) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 618042b1..88de6ba3 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -194,12 +194,19 @@ namespace Opm //TODO: later, it should be extended to update group targets bool WellCollection::needUpdateWellTargets() const { + bool any_group_control_node = false; + bool any_should_update_node = false; for (size_t i = 0; i < leaf_nodes_.size(); ++i) { - if (leaf_nodes_[i]->shouldUpdateWellTargets() && !leaf_nodes_[i]->individualControl()) { - return true; + std::cout << " well " << leaf_nodes_[i]->name() << " under group control ? " << !leaf_nodes_[i]->individualControl() << " should update well target? " << leaf_nodes_[i]->shouldUpdateWellTargets() << std::endl; + if (leaf_nodes_[i]->shouldUpdateWellTargets()) { + any_should_update_node = true; + } + if (!leaf_nodes_[i]->individualControl()) { + any_group_control_node = true; } } - return false; + std::cout << " any_group_control_node " << any_group_control_node << " any_should_update_node " << any_should_update_node << std::endl; + return (any_group_control_node && any_should_update_node); } @@ -215,4 +222,12 @@ namespace Opm return leaf_nodes_[i]; } + bool WellCollection::justUpdateWellTargets() const { + return just_update_well_targets_; + } + + void WellCollection::setJustUpdateWellTargets(const bool flag) { + just_update_well_targets_ = flag; + } + } diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index ee51313a..4822a722 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -124,6 +124,10 @@ namespace Opm template void updateWellTargets(const WellState& well_state); + bool justUpdateWellTargets() const; + + void setJustUpdateWellTargets(const bool flag); + private: // To account for the possibility of a forest std::vector > roots_; @@ -131,6 +135,8 @@ namespace Opm // This will be used to traverse the bottom nodes. std::vector leaf_nodes_; + bool just_update_well_targets_; + }; diff --git a/opm/core/wells/WellCollection_impl.hpp b/opm/core/wells/WellCollection_impl.hpp index 5ef4c183..14454a4d 100644 --- a/opm/core/wells/WellCollection_impl.hpp +++ b/opm/core/wells/WellCollection_impl.hpp @@ -32,14 +32,17 @@ namespace Opm // We believe the relations between groups are similar to the relations between different wells inside the same group. // While there will be somre more complication invloved for sure. for (size_t i = 0; i < leaf_nodes_.size(); ++i) { - // find a node needs to update targets, then update targets inside the group. - if (leaf_nodes_[i]->shouldUpdateWellTargets() && !leaf_nodes_[i]->individualControl()) { + // find a node needs to update targets, then update targets for all the wellls inside the group. + // if (leaf_nodes_[i]->shouldUpdateWellTargets() && !leaf_nodes_[i]->individualControl()) { + if (!leaf_nodes_[i]->individualControl()) { // TODO: will remove dynamic_cast with interface revision. WellsGroup* parent_node = dynamic_cast(leaf_nodes_[i]->getParent()); // update the target within this group. parent_node->updateWellTargets(well_state); } } + + setJustUpdateWellTargets(true); } } diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 4e9ebaa5..5e759a95 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -308,6 +308,9 @@ namespace Opm const double target, const bool forced) { + if (prodSpec().control_mode_ == ProductionSpecification::NONE) { + return; + } if (forced || (prodSpec().control_mode_ == ProductionSpecification::FLD || prodSpec().control_mode_ == ProductionSpecification::NONE)) { const double my_guide_rate = productionGuideRate(false); @@ -483,7 +486,7 @@ namespace Opm // Apply for all children. // Note, we do _not_ want to call the applyProdGroupControl in this object, // as that would check if we're under group control, something we're not. - const double children_guide_rate = children_[i]->productionGuideRate(true); + const double children_guide_rate = children_[i]->productionGuideRate(false); children_[i]->applyProdGroupControl(prod_mode, (children_guide_rate / my_guide_rate) * getTarget(prod_mode), false); @@ -930,13 +933,13 @@ namespace Opm const bool forced) { // Not changing if we're not forced to change - if (!forced && (prodSpec().control_mode_ != ProductionSpecification::GRUP + /* if (!forced && (prodSpec().control_mode_ != ProductionSpecification::GRUP && prodSpec().control_mode_ != ProductionSpecification::NONE)) { std::cout << "Returning" << std::endl; return; - } + } */ if (wells_->type[self_index_] != PRODUCER) { - assert(target == 0.0); + // assert(target == 0.0); return; } // We're a producer, so we need to negate the input @@ -988,6 +991,9 @@ namespace Opm OPM_THROW(std::runtime_error, "Group production control mode not handled: " << control_mode); } + std::cout << " well name " << name() << " group_control_index_ " << group_control_index_ << " ntarget " << ntarget + << std::endl; + if (group_control_index_ < 0) { // The well only had its own controls, no group controls. append_well_controls(wct, ntarget, invalid_alq, invalid_vfp, distr, self_index_, wells_); diff --git a/opm/core/wells/WellsGroup_impl.hpp b/opm/core/wells/WellsGroup_impl.hpp index c3414296..1947e816 100644 --- a/opm/core/wells/WellsGroup_impl.hpp +++ b/opm/core/wells/WellsGroup_impl.hpp @@ -67,22 +67,30 @@ namespace Opm const double oil_rate = well_state.wellRates()[np * well_index + 1]; const double water_rate = well_state.wellRates()[np * well_index]; std::cout << " oil_rate is " << oil_rate << " water_rate is " << water_rate << " liquid rate is " << oil_rate + water_rate << std::endl; - rate_individual_control -= std::abs(oil_rate + water_rate); + rate_individual_control += std::abs(oil_rate + water_rate); } } const double rate_for_group_control = target_rate - rate_individual_control; + std::cout << " rate_for_group_control " << rate_for_group_control << std::endl; const double my_guide_rate = productionGuideRate(true); + std::cout << " my_guide_rate is " << my_guide_rate << " when updateWellTargets " << std::endl; if (my_guide_rate == 0) { std::cout << " something wrong with the my_guide_rate, need to check, it should have come here " << std::endl; std::cin.ignore(); } for (size_t i = 0; i < children_.size(); ++i) { - const double children_guide_rate = children_[i]->productionGuideRate(true); - children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, false); - children_[i]->setShouldUpdateWellTargets(false); + // if (children_[i]->shouldUpdateWellTargets() && !children_[i]->individualControl()) { + if (!children_[i]->individualControl()) { + const double children_guide_rate = children_[i]->productionGuideRate(true); + std::cout << " well_name " << children_[i]->name() << " children_guide_rate " << children_guide_rate << " my_guide_rate " << my_guide_rate << std::endl; + std::cout << " new target rate is " << (children_guide_rate/my_guide_rate) * rate_for_group_control * 86400/0.1590 << std::endl; + // children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, false); + children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, false); + children_[i]->setShouldUpdateWellTargets(false); + } } std::cin.ignore(); // liquid_max_rate diff --git a/opm/core/wells/WellsManager_impl.hpp b/opm/core/wells/WellsManager_impl.hpp index b6fd9e2c..7bae00e8 100644 --- a/opm/core/wells/WellsManager_impl.hpp +++ b/opm/core/wells/WellsManager_impl.hpp @@ -411,6 +411,7 @@ WellsManager::init(const Opm::EclipseState& eclipseState, well_collection_.addField(fieldGroup, timeStep, pu); addChildGroups(*fieldNode, schedule, timeStep, pu); + well_collection_.setJustUpdateWellTargets(false); } for (auto w = wells.begin(), e = wells.end(); w != e; ++w) { From e28715b601dde04a47c7d7f3c8061da0b255f022 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 7 Oct 2016 12:56:21 +0200 Subject: [PATCH 10/37] parameter forced to only_group from applyInjGroup applyProdGroup forced and only_group basically mean two opposite things. Having both of them in the same context will be really confusing and error-prone. And also, we do not do anything forcedly. We do things base on what setup tells us to do. Only_group may not be the final name, while deinitely a better one than forced. --- opm/core/wells/WellsGroup.cpp | 48 +++++++++++++++--------------- opm/core/wells/WellsGroup.hpp | 36 +++++++++++----------- opm/core/wells/WellsGroup_impl.hpp | 2 +- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 5e759a95..ad85eaaf 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -278,22 +278,22 @@ namespace Opm /// Sets the current active control to the provided one for all injectors within the group. /// After this call, the combined rate (which rate depending on control_mode) of the group /// shall be equal to target. - /// \param[in] forced if true, all children will be set under group control, otherwise - /// only children that are under group control will be changed. + /// \param[in] only_group if true, only children that are under group control will be changed. + /// otherwise, all children will be set under group control void WellsGroup::applyInjGroupControl(const InjectionSpecification::ControlMode control_mode, const double target, - const bool forced) + const bool only_group) { - if (forced || injSpec().control_mode_ == InjectionSpecification::FLD + if (!only_group || injSpec().control_mode_ == InjectionSpecification::FLD || injSpec().control_mode_ == InjectionSpecification::NONE) { - const double my_guide_rate = injectionGuideRate(!forced); + const double my_guide_rate = injectionGuideRate(only_group); if (my_guide_rate == 0.0) { // Nothing to do here return; } for (size_t i = 0; i < children_.size(); ++i) { - const double child_target = target * children_[i]->injectionGuideRate(!forced) / my_guide_rate; - children_[i]->applyInjGroupControl(control_mode, child_target, true); + const double child_target = target * children_[i]->injectionGuideRate(only_group) / my_guide_rate; + children_[i]->applyInjGroupControl(control_mode, child_target, false); } injSpec().control_mode_ = InjectionSpecification::FLD; } @@ -302,19 +302,19 @@ namespace Opm /// Sets the current active control to the provided one for all producers within the group. /// After this call, the combined rate (which rate depending on control_mode) of the group /// shall be equal to target. - /// \param[in] forced if true, all children will be set under group control, otherwise - /// only children that are under group control will be changed. + /// \param[in] only_group if true, only children that are under group control will be changed. + /// otherwise, all children will be set under group control void WellsGroup::applyProdGroupControl(const ProductionSpecification::ControlMode control_mode, const double target, - const bool forced) + const bool only_group) { if (prodSpec().control_mode_ == ProductionSpecification::NONE) { return; } - if (forced || (prodSpec().control_mode_ == ProductionSpecification::FLD + if (!only_group || (prodSpec().control_mode_ == ProductionSpecification::FLD || prodSpec().control_mode_ == ProductionSpecification::NONE)) { const double my_guide_rate = productionGuideRate(false); - std::cout << " forced " << forced << std::endl; + std::cout << " only_group " << only_group << std::endl; std::cout << " name " << name () << std::endl; std::cout << " my_guide_rate is " << my_guide_rate << std::endl; if (my_guide_rate == 0.0) { @@ -323,8 +323,8 @@ namespace Opm return; } for (size_t i = 0; i < children_.size(); ++i) { - const double child_target = target * children_[i]->productionGuideRate(!forced) / my_guide_rate; - children_[i]->applyProdGroupControl(control_mode, child_target, true); + const double child_target = target * children_[i]->productionGuideRate(only_group) / my_guide_rate; + children_[i]->applyProdGroupControl(control_mode, child_target, false); } prodSpec().control_mode_ = ProductionSpecification::FLD; } @@ -370,7 +370,7 @@ namespace Opm + " target not met for group " + name() + "\n" + "target = " + std::to_string(target_rate) + "\n" + "rate = " + std::to_string(my_rate)); - applyInjGroupControl(mode, target_rate, true); + applyInjGroupControl(mode, target_rate, false); injSpec().control_mode_ = mode; return false; } @@ -421,7 +421,7 @@ namespace Opm std::cout << "Applying group control" << std::endl; applyProdGroupControl(production_mode_violated, getTarget(production_mode_violated), - true); + false); return false; case ProductionSpecification::NONE_P: // Do nothing @@ -530,7 +530,7 @@ namespace Opm const double children_guide_rate = children_[i]->injectionGuideRate(false); children_[i]->applyInjGroupControl(inj_mode, (children_guide_rate / my_guide_rate) * getTarget(inj_mode), - false); + true); } return; } @@ -633,11 +633,11 @@ namespace Opm #ifdef DIRTY_WELLCTRL_HACK children_[i]->applyInjGroupControl(InjectionSpecification::RESV, (children_guide_rate / my_guide_rate) * total_reinjected * injSpec().reinjection_fraction_target_, - false); + true); #else children_[i]->applyInjGroupControl(InjectionSpecification::RATE, (children_guide_rate / my_guide_rate) * total_reinjected * injSpec().reinjection_fraction_target_, - false); + true); #endif } } @@ -661,7 +661,7 @@ namespace Opm const double children_guide_rate = children_[i]->injectionGuideRate(true); children_[i]->applyInjGroupControl(InjectionSpecification::RESV, (children_guide_rate / my_guide_rate) * total_reinjected * injSpec().voidage_replacment_fraction_, - false); + true); } } @@ -849,13 +849,13 @@ namespace Opm void WellNode::applyInjGroupControl(const InjectionSpecification::ControlMode control_mode, const double target, - const bool forced) + const bool only_group) { // Not changing if we're not forced to change // It should be the well will under group control, if we prevent the well from group control // with keyword WGRUPCON. // It is just current undertstanding, while further change in the understanding will be possible. - // if (!forced + // if (only_group // && (injSpec().control_mode_ != InjectionSpecification::GRUP && injSpec().control_mode_ != InjectionSpecification::NONE)) { // return; // } @@ -930,10 +930,10 @@ namespace Opm } void WellNode::applyProdGroupControl(const ProductionSpecification::ControlMode control_mode, const double target, - const bool forced) + const bool only_group) { // Not changing if we're not forced to change - /* if (!forced && (prodSpec().control_mode_ != ProductionSpecification::GRUP + /* if (only_group && (prodSpec().control_mode_ != ProductionSpecification::GRUP && prodSpec().control_mode_ != ProductionSpecification::NONE)) { std::cout << "Returning" << std::endl; return; diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 4d7de15c..82f93a43 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -130,19 +130,19 @@ namespace Opm /// Sets the current active control to the provided one for all injectors within the group. /// After this call, the combined rate (which rate depending on control_mode) of the group /// shall be equal to target. - /// \param[in] forced if true, all children will be set under group control, otherwise - /// only children that are under group control will be changed. + /// \param[in] only_group if true, only children that are under group control will be changed. + // otherwise, all children will be set under group control virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode, const double target, - const bool forced) = 0; + const bool only_group) = 0; /// Sets the current active control to the provided one for all producers within the group. /// After this call, the combined rate (which rate depending on control_mode) of the group /// shall be equal to target. - /// \param[in] forced if true, all children will be set under group control, otherwise - /// only children that are under group control will be changed. + /// \param[in] only_group if true, only children that are under group control will be changed. + // otherwise, all children will be set under group control virtual void applyProdGroupControl(const ProductionSpecification::ControlMode control_mode, const double target, - const bool forced) = 0; + const bool only_group) = 0; /// Gets the worst offending well based on the input /// \param[in] well_reservoirrates_phase @@ -271,20 +271,20 @@ namespace Opm /// Sets the current active control to the provided one for all injectors within the group. /// After this call, the combined rate (which rate depending on control_mode) of the group /// shall be equal to target. - /// \param[in] forced if true, all children will be set under group control, otherwise - /// only children that are under group control will be changed. + /// \param[in] only_group if true, only children that are under group control will be changed. + // otherwise, all children will be set under group control virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode, const double target, - bool forced); + bool only_group); /// Sets the current active control to the provided one for all producers within the group. /// After this call, the combined rate (which rate depending on control_mode) of the group /// shall be equal to target. - /// \param[in] forced if true, all children will be set under group control, otherwise - /// only children that are under group control will be changed. + /// \param[in] only_group if true, only children that are under group control will be changed. + // otherwise, all children will be set under group control virtual void applyProdGroupControl(const ProductionSpecification::ControlMode control_mode, const double target, - bool forced); + bool only_group); /// Applies any production group control relevant to all children nodes. /// If no group control is set, this is called recursively to the children. @@ -363,20 +363,20 @@ namespace Opm /// Sets the current active control to the provided one for all injectors within the group. /// After this call, the combined rate (which rate depending on control_mode) of the group /// shall be equal to target. - /// \param[in] forced if true, all children will be set under group control, otherwise - /// only children that are under group control will be changed. + /// \param[in] only_group if true, only children that are under group control will be changed. + /// otherwise, all children will be set under group control virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode, const double target, - bool forced); + bool only_group); /// Sets the current active control to the provided one for all producers within the group. /// After this call, the combined rate (which rate depending on control_mode) of the group /// shall be equal to target. - /// \param[in] forced if true, all children will be set under group control, otherwise - /// only children that are under group control will be changed. + /// \param[in] only_group if true, only children that are under group control will be changed. + /// otherwise, all children will be set under group control virtual void applyProdGroupControl(const ProductionSpecification::ControlMode control_mode, const double target, - bool forced); + bool only_group); /// Applies any production group control relevant to all children nodes. /// If no group control is set, this is called recursively to the children. diff --git a/opm/core/wells/WellsGroup_impl.hpp b/opm/core/wells/WellsGroup_impl.hpp index 1947e816..eba7d9a7 100644 --- a/opm/core/wells/WellsGroup_impl.hpp +++ b/opm/core/wells/WellsGroup_impl.hpp @@ -88,7 +88,7 @@ namespace Opm std::cout << " well_name " << children_[i]->name() << " children_guide_rate " << children_guide_rate << " my_guide_rate " << my_guide_rate << std::endl; std::cout << " new target rate is " << (children_guide_rate/my_guide_rate) * rate_for_group_control * 86400/0.1590 << std::endl; // children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, false); - children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, false); + children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, true); children_[i]->setShouldUpdateWellTargets(false); } } From 6942a986da5caef2053beeaa043bc83142a95728 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 7 Oct 2016 13:37:35 +0200 Subject: [PATCH 11/37] adding isProducer() and isProjector() to wellNode class. Did not see type() function there, while it should still be a okay idea. --- opm/core/wells/WellsGroup.cpp | 24 ++++++++++++++++++------ opm/core/wells/WellsGroup.hpp | 4 ++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index ad85eaaf..1e93fb48 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -701,7 +701,7 @@ namespace Opm // Report on our rates. const int np = phaseUsage().num_phases; for (int phase = 0; phase < np; ++phase) { - if (wells_->type[self_index_] == INJECTOR) { + if (isInjector()) { summed_phases.res_inj_rates[phase] = well_reservoirrates_phase[np*self_index_ + phase]; summed_phases.surf_inj_rates[phase] = well_surfacerates_phase[np*self_index_ + phase]; } else { @@ -711,7 +711,6 @@ namespace Opm } // Check constraints. - bool is_producer = (wells_->type[self_index_] == PRODUCER); const WellControls * ctrls = wells_->ctrls[self_index_]; for (int ctrl_index = 0; ctrl_index < well_controls_get_num(ctrls); ++ctrl_index) { if (ctrl_index == well_controls_get_current(ctrls) || ctrl_index == group_control_index_) { @@ -725,7 +724,7 @@ namespace Opm case BHP: { const double my_well_bhp = well_bhp[self_index_]; const double my_target_bhp = well_controls_iget_target( ctrls , ctrl_index); - ctrl_violated = is_producer ? (my_target_bhp > my_well_bhp) + ctrl_violated = isProducer() ? (my_target_bhp > my_well_bhp) : (my_target_bhp < my_well_bhp); if (ctrl_violated) { OpmLog::info("BHP limit violated for well " + name() + ":\n" @@ -859,7 +858,7 @@ namespace Opm // && (injSpec().control_mode_ != InjectionSpecification::GRUP && injSpec().control_mode_ != InjectionSpecification::NONE)) { // return; // } - if (wells_->type[self_index_] != INJECTOR) { + if ( !isInjector() ) { assert(target == 0.0); return; } @@ -904,7 +903,7 @@ namespace Opm double WellNode::getTotalProductionFlow(const std::vector& phase_flows, const BlackoilPhases::PhaseIndex phase) { - if (type() == INJECTOR) { + if (isInjector()) { return 0.0; } return phase_flows[self_index_*phaseUsage().num_phases + phaseUsage().phase_pos[phase]]; @@ -938,7 +937,7 @@ namespace Opm std::cout << "Returning" << std::endl; return; } */ - if (wells_->type[self_index_] != PRODUCER) { + if ( !isProducer() ) { // assert(target == 0.0); return; } @@ -1056,6 +1055,19 @@ namespace Opm } + /// Returing whether the well is a producer + bool WellNode::isProducer() const + { + return (type() == PRODUCER); + } + + /// Returing whether the well is a injector + bool WellNode::isInjector() const + { + return (type() == INJECTOR); + } + + namespace { diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 82f93a43..309e770e 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -420,6 +420,10 @@ namespace Opm const std::vector& well_surfacerates_phase); int groupControlIndex() const; + bool isProducer() const; + + bool isInjector() const; + private: Wells* wells_; int self_index_; From 46a9a62741afffc38a2a91725d1b1045fc89dc07 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 7 Oct 2016 14:54:53 +0200 Subject: [PATCH 12/37] functions for indicating injection and production upating. it is for WellCollection, which is logically wrong. It should be done in the group level, while things will be different for multi-level groups. The current implementation basically works for current needs, that we only have one group. --- opm/core/wells/WellCollection.cpp | 43 ++++++++++++++++++++++++++----- opm/core/wells/WellCollection.hpp | 3 +++ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 88de6ba3..9bcaf140 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -193,22 +193,51 @@ namespace Opm //TODO: later, it should be extended to update group targets bool WellCollection::needUpdateWellTargets() const + { + return needUpdateInjectionTargets() || needUpdateProductionTargets(); + } + + + bool WellCollection::needUpdateInjectionTargets() const { bool any_group_control_node = false; bool any_should_update_node = false; + for (size_t i = 0; i < leaf_nodes_.size(); ++i) { - std::cout << " well " << leaf_nodes_[i]->name() << " under group control ? " << !leaf_nodes_[i]->individualControl() << " should update well target? " << leaf_nodes_[i]->shouldUpdateWellTargets() << std::endl; - if (leaf_nodes_[i]->shouldUpdateWellTargets()) { - any_should_update_node = true; - } - if (!leaf_nodes_[i]->individualControl()) { - any_group_control_node = true; + if (leaf_nodes_[i]->isInjector()) { + if (leaf_nodes_[i]->shouldUpdateWellTargets()) { + any_should_update_node = true; + } + + if (leaf_nodes_[i]->individualControl()) { + any_group_control_node = true; + } } } - std::cout << " any_group_control_node " << any_group_control_node << " any_should_update_node " << any_should_update_node << std::endl; + return (any_group_control_node && any_should_update_node); } + bool WellCollection::needUpdateProductionTargets() const { + bool any_group_control_node = false; + bool any_should_update_node = false; + + for (size_t i = 0; i < leaf_nodes_.size(); ++i) { + if (leaf_nodes_[i]->isProducer()) { + if (leaf_nodes_[i]->shouldUpdateWellTargets()) { + any_should_update_node = true; + } + + if (leaf_nodes_[i]->individualControl()) { + any_group_control_node = true; + } + } + } + + return (any_group_control_node && any_should_update_node); + } + + const size_t WellCollection::numNode() const { diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index 4822a722..d19e5673 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -117,6 +117,9 @@ namespace Opm /// strategy might be required. bool needUpdateWellTargets() const; + bool needUpdateInjectionTargets() const; + bool needUpdateProductionTargets() const; + const size_t numNode() const; WellNode* getNode(size_t i) const; From 7295f26f541172d3336f6b040e62db9fb6d3a731 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 7 Oct 2016 16:18:09 +0200 Subject: [PATCH 13/37] adding updateWellInjectionTargets updateWellProductionTargets For WellsGroup. At least for the current moment, the updation of the well targets for injectors and producers should be handled in a seprate way. --- opm/core/wells/WellCollection.cpp | 4 +-- opm/core/wells/WellCollection_impl.hpp | 8 ++++- opm/core/wells/WellsGroup.hpp | 5 ++- opm/core/wells/WellsGroup_impl.hpp | 44 +++++++++++--------------- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 9bcaf140..9fa9909f 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -209,7 +209,7 @@ namespace Opm any_should_update_node = true; } - if (leaf_nodes_[i]->individualControl()) { + if (!leaf_nodes_[i]->individualControl()) { any_group_control_node = true; } } @@ -228,7 +228,7 @@ namespace Opm any_should_update_node = true; } - if (leaf_nodes_[i]->individualControl()) { + if (!leaf_nodes_[i]->individualControl()) { any_group_control_node = true; } } diff --git a/opm/core/wells/WellCollection_impl.hpp b/opm/core/wells/WellCollection_impl.hpp index 14454a4d..5f8085b7 100644 --- a/opm/core/wells/WellCollection_impl.hpp +++ b/opm/core/wells/WellCollection_impl.hpp @@ -38,7 +38,13 @@ namespace Opm // TODO: will remove dynamic_cast with interface revision. WellsGroup* parent_node = dynamic_cast(leaf_nodes_[i]->getParent()); // update the target within this group. - parent_node->updateWellTargets(well_state); + if (leaf_nodes_[i]->isProducer()) { + parent_node->updateWellProductionTargets(well_state); + } + + if (leaf_nodes_[i]->isInjector()) { + parent_node->updateWellInjectionTargets(well_state); + } } } diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 309e770e..92ce8147 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -325,7 +325,10 @@ namespace Opm const std::vector& well_surfacerates_phase); template - void updateWellTargets(const WellState& well_state); + void updateWellProductionTargets(const WellState& well_state); + + template + void updateWellInjectionTargets(const WellState& well_state); private: std::vector > children_; diff --git a/opm/core/wells/WellsGroup_impl.hpp b/opm/core/wells/WellsGroup_impl.hpp index eba7d9a7..dba8f266 100644 --- a/opm/core/wells/WellsGroup_impl.hpp +++ b/opm/core/wells/WellsGroup_impl.hpp @@ -27,38 +27,28 @@ namespace Opm template - void WellsGroup::updateWellTargets(const WellState& well_state) + void WellsGroup::updateWellProductionTargets(const WellState& well_state) { // TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells // We believe the relations between groups are similar to the relations between different wells inside the same group. // While there will be somre more complication invloved for sure. // Basically, we need to update the target rates for the wells still under group control. - // What facility need to be put in? - // update the production control - // What we need there? 1. The target. 2. The control mode. 3. The share produced by the wells under individual control - // 4. The guide rate. - // control mode ProductionSpecification::ControlMode control_mode = prodSpec().control_mode_; double target_rate = prodSpec().liquid_max_rate_; - std::cout << " control mode is " << ProductionSpecification::toString(control_mode); - std::cout << " rate is " << target_rate << std::endl; if (ProductionSpecification::toString(control_mode) == "FLD") { auto* parent_node = getParent(); control_mode = parent_node->prodSpec().control_mode_; target_rate = parent_node->prodSpec().liquid_max_rate_; - std::cout << " control mode is " << ProductionSpecification::toString(control_mode); - std::cout << " rate is " << target_rate << std::endl; } double rate_individual_control = 0; for (size_t i = 0; i < children_.size(); ++i) { - if (children_[i]->individualControl()) { + if (children_[i]->individualControl() && std::dynamic_pointer_cast(children_[i])->isProducer()) { // get the rate here. const std::string well_name = children_[i]->name(); - std::cout << "well_name " << well_name; typedef typename WellState::WellMapType::const_iterator const_iterator; const_iterator it = well_state.wellMap().find(well_name); const int well_index = (*it).second[0]; @@ -66,36 +56,40 @@ namespace Opm const double oil_rate = well_state.wellRates()[np * well_index + 1]; const double water_rate = well_state.wellRates()[np * well_index]; - std::cout << " oil_rate is " << oil_rate << " water_rate is " << water_rate << " liquid rate is " << oil_rate + water_rate << std::endl; rate_individual_control += std::abs(oil_rate + water_rate); } } const double rate_for_group_control = target_rate - rate_individual_control; - std::cout << " rate_for_group_control " << rate_for_group_control << std::endl; const double my_guide_rate = productionGuideRate(true); - std::cout << " my_guide_rate is " << my_guide_rate << " when updateWellTargets " << std::endl; - if (my_guide_rate == 0) { - std::cout << " something wrong with the my_guide_rate, need to check, it should have come here " << std::endl; - std::cin.ignore(); - } for (size_t i = 0; i < children_.size(); ++i) { // if (children_[i]->shouldUpdateWellTargets() && !children_[i]->individualControl()) { - if (!children_[i]->individualControl()) { + if (!children_[i]->individualControl() && std::dynamic_pointer_cast(children_[i])->isProducer()) { const double children_guide_rate = children_[i]->productionGuideRate(true); - std::cout << " well_name " << children_[i]->name() << " children_guide_rate " << children_guide_rate << " my_guide_rate " << my_guide_rate << std::endl; - std::cout << " new target rate is " << (children_guide_rate/my_guide_rate) * rate_for_group_control * 86400/0.1590 << std::endl; // children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, false); children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, true); children_[i]->setShouldUpdateWellTargets(false); } } - std::cin.ignore(); - // liquid_max_rate + } + + + + + + + template + void WellsGroup::updateWellInjectionTargets(const WellState&) { + // NOT doing anything yet. + // Will finish it when having an examples with more than one injection wells within same injection group. + for (size_t i = 0; i < children_.size(); ++i) { + if (!children_[i]->individualControl() && std::dynamic_pointer_cast(children_[i])->isInjector()) { + children_[i]->setShouldUpdateWellTargets(false); + } + } - // update the injectioin control } } From e183ab6ccd9977fca5e3b8e10fcf5fd0e734103b Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 7 Oct 2016 17:06:22 +0200 Subject: [PATCH 14/37] revising injectionGuideRate and productionGuideRate for WellNode. It gives a better logic. --- opm/core/wells/WellsGroup.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 1e93fb48..aa51f245 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -1026,13 +1026,12 @@ namespace Opm { // Current understanding. Two ways might prevent to return the guide_rate here // 1. preventing the well from group control with keyword WGRUPCON - // 2. the well violating some limits and working under limits. We do not have strategy - // to handle this situation yet. - // if (!only_group || prodSpec().control_mode_ == ProductionSpecification::GRUP) { - std::cout << "guide_rate for well " << name() << " is " << prodSpec().guide_rate_ << std::endl; - return prodSpec().guide_rate_; - // } - // return 0.0; + // 2. the well violating some limits and working under limits. + if (!only_group || !individual_control_) { + return prodSpec().guide_rate_; + } else { + return 0.0; + } } /// Calculates the injection guide rate for the group. @@ -1040,10 +1039,11 @@ namespace Opm /// wells under group control double WellNode::injectionGuideRate(bool only_group) { - if (!only_group || injSpec().control_mode_ == InjectionSpecification::GRUP) { + if (!only_group || !individual_control_) { return injSpec().guide_rate_; + } else { + return 0.0; } - return 0.0; } From fec53a1af5d6a1248ea66648df4648702b3aa8a0 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 10 Oct 2016 11:37:22 +0200 Subject: [PATCH 15/37] fixing the comilation problem from rebasing. --- opm/core/wells/WellCollection.cpp | 2 +- opm/core/wells/WellCollection.hpp | 2 +- opm/core/wells/WellsGroup.cpp | 4 ++-- opm/core/wells/WellsGroup.hpp | 11 ++++++----- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 9fa9909f..04c7f2d5 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -239,7 +239,7 @@ namespace Opm - const size_t WellCollection::numNode() const + size_t WellCollection::numNode() const { return leaf_nodes_.size(); } diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index d19e5673..d1d0ab63 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -120,7 +120,7 @@ namespace Opm bool needUpdateInjectionTargets() const; bool needUpdateProductionTargets() const; - const size_t numNode() const; + size_t numNode() const; WellNode* getNode(size_t i) const; diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index aa51f245..476a10dd 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -1027,7 +1027,7 @@ namespace Opm // Current understanding. Two ways might prevent to return the guide_rate here // 1. preventing the well from group control with keyword WGRUPCON // 2. the well violating some limits and working under limits. - if (!only_group || !individual_control_) { + if (!only_group || !individualControl()) { return prodSpec().guide_rate_; } else { return 0.0; @@ -1039,7 +1039,7 @@ namespace Opm /// wells under group control double WellNode::injectionGuideRate(bool only_group) { - if (!only_group || !individual_control_) { + if (!only_group || !individualControl()) { return injSpec().guide_rate_; } else { return 0.0; diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 92ce8147..d5e83e1e 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -230,11 +230,6 @@ namespace Opm WellsGroupInterface* parent_; - private: - std::string name_; - ProductionSpecification production_specification_; - InjectionSpecification injection_specification_; - PhaseUsage phase_usage_; // when some well (mabye group also later), change status from group control // to individual control, or the other way, the targets for the wells in the group need to be redistributed. bool should_update_well_targets_; @@ -242,6 +237,12 @@ namespace Opm // Current only consider one level of control. // So not putting it in the WellsGroupInterface yet. bool individual_control_; + + private: + std::string name_; + ProductionSpecification production_specification_; + InjectionSpecification injection_specification_; + PhaseUsage phase_usage_; }; From 32e9b26ce82cb9c096d70837e1030a0e1a53dd06 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 10 Oct 2016 14:47:19 +0200 Subject: [PATCH 16/37] revising updateWellTargets to remove the dependency of WellState avoiding template using here. It is possible we will need WellState eventually, while only using the well_rates for the moment. --- opm/core/wells/WellCollection.cpp | 34 ++++++++- opm/core/wells/WellCollection.hpp | 4 +- opm/core/wells/WellCollection_impl.hpp | 54 --------------- opm/core/wells/WellsGroup.cpp | 81 ++++++++++++++++++++-- opm/core/wells/WellsGroup.hpp | 19 +++--- opm/core/wells/WellsGroup_impl.hpp | 95 -------------------------- 6 files changed, 118 insertions(+), 169 deletions(-) delete mode 100644 opm/core/wells/WellCollection_impl.hpp delete mode 100644 opm/core/wells/WellsGroup_impl.hpp diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 04c7f2d5..6aff1274 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -218,7 +218,8 @@ namespace Opm return (any_group_control_node && any_should_update_node); } - bool WellCollection::needUpdateProductionTargets() const { + bool WellCollection::needUpdateProductionTargets() const + { bool any_group_control_node = false; bool any_should_update_node = false; @@ -251,12 +252,39 @@ namespace Opm return leaf_nodes_[i]; } - bool WellCollection::justUpdateWellTargets() const { + bool WellCollection::justUpdateWellTargets() const + { return just_update_well_targets_; } - void WellCollection::setJustUpdateWellTargets(const bool flag) { + void WellCollection::setJustUpdateWellTargets(const bool flag) + { just_update_well_targets_ = flag; } + void WellCollection::updateWellTargets(const std::vector well_rates) + { + // TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells + // We believe the relations between groups are similar to the relations between different wells inside the same group. + // While there will be somre more complication invloved for sure. + for (size_t i = 0; i < leaf_nodes_.size(); ++i) { + // find a node needs to update targets, then update targets for all the wellls inside the group. + // if (leaf_nodes_[i]->shouldUpdateWellTargets() && !leaf_nodes_[i]->individualControl()) { + if (!leaf_nodes_[i]->individualControl()) { + // TODO: will remove dynamic_cast with interface revision. + WellsGroup* parent_node = dynamic_cast(leaf_nodes_[i]->getParent()); + // update the target within this group. + if (leaf_nodes_[i]->isProducer()) { + parent_node->updateWellProductionTargets(well_rates); + } + + if (leaf_nodes_[i]->isInjector()) { + parent_node->updateWellInjectionTargets(well_rates); + } + } + } + + setJustUpdateWellTargets(true); + } + } diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index d1d0ab63..62c8f669 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -124,8 +124,7 @@ namespace Opm WellNode* getNode(size_t i) const; - template - void updateWellTargets(const WellState& well_state); + void updateWellTargets(const std::vector well_rates); bool justUpdateWellTargets() const; @@ -145,6 +144,5 @@ namespace Opm } // namespace Opm -#include "WellCollection_impl.hpp" #endif /* OPM_WELLCOLLECTION_HPP */ diff --git a/opm/core/wells/WellCollection_impl.hpp b/opm/core/wells/WellCollection_impl.hpp deleted file mode 100644 index 5f8085b7..00000000 --- a/opm/core/wells/WellCollection_impl.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - Copyright 2016 SINTEF ICT, Applied Mathematics. - Copyright 2016 Statoil 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 . -*/ - -#include - - -namespace Opm -{ - - - template - void WellCollection::updateWellTargets(const WellState& well_state) - { - // TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells - // We believe the relations between groups are similar to the relations between different wells inside the same group. - // While there will be somre more complication invloved for sure. - for (size_t i = 0; i < leaf_nodes_.size(); ++i) { - // find a node needs to update targets, then update targets for all the wellls inside the group. - // if (leaf_nodes_[i]->shouldUpdateWellTargets() && !leaf_nodes_[i]->individualControl()) { - if (!leaf_nodes_[i]->individualControl()) { - // TODO: will remove dynamic_cast with interface revision. - WellsGroup* parent_node = dynamic_cast(leaf_nodes_[i]->getParent()); - // update the target within this group. - if (leaf_nodes_[i]->isProducer()) { - parent_node->updateWellProductionTargets(well_state); - } - - if (leaf_nodes_[i]->isInjector()) { - parent_node->updateWellInjectionTargets(well_state); - } - } - } - - setJustUpdateWellTargets(true); - } - -} diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 476a10dd..b420651c 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -65,12 +65,12 @@ namespace Opm const InjectionSpecification& inje_spec, const PhaseUsage& phase_usage) : parent_(NULL), + should_update_well_targets_(false), + individual_control_(true), // always begin with individual control name_(myname), production_specification_(prod_spec), injection_specification_(inje_spec), - phase_usage_(phase_usage), - individual_control_(true), // always begin with individual control - should_update_well_targets_(false) + phase_usage_(phase_usage) { } @@ -587,7 +587,7 @@ namespace Opm /// \param[in] phase The phase for which to sum up. double WellsGroup::getTotalProductionFlow(const std::vector& phase_flows, - const BlackoilPhases::PhaseIndex phase) + const BlackoilPhases::PhaseIndex phase) const { double sum = 0.0; for (size_t i = 0; i < children_.size(); ++i) { @@ -668,6 +668,57 @@ namespace Opm } + void WellsGroup::updateWellProductionTargets(const std::vector& well_rates) + { + // TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells + // We believe the relations between groups are similar to the relations between different wells inside the same group. + // While there will be somre more complication invloved for sure. + // Basically, we need to update the target rates for the wells still under group control. + + ProductionSpecification::ControlMode control_mode = prodSpec().control_mode_; + double target_rate = prodSpec().liquid_max_rate_; + + if (ProductionSpecification::toString(control_mode) == "FLD") { + auto* parent_node = getParent(); + control_mode = parent_node->prodSpec().control_mode_; + target_rate = parent_node->prodSpec().liquid_max_rate_; + } + + double rate_individual_control = 0.; + + for (size_t i = 0; i < children_.size(); ++i) { + const std::shared_ptr well_node = std::dynamic_pointer_cast(children_[i]); + if (well_node->individualControl() && well_node->isProducer()) { + rate_individual_control += std::abs(well_node->getLiquidProductionRate(well_rates)); + } + } + + const double rate_for_group_control = target_rate - rate_individual_control; + + const double my_guide_rate = productionGuideRate(true); + + for (size_t i = 0; i < children_.size(); ++i) { + const std::shared_ptr well_node = std::dynamic_pointer_cast(children_[i]); + if (!well_node->individualControl() && well_node->isProducer()) { + const double children_guide_rate = well_node->productionGuideRate(true); + well_node->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, true); + well_node->setShouldUpdateWellTargets(false); + } + } + } + + void WellsGroup::updateWellInjectionTargets(const std::vector& well_rates) + { + // NOT doing anything yet. + // Will finish it when having an examples with more than one injection wells within same injection group. + for (size_t i = 0; i < children_.size(); ++i) { + if (!children_[i]->individualControl() && std::dynamic_pointer_cast(children_[i])->isInjector()) { + children_[i]->setShouldUpdateWellTargets(false); + } + } + } + + bool WellsGroupInterface::individualControl() const { return individual_control_; } @@ -901,7 +952,7 @@ namespace Opm /// \param[in] phase The phase for which to sum up. double WellNode::getTotalProductionFlow(const std::vector& phase_flows, - const BlackoilPhases::PhaseIndex phase) + const BlackoilPhases::PhaseIndex phase) const { if (isInjector()) { return 0.0; @@ -931,7 +982,6 @@ namespace Opm const double target, const bool only_group) { - // Not changing if we're not forced to change /* if (only_group && (prodSpec().control_mode_ != ProductionSpecification::GRUP && prodSpec().control_mode_ != ProductionSpecification::NONE)) { std::cout << "Returning" << std::endl; @@ -1068,6 +1118,25 @@ namespace Opm } + + double WellNode::getLiquidProductionRate(const std::vector& well_rates) const + { + return ( getTotalProductionFlow(well_rates, BlackoilPhases::Liquid) + + getTotalProductionFlow(well_rates, BlackoilPhases::Aqua) ); + + } + + double WellNode::getOilProductionRate(const std::vector& well_rates) const + { + return getTotalProductionFlow(well_rates, BlackoilPhases::Liquid); + } + + double WellNode::getWaterProductionRate(const std::vector& well_rates) const + { + return getTotalProductionFlow(well_rates, BlackoilPhases::Aqua); + } + + namespace { diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index d5e83e1e..8fa79b15 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -190,7 +190,7 @@ namespace Opm /// with all phase rates of a single well adjacent in the array. /// \param[in] phase The phase for which to sum up. virtual double getTotalProductionFlow(const std::vector& phase_flows, - const BlackoilPhases::PhaseIndex phase) = 0; + const BlackoilPhases::PhaseIndex phase) const = 0; /// Applies explicit reinjection controls. This must be called at each timestep to be correct. /// \param[in] well_reservoirrates_phase @@ -311,7 +311,7 @@ namespace Opm /// with all phase rates of a single well adjacent in the array. /// \param[in] phase The phase for which to sum up. virtual double getTotalProductionFlow(const std::vector& phase_flows, - const BlackoilPhases::PhaseIndex phase); + const BlackoilPhases::PhaseIndex phase) const; /// Applies explicit reinjection controls. This must be called at each timestep to be correct. /// \param[in] well_reservoirrates_phase @@ -325,11 +325,9 @@ namespace Opm virtual void applyExplicitReinjectionControls(const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase); - template - void updateWellProductionTargets(const WellState& well_state); + void updateWellProductionTargets(const std::vector& well_rates); - template - void updateWellInjectionTargets(const WellState& well_state); + void updateWellInjectionTargets(const std::vector& well_rates); private: std::vector > children_; @@ -406,7 +404,7 @@ namespace Opm /// with all phase rates of a single well adjacent in the array. /// \param[in] phase The phase for which to sum up. virtual double getTotalProductionFlow(const std::vector& phase_flows, - const BlackoilPhases::PhaseIndex phase); + const BlackoilPhases::PhaseIndex phase) const; /// Returns the type of the well. WellType type() const; @@ -428,6 +426,12 @@ namespace Opm bool isInjector() const; + double getLiquidProductionRate(const std::vector& well_rates) const; + + double getOilProductionRate(const std::vector& well_rates) const; + + double getWaterProductionRate(const std::vector& well_rates) const; + private: Wells* wells_; int self_index_; @@ -450,6 +454,5 @@ namespace Opm const PhaseUsage& phase_usage ); } -#include "WellsGroup_impl.hpp" #endif /* OPM_WELLSGROUP_HPP */ diff --git a/opm/core/wells/WellsGroup_impl.hpp b/opm/core/wells/WellsGroup_impl.hpp deleted file mode 100644 index dba8f266..00000000 --- a/opm/core/wells/WellsGroup_impl.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - Copyright 2016 SINTEF ICT, Applied Mathematics. - Copyright 2016 Statoil 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 . -*/ - -#include -#include - - -namespace Opm -{ - - - template - void WellsGroup::updateWellProductionTargets(const WellState& well_state) - { - // TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells - // We believe the relations between groups are similar to the relations between different wells inside the same group. - // While there will be somre more complication invloved for sure. - // Basically, we need to update the target rates for the wells still under group control. - - ProductionSpecification::ControlMode control_mode = prodSpec().control_mode_; - double target_rate = prodSpec().liquid_max_rate_; - - if (ProductionSpecification::toString(control_mode) == "FLD") { - auto* parent_node = getParent(); - control_mode = parent_node->prodSpec().control_mode_; - target_rate = parent_node->prodSpec().liquid_max_rate_; - } - - double rate_individual_control = 0; - - for (size_t i = 0; i < children_.size(); ++i) { - if (children_[i]->individualControl() && std::dynamic_pointer_cast(children_[i])->isProducer()) { - // get the rate here. - const std::string well_name = children_[i]->name(); - typedef typename WellState::WellMapType::const_iterator const_iterator; - const_iterator it = well_state.wellMap().find(well_name); - const int well_index = (*it).second[0]; - const int np = well_state.numPhases(); - - const double oil_rate = well_state.wellRates()[np * well_index + 1]; - const double water_rate = well_state.wellRates()[np * well_index]; - rate_individual_control += std::abs(oil_rate + water_rate); - } - } - - const double rate_for_group_control = target_rate - rate_individual_control; - - const double my_guide_rate = productionGuideRate(true); - - for (size_t i = 0; i < children_.size(); ++i) { - // if (children_[i]->shouldUpdateWellTargets() && !children_[i]->individualControl()) { - if (!children_[i]->individualControl() && std::dynamic_pointer_cast(children_[i])->isProducer()) { - const double children_guide_rate = children_[i]->productionGuideRate(true); - // children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, false); - children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, true); - children_[i]->setShouldUpdateWellTargets(false); - } - } - } - - - - - - - template - void WellsGroup::updateWellInjectionTargets(const WellState&) { - // NOT doing anything yet. - // Will finish it when having an examples with more than one injection wells within same injection group. - for (size_t i = 0; i < children_.size(); ++i) { - if (!children_[i]->individualControl() && std::dynamic_pointer_cast(children_[i])->isInjector()) { - children_[i]->setShouldUpdateWellTargets(false); - } - } - - } - -} From 352c185edf897fb33115fdfab0868421831e45d9 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 10 Oct 2016 15:30:15 +0200 Subject: [PATCH 17/37] removing the use of cast between base class and derived class between WellsGroupInterface and WellsGroup, WellNode. --- opm/core/wells/WellCollection.cpp | 3 +- opm/core/wells/WellsGroup.cpp | 52 +++++++++++++++++++++++-------- opm/core/wells/WellsGroup.hpp | 52 ++++++++++++++++++++++++++----- 3 files changed, 85 insertions(+), 22 deletions(-) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 6aff1274..0f6aff9d 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -271,8 +271,7 @@ namespace Opm // find a node needs to update targets, then update targets for all the wellls inside the group. // if (leaf_nodes_[i]->shouldUpdateWellTargets() && !leaf_nodes_[i]->individualControl()) { if (!leaf_nodes_[i]->individualControl()) { - // TODO: will remove dynamic_cast with interface revision. - WellsGroup* parent_node = dynamic_cast(leaf_nodes_[i]->getParent()); + WellsGroupInterface* parent_node = leaf_nodes_[i]->getParent(); // update the target within this group. if (leaf_nodes_[i]->isProducer()) { parent_node->updateWellProductionTargets(well_rates); diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index b420651c..1e54e71f 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -246,6 +246,15 @@ namespace Opm should_update_well_targets_ = should_update_well_targets; } + bool WellsGroupInterface::individualControl() const { + return individual_control_; + } + + void WellsGroupInterface::setIndividualControl(const bool individual_control) { + individual_control_ = individual_control; + } + + // ============== WellsGroup members ============= @@ -687,9 +696,8 @@ namespace Opm double rate_individual_control = 0.; for (size_t i = 0; i < children_.size(); ++i) { - const std::shared_ptr well_node = std::dynamic_pointer_cast(children_[i]); - if (well_node->individualControl() && well_node->isProducer()) { - rate_individual_control += std::abs(well_node->getLiquidProductionRate(well_rates)); + if (children_[i]->individualControl() && children_[i]->isProducer()) { + rate_individual_control += std::abs(children_[i]->getLiquidProductionRate(well_rates)); } } @@ -698,11 +706,10 @@ namespace Opm const double my_guide_rate = productionGuideRate(true); for (size_t i = 0; i < children_.size(); ++i) { - const std::shared_ptr well_node = std::dynamic_pointer_cast(children_[i]); - if (!well_node->individualControl() && well_node->isProducer()) { - const double children_guide_rate = well_node->productionGuideRate(true); - well_node->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, true); - well_node->setShouldUpdateWellTargets(false); + if (!children_[i]->individualControl() && children_[i]->isProducer()) { + const double children_guide_rate = children_[i]->productionGuideRate(true); + children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, true); + children_[i]->setShouldUpdateWellTargets(false); } } } @@ -712,19 +719,31 @@ namespace Opm // NOT doing anything yet. // Will finish it when having an examples with more than one injection wells within same injection group. for (size_t i = 0; i < children_.size(); ++i) { - if (!children_[i]->individualControl() && std::dynamic_pointer_cast(children_[i])->isInjector()) { + if (!children_[i]->individualControl() && children_[i]->isInjector()) { children_[i]->setShouldUpdateWellTargets(false); } } } - bool WellsGroupInterface::individualControl() const { - return individual_control_; + bool WellsGroup::isProducer() const + { } - void WellsGroupInterface::setIndividualControl(const bool individual_control) { - individual_control_ = individual_control; + bool WellsGroup::isInjector() const + { + } + + double WellsGroup::getLiquidProductionRate(const std::vector& /*well_rates*/) const + { + } + + double WellsGroup::getOilProductionRate(const std::vector& /*well_rates*/) const + { + } + + double WellsGroup::getWaterProductionRate(const std::vector& /*well_rates*/) const + { } @@ -1136,6 +1155,13 @@ namespace Opm return getTotalProductionFlow(well_rates, BlackoilPhases::Aqua); } + void WellNode::updateWellProductionTargets(const std::vector& /*well_rates*/) + { + } + + void WellNode::updateWellInjectionTargets(const std::vector& /*well_rates*/) + { + } namespace { diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 8fa79b15..a552f2d8 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -217,6 +217,25 @@ namespace Opm virtual bool setShouldUpdateWellTargets(const bool); + /// Whether it is a production well + /// Should only appy for WellNode + virtual bool isProducer() const = 0; + + /// Whether it is an injection well + /// Should only appy for WellNode + virtual bool isInjector() const = 0; + + virtual double getLiquidProductionRate(const std::vector& well_rates) const = 0; + + virtual double getOilProductionRate(const std::vector& well_rates) const = 0; + + virtual double getWaterProductionRate(const std::vector& well_rates) const = 0; + + virtual void updateWellProductionTargets(const std::vector& well_rates) = 0; + + virtual void updateWellInjectionTargets(const std::vector& well_rates) = 0; + + protected: /// Calculates the correct rate for the given ProductionSpecification::ControlMode double rateByMode(const double* res_rates, @@ -325,9 +344,23 @@ namespace Opm virtual void applyExplicitReinjectionControls(const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase); - void updateWellProductionTargets(const std::vector& well_rates); + virtual void updateWellProductionTargets(const std::vector& well_rates); - void updateWellInjectionTargets(const std::vector& well_rates); + virtual void updateWellInjectionTargets(const std::vector& well_rates); + + /// Whether it is a production well + /// Should only appy for WellNode + virtual bool isProducer() const; + + /// Whether it is an injection well + /// Should only appy for WellNode + virtual bool isInjector() const; + + virtual double getLiquidProductionRate(const std::vector& well_rates) const; + + virtual double getOilProductionRate(const std::vector& well_rates) const; + + virtual double getWaterProductionRate(const std::vector& well_rates) const; private: std::vector > children_; @@ -422,15 +455,20 @@ namespace Opm const std::vector& well_surfacerates_phase); int groupControlIndex() const; - bool isProducer() const; + virtual bool isProducer() const; - bool isInjector() const; + virtual bool isInjector() const; - double getLiquidProductionRate(const std::vector& well_rates) const; + virtual double getLiquidProductionRate(const std::vector& well_rates) const; - double getOilProductionRate(const std::vector& well_rates) const; + virtual double getOilProductionRate(const std::vector& well_rates) const; + + virtual double getWaterProductionRate(const std::vector& well_rates) const; + + virtual void updateWellProductionTargets(const std::vector& well_rates); + + virtual void updateWellInjectionTargets(const std::vector& well_rates); - double getWaterProductionRate(const std::vector& well_rates) const; private: Wells* wells_; From 65d61d1c4f224f8340efe1f85c9533c21fb7d9a7 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 10 Oct 2016 17:09:02 +0200 Subject: [PATCH 18/37] output cleanining up --- opm/core/wells/WellsGroup.cpp | 45 +++++++++++++++-------------------- opm/core/wells/WellsGroup.hpp | 2 +- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 1e54e71f..16359f1e 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -242,7 +242,7 @@ namespace Opm } - bool WellsGroupInterface::setShouldUpdateWellTargets(const bool should_update_well_targets) { + void WellsGroupInterface::setShouldUpdateWellTargets(const bool should_update_well_targets) { should_update_well_targets_ = should_update_well_targets; } @@ -323,12 +323,8 @@ namespace Opm if (!only_group || (prodSpec().control_mode_ == ProductionSpecification::FLD || prodSpec().control_mode_ == ProductionSpecification::NONE)) { const double my_guide_rate = productionGuideRate(false); - std::cout << " only_group " << only_group << std::endl; - std::cout << " name " << name () << std::endl; - std::cout << " my_guide_rate is " << my_guide_rate << std::endl; if (my_guide_rate == 0.0) { // Nothing to do here - std::cout << "returning" << std::endl; return; } for (size_t i = 0; i < children_.size(); ++i) { @@ -427,7 +423,6 @@ namespace Opm production_mode_violated).first->shutWell(); return false; case ProductionSpecification::RATE: - std::cout << "Applying group control" << std::endl; applyProdGroupControl(production_mode_violated, getTarget(production_mode_violated), false); @@ -487,7 +482,6 @@ namespace Opm { // const double my_guide_rate = productionGuideRate(true); const double my_guide_rate = productionGuideRate(false); - std::cout << "my_guide_rate of group " << name() << " is " << my_guide_rate << std::endl; if (my_guide_rate == 0) { OPM_THROW(std::runtime_error, "Can't apply group control for group " << name() << " as the sum of guide rates for all group controlled wells is zero."); } @@ -714,7 +708,7 @@ namespace Opm } } - void WellsGroup::updateWellInjectionTargets(const std::vector& well_rates) + void WellsGroup::updateWellInjectionTargets(const std::vector& /*well_rates*/) { // NOT doing anything yet. // Will finish it when having an examples with more than one injection wells within same injection group. @@ -728,22 +722,30 @@ namespace Opm bool WellsGroup::isProducer() const { + return false; } bool WellsGroup::isInjector() const { + return false; } double WellsGroup::getLiquidProductionRate(const std::vector& /*well_rates*/) const { + // TODO: to be implemented + return -1.e98; } double WellsGroup::getOilProductionRate(const std::vector& /*well_rates*/) const { + // TODO: to be implemented + return -1.e98; } double WellsGroup::getWaterProductionRate(const std::vector& /*well_rates*/) const { + // TODO: to be implemented + return -1.e98; } @@ -920,19 +922,15 @@ namespace Opm const double target, const bool only_group) { - // Not changing if we're not forced to change - // It should be the well will under group control, if we prevent the well from group control - // with keyword WGRUPCON. - // It is just current undertstanding, while further change in the understanding will be possible. - // if (only_group - // && (injSpec().control_mode_ != InjectionSpecification::GRUP && injSpec().control_mode_ != InjectionSpecification::NONE)) { - // return; - // } if ( !isInjector() ) { assert(target == 0.0); return; } + if (only_group && individualControl()) { + return; + } + const double distr[3] = { 1.0, 1.0, 1.0 }; WellControlType wct; switch (control_mode) { @@ -1001,13 +999,12 @@ namespace Opm const double target, const bool only_group) { - /* if (only_group && (prodSpec().control_mode_ != ProductionSpecification::GRUP - && prodSpec().control_mode_ != ProductionSpecification::NONE)) { - std::cout << "Returning" << std::endl; - return; - } */ if ( !isProducer() ) { - // assert(target == 0.0); + assert(target == 0.0); + return; + } + + if (only_group && individualControl()) { return; } // We're a producer, so we need to negate the input @@ -1040,7 +1037,6 @@ namespace Opm distr[phase_pos[BlackoilPhases::Vapour]] = 1.0; break; case ProductionSpecification::LRAT: - std::cout << "applying rate" << std::endl; wct = SURFACE_RATE; if (!phase_used[BlackoilPhases::Liquid]) { OPM_THROW(std::runtime_error, "Oil phase not active and LRAT control specified."); @@ -1059,9 +1055,6 @@ namespace Opm OPM_THROW(std::runtime_error, "Group production control mode not handled: " << control_mode); } - std::cout << " well name " << name() << " group_control_index_ " << group_control_index_ << " ntarget " << ntarget - << std::endl; - if (group_control_index_ < 0) { // The well only had its own controls, no group controls. append_well_controls(wct, ntarget, invalid_alq, invalid_vfp, distr, self_index_, wells_); diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index a552f2d8..12159217 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -215,7 +215,7 @@ namespace Opm virtual bool shouldUpdateWellTargets() const; - virtual bool setShouldUpdateWellTargets(const bool); + virtual void setShouldUpdateWellTargets(const bool); /// Whether it is a production well /// Should only appy for WellNode From b8ac674f9b6595a50b40af3259a13957e3a051c0 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 13 Oct 2016 10:46:54 +0200 Subject: [PATCH 19/37] When NONE is specified, no group control enforcement. NONE is specified in GCONPROD or GCONINJE. --- opm/core/wells/WellsGroup.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 16359f1e..799b3421 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -293,8 +293,11 @@ namespace Opm const double target, const bool only_group) { - if (!only_group || injSpec().control_mode_ == InjectionSpecification::FLD - || injSpec().control_mode_ == InjectionSpecification::NONE) { + if (injSpec().control_mode_ == InjectionSpecification::NONE) { + return; + } + + if (!only_group || injSpec().control_mode_ == InjectionSpecification::FLD) { const double my_guide_rate = injectionGuideRate(only_group); if (my_guide_rate == 0.0) { // Nothing to do here @@ -320,8 +323,7 @@ namespace Opm if (prodSpec().control_mode_ == ProductionSpecification::NONE) { return; } - if (!only_group || (prodSpec().control_mode_ == ProductionSpecification::FLD - || prodSpec().control_mode_ == ProductionSpecification::NONE)) { + if (!only_group || prodSpec().control_mode_ == ProductionSpecification::FLD) { const double my_guide_rate = productionGuideRate(false); if (my_guide_rate == 0.0) { // Nothing to do here From 2e135388a64c950abccb4eed36bb84c78b82106f Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 13 Oct 2016 12:37:07 +0200 Subject: [PATCH 20/37] refactoring function updateWellProductionTargets() To handle different types of control mode. --- opm/core/wells/ProductionSpecification.cpp | 1 + opm/core/wells/WellsGroup.cpp | 78 ++++++++++++---------- opm/core/wells/WellsGroup.hpp | 21 ++---- 3 files changed, 49 insertions(+), 51 deletions(-) diff --git a/opm/core/wells/ProductionSpecification.cpp b/opm/core/wells/ProductionSpecification.cpp index 20abe715..1bdaac30 100644 --- a/opm/core/wells/ProductionSpecification.cpp +++ b/opm/core/wells/ProductionSpecification.cpp @@ -82,6 +82,7 @@ namespace Opm case GuideRateType::OIL : return "OIL" ; case GuideRateType::GAS : return "GAS" ; case GuideRateType::WATER : return "WATER" ; + case GuideRateType::LIQ : return "LIQ" ; case GuideRateType::NONE_GRT: return "NONE_GRT"; } OPM_THROW(std::domain_error, "Unknown guide rate type " << type << " encountered in production specification"); diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 799b3421..583c519c 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -680,23 +680,39 @@ namespace Opm // While there will be somre more complication invloved for sure. // Basically, we need to update the target rates for the wells still under group control. - ProductionSpecification::ControlMode control_mode = prodSpec().control_mode_; - double target_rate = prodSpec().liquid_max_rate_; + ProductionSpecification::ControlMode prod_mode = prodSpec().control_mode_; + double target_rate = -1.0; - if (ProductionSpecification::toString(control_mode) == "FLD") { - auto* parent_node = getParent(); - control_mode = parent_node->prodSpec().control_mode_; - target_rate = parent_node->prodSpec().liquid_max_rate_; + switch(prod_mode) { + case ProductionSpecification::FLD : + { + auto* parent_node = getParent(); + prod_mode = parent_node->prodSpec().control_mode_; + target_rate = parent_node->getTarget(prod_mode); + break; + } + case ProductionSpecification::LRAT : + case ProductionSpecification::ORAT : + case ProductionSpecification::GRAT : + case ProductionSpecification::WRAT : + target_rate = getTarget(prod_mode); + break; + default: + OPM_THROW(std::runtime_error, "Not supporting type " << ProductionSpecification::toString(prod_mode) << + " when updating well targets "); } + // the rates contributed from wells under individual control due to their own limits. + // TODO: will handle wells specified not to join group control later. double rate_individual_control = 0.; for (size_t i = 0; i < children_.size(); ++i) { if (children_[i]->individualControl() && children_[i]->isProducer()) { - rate_individual_control += std::abs(children_[i]->getLiquidProductionRate(well_rates)); + rate_individual_control += std::abs(children_[i]->getProductionRate(well_rates, prod_mode)); } } + // the rates left for the wells under group control to split const double rate_for_group_control = target_rate - rate_individual_control; const double my_guide_rate = productionGuideRate(true); @@ -704,7 +720,7 @@ namespace Opm for (size_t i = 0; i < children_.size(); ++i) { if (!children_[i]->individualControl() && children_[i]->isProducer()) { const double children_guide_rate = children_[i]->productionGuideRate(true); - children_[i]->applyProdGroupControl(control_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, true); + children_[i]->applyProdGroupControl(prod_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, true); children_[i]->setShouldUpdateWellTargets(false); } } @@ -732,25 +748,13 @@ namespace Opm return false; } - double WellsGroup::getLiquidProductionRate(const std::vector& /*well_rates*/) const + double WellsGroup::getProductionRate(const std::vector& /* well_rates */, + const ProductionSpecification::ControlMode /* prod_mode */) const { // TODO: to be implemented return -1.e98; } - double WellsGroup::getOilProductionRate(const std::vector& /*well_rates*/) const - { - // TODO: to be implemented - return -1.e98; - } - - double WellsGroup::getWaterProductionRate(const std::vector& /*well_rates*/) const - { - // TODO: to be implemented - return -1.e98; - } - - // ============== WellNode members ============ @@ -1133,21 +1137,23 @@ namespace Opm - double WellNode::getLiquidProductionRate(const std::vector& well_rates) const + double WellNode::getProductionRate(const std::vector& well_rates, + const ProductionSpecification::ControlMode prod_mode) const { - return ( getTotalProductionFlow(well_rates, BlackoilPhases::Liquid) + - getTotalProductionFlow(well_rates, BlackoilPhases::Aqua) ); - - } - - double WellNode::getOilProductionRate(const std::vector& well_rates) const - { - return getTotalProductionFlow(well_rates, BlackoilPhases::Liquid); - } - - double WellNode::getWaterProductionRate(const std::vector& well_rates) const - { - return getTotalProductionFlow(well_rates, BlackoilPhases::Aqua); + switch(prod_mode) { + case ProductionSpecification::LRAT : + return ( getTotalProductionFlow(well_rates, BlackoilPhases::Liquid) + + getTotalProductionFlow(well_rates, BlackoilPhases::Aqua) ); + case ProductionSpecification::ORAT : + return getTotalProductionFlow(well_rates, BlackoilPhases::Liquid); + case ProductionSpecification::WRAT : + return getTotalProductionFlow(well_rates, BlackoilPhases::Aqua); + case ProductionSpecification::GRAT : + return getTotalProductionFlow(well_rates, BlackoilPhases::Vapour); + default: + OPM_THROW(std::runtime_error, "Not supporting type " << ProductionSpecification::toString(prod_mode) << + " for production rate calculation "); + } } void WellNode::updateWellProductionTargets(const std::vector& /*well_rates*/) diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 12159217..c456db95 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -225,11 +225,8 @@ namespace Opm /// Should only appy for WellNode virtual bool isInjector() const = 0; - virtual double getLiquidProductionRate(const std::vector& well_rates) const = 0; - - virtual double getOilProductionRate(const std::vector& well_rates) const = 0; - - virtual double getWaterProductionRate(const std::vector& well_rates) const = 0; + virtual double getProductionRate(const std::vector& well_rates, + const ProductionSpecification::ControlMode prod_mode) const = 0; virtual void updateWellProductionTargets(const std::vector& well_rates) = 0; @@ -356,11 +353,8 @@ namespace Opm /// Should only appy for WellNode virtual bool isInjector() const; - virtual double getLiquidProductionRate(const std::vector& well_rates) const; - - virtual double getOilProductionRate(const std::vector& well_rates) const; - - virtual double getWaterProductionRate(const std::vector& well_rates) const; + virtual double getProductionRate(const std::vector& well_rates, + const ProductionSpecification::ControlMode prod_mode) const; private: std::vector > children_; @@ -459,11 +453,8 @@ namespace Opm virtual bool isInjector() const; - virtual double getLiquidProductionRate(const std::vector& well_rates) const; - - virtual double getOilProductionRate(const std::vector& well_rates) const; - - virtual double getWaterProductionRate(const std::vector& well_rates) const; + virtual double getProductionRate(const std::vector& well_rates, + const ProductionSpecification::ControlMode prod_mode) const; virtual void updateWellProductionTargets(const std::vector& well_rates); From 013c907e66d484002c64763719a62feb6fce77ec Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Tue, 18 Oct 2016 14:26:06 +0200 Subject: [PATCH 21/37] adding efficiency factor to the WellsGroupInterface. The one for the WellNode should be specified with WEFAC, which we are not handling for the moment, so we just set it to be 1.0 for the moment. --- opm/core/wells/WellsGroup.cpp | 35 ++++++++++++++++++++++++++++------- opm/core/wells/WellsGroup.hpp | 9 +++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 583c519c..6770b5a1 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -61,12 +61,14 @@ namespace Opm WellsGroupInterface::WellsGroupInterface(const std::string& myname, + const double efficicency_factor, const ProductionSpecification& prod_spec, const InjectionSpecification& inje_spec, const PhaseUsage& phase_usage) : parent_(NULL), should_update_well_targets_(false), individual_control_(true), // always begin with individual control + efficicency_factor_(efficicency_factor), name_(myname), production_specification_(prod_spec), injection_specification_(inje_spec), @@ -237,23 +239,38 @@ namespace Opm } - bool WellsGroupInterface::shouldUpdateWellTargets() const { + bool WellsGroupInterface::shouldUpdateWellTargets() const + { return should_update_well_targets_; } - void WellsGroupInterface::setShouldUpdateWellTargets(const bool should_update_well_targets) { + void WellsGroupInterface::setShouldUpdateWellTargets(const bool should_update_well_targets) + { should_update_well_targets_ = should_update_well_targets; } - bool WellsGroupInterface::individualControl() const { + bool WellsGroupInterface::individualControl() const + { return individual_control_; } - void WellsGroupInterface::setIndividualControl(const bool individual_control) { + void WellsGroupInterface::setIndividualControl(const bool individual_control) + { individual_control_ = individual_control; } + double WellsGroupInterface::efficicencyFactor() const + { + return efficicency_factor_; + } + + void WellsGroupInterface::setEfficiencyFactor(const double efficicency_factor) + { + efficicency_factor_=efficicency_factor; + } + + // ============== WellsGroup members ============= @@ -277,10 +294,11 @@ namespace Opm WellsGroup::WellsGroup(const std::string& myname, + const double efficiency_factor, const ProductionSpecification& prod_spec, const InjectionSpecification& inj_spec, const PhaseUsage& phase_usage) - : WellsGroupInterface(myname, prod_spec, inj_spec, phase_usage) + : WellsGroupInterface(myname, efficiency_factor, prod_spec, inj_spec, phase_usage) { } @@ -760,10 +778,11 @@ namespace Opm WellNode::WellNode(const std::string& myname, + const double efficiency_factor, const ProductionSpecification& prod_spec, const InjectionSpecification& inj_spec, const PhaseUsage& phase_usage) - : WellsGroupInterface(myname, prod_spec, inj_spec, phase_usage), + : WellsGroupInterface(myname, efficiency_factor, prod_spec, inj_spec, phase_usage), wells_(0), self_index_(-1), group_control_index_(-1), @@ -1315,7 +1334,9 @@ namespace Opm production_specification.control_mode_ = toProductionControlMode(WellProducer::ControlMode2String(properties.controlMode)); } } - std::shared_ptr wells_group(new WellNode(well->name(), production_specification, injection_specification, phase_usage)); + // TODO: should be specified with WEFAC, while we do not have this keyword support yet. + const double efficiency_factor = 1.0; + std::shared_ptr wells_group(new WellNode(well->name(), efficiency_factor, production_specification, injection_specification, phase_usage)); return wells_group; } } diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index c456db95..4a7d50ca 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -55,6 +55,7 @@ namespace Opm { public: WellsGroupInterface(const std::string& name, + const double efficicency_factor, const ProductionSpecification& prod_spec, const InjectionSpecification& inj_spec, const PhaseUsage& phase_usage); @@ -244,6 +245,9 @@ namespace Opm const double* surf_rates, const InjectionSpecification::ControlMode mode); + double efficicencyFactor() const; + void setEfficiencyFactor(const double efficicency_factor); + WellsGroupInterface* parent_; // when some well (mabye group also later), change status from group control @@ -254,6 +258,9 @@ namespace Opm // So not putting it in the WellsGroupInterface yet. bool individual_control_; + // Efficiency factor + double efficicency_factor_; + private: std::string name_; ProductionSpecification production_specification_; @@ -267,6 +274,7 @@ namespace Opm { public: WellsGroup(const std::string& name, + const double efficicency_factor, const ProductionSpecification& prod_spec, const InjectionSpecification& inj_spec, const PhaseUsage& phase_usage); @@ -366,6 +374,7 @@ namespace Opm { public: WellNode(const std::string& name, + const double efficicency_factor, const ProductionSpecification& prod_spec, const InjectionSpecification& inj_spec, const PhaseUsage& phase_usage); From a0e1fcf89dfeec10b648f492eafd1905fcb8422e Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Tue, 18 Oct 2016 15:28:21 +0200 Subject: [PATCH 22/37] function for accumulative efficiency factor for WellNode This is the final efficiency factor that goes to the source/sink terms in the material balance equations. --- opm/core/wells/WellsGroup.cpp | 21 ++++++++++++++++++++- opm/core/wells/WellsGroup.hpp | 9 ++++++--- tutorials/tutorial4.cpp | 10 ++++++---- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 6770b5a1..2ffa49ef 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -1295,7 +1295,9 @@ namespace Opm production_specification.reservoir_flow_max_rate_ = group.getReservoirVolumeTargetRate(timeStep); } - std::shared_ptr wells_group(new WellsGroup(group.name(), production_specification, injection_specification, phase_usage)); + const double efficiency_factor = group.getGroupEfficiencyFactor(timeStep); + + std::shared_ptr wells_group(new WellsGroup(group.name(), efficiency_factor, production_specification, injection_specification, phase_usage)); return wells_group; } @@ -1339,4 +1341,21 @@ namespace Opm std::shared_ptr wells_group(new WellNode(well->name(), efficiency_factor, production_specification, injection_specification, phase_usage)); return wells_group; } + + + + + double WellNode::getAccumulativeEfficiencyFactor() const { + // TODO: not sure whether a well can be exempted from repsponding to the efficiency factor + // for the parent group. + double efficicency_factor = efficicencyFactor(); + const WellsGroupInterface* parent_node = getParent(); + while (parent_node != nullptr) { + efficicency_factor *= parent_node->efficicencyFactor(); + parent_node = parent_node->getParent(); + } + + return efficicency_factor; + } + } diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 4a7d50ca..cb59217a 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -233,6 +233,9 @@ namespace Opm virtual void updateWellInjectionTargets(const std::vector& well_rates) = 0; + double efficicencyFactor() const; + + void setEfficiencyFactor(const double efficicency_factor); protected: /// Calculates the correct rate for the given ProductionSpecification::ControlMode @@ -245,9 +248,6 @@ namespace Opm const double* surf_rates, const InjectionSpecification::ControlMode mode); - double efficicencyFactor() const; - void setEfficiencyFactor(const double efficicency_factor); - WellsGroupInterface* parent_; // when some well (mabye group also later), change status from group control @@ -469,6 +469,9 @@ namespace Opm virtual void updateWellInjectionTargets(const std::vector& well_rates); + /// the efficiency factor for groups are muliplitive, this function return the resulted final efficiency factor + /// to the well in a multi-layer group structure. + double getAccumulativeEfficiencyFactor() const; private: Wells* wells_; diff --git a/tutorials/tutorial4.cpp b/tutorials/tutorial4.cpp index d9e5f0bc..5eee336a 100644 --- a/tutorials/tutorial4.cpp +++ b/tutorials/tutorial4.cpp @@ -265,6 +265,7 @@ try well_group_prod_spec.control_mode_ = ProductionSpecification::RESV; /// \internal[production specification] /// \endinternal + const double group_efficiency_factor = 0.9; /// \page tutorial4 /// \details Create our well group. We hand it an empty injection specification, @@ -272,8 +273,8 @@ try /// what the interface expects. The first argument is the (unique) name of the group. /// \snippet tutorial4.cpp injection specification /// \internal[injection specification] - std::shared_ptr well_group(new WellsGroup("group", well_group_prod_spec, InjectionSpecification(), - phase_usage)); + std::shared_ptr well_group(new WellsGroup("group", group_efficiency_factor, well_group_prod_spec, + InjectionSpecification(), phase_usage)); /// \internal[injection specification] /// \endinternal @@ -297,8 +298,9 @@ try well_name << "well" << i; ProductionSpecification production_specification; production_specification.control_mode_ = ProductionSpecification::GRUP; - std::shared_ptr well_leaf_node(new WellNode(well_name.str(), production_specification, InjectionSpecification(), - phase_usage)); + const double efficiency_factor = 0.8; + std::shared_ptr well_leaf_node(new WellNode(well_name.str(), efficiency_factor, production_specification, + InjectionSpecification(), phase_usage)); well_collection.addChild(well_leaf_node, "group"); } From 63e5755fa9c61b84544b883b0a3e5d8b6afd35a2 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Tue, 18 Oct 2016 16:43:24 +0200 Subject: [PATCH 23/37] applying efficiency factor to the group control. --- opm/core/wells/WellsGroup.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 2ffa49ef..b6f0b379 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -322,7 +322,7 @@ namespace Opm return; } for (size_t i = 0; i < children_.size(); ++i) { - const double child_target = target * children_[i]->injectionGuideRate(only_group) / my_guide_rate; + const double child_target = target / efficicencyFactor() * children_[i]->injectionGuideRate(only_group) / my_guide_rate; children_[i]->applyInjGroupControl(control_mode, child_target, false); } injSpec().control_mode_ = InjectionSpecification::FLD; @@ -348,7 +348,7 @@ namespace Opm return; } for (size_t i = 0; i < children_.size(); ++i) { - const double child_target = target * children_[i]->productionGuideRate(only_group) / my_guide_rate; + const double child_target = target / efficicencyFactor() * children_[i]->productionGuideRate(only_group) / my_guide_rate; children_[i]->applyProdGroupControl(control_mode, child_target, false); } prodSpec().control_mode_ = ProductionSpecification::FLD; @@ -552,7 +552,7 @@ namespace Opm // as that would check if we're under group control, something we're not. const double children_guide_rate = children_[i]->injectionGuideRate(false); children_[i]->applyInjGroupControl(inj_mode, - (children_guide_rate / my_guide_rate) * getTarget(inj_mode), + (children_guide_rate / my_guide_rate) * getTarget(inj_mode) / efficicencyFactor(), true); } return; @@ -706,7 +706,7 @@ namespace Opm { auto* parent_node = getParent(); prod_mode = parent_node->prodSpec().control_mode_; - target_rate = parent_node->getTarget(prod_mode); + target_rate = parent_node->getTarget(prod_mode) / parent_node->efficicencyFactor(); break; } case ProductionSpecification::LRAT : @@ -720,13 +720,15 @@ namespace Opm " when updating well targets "); } + target_rate /= efficicencyFactor(); + // the rates contributed from wells under individual control due to their own limits. // TODO: will handle wells specified not to join group control later. double rate_individual_control = 0.; for (size_t i = 0; i < children_.size(); ++i) { if (children_[i]->individualControl() && children_[i]->isProducer()) { - rate_individual_control += std::abs(children_[i]->getProductionRate(well_rates, prod_mode)); + rate_individual_control += std::abs(children_[i]->getProductionRate(well_rates, prod_mode) * children_[i]->efficicencyFactor()); } } @@ -738,7 +740,7 @@ namespace Opm for (size_t i = 0; i < children_.size(); ++i) { if (!children_[i]->individualControl() && children_[i]->isProducer()) { const double children_guide_rate = children_[i]->productionGuideRate(true); - children_[i]->applyProdGroupControl(prod_mode, (children_guide_rate/my_guide_rate) * rate_for_group_control, true); + children_[i]->applyProdGroupControl(prod_mode, (children_guide_rate / my_guide_rate) * rate_for_group_control, true); children_[i]->setShouldUpdateWellTargets(false); } } @@ -956,6 +958,9 @@ namespace Opm return; } + // considering the efficiency factor + const double effective_target = target / efficicencyFactor(); + const double distr[3] = { 1.0, 1.0, 1.0 }; WellControlType wct; switch (control_mode) { @@ -971,13 +976,13 @@ namespace Opm if (group_control_index_ < 0) { // The well only had its own controls, no group controls. - append_well_controls(wct, target, invalid_alq, invalid_vfp, distr, self_index_, wells_); + append_well_controls(wct, effective_target, invalid_alq, invalid_vfp, distr, self_index_, wells_); group_control_index_ = well_controls_get_num(wells_->ctrls[self_index_]) - 1; } else { // We will now modify the last control, that // "belongs to" the group control. well_controls_iset_type(wells_->ctrls[self_index_] , group_control_index_ , wct); - well_controls_iset_target(wells_->ctrls[self_index_] , group_control_index_ ,target); + well_controls_iset_target(wells_->ctrls[self_index_] , group_control_index_ , effective_target); well_controls_iset_alq(wells_->ctrls[self_index_] , group_control_index_ , -1e100); well_controls_iset_distr(wells_->ctrls[self_index_] , group_control_index_ , distr); } @@ -1033,7 +1038,7 @@ namespace Opm return; } // We're a producer, so we need to negate the input - double ntarget = -target; + double ntarget = -target / efficicencyFactor(); double distr[3] = { 0.0, 0.0, 0.0 }; const int* phase_pos = phaseUsage().phase_pos; From 2b289f896474b96c10f9a21bfa6cb6dc68a76467 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 24 Oct 2016 13:24:41 +0200 Subject: [PATCH 24/37] adding basic support for group injection control. more testing will be required later. --- opm/core/wells/WellsGroup.cpp | 46 +++++++++++++++++++++++++++++------ opm/core/wells/WellsGroup.hpp | 3 +++ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index b6f0b379..42660069 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -308,10 +308,12 @@ namespace Opm /// \param[in] only_group if true, only children that are under group control will be changed. /// otherwise, all children will be set under group control void WellsGroup::applyInjGroupControl(const InjectionSpecification::ControlMode control_mode, + const InjectionSpecification::InjectorType injector_type, const double target, const bool only_group) { if (injSpec().control_mode_ == InjectionSpecification::NONE) { + // TODO: for multiple level of group control, it can be wrong to return here. return; } @@ -323,7 +325,7 @@ namespace Opm } for (size_t i = 0; i < children_.size(); ++i) { const double child_target = target / efficicencyFactor() * children_[i]->injectionGuideRate(only_group) / my_guide_rate; - children_[i]->applyInjGroupControl(control_mode, child_target, false); + children_[i]->applyInjGroupControl(control_mode, injector_type, child_target, false); } injSpec().control_mode_ = InjectionSpecification::FLD; } @@ -361,6 +363,8 @@ namespace Opm const std::vector& well_surfacerates_phase, WellPhasesSummed& summed_phases) { + // TODO: adding here for compilation, not sure everything will work correctly. + const InjectionSpecification::InjectorType injector_type = injSpec().injector_type_; // Check children's constraints recursively. WellPhasesSummed child_phases_summed; for (size_t i = 0; i < children_.size(); ++i) { @@ -395,7 +399,7 @@ namespace Opm + " target not met for group " + name() + "\n" + "target = " + std::to_string(target_rate) + "\n" + "rate = " + std::to_string(my_rate)); - applyInjGroupControl(mode, target_rate, false); + applyInjGroupControl(mode, injector_type, target_rate, false); injSpec().control_mode_ = mode; return false; } @@ -531,6 +535,7 @@ namespace Opm void WellsGroup::applyInjGroupControls() { InjectionSpecification::ControlMode inj_mode = injSpec().control_mode_; + InjectionSpecification::InjectorType inj_type = injSpec().injector_type_; switch (inj_mode) { case InjectionSpecification::RATE: // need to be careful in the future. @@ -551,9 +556,9 @@ namespace Opm // Note, we do _not_ want to call the applyProdGroupControl in this object, // as that would check if we're under group control, something we're not. const double children_guide_rate = children_[i]->injectionGuideRate(false); - children_[i]->applyInjGroupControl(inj_mode, + children_[i]->applyInjGroupControl(inj_mode, inj_type, (children_guide_rate / my_guide_rate) * getTarget(inj_mode) / efficicencyFactor(), - true); + false); } return; } @@ -631,6 +636,7 @@ namespace Opm void WellsGroup::applyExplicitReinjectionControls(const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase) { + const InjectionSpecification::InjectorType injector_type = injSpec().injector_type_; if (injSpec().control_mode_ == InjectionSpecification::REIN) { // Defaulting to water to satisfy -Wmaybe-uninitialized BlackoilPhases::PhaseIndex phase = BlackoilPhases::Aqua; @@ -658,7 +664,7 @@ namespace Opm (children_guide_rate / my_guide_rate) * total_reinjected * injSpec().reinjection_fraction_target_, true); #else - children_[i]->applyInjGroupControl(InjectionSpecification::RATE, + children_[i]->applyInjGroupControl(InjectionSpecification::RATE, injector_type, (children_guide_rate / my_guide_rate) * total_reinjected * injSpec().reinjection_fraction_target_, true); #endif @@ -682,7 +688,7 @@ namespace Opm // Note, we do _not_ want to call the applyProdGroupControl in this object, // as that would check if we're under group control, something we're not. const double children_guide_rate = children_[i]->injectionGuideRate(true); - children_[i]->applyInjGroupControl(InjectionSpecification::RESV, + children_[i]->applyInjGroupControl(InjectionSpecification::RESV, injector_type, (children_guide_rate / my_guide_rate) * total_reinjected * injSpec().voidage_replacment_fraction_, true); } @@ -946,6 +952,7 @@ namespace Opm } void WellNode::applyInjGroupControl(const InjectionSpecification::ControlMode control_mode, + const InjectionSpecification::InjectorType injector_type, const double target, const bool only_group) { @@ -961,7 +968,32 @@ namespace Opm // considering the efficiency factor const double effective_target = target / efficicencyFactor(); - const double distr[3] = { 1.0, 1.0, 1.0 }; + const int* phase_pos = phaseUsage().phase_pos; + const int* phase_used = phaseUsage().phase_used; + double distr[3] = { 0.0, 0.0, 0.0 }; + switch(injector_type) { + case InjectionSpecification::WATER: + if (!phase_used[BlackoilPhases::Aqua]) { + OPM_THROW(std::runtime_error, "Water phase not active while WATER phase injection specified."); + } + distr[phase_pos[BlackoilPhases::Aqua]] = 1.0; + break; + case InjectionSpecification::OIL: + if (!phase_used[BlackoilPhases::Liquid]) { + OPM_THROW(std::runtime_error, "Oil phase not active while OIL phase injection specified."); + } + distr[phase_pos[BlackoilPhases::Liquid]] = 1.0; + break; + case InjectionSpecification::GAS: + if (!phase_used[BlackoilPhases::Vapour]) { + OPM_THROW(std::runtime_error, "Gas phase not active while GAS phase injection specified."); + } + distr[phase_pos[BlackoilPhases::Vapour]] = 1.0; + break; + default: + OPM_THROW(std::runtime_error, "Group injection phase not handled: " << InjectionSpecification::toString(injector_type)); + } + WellControlType wct; switch (control_mode) { case InjectionSpecification::RATE: diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index cb59217a..62c2e1e5 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -134,6 +134,7 @@ namespace Opm /// \param[in] only_group if true, only children that are under group control will be changed. // otherwise, all children will be set under group control virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode, + const InjectionSpecification::InjectorType injector_type, const double target, const bool only_group) = 0; /// Sets the current active control to the provided one for all producers within the group. @@ -299,6 +300,7 @@ namespace Opm /// \param[in] only_group if true, only children that are under group control will be changed. // otherwise, all children will be set under group control virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode, + const InjectionSpecification::InjectorType injector_type, const double target, bool only_group); @@ -404,6 +406,7 @@ namespace Opm /// \param[in] only_group if true, only children that are under group control will be changed. /// otherwise, all children will be set under group control virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode, + const InjectionSpecification::InjectorType injector_type, const double target, bool only_group); From 06d380df51e4f465171900346ab1fe692b6f7e7c Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 24 Oct 2016 14:54:48 +0200 Subject: [PATCH 25/37] correcting the typo in efficiency It was efficicency, which causes inconvenience when searching variables or functions. --- opm/core/wells/WellsGroup.cpp | 34 +++++++++++++++++----------------- opm/core/wells/WellsGroup.hpp | 12 ++++++------ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 42660069..ba9b4961 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -61,14 +61,14 @@ namespace Opm WellsGroupInterface::WellsGroupInterface(const std::string& myname, - const double efficicency_factor, + const double efficiency_factor, const ProductionSpecification& prod_spec, const InjectionSpecification& inje_spec, const PhaseUsage& phase_usage) : parent_(NULL), should_update_well_targets_(false), individual_control_(true), // always begin with individual control - efficicency_factor_(efficicency_factor), + efficiency_factor_(efficiency_factor), name_(myname), production_specification_(prod_spec), injection_specification_(inje_spec), @@ -260,14 +260,14 @@ namespace Opm individual_control_ = individual_control; } - double WellsGroupInterface::efficicencyFactor() const + double WellsGroupInterface::efficiencyFactor() const { - return efficicency_factor_; + return efficiency_factor_; } - void WellsGroupInterface::setEfficiencyFactor(const double efficicency_factor) + void WellsGroupInterface::setEfficiencyFactor(const double efficiency_factor) { - efficicency_factor_=efficicency_factor; + efficiency_factor_=efficiency_factor; } @@ -324,7 +324,7 @@ namespace Opm return; } for (size_t i = 0; i < children_.size(); ++i) { - const double child_target = target / efficicencyFactor() * children_[i]->injectionGuideRate(only_group) / my_guide_rate; + const double child_target = target / efficiencyFactor() * children_[i]->injectionGuideRate(only_group) / my_guide_rate; children_[i]->applyInjGroupControl(control_mode, injector_type, child_target, false); } injSpec().control_mode_ = InjectionSpecification::FLD; @@ -350,7 +350,7 @@ namespace Opm return; } for (size_t i = 0; i < children_.size(); ++i) { - const double child_target = target / efficicencyFactor() * children_[i]->productionGuideRate(only_group) / my_guide_rate; + const double child_target = target / efficiencyFactor() * children_[i]->productionGuideRate(only_group) / my_guide_rate; children_[i]->applyProdGroupControl(control_mode, child_target, false); } prodSpec().control_mode_ = ProductionSpecification::FLD; @@ -557,7 +557,7 @@ namespace Opm // as that would check if we're under group control, something we're not. const double children_guide_rate = children_[i]->injectionGuideRate(false); children_[i]->applyInjGroupControl(inj_mode, inj_type, - (children_guide_rate / my_guide_rate) * getTarget(inj_mode) / efficicencyFactor(), + (children_guide_rate / my_guide_rate) * getTarget(inj_mode) / efficiencyFactor(), false); } return; @@ -712,7 +712,7 @@ namespace Opm { auto* parent_node = getParent(); prod_mode = parent_node->prodSpec().control_mode_; - target_rate = parent_node->getTarget(prod_mode) / parent_node->efficicencyFactor(); + target_rate = parent_node->getTarget(prod_mode) / parent_node->efficiencyFactor(); break; } case ProductionSpecification::LRAT : @@ -726,7 +726,7 @@ namespace Opm " when updating well targets "); } - target_rate /= efficicencyFactor(); + target_rate /= efficiencyFactor(); // the rates contributed from wells under individual control due to their own limits. // TODO: will handle wells specified not to join group control later. @@ -734,7 +734,7 @@ namespace Opm for (size_t i = 0; i < children_.size(); ++i) { if (children_[i]->individualControl() && children_[i]->isProducer()) { - rate_individual_control += std::abs(children_[i]->getProductionRate(well_rates, prod_mode) * children_[i]->efficicencyFactor()); + rate_individual_control += std::abs(children_[i]->getProductionRate(well_rates, prod_mode) * children_[i]->efficiencyFactor()); } } @@ -966,7 +966,7 @@ namespace Opm } // considering the efficiency factor - const double effective_target = target / efficicencyFactor(); + const double effective_target = target / efficiencyFactor(); const int* phase_pos = phaseUsage().phase_pos; const int* phase_used = phaseUsage().phase_used; @@ -1070,7 +1070,7 @@ namespace Opm return; } // We're a producer, so we need to negate the input - double ntarget = -target / efficicencyFactor(); + double ntarget = -target / efficiencyFactor(); double distr[3] = { 0.0, 0.0, 0.0 }; const int* phase_pos = phaseUsage().phase_pos; @@ -1385,14 +1385,14 @@ namespace Opm double WellNode::getAccumulativeEfficiencyFactor() const { // TODO: not sure whether a well can be exempted from repsponding to the efficiency factor // for the parent group. - double efficicency_factor = efficicencyFactor(); + double efficiency_factor = efficiencyFactor(); const WellsGroupInterface* parent_node = getParent(); while (parent_node != nullptr) { - efficicency_factor *= parent_node->efficicencyFactor(); + efficiency_factor *= parent_node->efficiencyFactor(); parent_node = parent_node->getParent(); } - return efficicency_factor; + return efficiency_factor; } } diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 62c2e1e5..88d84cc4 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -55,7 +55,7 @@ namespace Opm { public: WellsGroupInterface(const std::string& name, - const double efficicency_factor, + const double efficiency_factor, const ProductionSpecification& prod_spec, const InjectionSpecification& inj_spec, const PhaseUsage& phase_usage); @@ -234,9 +234,9 @@ namespace Opm virtual void updateWellInjectionTargets(const std::vector& well_rates) = 0; - double efficicencyFactor() const; + double efficiencyFactor() const; - void setEfficiencyFactor(const double efficicency_factor); + void setEfficiencyFactor(const double efficiency_factor); protected: /// Calculates the correct rate for the given ProductionSpecification::ControlMode @@ -260,7 +260,7 @@ namespace Opm bool individual_control_; // Efficiency factor - double efficicency_factor_; + double efficiency_factor_; private: std::string name_; @@ -275,7 +275,7 @@ namespace Opm { public: WellsGroup(const std::string& name, - const double efficicency_factor, + const double efficiency_factor, const ProductionSpecification& prod_spec, const InjectionSpecification& inj_spec, const PhaseUsage& phase_usage); @@ -376,7 +376,7 @@ namespace Opm { public: WellNode(const std::string& name, - const double efficicency_factor, + const double efficiency_factor, const ProductionSpecification& prod_spec, const InjectionSpecification& inj_spec, const PhaseUsage& phase_usage); From 88181f49488f896073a56664e38af954272a4ba8 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 26 Oct 2016 11:34:40 +0200 Subject: [PATCH 26/37] using variable only_group instead of hard-coded false. when applying group production control. --- opm/core/wells/WellsGroup.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index ba9b4961..5ce8a978 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -344,14 +344,14 @@ namespace Opm return; } if (!only_group || prodSpec().control_mode_ == ProductionSpecification::FLD) { - const double my_guide_rate = productionGuideRate(false); + const double my_guide_rate = productionGuideRate(only_group); if (my_guide_rate == 0.0) { // Nothing to do here return; } for (size_t i = 0; i < children_.size(); ++i) { const double child_target = target / efficiencyFactor() * children_[i]->productionGuideRate(only_group) / my_guide_rate; - children_[i]->applyProdGroupControl(control_mode, child_target, false); + children_[i]->applyProdGroupControl(control_mode, child_target, only_group); } prodSpec().control_mode_ = ProductionSpecification::FLD; } From 76a2108ea99a09e981c0e4d2a52d1cdd3f714721 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 21 Oct 2016 17:39:31 +0200 Subject: [PATCH 27/37] adding VREP injection support. not handling multiple injection wells for moment. --- opm/core/wells/WellCollection.cpp | 21 ++++ opm/core/wells/WellCollection.hpp | 11 ++ opm/core/wells/WellsGroup.cpp | 153 ++++++++++++++++++++++++++- opm/core/wells/WellsGroup.hpp | 34 ++++++ opm/core/wells/WellsManager_impl.hpp | 1 + 5 files changed, 216 insertions(+), 4 deletions(-) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 0f6aff9d..a8675f75 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -52,6 +52,10 @@ namespace Opm std::shared_ptr child = createGroupWellsGroup(groupChild, timeStep, phaseUsage); + if (child->injSpec().control_mode_ == InjectionSpecification::VREP) { + having_vrep_groups_ = true; + } + WellsGroup* parent_as_group = static_cast (parent); if (!parent_as_group) { OPM_THROW(std::runtime_error, "Trying to add child group to group named " << parent->name() << ", but it's not a group."); @@ -191,6 +195,15 @@ namespace Opm } + void WellCollection::applyVREPGroupControls(const std::vector& well_voidage_rates, + const std::vector& conversion_coeffs) + { + for (size_t i = 0; i < roots_.size(); ++i) { + roots_[i]->applyVREPGroupControls(well_voidage_rates, conversion_coeffs); + } + } + + //TODO: later, it should be extended to update group targets bool WellCollection::needUpdateWellTargets() const { @@ -286,4 +299,12 @@ namespace Opm setJustUpdateWellTargets(true); } + bool WellCollection::havingVREPGroups() const { + return having_vrep_groups_; + } + + void WellCollection::setHavingVREPGroups(const bool vrep) { + having_vrep_groups_ = vrep; + } + } diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index 62c8f669..3c8b5f73 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -110,6 +110,12 @@ namespace Opm void applyExplicitReinjectionControls(const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase); + + // TODO: should have tried to use the above applyExplicitReinjectionControls + // For prototyping, make a new function here at the moment. + void applyVREPGroupControls(const std::vector& well_voidage_rates, + const std::vector& conversion_coeffs); + /// Checking whehter need to update the targets of the wells / or the groups later /// True need to update well targets within this iteration, no switching control within this iteration. /// False no need to update well targets within this iteration, continuing as usual. @@ -130,6 +136,10 @@ namespace Opm void setJustUpdateWellTargets(const bool flag); + bool havingVREPGroups() const; + + void setHavingVREPGroups(const bool vrep); + private: // To account for the possibility of a forest std::vector > roots_; @@ -138,6 +148,7 @@ namespace Opm std::vector leaf_nodes_; bool just_update_well_targets_; + bool having_vrep_groups_; }; diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 5ce8a978..8dd9766f 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -563,6 +563,18 @@ namespace Opm return; } case InjectionSpecification::VREP: + { + // really not sure whether to give a initialized target will be a good idea. It can cause the initial guess too far + // from the reasonable result and numerical convergence failure. + // Let us try to see what will happen. We begin with 100 / day, which is about 0.001. + // const double my_guide_rate = injectionGuideRate(false); + + /* for (size_t i = 0; i < children_.size(); ++i) { + const double children_guide_rate = children_[i] -> injectionGuideRate(false); + children_[i]->applyInjGroupControl(, inj_type, + (children_guide_rate / my_guide_rate) * target / efficiencyFactor(), true); + } */ + } case InjectionSpecification::REIN: std::cout << "Replacement keywords found, remember to call applyExplicitReinjectionControls." << std::endl; return; @@ -624,6 +636,16 @@ namespace Opm return sum; } + + double WellsGroup::getTotalVoidageRate(const std::vector& well_voidage_rates) + { + double sum = 0.0; + for (size_t i = 0; i < children_.size(); ++i) { + sum += children_[i]->getTotalVoidageRate(well_voidage_rates); + } + return sum; + } + /// Applies explicit reinjection controls. This must be called at each timestep to be correct. /// \param[in] well_reservoirrates_phase /// A vector containing reservoir rates by phase for each well. @@ -687,16 +709,73 @@ namespace Opm // Apply for all children. // Note, we do _not_ want to call the applyProdGroupControl in this object, // as that would check if we're under group control, something we're not. - const double children_guide_rate = children_[i]->injectionGuideRate(true); + const double children_guide_rate = children_[i]->injectionGuideRate(false); children_[i]->applyInjGroupControl(InjectionSpecification::RESV, injector_type, (children_guide_rate / my_guide_rate) * total_reinjected * injSpec().voidage_replacment_fraction_, - true); + false); } } } + void WellsGroup::applyVREPGroupControls(const std::vector& well_voidage_rates, + const std::vector& conversion_coeffs) + { + const InjectionSpecification::ControlMode inj_mode = injSpec().control_mode_; + switch (inj_mode) { + case InjectionSpecification::VREP: + { + const double total_reinjected = getTotalVoidageRate(well_voidage_rates); + // TODO: we might need the reservoir condition well potentials here + const double my_guide_rate = injectionGuideRate(false); + for (size_t i = 0; i < children_.size(); ++i ) { + const double child_guide_rate = children_[i]->injectionGuideRate(false); + const double child_target = child_guide_rate / my_guide_rate * total_reinjected * injSpec().voidage_replacment_fraction_; + children_[i]->applyVREPGroupControl(child_target, well_voidage_rates, conversion_coeffs, false); + } + } + break; + default: + { + for (size_t i = 0; i < children_.size(); ++i ) { + children_[i]->applyVREPGroupControls(well_voidage_rates, conversion_coeffs); + } + } + } + } + + + // TODO: actually, it is not tested since it never get into this function. + void WellsGroup::applyVREPGroupControl(const double target, + const std::vector& well_voidage_rates, + const std::vector& conversion_coeffs, + const bool only_group) + { + if (injSpec().control_mode_ == InjectionSpecification::NONE) { + // TODO: for multiple level of group control, it can be wrong to return here. + return; + } + + // TODO: this condition will eventually be wrong. + if (!only_group || injSpec().control_mode_ == InjectionSpecification::FLD) { + // We should provide the well potentials under reservoir condition. + const double my_guide_rate = injectionGuideRate(only_group); + if (my_guide_rate == 0.0) { + // TODO: might not should return here + // Nothing to do here + return; + } + for (size_t i = 0; i < children_.size(); ++i) { + const double child_target = target * children_[i]->injectionGuideRate(only_group) / my_guide_rate; + children_[i]->applyVREPGroupControl(child_target, well_voidage_rates, conversion_coeffs, false); + } + // I do not know why here. + injSpec().control_mode_ = InjectionSpecification::FLD; + } + } + + void WellsGroup::updateWellProductionTargets(const std::vector& well_rates) { // TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells @@ -957,7 +1036,7 @@ namespace Opm const bool only_group) { if ( !isInjector() ) { - assert(target == 0.0); + // assert(target == 0.0); return; } @@ -1019,7 +1098,7 @@ namespace Opm well_controls_iset_distr(wells_->ctrls[self_index_] , group_control_index_ , distr); } set_current_control(self_index_, group_control_index_, wells_); - // TODO: it might always be the case + // TODO: it might not always be the case setIndividualControl(false); } @@ -1039,6 +1118,15 @@ namespace Opm return phase_flows[self_index_*phaseUsage().num_phases + phaseUsage().phase_pos[phase]]; } + double WellNode::getTotalVoidageRate(const std::vector& well_voidage_rates) + { + if (isProducer()) { + return well_voidage_rates[self_index_]; + } else { + return 0; + } + } + WellType WellNode::type() const { return wells_->type[self_index_]; } @@ -1057,6 +1145,63 @@ namespace Opm { // Do nothing at well level. } + + + void WellNode::applyVREPGroupControls(const std::vector&, + const std::vector&) + { + // It is the end, nothing should be done here. + } + + void WellNode::applyVREPGroupControl(const double target, + const std::vector& /*well_voidage_rates*/, + const std::vector& conversion_coeffs, + const bool only_group) + { + if (!isInjector()) { + return; + } + + if (only_group && individualControl()) { + return; + } + + const int np = phaseUsage().num_phases; + // WellControls* ctrl = wells_->ctrls[self_index_]; + // for this case, distr contains the FVF information + // which results in the previous implementation of RESV keywords. + std::vector distr(np); + std::copy(conversion_coeffs.begin() + np * self_index_, + conversion_coeffs.begin() + np * (self_index_ + 1), + distr.begin()); + + + const double invalid_alq = -std::numeric_limits::max(); + const int invalid_vfp = -std::numeric_limits::max(); + + if (group_control_index_ < 0) { + append_well_controls(RESERVOIR_RATE, target, invalid_alq, invalid_vfp, &distr[0], self_index_, wells_); + // TODO: basically, on group control index is not enough eventually. There can be more than one sources for the + // group control + group_control_index_ = well_controls_get_num(wells_->ctrls[self_index_]) - 1; + } else { + well_controls_iset_type(wells_->ctrls[self_index_] , group_control_index_ , RESERVOIR_RATE); + well_controls_iset_target(wells_->ctrls[self_index_] , group_control_index_ , target); + well_controls_iset_alq(wells_->ctrls[self_index_] , group_control_index_ , -1e100); + well_controls_iset_distr(wells_->ctrls[self_index_] , group_control_index_ , &distr[0]); + } + + // the way in computeRESV from the SimulatorBase + // looks like they specify the control already, while without giving the distr. + // The target will look like alreay there. + // Here, we should create a new control here. + // In theory, there can be more than one RESV controls and more than one other same types of control, + // which will really mess up the multi-layer controls. + // When we update them the next time, we need to find this control then update the distr and target instead of adding one + // Basically, we need to store the control and the source of the control (from which group or the well, so we can still + // identify them and update the value later in case we specify the same control with different value again) + } + void WellNode::applyProdGroupControl(const ProductionSpecification::ControlMode control_mode, const double target, const bool only_group) diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 88d84cc4..fbdb5217 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -206,6 +206,17 @@ namespace Opm virtual void applyExplicitReinjectionControls(const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase) = 0; + /// TODO: prototyping a VREP enforcement function. + virtual void applyVREPGroupControls(const std::vector& well_voidage_rates, + const std::vector& conversion_coeffs) = 0; + + virtual void applyVREPGroupControl(const double target, + const std::vector& well_voidage_rates, + const std::vector& conversion_coeffs, + const bool only_group) = 0; + + virtual double getTotalVoidageRate(const std::vector& well_voidage_rates) = 0; + /// Return whether the well is running under group control target /// or under their own limit. /// True under their own limit. @@ -351,6 +362,17 @@ namespace Opm virtual void applyExplicitReinjectionControls(const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase); + /// TODO: prototyping a VREP enforcement function. + virtual void applyVREPGroupControls(const std::vector& well_voidage_rates, + const std::vector& conversion_coeffs); + + virtual void applyVREPGroupControl(const double target, + const std::vector& well_voidage_rates, + const std::vector& conversion_coeffs, + const bool only_group); + + virtual double getTotalVoidageRate(const std::vector& well_voidage_rates); + virtual void updateWellProductionTargets(const std::vector& well_rates); virtual void updateWellInjectionTargets(const std::vector& well_rates); @@ -459,6 +481,18 @@ namespace Opm /// with all phase rates of a single well adjacent in the array. virtual void applyExplicitReinjectionControls(const std::vector& well_reservoirrates_phase, const std::vector& well_surfacerates_phase); + + /// TODO: prototyping a VREP enforcement function. + virtual void applyVREPGroupControls(const std::vector& well_voidage_rates, + const std::vector& conversion_coeffs); + + virtual void applyVREPGroupControl(const double target, + const std::vector& well_voidage_rates, + const std::vector& conversion_coeffs, + const bool only_group); + + virtual double getTotalVoidageRate(const std::vector& well_voidage_rates); + int groupControlIndex() const; virtual bool isProducer() const; diff --git a/opm/core/wells/WellsManager_impl.hpp b/opm/core/wells/WellsManager_impl.hpp index 7bae00e8..3e301416 100644 --- a/opm/core/wells/WellsManager_impl.hpp +++ b/opm/core/wells/WellsManager_impl.hpp @@ -409,6 +409,7 @@ WellsManager::init(const Opm::EclipseState& eclipseState, const auto& fieldGroup = schedule.getGroup(fieldNode->name()); + well_collection_.setHavingVREPGroups(false); well_collection_.addField(fieldGroup, timeStep, pu); addChildGroups(*fieldNode, schedule, timeStep, pu); well_collection_.setJustUpdateWellTargets(false); From 3e8b1bdb82fb0b8f06dabc79ad79e713b985f274 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 31 Oct 2016 16:50:12 +0100 Subject: [PATCH 28/37] applying the efficiency factor to VREP control. --- opm/core/wells/WellsGroup.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 8dd9766f..4975a05f 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -643,7 +643,7 @@ namespace Opm for (size_t i = 0; i < children_.size(); ++i) { sum += children_[i]->getTotalVoidageRate(well_voidage_rates); } - return sum; + return sum * efficiencyFactor(); } /// Applies explicit reinjection controls. This must be called at each timestep to be correct. @@ -731,7 +731,8 @@ namespace Opm const double my_guide_rate = injectionGuideRate(false); for (size_t i = 0; i < children_.size(); ++i ) { const double child_guide_rate = children_[i]->injectionGuideRate(false); - const double child_target = child_guide_rate / my_guide_rate * total_reinjected * injSpec().voidage_replacment_fraction_; + const double child_target = child_guide_rate / my_guide_rate * total_reinjected / efficiencyFactor() + * injSpec().voidage_replacment_fraction_; children_[i]->applyVREPGroupControl(child_target, well_voidage_rates, conversion_coeffs, false); } } @@ -767,7 +768,7 @@ namespace Opm return; } for (size_t i = 0; i < children_.size(); ++i) { - const double child_target = target * children_[i]->injectionGuideRate(only_group) / my_guide_rate; + const double child_target = target / efficiencyFactor() * children_[i]->injectionGuideRate(only_group) / my_guide_rate; children_[i]->applyVREPGroupControl(child_target, well_voidage_rates, conversion_coeffs, false); } // I do not know why here. @@ -1121,7 +1122,7 @@ namespace Opm double WellNode::getTotalVoidageRate(const std::vector& well_voidage_rates) { if (isProducer()) { - return well_voidage_rates[self_index_]; + return well_voidage_rates[self_index_] * efficiencyFactor(); } else { return 0; } @@ -1166,6 +1167,9 @@ namespace Opm return; } + // applying the efficiency factor + const double ntarget = target / efficiencyFactor(); + const int np = phaseUsage().num_phases; // WellControls* ctrl = wells_->ctrls[self_index_]; // for this case, distr contains the FVF information @@ -1180,13 +1184,13 @@ namespace Opm const int invalid_vfp = -std::numeric_limits::max(); if (group_control_index_ < 0) { - append_well_controls(RESERVOIR_RATE, target, invalid_alq, invalid_vfp, &distr[0], self_index_, wells_); + append_well_controls(RESERVOIR_RATE, ntarget, invalid_alq, invalid_vfp, &distr[0], self_index_, wells_); // TODO: basically, on group control index is not enough eventually. There can be more than one sources for the // group control group_control_index_ = well_controls_get_num(wells_->ctrls[self_index_]) - 1; } else { well_controls_iset_type(wells_->ctrls[self_index_] , group_control_index_ , RESERVOIR_RATE); - well_controls_iset_target(wells_->ctrls[self_index_] , group_control_index_ , target); + well_controls_iset_target(wells_->ctrls[self_index_] , group_control_index_ , ntarget); well_controls_iset_alq(wells_->ctrls[self_index_] , group_control_index_ , -1e100); well_controls_iset_distr(wells_->ctrls[self_index_] , group_control_index_ , &distr[0]); } From b319e1a75d95b2106e54261b62669139c43e2cf8 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 2 Nov 2016 13:53:30 +0100 Subject: [PATCH 29/37] cleaning up and adding more comments for better understanding. No functional change. --- opm/core/wells/WellCollection.cpp | 8 +++++++- opm/core/wells/WellCollection.hpp | 19 ++++++++++++++----- opm/core/wells/WellsGroup.cpp | 27 +++------------------------ 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index a8675f75..d94aa947 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -204,7 +204,7 @@ namespace Opm } - //TODO: later, it should be extended to update group targets + // TODO: later, it should be extended to update group targets bool WellCollection::needUpdateWellTargets() const { return needUpdateInjectionTargets() || needUpdateProductionTargets(); @@ -213,6 +213,9 @@ namespace Opm bool WellCollection::needUpdateInjectionTargets() const { + // TODO: it should based on individual group + // With current approach, it will potentially result in more update, + // thus more iterations, while it will not cause result wrong. bool any_group_control_node = false; bool any_should_update_node = false; @@ -233,6 +236,9 @@ namespace Opm bool WellCollection::needUpdateProductionTargets() const { + // TODO: it should based on individual group + // With current approach, it will potentially result in more update, + // thus more iterations, while it will not cause result wrong. bool any_group_control_node = false; bool any_should_update_node = false; diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index 3c8b5f73..b98d992f 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -111,33 +111,42 @@ namespace Opm const std::vector& well_surfacerates_phase); - // TODO: should have tried to use the above applyExplicitReinjectionControls - // For prototyping, make a new function here at the moment. + /// applying VREP group control based on calculated voidage rates void applyVREPGroupControls(const std::vector& well_voidage_rates, const std::vector& conversion_coeffs); - /// Checking whehter need to update the targets of the wells / or the groups later + /// Checking whether need to update the targets of the wells / or the groups later /// True need to update well targets within this iteration, no switching control within this iteration. /// False no need to update well targets within this iteration, continuing as usual. - /// TODO: currently return true whenever a wellNode needs to be updated. Later some more sophiscated - /// strategy might be required. bool needUpdateWellTargets() const; + /// Checking whether need to update the targets for the injection wells. bool needUpdateInjectionTargets() const; + + /// Checking whehter need to update the targets for the production wells. bool needUpdateProductionTargets() const; + /// Number of the well nodes. size_t numNode() const; + /// Getting the ith well node. WellNode* getNode(size_t i) const; + /// Updating the well targets based on the well rates. void updateWellTargets(const std::vector well_rates); + /// True right after updating the well targets due to wells switching between individual control and group control. + /// It is used to force the simulation continue for another iteration in case that update the well targets are updated, + /// at the same time, the simulation is ended because of achieving the convergence with previous well targets. bool justUpdateWellTargets() const; + /// Setting the value for just_update_well_targets_ void setJustUpdateWellTargets(const bool flag); + /// When we have VREP group, we need to update the targets based on the updated production voidage rates for each iteration. bool havingVREPGroups() const; + /// Setting the VREP group flag when creating the well collection. void setHavingVREPGroups(const bool vrep); private: diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 4975a05f..6562c4da 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -538,23 +538,14 @@ namespace Opm InjectionSpecification::InjectorType inj_type = injSpec().injector_type_; switch (inj_mode) { case InjectionSpecification::RATE: - // need to be careful in the future. - // pay attention to the phase under control and the phase for the guide rate - // they can be different, and more delicate situatioin can happen here. case InjectionSpecification::RESV: { - // very hacky way here. - // The logic of the code is that only a well is specified under GRUP control, it is under group control. - // Which is not the case observed from the result. - // From the result, if we specify group control with GCONPROD and WCONPROD for a well, it looks like - // the well will be under group control. - // TODO: make the logic correct here instead of using `false here`. + // all the wells will be assinged a group control target. + // TODO: when we consider WGRUPCON and well groups not responding to higher level group control const double my_guide_rate = injectionGuideRate(false); for (size_t i = 0; i < children_.size(); ++i) { - // Apply for all children. - // Note, we do _not_ want to call the applyProdGroupControl in this object, - // as that would check if we're under group control, something we're not. + // Apply group control to all children. const double children_guide_rate = children_[i]->injectionGuideRate(false); children_[i]->applyInjGroupControl(inj_mode, inj_type, (children_guide_rate / my_guide_rate) * getTarget(inj_mode) / efficiencyFactor(), @@ -563,18 +554,6 @@ namespace Opm return; } case InjectionSpecification::VREP: - { - // really not sure whether to give a initialized target will be a good idea. It can cause the initial guess too far - // from the reasonable result and numerical convergence failure. - // Let us try to see what will happen. We begin with 100 / day, which is about 0.001. - // const double my_guide_rate = injectionGuideRate(false); - - /* for (size_t i = 0; i < children_.size(); ++i) { - const double children_guide_rate = children_[i] -> injectionGuideRate(false); - children_[i]->applyInjGroupControl(, inj_type, - (children_guide_rate / my_guide_rate) * target / efficiencyFactor(), true); - } */ - } case InjectionSpecification::REIN: std::cout << "Replacement keywords found, remember to call applyExplicitReinjectionControls." << std::endl; return; From 085785bf26de99e12c2405537c7b7f59dc28b3ae Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 3 Nov 2016 13:12:12 +0100 Subject: [PATCH 30/37] adding function findWellNode() to WellCollection to return the WellNode* instead of WellGroupInterface* --- opm/core/wells/WellCollection.cpp | 15 +++++++++++++++ opm/core/wells/WellCollection.hpp | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index d94aa947..720282d4 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -116,6 +116,21 @@ namespace Opm return NULL; } + + WellNode* WellCollection::findWellNode(const std::string& name) const + { + auto well_node = std::find_if(leaf_nodes_.begin(), leaf_nodes_.end(), + [&] ( WellNode* w) { + return w->name() == name; + }); + + if (well_node != leaf_nodes_.end()) { + return *well_node; + } else { + return nullptr; + } + } + /// Adds the child to the collection /// and appends it to parent's children. /// \param[in] child the child node diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index b98d992f..d4ac7d70 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -95,6 +95,10 @@ namespace Opm /// \return the pointer to the group if found, NULL otherwise const WellsGroupInterface* findNode(const std::string& name) const; + + WellNode* findWellNode(const std::string& name) const; + + /// Applies all group controls (injection and production) void applyGroupControls(); From 95997e208ccc9c979c917ffce3d835c46548c591 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 4 Nov 2016 13:37:50 +0100 Subject: [PATCH 31/37] different strategy is using when updating the well targets When the group has wells both under individual control and group control, since the well rates under individual control changes each iteration, the well targets for this kind of group need to be updated each iteration. When we change to use implicit well potentials later, which is supposed to be more accurate, we probably should always (unless we decided not to) update the well targets each iteration. --- opm/core/wells/WellCollection.cpp | 42 +++++++++++----------------- opm/core/wells/WellCollection.hpp | 8 ------ opm/core/wells/WellsGroup.cpp | 16 +++++++---- opm/core/wells/WellsGroup.hpp | 2 ++ opm/core/wells/WellsManager_impl.hpp | 1 - 5 files changed, 29 insertions(+), 40 deletions(-) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 720282d4..5305f1f2 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -231,45 +231,47 @@ namespace Opm // TODO: it should based on individual group // With current approach, it will potentially result in more update, // thus more iterations, while it will not cause result wrong. + // If the group control and individual control is mixed, then it need to + // update the well targets bool any_group_control_node = false; - bool any_should_update_node = false; + bool any_individual_control_node = false; for (size_t i = 0; i < leaf_nodes_.size(); ++i) { if (leaf_nodes_[i]->isInjector()) { - if (leaf_nodes_[i]->shouldUpdateWellTargets()) { - any_should_update_node = true; - } - - if (!leaf_nodes_[i]->individualControl()) { + if (leaf_nodes_[i]->individualControl()) { + any_individual_control_node = true; + } else { any_group_control_node = true; } } } - return (any_group_control_node && any_should_update_node); + return (any_group_control_node && any_individual_control_node); } + + // These two functions should be made one bool WellCollection::needUpdateProductionTargets() const { // TODO: it should based on individual group // With current approach, it will potentially result in more update, // thus more iterations, while it will not cause result wrong. + // If the group control and individual control is mixed, then it need to + // update the well targets bool any_group_control_node = false; - bool any_should_update_node = false; + bool any_individual_control_node = false; for (size_t i = 0; i < leaf_nodes_.size(); ++i) { if (leaf_nodes_[i]->isProducer()) { - if (leaf_nodes_[i]->shouldUpdateWellTargets()) { - any_should_update_node = true; - } - - if (!leaf_nodes_[i]->individualControl()) { + if (leaf_nodes_[i]->individualControl()) { + any_individual_control_node = true; + } else { any_group_control_node = true; } } } - return (any_group_control_node && any_should_update_node); + return (any_group_control_node && any_individual_control_node); } @@ -286,16 +288,6 @@ namespace Opm return leaf_nodes_[i]; } - bool WellCollection::justUpdateWellTargets() const - { - return just_update_well_targets_; - } - - void WellCollection::setJustUpdateWellTargets(const bool flag) - { - just_update_well_targets_ = flag; - } - void WellCollection::updateWellTargets(const std::vector well_rates) { // TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells @@ -316,8 +308,6 @@ namespace Opm } } } - - setJustUpdateWellTargets(true); } bool WellCollection::havingVREPGroups() const { diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index d4ac7d70..1a6b6195 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -139,14 +139,6 @@ namespace Opm /// Updating the well targets based on the well rates. void updateWellTargets(const std::vector well_rates); - /// True right after updating the well targets due to wells switching between individual control and group control. - /// It is used to force the simulation continue for another iteration in case that update the well targets are updated, - /// at the same time, the simulation is ended because of achieving the convergence with previous well targets. - bool justUpdateWellTargets() const; - - /// Setting the value for just_update_well_targets_ - void setJustUpdateWellTargets(const bool flag); - /// When we have VREP group, we need to update the targets based on the updated production voidage rates for each iteration. bool havingVREPGroups() const; diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index 6562c4da..fdc342a0 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -555,7 +555,6 @@ namespace Opm } case InjectionSpecification::VREP: case InjectionSpecification::REIN: - std::cout << "Replacement keywords found, remember to call applyExplicitReinjectionControls." << std::endl; return; case InjectionSpecification::FLD: case InjectionSpecification::NONE: @@ -1069,6 +1068,8 @@ namespace Opm // The well only had its own controls, no group controls. append_well_controls(wct, effective_target, invalid_alq, invalid_vfp, distr, self_index_, wells_); group_control_index_ = well_controls_get_num(wells_->ctrls[self_index_]) - 1; + // It will possibly be changed when initializing WellState + // set_current_control(self_index_, group_control_index_, wells_); } else { // We will now modify the last control, that // "belongs to" the group control. @@ -1077,9 +1078,6 @@ namespace Opm well_controls_iset_alq(wells_->ctrls[self_index_] , group_control_index_ , -1e100); well_controls_iset_distr(wells_->ctrls[self_index_] , group_control_index_ , distr); } - set_current_control(self_index_, group_control_index_, wells_); - // TODO: it might not always be the case - setIndividualControl(false); } @@ -1167,6 +1165,8 @@ namespace Opm // TODO: basically, on group control index is not enough eventually. There can be more than one sources for the // group control group_control_index_ = well_controls_get_num(wells_->ctrls[self_index_]) - 1; + // it should only apply for nodes with GRUP injeciton control + individual_control_ = false; } else { well_controls_iset_type(wells_->ctrls[self_index_] , group_control_index_ , RESERVOIR_RATE); well_controls_iset_target(wells_->ctrls[self_index_] , group_control_index_ , ntarget); @@ -1249,6 +1249,8 @@ namespace Opm // The well only had its own controls, no group controls. append_well_controls(wct, ntarget, invalid_alq, invalid_vfp, distr, self_index_, wells_); group_control_index_ = well_controls_get_num(wells_->ctrls[self_index_]) - 1; + // It will possibly be changed when initializing WellState. + // set_current_control(self_index_, group_control_index_, wells_); } else { // We will now modify the last control, that // "belongs to" the group control. @@ -1257,7 +1259,6 @@ namespace Opm well_controls_iset_alq(wells_->ctrls[self_index_] , group_control_index_ , -1e100); well_controls_iset_distr(wells_->ctrls[self_index_] , group_control_index_ , distr); } - set_current_control(self_index_, group_control_index_, wells_); } @@ -1523,4 +1524,9 @@ namespace Opm return efficiency_factor; } + + int WellNode::selfIndex() const { + return self_index_; + } + } diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index fbdb5217..75948e4a 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -510,6 +510,8 @@ namespace Opm /// to the well in a multi-layer group structure. double getAccumulativeEfficiencyFactor() const; + int selfIndex() const; + private: Wells* wells_; int self_index_; diff --git a/opm/core/wells/WellsManager_impl.hpp b/opm/core/wells/WellsManager_impl.hpp index 3e301416..17667710 100644 --- a/opm/core/wells/WellsManager_impl.hpp +++ b/opm/core/wells/WellsManager_impl.hpp @@ -412,7 +412,6 @@ WellsManager::init(const Opm::EclipseState& eclipseState, well_collection_.setHavingVREPGroups(false); well_collection_.addField(fieldGroup, timeStep, pu); addChildGroups(*fieldNode, schedule, timeStep, pu); - well_collection_.setJustUpdateWellTargets(false); } for (auto w = wells.begin(), e = wells.end(); w != e; ++w) { From 91b8c872eb0856ee8a2da4c31d02b0f610bbcf7f Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 10 Nov 2016 17:50:30 +0100 Subject: [PATCH 32/37] removing a few not-used function with the new strategy. --- opm/core/wells/WellsGroup.cpp | 18 ------------------ opm/core/wells/WellsGroup.hpp | 4 ---- 2 files changed, 22 deletions(-) diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index fdc342a0..fc7358a0 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -238,18 +238,6 @@ namespace Opm return target; } - - bool WellsGroupInterface::shouldUpdateWellTargets() const - { - return should_update_well_targets_; - } - - - void WellsGroupInterface::setShouldUpdateWellTargets(const bool should_update_well_targets) - { - should_update_well_targets_ = should_update_well_targets; - } - bool WellsGroupInterface::individualControl() const { return individual_control_; @@ -805,7 +793,6 @@ namespace Opm if (!children_[i]->individualControl() && children_[i]->isProducer()) { const double children_guide_rate = children_[i]->productionGuideRate(true); children_[i]->applyProdGroupControl(prod_mode, (children_guide_rate / my_guide_rate) * rate_for_group_control, true); - children_[i]->setShouldUpdateWellTargets(false); } } } @@ -814,11 +801,6 @@ namespace Opm { // NOT doing anything yet. // Will finish it when having an examples with more than one injection wells within same injection group. - for (size_t i = 0; i < children_.size(); ++i) { - if (!children_[i]->individualControl() && children_[i]->isInjector()) { - children_[i]->setShouldUpdateWellTargets(false); - } - } } diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 75948e4a..0cf9fa39 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -226,10 +226,6 @@ namespace Opm /// Update the status for individual contrl void setIndividualControl(const bool); - virtual bool shouldUpdateWellTargets() const; - - virtual void setShouldUpdateWellTargets(const bool); - /// Whether it is a production well /// Should only appy for WellNode virtual bool isProducer() const = 0; From f9f5bacee45acf6e0b59009ef068e1eb44f4b1af Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 11 Nov 2016 11:29:12 +0100 Subject: [PATCH 33/37] cleaning up more unused flag from WellsGroup --- opm/core/wells/WellCollection.hpp | 1 - opm/core/wells/WellsGroup.cpp | 3 +-- opm/core/wells/WellsGroup.hpp | 3 --- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index 1a6b6195..77662e6c 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -152,7 +152,6 @@ namespace Opm // This will be used to traverse the bottom nodes. std::vector leaf_nodes_; - bool just_update_well_targets_; bool having_vrep_groups_; diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index fc7358a0..b307e39d 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -66,7 +66,6 @@ namespace Opm const InjectionSpecification& inje_spec, const PhaseUsage& phase_usage) : parent_(NULL), - should_update_well_targets_(false), individual_control_(true), // always begin with individual control efficiency_factor_(efficiency_factor), name_(myname), @@ -1144,7 +1143,7 @@ namespace Opm if (group_control_index_ < 0) { append_well_controls(RESERVOIR_RATE, ntarget, invalid_alq, invalid_vfp, &distr[0], self_index_, wells_); - // TODO: basically, on group control index is not enough eventually. There can be more than one sources for the + // TODO: basically, one group control index is not enough eventually. There can be more than one sources for the // group control group_control_index_ = well_controls_get_num(wells_->ctrls[self_index_]) - 1; // it should only apply for nodes with GRUP injeciton control diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 0cf9fa39..984be04c 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -258,9 +258,6 @@ namespace Opm WellsGroupInterface* parent_; - // when some well (mabye group also later), change status from group control - // to individual control, or the other way, the targets for the wells in the group need to be redistributed. - bool should_update_well_targets_; // Whether well is running under the group control target. // Current only consider one level of control. // So not putting it in the WellsGroupInterface yet. From 55eec0b2ed35effbe2a3e950fea9197b7d9c8634 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Tue, 15 Nov 2016 13:56:49 +0100 Subject: [PATCH 34/37] checking whehter need to update before updateWellTargets. --- opm/core/wells/WellCollection.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 5305f1f2..651f5339 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -290,6 +290,10 @@ namespace Opm void WellCollection::updateWellTargets(const std::vector well_rates) { + if ( !needUpdateWellTargets() ) { + return; + } + // TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells // We believe the relations between groups are similar to the relations between different wells inside the same group. // While there will be somre more complication invloved for sure. From bf2f9b3f06e462aec7a9b89982ad883e98c36b1e Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Tue, 15 Nov 2016 14:36:19 +0100 Subject: [PATCH 35/37] adding target_updated_ flag to WellNode to save some repeated efforts when updating Well Targets. --- opm/core/wells/WellCollection.cpp | 7 ++++++- opm/core/wells/WellsGroup.cpp | 19 ++++++++++++++++++- opm/core/wells/WellsGroup.hpp | 10 ++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 651f5339..095d1763 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -294,13 +294,18 @@ namespace Opm return; } + // set the target_updated to be false + for (WellNode* well_node : leaf_nodes_) { + well_node->setTargetUpdated(false); + } + // TODO: currently, we only handle the level of the well groups for the moment, i.e. the level just above wells // We believe the relations between groups are similar to the relations between different wells inside the same group. // While there will be somre more complication invloved for sure. for (size_t i = 0; i < leaf_nodes_.size(); ++i) { // find a node needs to update targets, then update targets for all the wellls inside the group. // if (leaf_nodes_[i]->shouldUpdateWellTargets() && !leaf_nodes_[i]->individualControl()) { - if (!leaf_nodes_[i]->individualControl()) { + if (!leaf_nodes_[i]->individualControl() && !leaf_nodes_[i]->targetUpdated()) { WellsGroupInterface* parent_node = leaf_nodes_[i]->getParent(); // update the target within this group. if (leaf_nodes_[i]->isProducer()) { diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index b307e39d..da3bac84 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -792,6 +792,7 @@ namespace Opm if (!children_[i]->individualControl() && children_[i]->isProducer()) { const double children_guide_rate = children_[i]->productionGuideRate(true); children_[i]->applyProdGroupControl(prod_mode, (children_guide_rate / my_guide_rate) * rate_for_group_control, true); + children_[i]->setTargetUpdated(true); } } } @@ -802,6 +803,11 @@ namespace Opm // Will finish it when having an examples with more than one injection wells within same injection group. } + void WellsGroup::setTargetUpdated(const bool /* flag */) + { + // do nothing + } + bool WellsGroup::isProducer() const { @@ -833,7 +839,8 @@ namespace Opm wells_(0), self_index_(-1), group_control_index_(-1), - shut_well_(true) // This is default for now + shut_well_(true), // This is default for now + target_updated_(false) // This is default for now, not sure whether to use the default value { } @@ -1510,4 +1517,14 @@ namespace Opm return self_index_; } + + bool WellNode::targetUpdated() const { + return target_updated_; + } + + + void WellNode::setTargetUpdated(const bool flag) { + target_updated_ = flag; + } + } diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 984be04c..6f3c6c11 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -241,6 +241,8 @@ namespace Opm virtual void updateWellInjectionTargets(const std::vector& well_rates) = 0; + virtual void setTargetUpdated(const bool flag) = 0; + double efficiencyFactor() const; void setEfficiencyFactor(const double efficiency_factor); @@ -370,6 +372,8 @@ namespace Opm virtual void updateWellInjectionTargets(const std::vector& well_rates); + virtual void setTargetUpdated(const bool flag); + /// Whether it is a production well /// Should only appy for WellNode virtual bool isProducer() const; @@ -505,11 +509,17 @@ namespace Opm int selfIndex() const; + bool targetUpdated() const; + + virtual void setTargetUpdated(const bool flag); + private: Wells* wells_; int self_index_; int group_control_index_; bool shut_well_; + // TODO: used when updating well targets + bool target_updated_; }; /// Creates the WellsGroupInterface for the given well From 708bfd169b3641b844e2a816ba84e6e5c65daa14 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 16 Nov 2016 09:51:06 +0100 Subject: [PATCH 36/37] addressing a few comments. --- opm/core/wells/WellCollection.cpp | 6 +----- opm/core/wells/WellCollection.hpp | 7 ++----- opm/core/wells/WellsManager_impl.hpp | 1 - 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 095d1763..1a21bd87 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -288,7 +288,7 @@ namespace Opm return leaf_nodes_[i]; } - void WellCollection::updateWellTargets(const std::vector well_rates) + void WellCollection::updateWellTargets(const std::vector& well_rates) { if ( !needUpdateWellTargets() ) { return; @@ -323,8 +323,4 @@ namespace Opm return having_vrep_groups_; } - void WellCollection::setHavingVREPGroups(const bool vrep) { - having_vrep_groups_ = vrep; - } - } diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index 77662e6c..b4018db3 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -137,14 +137,11 @@ namespace Opm WellNode* getNode(size_t i) const; /// Updating the well targets based on the well rates. - void updateWellTargets(const std::vector well_rates); + void updateWellTargets(const std::vector& well_rates); /// When we have VREP group, we need to update the targets based on the updated production voidage rates for each iteration. bool havingVREPGroups() const; - /// Setting the VREP group flag when creating the well collection. - void setHavingVREPGroups(const bool vrep); - private: // To account for the possibility of a forest std::vector > roots_; @@ -152,7 +149,7 @@ namespace Opm // This will be used to traverse the bottom nodes. std::vector leaf_nodes_; - bool having_vrep_groups_; + bool having_vrep_groups_ = false; }; diff --git a/opm/core/wells/WellsManager_impl.hpp b/opm/core/wells/WellsManager_impl.hpp index 17667710..b6fd9e2c 100644 --- a/opm/core/wells/WellsManager_impl.hpp +++ b/opm/core/wells/WellsManager_impl.hpp @@ -409,7 +409,6 @@ WellsManager::init(const Opm::EclipseState& eclipseState, const auto& fieldGroup = schedule.getGroup(fieldNode->name()); - well_collection_.setHavingVREPGroups(false); well_collection_.addField(fieldGroup, timeStep, pu); addChildGroups(*fieldNode, schedule, timeStep, pu); } From c3b00dc7fde23304a473f38fcd7ab60759da6b72 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 16 Nov 2016 11:40:10 +0100 Subject: [PATCH 37/37] fixing the comments. No change in the functions and results. --- opm/core/wells/WellCollection.cpp | 14 +------------- opm/core/wells/WellCollection.hpp | 6 ------ opm/core/wells/WellsGroup.cpp | 30 +++++++++++------------------- opm/core/wells/WellsGroup.hpp | 24 ++++-------------------- 4 files changed, 16 insertions(+), 58 deletions(-) diff --git a/opm/core/wells/WellCollection.cpp b/opm/core/wells/WellCollection.cpp index 1a21bd87..bd4f250e 100644 --- a/opm/core/wells/WellCollection.cpp +++ b/opm/core/wells/WellCollection.cpp @@ -275,19 +275,6 @@ namespace Opm } - - size_t WellCollection::numNode() const - { - return leaf_nodes_.size(); - } - - - WellNode* WellCollection::getNode(size_t i) const - { - assert( i< numNode()); - return leaf_nodes_[i]; - } - void WellCollection::updateWellTargets(const std::vector& well_rates) { if ( !needUpdateWellTargets() ) { @@ -319,6 +306,7 @@ namespace Opm } } + bool WellCollection::havingVREPGroups() const { return having_vrep_groups_; } diff --git a/opm/core/wells/WellCollection.hpp b/opm/core/wells/WellCollection.hpp index b4018db3..32b05e81 100644 --- a/opm/core/wells/WellCollection.hpp +++ b/opm/core/wells/WellCollection.hpp @@ -130,12 +130,6 @@ namespace Opm /// Checking whehter need to update the targets for the production wells. bool needUpdateProductionTargets() const; - /// Number of the well nodes. - size_t numNode() const; - - /// Getting the ith well node. - WellNode* getNode(size_t i) const; - /// Updating the well targets based on the well rates. void updateWellTargets(const std::vector& well_rates); diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp index da3bac84..5912f999 100644 --- a/opm/core/wells/WellsGroup.cpp +++ b/opm/core/wells/WellsGroup.cpp @@ -778,7 +778,7 @@ namespace Opm double rate_individual_control = 0.; for (size_t i = 0; i < children_.size(); ++i) { - if (children_[i]->individualControl() && children_[i]->isProducer()) { + if (children_[i]->individualControl()) { rate_individual_control += std::abs(children_[i]->getProductionRate(well_rates, prod_mode) * children_[i]->efficiencyFactor()); } } @@ -789,7 +789,7 @@ namespace Opm const double my_guide_rate = productionGuideRate(true); for (size_t i = 0; i < children_.size(); ++i) { - if (!children_[i]->individualControl() && children_[i]->isProducer()) { + if (!children_[i]->individualControl()) { const double children_guide_rate = children_[i]->productionGuideRate(true); children_[i]->applyProdGroupControl(prod_mode, (children_guide_rate / my_guide_rate) * rate_for_group_control, true); children_[i]->setTargetUpdated(true); @@ -808,22 +808,14 @@ namespace Opm // do nothing } - - bool WellsGroup::isProducer() const + double WellsGroup::getProductionRate(const std::vector& well_rates, + const ProductionSpecification::ControlMode prod_mode) const { - return false; - } - - bool WellsGroup::isInjector() const - { - return false; - } - - double WellsGroup::getProductionRate(const std::vector& /* well_rates */, - const ProductionSpecification::ControlMode /* prod_mode */) const - { - // TODO: to be implemented - return -1.e98; + double total_production_rate = 0.0; + for (const std::shared_ptr& child_node : children_) { + total_production_rate += child_node->getProductionRate(well_rates, prod_mode); + } + return total_production_rate; } // ============== WellNode members ============ @@ -1268,7 +1260,7 @@ namespace Opm // Current understanding. Two ways might prevent to return the guide_rate here // 1. preventing the well from group control with keyword WGRUPCON // 2. the well violating some limits and working under limits. - if (!only_group || !individualControl()) { + if ( (!only_group || !individualControl()) && isProducer() ) { return prodSpec().guide_rate_; } else { return 0.0; @@ -1280,7 +1272,7 @@ namespace Opm /// wells under group control double WellNode::injectionGuideRate(bool only_group) { - if (!only_group || !individualControl()) { + if ( (!only_group || !individualControl()) && isInjector() ) { return injSpec().guide_rate_; } else { return 0.0; diff --git a/opm/core/wells/WellsGroup.hpp b/opm/core/wells/WellsGroup.hpp index 6f3c6c11..057f7151 100644 --- a/opm/core/wells/WellsGroup.hpp +++ b/opm/core/wells/WellsGroup.hpp @@ -226,14 +226,6 @@ namespace Opm /// Update the status for individual contrl void setIndividualControl(const bool); - /// Whether it is a production well - /// Should only appy for WellNode - virtual bool isProducer() const = 0; - - /// Whether it is an injection well - /// Should only appy for WellNode - virtual bool isInjector() const = 0; - virtual double getProductionRate(const std::vector& well_rates, const ProductionSpecification::ControlMode prod_mode) const = 0; @@ -374,14 +366,6 @@ namespace Opm virtual void setTargetUpdated(const bool flag); - /// Whether it is a production well - /// Should only appy for WellNode - virtual bool isProducer() const; - - /// Whether it is an injection well - /// Should only appy for WellNode - virtual bool isInjector() const; - virtual double getProductionRate(const std::vector& well_rates, const ProductionSpecification::ControlMode prod_mode) const; @@ -492,10 +476,6 @@ namespace Opm int groupControlIndex() const; - virtual bool isProducer() const; - - virtual bool isInjector() const; - virtual double getProductionRate(const std::vector& well_rates, const ProductionSpecification::ControlMode prod_mode) const; @@ -507,6 +487,10 @@ namespace Opm /// to the well in a multi-layer group structure. double getAccumulativeEfficiencyFactor() const; + bool isProducer() const; + + bool isInjector() const; + int selfIndex() const; bool targetUpdated() const;