Merge pull request #1088 from GitPaean/group_control
group control_updating well production targets within a group.
This commit is contained in:
commit
c901e2ec7c
@ -82,6 +82,7 @@ namespace Opm
|
|||||||
case GuideRateType::OIL : return "OIL" ;
|
case GuideRateType::OIL : return "OIL" ;
|
||||||
case GuideRateType::GAS : return "GAS" ;
|
case GuideRateType::GAS : return "GAS" ;
|
||||||
case GuideRateType::WATER : return "WATER" ;
|
case GuideRateType::WATER : return "WATER" ;
|
||||||
|
case GuideRateType::LIQ : return "LIQ" ;
|
||||||
case GuideRateType::NONE_GRT: return "NONE_GRT";
|
case GuideRateType::NONE_GRT: return "NONE_GRT";
|
||||||
}
|
}
|
||||||
OPM_THROW(std::domain_error, "Unknown guide rate type " << type << " encountered in production specification");
|
OPM_THROW(std::domain_error, "Unknown guide rate type " << type << " encountered in production specification");
|
||||||
|
@ -22,7 +22,7 @@ namespace Opm
|
|||||||
|
|
||||||
enum GuideRateType
|
enum GuideRateType
|
||||||
{
|
{
|
||||||
OIL, GAS, WATER, NONE_GRT
|
OIL, GAS, WATER, LIQ, NONE_GRT
|
||||||
};
|
};
|
||||||
|
|
||||||
ProductionSpecification();
|
ProductionSpecification();
|
||||||
@ -46,4 +46,3 @@ namespace Opm
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif /* OPM_PRODUCTIONSPECIFICATION_HPP */
|
#endif /* OPM_PRODUCTIONSPECIFICATION_HPP */
|
||||||
|
|
||||||
|
@ -52,6 +52,10 @@ namespace Opm
|
|||||||
|
|
||||||
std::shared_ptr<WellsGroupInterface> child = createGroupWellsGroup(groupChild, timeStep, phaseUsage);
|
std::shared_ptr<WellsGroupInterface> child = createGroupWellsGroup(groupChild, timeStep, phaseUsage);
|
||||||
|
|
||||||
|
if (child->injSpec().control_mode_ == InjectionSpecification::VREP) {
|
||||||
|
having_vrep_groups_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
WellsGroup* parent_as_group = static_cast<WellsGroup*> (parent);
|
WellsGroup* parent_as_group = static_cast<WellsGroup*> (parent);
|
||||||
if (!parent_as_group) {
|
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.");
|
OPM_THROW(std::runtime_error, "Trying to add child group to group named " << parent->name() << ", but it's not a group.");
|
||||||
@ -112,6 +116,21 @@ namespace Opm
|
|||||||
return NULL;
|
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
|
/// Adds the child to the collection
|
||||||
/// and appends it to parent's children.
|
/// and appends it to parent's children.
|
||||||
/// \param[in] child the child node
|
/// \param[in] child the child node
|
||||||
@ -189,4 +208,107 @@ namespace Opm
|
|||||||
roots_[i]->applyExplicitReinjectionControls(well_reservoirrates_phase, well_surfacerates_phase);
|
roots_[i]->applyExplicitReinjectionControls(well_reservoirrates_phase, well_surfacerates_phase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WellCollection::applyVREPGroupControls(const std::vector<double>& well_voidage_rates,
|
||||||
|
const std::vector<double>& 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
|
||||||
|
{
|
||||||
|
return needUpdateInjectionTargets() || needUpdateProductionTargets();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
// 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_individual_control_node = false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < leaf_nodes_.size(); ++i) {
|
||||||
|
if (leaf_nodes_[i]->isInjector()) {
|
||||||
|
if (leaf_nodes_[i]->individualControl()) {
|
||||||
|
any_individual_control_node = true;
|
||||||
|
} else {
|
||||||
|
any_group_control_node = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_individual_control_node = false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < leaf_nodes_.size(); ++i) {
|
||||||
|
if (leaf_nodes_[i]->isProducer()) {
|
||||||
|
if (leaf_nodes_[i]->individualControl()) {
|
||||||
|
any_individual_control_node = true;
|
||||||
|
} else {
|
||||||
|
any_group_control_node = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (any_group_control_node && any_individual_control_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WellCollection::updateWellTargets(const std::vector<double>& well_rates)
|
||||||
|
{
|
||||||
|
if ( !needUpdateWellTargets() ) {
|
||||||
|
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() && !leaf_nodes_[i]->targetUpdated()) {
|
||||||
|
WellsGroupInterface* parent_node = 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool WellCollection::havingVREPGroups() const {
|
||||||
|
return having_vrep_groups_;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,10 @@ namespace Opm
|
|||||||
/// \return the pointer to the group if found, NULL otherwise
|
/// \return the pointer to the group if found, NULL otherwise
|
||||||
const WellsGroupInterface* findNode(const std::string& name) const;
|
const WellsGroupInterface* findNode(const std::string& name) const;
|
||||||
|
|
||||||
|
|
||||||
|
WellNode* findWellNode(const std::string& name) const;
|
||||||
|
|
||||||
|
|
||||||
/// Applies all group controls (injection and production)
|
/// Applies all group controls (injection and production)
|
||||||
void applyGroupControls();
|
void applyGroupControls();
|
||||||
|
|
||||||
@ -110,6 +114,28 @@ namespace Opm
|
|||||||
void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
||||||
const std::vector<double>& well_surfacerates_phase);
|
const std::vector<double>& well_surfacerates_phase);
|
||||||
|
|
||||||
|
|
||||||
|
/// applying VREP group control based on calculated voidage rates
|
||||||
|
void applyVREPGroupControls(const std::vector<double>& well_voidage_rates,
|
||||||
|
const std::vector<double>& conversion_coeffs);
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
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;
|
||||||
|
|
||||||
|
/// Updating the well targets based on the well rates.
|
||||||
|
void updateWellTargets(const std::vector<double>& 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;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// To account for the possibility of a forest
|
// To account for the possibility of a forest
|
||||||
std::vector<std::shared_ptr<WellsGroupInterface> > roots_;
|
std::vector<std::shared_ptr<WellsGroupInterface> > roots_;
|
||||||
@ -117,9 +143,12 @@ namespace Opm
|
|||||||
// This will be used to traverse the bottom nodes.
|
// This will be used to traverse the bottom nodes.
|
||||||
std::vector<WellNode*> leaf_nodes_;
|
std::vector<WellNode*> leaf_nodes_;
|
||||||
|
|
||||||
|
bool having_vrep_groups_ = false;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Opm
|
} // namespace Opm
|
||||||
|
|
||||||
#endif /* OPM_WELLCOLLECTION_HPP */
|
#endif /* OPM_WELLCOLLECTION_HPP */
|
||||||
|
|
||||||
|
@ -61,10 +61,13 @@ namespace Opm
|
|||||||
|
|
||||||
|
|
||||||
WellsGroupInterface::WellsGroupInterface(const std::string& myname,
|
WellsGroupInterface::WellsGroupInterface(const std::string& myname,
|
||||||
|
const double efficiency_factor,
|
||||||
const ProductionSpecification& prod_spec,
|
const ProductionSpecification& prod_spec,
|
||||||
const InjectionSpecification& inje_spec,
|
const InjectionSpecification& inje_spec,
|
||||||
const PhaseUsage& phase_usage)
|
const PhaseUsage& phase_usage)
|
||||||
: parent_(NULL),
|
: parent_(NULL),
|
||||||
|
individual_control_(true), // always begin with individual control
|
||||||
|
efficiency_factor_(efficiency_factor),
|
||||||
name_(myname),
|
name_(myname),
|
||||||
production_specification_(prod_spec),
|
production_specification_(prod_spec),
|
||||||
injection_specification_(inje_spec),
|
injection_specification_(inje_spec),
|
||||||
@ -80,6 +83,12 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
return parent_;
|
return parent_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WellsGroupInterface* WellsGroupInterface::getParent()
|
||||||
|
{
|
||||||
|
return parent_;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& WellsGroupInterface::name() const
|
const std::string& WellsGroupInterface::name() const
|
||||||
{
|
{
|
||||||
return name_;
|
return name_;
|
||||||
@ -228,6 +237,25 @@ namespace Opm
|
|||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WellsGroupInterface::individualControl() const
|
||||||
|
{
|
||||||
|
return individual_control_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WellsGroupInterface::setIndividualControl(const bool individual_control)
|
||||||
|
{
|
||||||
|
individual_control_ = individual_control;
|
||||||
|
}
|
||||||
|
|
||||||
|
double WellsGroupInterface::efficiencyFactor() const
|
||||||
|
{
|
||||||
|
return efficiency_factor_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WellsGroupInterface::setEfficiencyFactor(const double efficiency_factor)
|
||||||
|
{
|
||||||
|
efficiency_factor_=efficiency_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -253,32 +281,38 @@ namespace Opm
|
|||||||
|
|
||||||
|
|
||||||
WellsGroup::WellsGroup(const std::string& myname,
|
WellsGroup::WellsGroup(const std::string& myname,
|
||||||
|
const double efficiency_factor,
|
||||||
const ProductionSpecification& prod_spec,
|
const ProductionSpecification& prod_spec,
|
||||||
const InjectionSpecification& inj_spec,
|
const InjectionSpecification& inj_spec,
|
||||||
const PhaseUsage& phase_usage)
|
const PhaseUsage& phase_usage)
|
||||||
: WellsGroupInterface(myname, prod_spec, inj_spec, phase_usage)
|
: WellsGroupInterface(myname, efficiency_factor, prod_spec, inj_spec, phase_usage)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the current active control to the provided one for all injectors within the group.
|
/// 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
|
/// After this call, the combined rate (which rate depending on control_mode) of the group
|
||||||
/// shall be equal to target.
|
/// shall be equal to target.
|
||||||
/// \param[in] forced if true, all children will be set under group control, otherwise
|
/// \param[in] only_group if true, only children that are under group control will be changed.
|
||||||
/// 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,
|
void WellsGroup::applyInjGroupControl(const InjectionSpecification::ControlMode control_mode,
|
||||||
|
const InjectionSpecification::InjectorType injector_type,
|
||||||
const double target,
|
const double target,
|
||||||
const bool forced)
|
const bool only_group)
|
||||||
{
|
{
|
||||||
if (forced || injSpec().control_mode_ == InjectionSpecification::FLD
|
if (injSpec().control_mode_ == InjectionSpecification::NONE) {
|
||||||
|| injSpec().control_mode_ == InjectionSpecification::NONE) {
|
// TODO: for multiple level of group control, it can be wrong to return here.
|
||||||
const double my_guide_rate = injectionGuideRate(!forced);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!only_group || injSpec().control_mode_ == InjectionSpecification::FLD) {
|
||||||
|
const double my_guide_rate = injectionGuideRate(only_group);
|
||||||
if (my_guide_rate == 0.0) {
|
if (my_guide_rate == 0.0) {
|
||||||
// Nothing to do here
|
// Nothing to do here
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < children_.size(); ++i) {
|
for (size_t i = 0; i < children_.size(); ++i) {
|
||||||
const double child_target = target * children_[i]->injectionGuideRate(!forced) / my_guide_rate;
|
const double child_target = target / efficiencyFactor() * children_[i]->injectionGuideRate(only_group) / my_guide_rate;
|
||||||
children_[i]->applyInjGroupControl(control_mode, child_target, true);
|
children_[i]->applyInjGroupControl(control_mode, injector_type, child_target, false);
|
||||||
}
|
}
|
||||||
injSpec().control_mode_ = InjectionSpecification::FLD;
|
injSpec().control_mode_ = InjectionSpecification::FLD;
|
||||||
}
|
}
|
||||||
@ -287,23 +321,24 @@ namespace Opm
|
|||||||
/// Sets the current active control to the provided one for all producers within the 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
|
/// After this call, the combined rate (which rate depending on control_mode) of the group
|
||||||
/// shall be equal to target.
|
/// shall be equal to target.
|
||||||
/// \param[in] forced if true, all children will be set under group control, otherwise
|
/// \param[in] only_group if true, only children that are under group control will be changed.
|
||||||
/// 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,
|
void WellsGroup::applyProdGroupControl(const ProductionSpecification::ControlMode control_mode,
|
||||||
const double target,
|
const double target,
|
||||||
const bool forced)
|
const bool only_group)
|
||||||
{
|
{
|
||||||
if (forced || (prodSpec().control_mode_ == ProductionSpecification::FLD
|
if (prodSpec().control_mode_ == ProductionSpecification::NONE) {
|
||||||
|| prodSpec().control_mode_ == ProductionSpecification::NONE)) {
|
return;
|
||||||
const double my_guide_rate = productionGuideRate(!forced);
|
}
|
||||||
|
if (!only_group || prodSpec().control_mode_ == ProductionSpecification::FLD) {
|
||||||
|
const double my_guide_rate = productionGuideRate(only_group);
|
||||||
if (my_guide_rate == 0.0) {
|
if (my_guide_rate == 0.0) {
|
||||||
// Nothing to do here
|
// Nothing to do here
|
||||||
std::cout << "returning" << std::endl;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < children_.size(); ++i) {
|
for (size_t i = 0; i < children_.size(); ++i) {
|
||||||
const double child_target = target * children_[i]->productionGuideRate(!forced) / my_guide_rate;
|
const double child_target = target / efficiencyFactor() * children_[i]->productionGuideRate(only_group) / my_guide_rate;
|
||||||
children_[i]->applyProdGroupControl(control_mode, child_target, true);
|
children_[i]->applyProdGroupControl(control_mode, child_target, only_group);
|
||||||
}
|
}
|
||||||
prodSpec().control_mode_ = ProductionSpecification::FLD;
|
prodSpec().control_mode_ = ProductionSpecification::FLD;
|
||||||
}
|
}
|
||||||
@ -315,6 +350,8 @@ namespace Opm
|
|||||||
const std::vector<double>& well_surfacerates_phase,
|
const std::vector<double>& well_surfacerates_phase,
|
||||||
WellPhasesSummed& summed_phases)
|
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.
|
// Check children's constraints recursively.
|
||||||
WellPhasesSummed child_phases_summed;
|
WellPhasesSummed child_phases_summed;
|
||||||
for (size_t i = 0; i < children_.size(); ++i) {
|
for (size_t i = 0; i < children_.size(); ++i) {
|
||||||
@ -349,7 +386,7 @@ namespace Opm
|
|||||||
+ " target not met for group " + name() + "\n"
|
+ " target not met for group " + name() + "\n"
|
||||||
+ "target = " + std::to_string(target_rate) + "\n"
|
+ "target = " + std::to_string(target_rate) + "\n"
|
||||||
+ "rate = " + std::to_string(my_rate));
|
+ "rate = " + std::to_string(my_rate));
|
||||||
applyInjGroupControl(mode, target_rate, true);
|
applyInjGroupControl(mode, injector_type, target_rate, false);
|
||||||
injSpec().control_mode_ = mode;
|
injSpec().control_mode_ = mode;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -397,10 +434,9 @@ namespace Opm
|
|||||||
production_mode_violated).first->shutWell();
|
production_mode_violated).first->shutWell();
|
||||||
return false;
|
return false;
|
||||||
case ProductionSpecification::RATE:
|
case ProductionSpecification::RATE:
|
||||||
std::cout << "Applying group control" << std::endl;
|
|
||||||
applyProdGroupControl(production_mode_violated,
|
applyProdGroupControl(production_mode_violated,
|
||||||
getTarget(production_mode_violated),
|
getTarget(production_mode_violated),
|
||||||
true);
|
false);
|
||||||
return false;
|
return false;
|
||||||
case ProductionSpecification::NONE_P:
|
case ProductionSpecification::NONE_P:
|
||||||
// Do nothing
|
// Do nothing
|
||||||
@ -455,7 +491,8 @@ namespace Opm
|
|||||||
case ProductionSpecification::LRAT:
|
case ProductionSpecification::LRAT:
|
||||||
case ProductionSpecification::RESV:
|
case ProductionSpecification::RESV:
|
||||||
{
|
{
|
||||||
const double my_guide_rate = productionGuideRate(true);
|
// const double my_guide_rate = productionGuideRate(true);
|
||||||
|
const double my_guide_rate = productionGuideRate(false);
|
||||||
if (my_guide_rate == 0) {
|
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.");
|
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.");
|
||||||
}
|
}
|
||||||
@ -463,7 +500,7 @@ namespace Opm
|
|||||||
// Apply for all children.
|
// Apply for all children.
|
||||||
// Note, we do _not_ want to call the applyProdGroupControl in this object,
|
// 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.
|
// 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_[i]->applyProdGroupControl(prod_mode,
|
||||||
(children_guide_rate / my_guide_rate) * getTarget(prod_mode),
|
(children_guide_rate / my_guide_rate) * getTarget(prod_mode),
|
||||||
false);
|
false);
|
||||||
@ -485,25 +522,26 @@ namespace Opm
|
|||||||
void WellsGroup::applyInjGroupControls()
|
void WellsGroup::applyInjGroupControls()
|
||||||
{
|
{
|
||||||
InjectionSpecification::ControlMode inj_mode = injSpec().control_mode_;
|
InjectionSpecification::ControlMode inj_mode = injSpec().control_mode_;
|
||||||
|
InjectionSpecification::InjectorType inj_type = injSpec().injector_type_;
|
||||||
switch (inj_mode) {
|
switch (inj_mode) {
|
||||||
case InjectionSpecification::RATE:
|
case InjectionSpecification::RATE:
|
||||||
case InjectionSpecification::RESV:
|
case InjectionSpecification::RESV:
|
||||||
{
|
{
|
||||||
const double my_guide_rate = injectionGuideRate(true);
|
// 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) {
|
for (size_t i = 0; i < children_.size(); ++i) {
|
||||||
// Apply for all children.
|
// Apply group control to all children.
|
||||||
// Note, we do _not_ want to call the applyProdGroupControl in this object,
|
const double children_guide_rate = children_[i]->injectionGuideRate(false);
|
||||||
// as that would check if we're under group control, something we're not.
|
children_[i]->applyInjGroupControl(inj_mode, inj_type,
|
||||||
const double children_guide_rate = children_[i]->injectionGuideRate(true);
|
(children_guide_rate / my_guide_rate) * getTarget(inj_mode) / efficiencyFactor(),
|
||||||
children_[i]->applyInjGroupControl(inj_mode,
|
|
||||||
(children_guide_rate / my_guide_rate) * getTarget(inj_mode),
|
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case InjectionSpecification::VREP:
|
case InjectionSpecification::VREP:
|
||||||
case InjectionSpecification::REIN:
|
case InjectionSpecification::REIN:
|
||||||
std::cout << "Replacement keywords found, remember to call applyExplicitReinjectionControls." << std::endl;
|
|
||||||
return;
|
return;
|
||||||
case InjectionSpecification::FLD:
|
case InjectionSpecification::FLD:
|
||||||
case InjectionSpecification::NONE:
|
case InjectionSpecification::NONE:
|
||||||
@ -524,7 +562,13 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
double sum = 0.0;
|
double sum = 0.0;
|
||||||
for (size_t i = 0; i < children_.size(); ++i) {
|
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;
|
return sum;
|
||||||
}
|
}
|
||||||
@ -548,7 +592,7 @@ namespace Opm
|
|||||||
/// \param[in] phase The phase for which to sum up.
|
/// \param[in] phase The phase for which to sum up.
|
||||||
|
|
||||||
double WellsGroup::getTotalProductionFlow(const std::vector<double>& phase_flows,
|
double WellsGroup::getTotalProductionFlow(const std::vector<double>& phase_flows,
|
||||||
const BlackoilPhases::PhaseIndex phase)
|
const BlackoilPhases::PhaseIndex phase) const
|
||||||
{
|
{
|
||||||
double sum = 0.0;
|
double sum = 0.0;
|
||||||
for (size_t i = 0; i < children_.size(); ++i) {
|
for (size_t i = 0; i < children_.size(); ++i) {
|
||||||
@ -557,6 +601,16 @@ namespace Opm
|
|||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double WellsGroup::getTotalVoidageRate(const std::vector<double>& 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 * efficiencyFactor();
|
||||||
|
}
|
||||||
|
|
||||||
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
|
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
|
||||||
/// \param[in] well_reservoirrates_phase
|
/// \param[in] well_reservoirrates_phase
|
||||||
/// A vector containing reservoir rates by phase for each well.
|
/// A vector containing reservoir rates by phase for each well.
|
||||||
@ -569,6 +623,7 @@ namespace Opm
|
|||||||
void WellsGroup::applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
void WellsGroup::applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
||||||
const std::vector<double>& well_surfacerates_phase)
|
const std::vector<double>& well_surfacerates_phase)
|
||||||
{
|
{
|
||||||
|
const InjectionSpecification::InjectorType injector_type = injSpec().injector_type_;
|
||||||
if (injSpec().control_mode_ == InjectionSpecification::REIN) {
|
if (injSpec().control_mode_ == InjectionSpecification::REIN) {
|
||||||
// Defaulting to water to satisfy -Wmaybe-uninitialized
|
// Defaulting to water to satisfy -Wmaybe-uninitialized
|
||||||
BlackoilPhases::PhaseIndex phase = BlackoilPhases::Aqua;
|
BlackoilPhases::PhaseIndex phase = BlackoilPhases::Aqua;
|
||||||
@ -594,11 +649,11 @@ namespace Opm
|
|||||||
#ifdef DIRTY_WELLCTRL_HACK
|
#ifdef DIRTY_WELLCTRL_HACK
|
||||||
children_[i]->applyInjGroupControl(InjectionSpecification::RESV,
|
children_[i]->applyInjGroupControl(InjectionSpecification::RESV,
|
||||||
(children_guide_rate / my_guide_rate) * total_reinjected * injSpec().reinjection_fraction_target_,
|
(children_guide_rate / my_guide_rate) * total_reinjected * injSpec().reinjection_fraction_target_,
|
||||||
false);
|
true);
|
||||||
#else
|
#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_,
|
(children_guide_rate / my_guide_rate) * total_reinjected * injSpec().reinjection_fraction_target_,
|
||||||
false);
|
true);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -619,8 +674,8 @@ namespace Opm
|
|||||||
// Apply for all children.
|
// Apply for all children.
|
||||||
// Note, we do _not_ want to call the applyProdGroupControl in this object,
|
// 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.
|
// 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,
|
children_[i]->applyInjGroupControl(InjectionSpecification::RESV, injector_type,
|
||||||
(children_guide_rate / my_guide_rate) * total_reinjected * injSpec().voidage_replacment_fraction_,
|
(children_guide_rate / my_guide_rate) * total_reinjected * injSpec().voidage_replacment_fraction_,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
@ -628,19 +683,156 @@ namespace Opm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WellsGroup::applyVREPGroupControls(const std::vector<double>& well_voidage_rates,
|
||||||
|
const std::vector<double>& 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 / efficiencyFactor()
|
||||||
|
* 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<double>& well_voidage_rates,
|
||||||
|
const std::vector<double>& 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 / 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.
|
||||||
|
injSpec().control_mode_ = InjectionSpecification::FLD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WellsGroup::updateWellProductionTargets(const std::vector<double>& 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 prod_mode = prodSpec().control_mode_;
|
||||||
|
double target_rate = -1.0;
|
||||||
|
|
||||||
|
switch(prod_mode) {
|
||||||
|
case ProductionSpecification::FLD :
|
||||||
|
{
|
||||||
|
auto* parent_node = getParent();
|
||||||
|
prod_mode = parent_node->prodSpec().control_mode_;
|
||||||
|
target_rate = parent_node->getTarget(prod_mode) / parent_node->efficiencyFactor();
|
||||||
|
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 ");
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
double rate_individual_control = 0.;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < children_.size(); ++i) {
|
||||||
|
if (children_[i]->individualControl()) {
|
||||||
|
rate_individual_control += std::abs(children_[i]->getProductionRate(well_rates, prod_mode) * children_[i]->efficiencyFactor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < children_.size(); ++i) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WellsGroup::updateWellInjectionTargets(const std::vector<double>& /*well_rates*/)
|
||||||
|
{
|
||||||
|
// NOT doing anything yet.
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
double WellsGroup::getProductionRate(const std::vector<double>& well_rates,
|
||||||
|
const ProductionSpecification::ControlMode prod_mode) const
|
||||||
|
{
|
||||||
|
double total_production_rate = 0.0;
|
||||||
|
for (const std::shared_ptr<const WellsGroupInterface>& child_node : children_) {
|
||||||
|
total_production_rate += child_node->getProductionRate(well_rates, prod_mode);
|
||||||
|
}
|
||||||
|
return total_production_rate;
|
||||||
|
}
|
||||||
|
|
||||||
// ============== WellNode members ============
|
// ============== WellNode members ============
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
WellNode::WellNode(const std::string& myname,
|
WellNode::WellNode(const std::string& myname,
|
||||||
|
const double efficiency_factor,
|
||||||
const ProductionSpecification& prod_spec,
|
const ProductionSpecification& prod_spec,
|
||||||
const InjectionSpecification& inj_spec,
|
const InjectionSpecification& inj_spec,
|
||||||
const PhaseUsage& phase_usage)
|
const PhaseUsage& phase_usage)
|
||||||
: WellsGroupInterface(myname, prod_spec, inj_spec, phase_usage),
|
: WellsGroupInterface(myname, efficiency_factor, prod_spec, inj_spec, phase_usage),
|
||||||
wells_(0),
|
wells_(0),
|
||||||
self_index_(-1),
|
self_index_(-1),
|
||||||
group_control_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
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,7 +844,7 @@ namespace Opm
|
|||||||
// Report on our rates.
|
// Report on our rates.
|
||||||
const int np = phaseUsage().num_phases;
|
const int np = phaseUsage().num_phases;
|
||||||
for (int phase = 0; phase < np; ++phase) {
|
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.res_inj_rates[phase] = well_reservoirrates_phase[np*self_index_ + phase];
|
||||||
summed_phases.surf_inj_rates[phase] = well_surfacerates_phase[np*self_index_ + phase];
|
summed_phases.surf_inj_rates[phase] = well_surfacerates_phase[np*self_index_ + phase];
|
||||||
} else {
|
} else {
|
||||||
@ -662,7 +854,6 @@ namespace Opm
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check constraints.
|
// Check constraints.
|
||||||
bool is_producer = (wells_->type[self_index_] == PRODUCER);
|
|
||||||
const WellControls * ctrls = wells_->ctrls[self_index_];
|
const WellControls * ctrls = wells_->ctrls[self_index_];
|
||||||
for (int ctrl_index = 0; ctrl_index < well_controls_get_num(ctrls); ++ctrl_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_) {
|
if (ctrl_index == well_controls_get_current(ctrls) || ctrl_index == group_control_index_) {
|
||||||
@ -676,7 +867,7 @@ namespace Opm
|
|||||||
case BHP: {
|
case BHP: {
|
||||||
const double my_well_bhp = well_bhp[self_index_];
|
const double my_well_bhp = well_bhp[self_index_];
|
||||||
const double my_target_bhp = well_controls_iget_target( ctrls , ctrl_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);
|
: (my_target_bhp < my_well_bhp);
|
||||||
if (ctrl_violated) {
|
if (ctrl_violated) {
|
||||||
OpmLog::info("BHP limit violated for well " + name() + ":\n"
|
OpmLog::info("BHP limit violated for well " + name() + ":\n"
|
||||||
@ -799,20 +990,48 @@ namespace Opm
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WellNode::applyInjGroupControl(const InjectionSpecification::ControlMode control_mode,
|
void WellNode::applyInjGroupControl(const InjectionSpecification::ControlMode control_mode,
|
||||||
|
const InjectionSpecification::InjectorType injector_type,
|
||||||
const double target,
|
const double target,
|
||||||
const bool forced)
|
const bool only_group)
|
||||||
{
|
{
|
||||||
// Not changing if we're not forced to change
|
if ( !isInjector() ) {
|
||||||
if (!forced
|
// assert(target == 0.0);
|
||||||
&& (injSpec().control_mode_ != InjectionSpecification::GRUP && injSpec().control_mode_ != InjectionSpecification::NONE)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (wells_->type[self_index_] != INJECTOR) {
|
|
||||||
assert(target == 0.0);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const double distr[3] = { 1.0, 1.0, 1.0 };
|
if (only_group && individualControl()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// considering the efficiency factor
|
||||||
|
const double effective_target = target / efficiencyFactor();
|
||||||
|
|
||||||
|
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;
|
WellControlType wct;
|
||||||
switch (control_mode) {
|
switch (control_mode) {
|
||||||
case InjectionSpecification::RATE:
|
case InjectionSpecification::RATE:
|
||||||
@ -827,17 +1046,18 @@ namespace Opm
|
|||||||
|
|
||||||
if (group_control_index_ < 0) {
|
if (group_control_index_ < 0) {
|
||||||
// The well only had its own controls, no group controls.
|
// 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;
|
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 {
|
} else {
|
||||||
// We will now modify the last control, that
|
// We will now modify the last control, that
|
||||||
// "belongs to" the group control.
|
// "belongs to" the group control.
|
||||||
well_controls_iset_type(wells_->ctrls[self_index_] , group_control_index_ , wct);
|
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_alq(wells_->ctrls[self_index_] , group_control_index_ , -1e100);
|
||||||
well_controls_iset_distr(wells_->ctrls[self_index_] , group_control_index_ , distr);
|
well_controls_iset_distr(wells_->ctrls[self_index_] , group_control_index_ , distr);
|
||||||
}
|
}
|
||||||
set_current_control(self_index_, group_control_index_, wells_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -848,14 +1068,23 @@ namespace Opm
|
|||||||
/// \param[in] phase The phase for which to sum up.
|
/// \param[in] phase The phase for which to sum up.
|
||||||
|
|
||||||
double WellNode::getTotalProductionFlow(const std::vector<double>& phase_flows,
|
double WellNode::getTotalProductionFlow(const std::vector<double>& phase_flows,
|
||||||
const BlackoilPhases::PhaseIndex phase)
|
const BlackoilPhases::PhaseIndex phase) const
|
||||||
{
|
{
|
||||||
if (type() == INJECTOR) {
|
if (isInjector()) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
return phase_flows[self_index_*phaseUsage().num_phases + phaseUsage().phase_pos[phase]];
|
return phase_flows[self_index_*phaseUsage().num_phases + phaseUsage().phase_pos[phase]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double WellNode::getTotalVoidageRate(const std::vector<double>& well_voidage_rates)
|
||||||
|
{
|
||||||
|
if (isProducer()) {
|
||||||
|
return well_voidage_rates[self_index_] * efficiencyFactor();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WellType WellNode::type() const {
|
WellType WellNode::type() const {
|
||||||
return wells_->type[self_index_];
|
return wells_->type[self_index_];
|
||||||
}
|
}
|
||||||
@ -874,22 +1103,82 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
// Do nothing at well level.
|
// Do nothing at well level.
|
||||||
}
|
}
|
||||||
void WellNode::applyProdGroupControl(const ProductionSpecification::ControlMode control_mode,
|
|
||||||
const double target,
|
|
||||||
const bool forced)
|
void WellNode::applyVREPGroupControls(const std::vector<double>&,
|
||||||
|
const std::vector<double>&)
|
||||||
{
|
{
|
||||||
// Not changing if we're not forced to change
|
// It is the end, nothing should be done here.
|
||||||
if (!forced && (prodSpec().control_mode_ != ProductionSpecification::GRUP
|
}
|
||||||
&& prodSpec().control_mode_ != ProductionSpecification::NONE)) {
|
|
||||||
std::cout << "Returning" << std::endl;
|
void WellNode::applyVREPGroupControl(const double target,
|
||||||
|
const std::vector<double>& /*well_voidage_rates*/,
|
||||||
|
const std::vector<double>& conversion_coeffs,
|
||||||
|
const bool only_group)
|
||||||
|
{
|
||||||
|
if (!isInjector()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (wells_->type[self_index_] != PRODUCER) {
|
|
||||||
|
if (only_group && individualControl()) {
|
||||||
|
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
|
||||||
|
// which results in the previous implementation of RESV keywords.
|
||||||
|
std::vector<double> 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<double>::max();
|
||||||
|
const int invalid_vfp = -std::numeric_limits<int>::max();
|
||||||
|
|
||||||
|
if (group_control_index_ < 0) {
|
||||||
|
append_well_controls(RESERVOIR_RATE, ntarget, invalid_alq, invalid_vfp, &distr[0], self_index_, wells_);
|
||||||
|
// 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
|
||||||
|
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);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if ( !isProducer() ) {
|
||||||
assert(target == 0.0);
|
assert(target == 0.0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (only_group && individualControl()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// We're a producer, so we need to negate the input
|
// We're a producer, so we need to negate the input
|
||||||
double ntarget = -target;
|
double ntarget = -target / efficiencyFactor();
|
||||||
|
|
||||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||||
const int* phase_pos = phaseUsage().phase_pos;
|
const int* phase_pos = phaseUsage().phase_pos;
|
||||||
@ -918,7 +1207,6 @@ namespace Opm
|
|||||||
distr[phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
distr[phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||||
break;
|
break;
|
||||||
case ProductionSpecification::LRAT:
|
case ProductionSpecification::LRAT:
|
||||||
std::cout << "applying rate" << std::endl;
|
|
||||||
wct = SURFACE_RATE;
|
wct = SURFACE_RATE;
|
||||||
if (!phase_used[BlackoilPhases::Liquid]) {
|
if (!phase_used[BlackoilPhases::Liquid]) {
|
||||||
OPM_THROW(std::runtime_error, "Oil phase not active and LRAT control specified.");
|
OPM_THROW(std::runtime_error, "Oil phase not active and LRAT control specified.");
|
||||||
@ -941,6 +1229,8 @@ namespace Opm
|
|||||||
// The well only had its own controls, no group controls.
|
// The well only had its own controls, no group controls.
|
||||||
append_well_controls(wct, ntarget, invalid_alq, invalid_vfp, distr, self_index_, wells_);
|
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;
|
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 {
|
} else {
|
||||||
// We will now modify the last control, that
|
// We will now modify the last control, that
|
||||||
// "belongs to" the group control.
|
// "belongs to" the group control.
|
||||||
@ -949,7 +1239,6 @@ namespace Opm
|
|||||||
well_controls_iset_alq(wells_->ctrls[self_index_] , group_control_index_ , -1e100);
|
well_controls_iset_alq(wells_->ctrls[self_index_] , group_control_index_ , -1e100);
|
||||||
well_controls_iset_distr(wells_->ctrls[self_index_] , group_control_index_ , distr);
|
well_controls_iset_distr(wells_->ctrls[self_index_] , group_control_index_ , distr);
|
||||||
}
|
}
|
||||||
set_current_control(self_index_, group_control_index_, wells_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -968,10 +1257,14 @@ namespace Opm
|
|||||||
/// wells under group control
|
/// wells under group control
|
||||||
double WellNode::productionGuideRate(bool only_group)
|
double WellNode::productionGuideRate(bool only_group)
|
||||||
{
|
{
|
||||||
if (!only_group || prodSpec().control_mode_ == ProductionSpecification::GRUP) {
|
// 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()) && isProducer() ) {
|
||||||
return prodSpec().guide_rate_;
|
return prodSpec().guide_rate_;
|
||||||
|
} else {
|
||||||
|
return 0.0;
|
||||||
}
|
}
|
||||||
return 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the injection guide rate for the group.
|
/// Calculates the injection guide rate for the group.
|
||||||
@ -979,13 +1272,63 @@ namespace Opm
|
|||||||
/// wells under group control
|
/// wells under group control
|
||||||
double WellNode::injectionGuideRate(bool only_group)
|
double WellNode::injectionGuideRate(bool only_group)
|
||||||
{
|
{
|
||||||
if (!only_group || injSpec().control_mode_ == InjectionSpecification::GRUP) {
|
if ( (!only_group || !individualControl()) && isInjector() ) {
|
||||||
return injSpec().guide_rate_;
|
return injSpec().guide_rate_;
|
||||||
|
} else {
|
||||||
|
return 0.0;
|
||||||
}
|
}
|
||||||
return 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Returning the group control index
|
||||||
|
int WellNode::groupControlIndex() const
|
||||||
|
{
|
||||||
|
return group_control_index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
double WellNode::getProductionRate(const std::vector<double>& well_rates,
|
||||||
|
const ProductionSpecification::ControlMode prod_mode) const
|
||||||
|
{
|
||||||
|
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<double>& /*well_rates*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WellNode::updateWellInjectionTargets(const std::vector<double>& /*well_rates*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -1087,7 +1430,8 @@ namespace Opm
|
|||||||
injection_specification.reinjection_fraction_target_ = group.getTargetReinjectFraction(timeStep);
|
injection_specification.reinjection_fraction_target_ = group.getTargetReinjectFraction(timeStep);
|
||||||
injection_specification.voidage_replacment_fraction_ = group.getTargetVoidReplacementFraction(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.oil_max_rate_ = group.getOilTargetRate(timeStep);
|
||||||
production_specification.control_mode_ = toProductionControlMode(GroupProduction::ControlEnum2String(group.getProductionControlMode(timeStep)));
|
production_specification.control_mode_ = toProductionControlMode(GroupProduction::ControlEnum2String(group.getProductionControlMode(timeStep)));
|
||||||
production_specification.water_max_rate_ = group.getWaterTargetRate(timeStep);
|
production_specification.water_max_rate_ = group.getWaterTargetRate(timeStep);
|
||||||
@ -1097,7 +1441,9 @@ namespace Opm
|
|||||||
production_specification.reservoir_flow_max_rate_ = group.getReservoirVolumeTargetRate(timeStep);
|
production_specification.reservoir_flow_max_rate_ = group.getReservoirVolumeTargetRate(timeStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<WellsGroupInterface> wells_group(new WellsGroup(group.name(), production_specification, injection_specification, phase_usage));
|
const double efficiency_factor = group.getGroupEfficiencyFactor(timeStep);
|
||||||
|
|
||||||
|
std::shared_ptr<WellsGroupInterface> wells_group(new WellsGroup(group.name(), efficiency_factor, production_specification, injection_specification, phase_usage));
|
||||||
return wells_group;
|
return wells_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1136,7 +1482,41 @@ namespace Opm
|
|||||||
production_specification.control_mode_ = toProductionControlMode(WellProducer::ControlMode2String(properties.controlMode));
|
production_specification.control_mode_ = toProductionControlMode(WellProducer::ControlMode2String(properties.controlMode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::shared_ptr<WellsGroupInterface> 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<WellsGroupInterface> wells_group(new WellNode(well->name(), efficiency_factor, production_specification, injection_specification, phase_usage));
|
||||||
return wells_group;
|
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 efficiency_factor = efficiencyFactor();
|
||||||
|
const WellsGroupInterface* parent_node = getParent();
|
||||||
|
while (parent_node != nullptr) {
|
||||||
|
efficiency_factor *= parent_node->efficiencyFactor();
|
||||||
|
parent_node = parent_node->getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return efficiency_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int WellNode::selfIndex() const {
|
||||||
|
return self_index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool WellNode::targetUpdated() const {
|
||||||
|
return target_updated_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WellNode::setTargetUpdated(const bool flag) {
|
||||||
|
target_updated_ = flag;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WellsGroupInterface(const std::string& name,
|
WellsGroupInterface(const std::string& name,
|
||||||
|
const double efficiency_factor,
|
||||||
const ProductionSpecification& prod_spec,
|
const ProductionSpecification& prod_spec,
|
||||||
const InjectionSpecification& inj_spec,
|
const InjectionSpecification& inj_spec,
|
||||||
const PhaseUsage& phase_usage);
|
const PhaseUsage& phase_usage);
|
||||||
@ -92,6 +93,8 @@ namespace Opm
|
|||||||
/// Gets the parent of the group, NULL if no parent.
|
/// Gets the parent of the group, NULL if no parent.
|
||||||
const WellsGroupInterface* getParent() const;
|
const WellsGroupInterface* getParent() const;
|
||||||
|
|
||||||
|
WellsGroupInterface* getParent();
|
||||||
|
|
||||||
/// Calculates the number of leaf nodes in the given group.
|
/// Calculates the number of leaf nodes in the given group.
|
||||||
/// A leaf node is defined to have one leaf node in its group.
|
/// A leaf node is defined to have one leaf node in its group.
|
||||||
virtual int numberOfLeafNodes() = 0;
|
virtual int numberOfLeafNodes() = 0;
|
||||||
@ -128,19 +131,20 @@ namespace Opm
|
|||||||
/// Sets the current active control to the provided one for all injectors within the group.
|
/// 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
|
/// After this call, the combined rate (which rate depending on control_mode) of the group
|
||||||
/// shall be equal to target.
|
/// shall be equal to target.
|
||||||
/// \param[in] forced if true, all children will be set under group control, otherwise
|
/// \param[in] only_group if true, only children that are under group control will be changed.
|
||||||
/// 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,
|
virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode,
|
||||||
|
const InjectionSpecification::InjectorType injector_type,
|
||||||
const double target,
|
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.
|
/// 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
|
/// After this call, the combined rate (which rate depending on control_mode) of the group
|
||||||
/// shall be equal to target.
|
/// shall be equal to target.
|
||||||
/// \param[in] forced if true, all children will be set under group control, otherwise
|
/// \param[in] only_group if true, only children that are under group control will be changed.
|
||||||
/// 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,
|
virtual void applyProdGroupControl(const ProductionSpecification::ControlMode control_mode,
|
||||||
const double target,
|
const double target,
|
||||||
const bool forced) = 0;
|
const bool only_group) = 0;
|
||||||
|
|
||||||
/// Gets the worst offending well based on the input
|
/// Gets the worst offending well based on the input
|
||||||
/// \param[in] well_reservoirrates_phase
|
/// \param[in] well_reservoirrates_phase
|
||||||
@ -188,7 +192,7 @@ namespace Opm
|
|||||||
/// with all phase rates of a single well adjacent in the array.
|
/// with all phase rates of a single well adjacent in the array.
|
||||||
/// \param[in] phase The phase for which to sum up.
|
/// \param[in] phase The phase for which to sum up.
|
||||||
virtual double getTotalProductionFlow(const std::vector<double>& phase_flows,
|
virtual double getTotalProductionFlow(const std::vector<double>& 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.
|
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
|
||||||
/// \param[in] well_reservoirrates_phase
|
/// \param[in] well_reservoirrates_phase
|
||||||
@ -202,6 +206,38 @@ namespace Opm
|
|||||||
virtual void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
virtual void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
||||||
const std::vector<double>& well_surfacerates_phase) = 0;
|
const std::vector<double>& well_surfacerates_phase) = 0;
|
||||||
|
|
||||||
|
/// TODO: prototyping a VREP enforcement function.
|
||||||
|
virtual void applyVREPGroupControls(const std::vector<double>& well_voidage_rates,
|
||||||
|
const std::vector<double>& conversion_coeffs) = 0;
|
||||||
|
|
||||||
|
virtual void applyVREPGroupControl(const double target,
|
||||||
|
const std::vector<double>& well_voidage_rates,
|
||||||
|
const std::vector<double>& conversion_coeffs,
|
||||||
|
const bool only_group) = 0;
|
||||||
|
|
||||||
|
virtual double getTotalVoidageRate(const std::vector<double>& well_voidage_rates) = 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 double getProductionRate(const std::vector<double>& well_rates,
|
||||||
|
const ProductionSpecification::ControlMode prod_mode) const = 0;
|
||||||
|
|
||||||
|
virtual void updateWellProductionTargets(const std::vector<double>& well_rates) = 0;
|
||||||
|
|
||||||
|
virtual void updateWellInjectionTargets(const std::vector<double>& well_rates) = 0;
|
||||||
|
|
||||||
|
virtual void setTargetUpdated(const bool flag) = 0;
|
||||||
|
|
||||||
|
double efficiencyFactor() const;
|
||||||
|
|
||||||
|
void setEfficiencyFactor(const double efficiency_factor);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Calculates the correct rate for the given ProductionSpecification::ControlMode
|
/// Calculates the correct rate for the given ProductionSpecification::ControlMode
|
||||||
@ -216,6 +252,14 @@ namespace Opm
|
|||||||
|
|
||||||
WellsGroupInterface* parent_;
|
WellsGroupInterface* parent_;
|
||||||
|
|
||||||
|
// 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_;
|
||||||
|
|
||||||
|
// Efficiency factor
|
||||||
|
double efficiency_factor_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name_;
|
std::string name_;
|
||||||
ProductionSpecification production_specification_;
|
ProductionSpecification production_specification_;
|
||||||
@ -229,6 +273,7 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WellsGroup(const std::string& name,
|
WellsGroup(const std::string& name,
|
||||||
|
const double efficiency_factor,
|
||||||
const ProductionSpecification& prod_spec,
|
const ProductionSpecification& prod_spec,
|
||||||
const InjectionSpecification& inj_spec,
|
const InjectionSpecification& inj_spec,
|
||||||
const PhaseUsage& phase_usage);
|
const PhaseUsage& phase_usage);
|
||||||
@ -250,20 +295,21 @@ namespace Opm
|
|||||||
/// Sets the current active control to the provided one for all injectors within the group.
|
/// 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
|
/// After this call, the combined rate (which rate depending on control_mode) of the group
|
||||||
/// shall be equal to target.
|
/// shall be equal to target.
|
||||||
/// \param[in] forced if true, all children will be set under group control, otherwise
|
/// \param[in] only_group if true, only children that are under group control will be changed.
|
||||||
/// 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,
|
virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode,
|
||||||
|
const InjectionSpecification::InjectorType injector_type,
|
||||||
const double target,
|
const double target,
|
||||||
bool forced);
|
bool only_group);
|
||||||
|
|
||||||
/// Sets the current active control to the provided one for all producers within the 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
|
/// After this call, the combined rate (which rate depending on control_mode) of the group
|
||||||
/// shall be equal to target.
|
/// shall be equal to target.
|
||||||
/// \param[in] forced if true, all children will be set under group control, otherwise
|
/// \param[in] only_group if true, only children that are under group control will be changed.
|
||||||
/// 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,
|
virtual void applyProdGroupControl(const ProductionSpecification::ControlMode control_mode,
|
||||||
const double target,
|
const double target,
|
||||||
bool forced);
|
bool only_group);
|
||||||
|
|
||||||
/// Applies any production group control relevant to all children nodes.
|
/// Applies any production group control relevant to all children nodes.
|
||||||
/// If no group control is set, this is called recursively to the children.
|
/// If no group control is set, this is called recursively to the children.
|
||||||
@ -289,7 +335,7 @@ namespace Opm
|
|||||||
/// with all phase rates of a single well adjacent in the array.
|
/// with all phase rates of a single well adjacent in the array.
|
||||||
/// \param[in] phase The phase for which to sum up.
|
/// \param[in] phase The phase for which to sum up.
|
||||||
virtual double getTotalProductionFlow(const std::vector<double>& phase_flows,
|
virtual double getTotalProductionFlow(const std::vector<double>& 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.
|
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
|
||||||
/// \param[in] well_reservoirrates_phase
|
/// \param[in] well_reservoirrates_phase
|
||||||
@ -303,6 +349,26 @@ namespace Opm
|
|||||||
virtual void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
virtual void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
||||||
const std::vector<double>& well_surfacerates_phase);
|
const std::vector<double>& well_surfacerates_phase);
|
||||||
|
|
||||||
|
/// TODO: prototyping a VREP enforcement function.
|
||||||
|
virtual void applyVREPGroupControls(const std::vector<double>& well_voidage_rates,
|
||||||
|
const std::vector<double>& conversion_coeffs);
|
||||||
|
|
||||||
|
virtual void applyVREPGroupControl(const double target,
|
||||||
|
const std::vector<double>& well_voidage_rates,
|
||||||
|
const std::vector<double>& conversion_coeffs,
|
||||||
|
const bool only_group);
|
||||||
|
|
||||||
|
virtual double getTotalVoidageRate(const std::vector<double>& well_voidage_rates);
|
||||||
|
|
||||||
|
virtual void updateWellProductionTargets(const std::vector<double>& well_rates);
|
||||||
|
|
||||||
|
virtual void updateWellInjectionTargets(const std::vector<double>& well_rates);
|
||||||
|
|
||||||
|
virtual void setTargetUpdated(const bool flag);
|
||||||
|
|
||||||
|
virtual double getProductionRate(const std::vector<double>& well_rates,
|
||||||
|
const ProductionSpecification::ControlMode prod_mode) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<WellsGroupInterface> > children_;
|
std::vector<std::shared_ptr<WellsGroupInterface> > children_;
|
||||||
};
|
};
|
||||||
@ -313,6 +379,7 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WellNode(const std::string& name,
|
WellNode(const std::string& name,
|
||||||
|
const double efficiency_factor,
|
||||||
const ProductionSpecification& prod_spec,
|
const ProductionSpecification& prod_spec,
|
||||||
const InjectionSpecification& inj_spec,
|
const InjectionSpecification& inj_spec,
|
||||||
const PhaseUsage& phase_usage);
|
const PhaseUsage& phase_usage);
|
||||||
@ -339,20 +406,21 @@ namespace Opm
|
|||||||
/// Sets the current active control to the provided one for all injectors within the group.
|
/// 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
|
/// After this call, the combined rate (which rate depending on control_mode) of the group
|
||||||
/// shall be equal to target.
|
/// shall be equal to target.
|
||||||
/// \param[in] forced if true, all children will be set under group control, otherwise
|
/// \param[in] only_group if true, only children that are under group control will be changed.
|
||||||
/// 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,
|
virtual void applyInjGroupControl(const InjectionSpecification::ControlMode control_mode,
|
||||||
|
const InjectionSpecification::InjectorType injector_type,
|
||||||
const double target,
|
const double target,
|
||||||
bool forced);
|
bool only_group);
|
||||||
|
|
||||||
/// Sets the current active control to the provided one for all producers within the 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
|
/// After this call, the combined rate (which rate depending on control_mode) of the group
|
||||||
/// shall be equal to target.
|
/// shall be equal to target.
|
||||||
/// \param[in] forced if true, all children will be set under group control, otherwise
|
/// \param[in] only_group if true, only children that are under group control will be changed.
|
||||||
/// 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,
|
virtual void applyProdGroupControl(const ProductionSpecification::ControlMode control_mode,
|
||||||
const double target,
|
const double target,
|
||||||
bool forced);
|
bool only_group);
|
||||||
|
|
||||||
/// Applies any production group control relevant to all children nodes.
|
/// Applies any production group control relevant to all children nodes.
|
||||||
/// If no group control is set, this is called recursively to the children.
|
/// If no group control is set, this is called recursively to the children.
|
||||||
@ -378,7 +446,7 @@ namespace Opm
|
|||||||
/// with all phase rates of a single well adjacent in the array.
|
/// with all phase rates of a single well adjacent in the array.
|
||||||
/// \param[in] phase The phase for which to sum up.
|
/// \param[in] phase The phase for which to sum up.
|
||||||
virtual double getTotalProductionFlow(const std::vector<double>& phase_flows,
|
virtual double getTotalProductionFlow(const std::vector<double>& phase_flows,
|
||||||
const BlackoilPhases::PhaseIndex phase);
|
const BlackoilPhases::PhaseIndex phase) const;
|
||||||
|
|
||||||
/// Returns the type of the well.
|
/// Returns the type of the well.
|
||||||
WellType type() const;
|
WellType type() const;
|
||||||
@ -395,11 +463,47 @@ namespace Opm
|
|||||||
virtual void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
virtual void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
||||||
const std::vector<double>& well_surfacerates_phase);
|
const std::vector<double>& well_surfacerates_phase);
|
||||||
|
|
||||||
|
/// TODO: prototyping a VREP enforcement function.
|
||||||
|
virtual void applyVREPGroupControls(const std::vector<double>& well_voidage_rates,
|
||||||
|
const std::vector<double>& conversion_coeffs);
|
||||||
|
|
||||||
|
virtual void applyVREPGroupControl(const double target,
|
||||||
|
const std::vector<double>& well_voidage_rates,
|
||||||
|
const std::vector<double>& conversion_coeffs,
|
||||||
|
const bool only_group);
|
||||||
|
|
||||||
|
virtual double getTotalVoidageRate(const std::vector<double>& well_voidage_rates);
|
||||||
|
|
||||||
|
int groupControlIndex() const;
|
||||||
|
|
||||||
|
virtual double getProductionRate(const std::vector<double>& well_rates,
|
||||||
|
const ProductionSpecification::ControlMode prod_mode) const;
|
||||||
|
|
||||||
|
virtual void updateWellProductionTargets(const std::vector<double>& well_rates);
|
||||||
|
|
||||||
|
virtual void updateWellInjectionTargets(const std::vector<double>& 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;
|
||||||
|
|
||||||
|
bool isProducer() const;
|
||||||
|
|
||||||
|
bool isInjector() const;
|
||||||
|
|
||||||
|
int selfIndex() const;
|
||||||
|
|
||||||
|
bool targetUpdated() const;
|
||||||
|
|
||||||
|
virtual void setTargetUpdated(const bool flag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Wells* wells_;
|
Wells* wells_;
|
||||||
int self_index_;
|
int self_index_;
|
||||||
int group_control_index_;
|
int group_control_index_;
|
||||||
bool shut_well_;
|
bool shut_well_;
|
||||||
|
// TODO: used when updating well targets
|
||||||
|
bool target_updated_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creates the WellsGroupInterface for the given well
|
/// Creates the WellsGroupInterface for the given well
|
||||||
@ -416,5 +520,6 @@ namespace Opm
|
|||||||
std::shared_ptr<WellsGroupInterface> createGroupWellsGroup(const Group& group, size_t timeStep,
|
std::shared_ptr<WellsGroupInterface> createGroupWellsGroup(const Group& group, size_t timeStep,
|
||||||
const PhaseUsage& phase_usage );
|
const PhaseUsage& phase_usage );
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* OPM_WELLSGROUP_HPP */
|
#endif /* OPM_WELLSGROUP_HPP */
|
||||||
|
|
||||||
|
@ -373,6 +373,12 @@ namespace Opm
|
|||||||
return well_collection_;
|
return well_collection_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WellCollection& WellsManager::wellCollection() {
|
||||||
|
return well_collection_;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool WellsManager::conditionsMet(const std::vector<double>& well_bhp,
|
bool WellsManager::conditionsMet(const std::vector<double>& well_bhp,
|
||||||
const std::vector<double>& well_reservoirrates_phase,
|
const std::vector<double>& well_reservoirrates_phase,
|
||||||
const std::vector<double>& well_surfacerates_phase)
|
const std::vector<double>& well_surfacerates_phase)
|
||||||
@ -783,7 +789,17 @@ namespace Opm
|
|||||||
if ( well->isProducer(timeStep) ) {
|
if ( well->isProducer(timeStep) ) {
|
||||||
// The guide rates is calculated based on the group control
|
// The guide rates is calculated based on the group control
|
||||||
// Currently only supporting WRAT, ORAT and GRAT.
|
// 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: {
|
case ProductionSpecification::WRAT: {
|
||||||
if (!phaseUsage.phase_used[BlackoilPhases::Aqua]) {
|
if (!phaseUsage.phase_used[BlackoilPhases::Aqua]) {
|
||||||
OPM_THROW(std::runtime_error, "Water phase not used, yet found water rate controlled well.");
|
OPM_THROW(std::runtime_error, "Water phase not used, yet found water rate controlled well.");
|
||||||
@ -811,6 +827,25 @@ namespace Opm
|
|||||||
wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::GAS;
|
wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::GAS;
|
||||||
break;
|
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: {
|
case ProductionSpecification::NONE: {
|
||||||
// Group control is not in use for this group.
|
// Group control is not in use for this group.
|
||||||
break;
|
break;
|
||||||
|
@ -114,6 +114,7 @@ namespace Opm
|
|||||||
|
|
||||||
/// Access the well group hierarchy.
|
/// Access the well group hierarchy.
|
||||||
const WellCollection& wellCollection() const;
|
const WellCollection& wellCollection() const;
|
||||||
|
WellCollection& wellCollection();
|
||||||
|
|
||||||
/// Checks if each condition is met, applies well controls where needed
|
/// Checks if each condition is met, applies well controls where needed
|
||||||
/// (that is, it either changes the active control of violating wells, or shuts
|
/// (that is, it either changes the active control of violating wells, or shuts
|
||||||
|
@ -265,6 +265,7 @@ try
|
|||||||
well_group_prod_spec.control_mode_ = ProductionSpecification::RESV;
|
well_group_prod_spec.control_mode_ = ProductionSpecification::RESV;
|
||||||
/// \internal[production specification]
|
/// \internal[production specification]
|
||||||
/// \endinternal
|
/// \endinternal
|
||||||
|
const double group_efficiency_factor = 0.9;
|
||||||
|
|
||||||
/// \page tutorial4
|
/// \page tutorial4
|
||||||
/// \details Create our well group. We hand it an empty injection specification,
|
/// \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.
|
/// what the interface expects. The first argument is the (unique) name of the group.
|
||||||
/// \snippet tutorial4.cpp injection specification
|
/// \snippet tutorial4.cpp injection specification
|
||||||
/// \internal[injection specification]
|
/// \internal[injection specification]
|
||||||
std::shared_ptr<WellsGroupInterface> well_group(new WellsGroup("group", well_group_prod_spec, InjectionSpecification(),
|
std::shared_ptr<WellsGroupInterface> well_group(new WellsGroup("group", group_efficiency_factor, well_group_prod_spec,
|
||||||
phase_usage));
|
InjectionSpecification(), phase_usage));
|
||||||
/// \internal[injection specification]
|
/// \internal[injection specification]
|
||||||
/// \endinternal
|
/// \endinternal
|
||||||
|
|
||||||
@ -297,8 +298,9 @@ try
|
|||||||
well_name << "well" << i;
|
well_name << "well" << i;
|
||||||
ProductionSpecification production_specification;
|
ProductionSpecification production_specification;
|
||||||
production_specification.control_mode_ = ProductionSpecification::GRUP;
|
production_specification.control_mode_ = ProductionSpecification::GRUP;
|
||||||
std::shared_ptr<WellsGroupInterface> well_leaf_node(new WellNode(well_name.str(), production_specification, InjectionSpecification(),
|
const double efficiency_factor = 0.8;
|
||||||
phase_usage));
|
std::shared_ptr<WellsGroupInterface> well_leaf_node(new WellNode(well_name.str(), efficiency_factor, production_specification,
|
||||||
|
InjectionSpecification(), phase_usage));
|
||||||
well_collection.addChild(well_leaf_node, "group");
|
well_collection.addChild(well_leaf_node, "group");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user