Merge pull request #1134 from GitPaean/group_ebos
updating the group control limit for individual control wells
This commit is contained in:
commit
674d97c660
@ -282,7 +282,7 @@ namespace Opm
|
|||||||
|
|
||||||
void WellCollection::updateWellTargets(const std::vector<double>& well_rates)
|
void WellCollection::updateWellTargets(const std::vector<double>& well_rates)
|
||||||
{
|
{
|
||||||
if ( !needUpdateWellTargets() ) {
|
if ( !needUpdateWellTargets() && groupTargetConverged(well_rates)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,4 +323,17 @@ namespace Opm
|
|||||||
return group_control_active_;
|
return group_control_active_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool WellCollection::groupTargetConverged(const std::vector<double>& well_rates) const
|
||||||
|
{
|
||||||
|
// TODO: eventually, there should be only one root node
|
||||||
|
// TODO: we also need to check the injection target, while we have not done that.
|
||||||
|
for (const std::shared_ptr<WellsGroupInterface>& root_node : roots_) {
|
||||||
|
if ( !root_node->groupProdTargetConverged(well_rates) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -139,6 +139,13 @@ namespace Opm
|
|||||||
/// Whether we have active group control
|
/// Whether we have active group control
|
||||||
bool groupControlActive() const;
|
bool groupControlActive() const;
|
||||||
|
|
||||||
|
/// Whether the group target is converged
|
||||||
|
// It is considered converged if eitehr the group targets are matched or the group targets are not matched while the wells are
|
||||||
|
// running under their own limits so that they can not produce more
|
||||||
|
// It is considered not converged if the group targets are not matched while some of the wells are still running under group control
|
||||||
|
// The strategy may need to be adjusted when more complicated multi-layered group control situation applied, not sure about thatyet.
|
||||||
|
bool groupTargetConverged(const std::vector<double>& well_rates) 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_;
|
||||||
|
@ -186,7 +186,7 @@ namespace Opm
|
|||||||
return tot_rate;
|
return tot_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
double WellsGroupInterface::getTarget(ProductionSpecification::ControlMode mode)
|
double WellsGroupInterface::getTarget(ProductionSpecification::ControlMode mode) const
|
||||||
{
|
{
|
||||||
double target = -1.0;
|
double target = -1.0;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@ -216,7 +216,7 @@ namespace Opm
|
|||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
double WellsGroupInterface::getTarget(InjectionSpecification::ControlMode mode)
|
double WellsGroupInterface::getTarget(InjectionSpecification::ControlMode mode) const
|
||||||
{
|
{
|
||||||
double target = -1.0;
|
double target = -1.0;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@ -793,6 +793,18 @@ namespace Opm
|
|||||||
const double children_guide_rate = children_[i]->productionGuideRate(true);
|
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]->setTargetUpdated(true);
|
children_[i]->setTargetUpdated(true);
|
||||||
|
} else {
|
||||||
|
// for the well not under group control, we need to update their group control limit
|
||||||
|
// to provide a mechanism for the well to return to group control
|
||||||
|
// putting its own rate back to the rate_for_group_control for redistribution
|
||||||
|
const double rate = std::abs(children_[i]->getProductionRate(well_rates, prod_mode) * children_[i]->efficiencyFactor());
|
||||||
|
const double temp_rate_for_group_control = rate_for_group_control + rate;
|
||||||
|
|
||||||
|
// TODO: the following might not be the correct thing to do for mutliple-layer group
|
||||||
|
const double children_guide_rate = children_[i]->productionGuideRate(false);
|
||||||
|
const double temp_my_guide_rate = my_guide_rate + children_guide_rate;
|
||||||
|
children_[i]->applyProdGroupControl(prod_mode, (children_guide_rate / temp_my_guide_rate) * temp_rate_for_group_control, false);
|
||||||
|
children_[i]->setTargetUpdated(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -808,12 +820,76 @@ namespace Opm
|
|||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool WellsGroup::canProduceMore() const
|
||||||
|
{
|
||||||
|
for (const std::shared_ptr<const WellsGroupInterface>& child_node : children_) {
|
||||||
|
if (child_node->canProduceMore()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool WellsGroup::groupProdTargetConverged(const std::vector<double>& well_rates) const
|
||||||
|
{
|
||||||
|
// TODO: should consider the efficiency factor in getProductionRate()
|
||||||
|
for (const std::shared_ptr<const WellsGroupInterface>& child_node : children_) {
|
||||||
|
if ( ! child_node->groupProdTargetConverged(well_rates) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to check whether the current group target is satisfied
|
||||||
|
// we need to decide the modes we want to support here.
|
||||||
|
const ProductionSpecification::ControlMode prod_mode = prodSpec().control_mode_;
|
||||||
|
switch(prod_mode) {
|
||||||
|
case ProductionSpecification::LRAT :
|
||||||
|
case ProductionSpecification::ORAT :
|
||||||
|
case ProductionSpecification::WRAT :
|
||||||
|
case ProductionSpecification::GRAT :
|
||||||
|
{
|
||||||
|
const double production_rate = std::abs(getProductionRate(well_rates, prod_mode));
|
||||||
|
const double production_target = std::abs(getTarget(prod_mode));
|
||||||
|
|
||||||
|
// 0.01 is a hard-coded relative tolerance
|
||||||
|
const double relative_tolerance = 0.01;
|
||||||
|
// the bigger one of the two values
|
||||||
|
const double bigger_of_two = std::max(production_rate, production_target);
|
||||||
|
|
||||||
|
if (std::abs(production_target - production_rate) > relative_tolerance * bigger_of_two) {
|
||||||
|
// underproducing the target while potentially can produce more
|
||||||
|
// then we should not consider the effort to match the group target is done yet
|
||||||
|
if (canProduceMore()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// can not produce more to meet the target
|
||||||
|
OpmLog::info("group " + name() + " can not meet its target!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ProductionSpecification::FLD :
|
||||||
|
case ProductionSpecification::NONE :
|
||||||
|
case ProductionSpecification::GRUP :
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
const std::string msg = "Not handling target checking for control type " + ProductionSpecification::toString(prod_mode);
|
||||||
|
OPM_THROW(std::runtime_error, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
double WellsGroup::getProductionRate(const std::vector<double>& well_rates,
|
double WellsGroup::getProductionRate(const std::vector<double>& well_rates,
|
||||||
const ProductionSpecification::ControlMode prod_mode) const
|
const ProductionSpecification::ControlMode prod_mode) const
|
||||||
{
|
{
|
||||||
double total_production_rate = 0.0;
|
double total_production_rate = 0.0;
|
||||||
for (const std::shared_ptr<const WellsGroupInterface>& child_node : children_) {
|
for (const std::shared_ptr<const WellsGroupInterface>& child_node : children_) {
|
||||||
total_production_rate += child_node->getProductionRate(well_rates, prod_mode);
|
total_production_rate += child_node->getProductionRate(well_rates, prod_mode) * child_node->efficiencyFactor();
|
||||||
}
|
}
|
||||||
return total_production_rate;
|
return total_production_rate;
|
||||||
}
|
}
|
||||||
@ -1214,6 +1290,7 @@ namespace Opm
|
|||||||
if (!phase_used[BlackoilPhases::Aqua]) {
|
if (!phase_used[BlackoilPhases::Aqua]) {
|
||||||
OPM_THROW(std::runtime_error, "Water phase not active and LRAT control specified.");
|
OPM_THROW(std::runtime_error, "Water phase not active and LRAT control specified.");
|
||||||
}
|
}
|
||||||
|
|
||||||
distr[phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
distr[phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||||
distr[phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
distr[phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||||
break;
|
break;
|
||||||
@ -1492,7 +1569,8 @@ namespace Opm
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
double WellNode::getAccumulativeEfficiencyFactor() const {
|
double WellNode::getAccumulativeEfficiencyFactor() const
|
||||||
|
{
|
||||||
// TODO: not sure whether a well can be exempted from repsponding to the efficiency factor
|
// TODO: not sure whether a well can be exempted from repsponding to the efficiency factor
|
||||||
// for the parent group.
|
// for the parent group.
|
||||||
double efficiency_factor = efficiencyFactor();
|
double efficiency_factor = efficiencyFactor();
|
||||||
@ -1506,18 +1584,33 @@ namespace Opm
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int WellNode::selfIndex() const {
|
int WellNode::selfIndex() const
|
||||||
|
{
|
||||||
return self_index_;
|
return self_index_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool WellNode::targetUpdated() const {
|
bool WellNode::targetUpdated() const
|
||||||
|
{
|
||||||
return target_updated_;
|
return target_updated_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WellNode::setTargetUpdated(const bool flag) {
|
void WellNode::setTargetUpdated(const bool flag)
|
||||||
|
{
|
||||||
target_updated_ = flag;
|
target_updated_ = flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool WellNode::canProduceMore() const
|
||||||
|
{
|
||||||
|
return (isProducer() && !individualControl());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool WellNode::groupProdTargetConverged(const std::vector<double>& /* well_rates */) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -163,10 +163,10 @@ namespace Opm
|
|||||||
ProductionSpecification::ControlMode mode) = 0;
|
ProductionSpecification::ControlMode mode) = 0;
|
||||||
|
|
||||||
/// Gets the target rate for the given mode.
|
/// Gets the target rate for the given mode.
|
||||||
double getTarget(ProductionSpecification::ControlMode mode);
|
double getTarget(ProductionSpecification::ControlMode mode) const;
|
||||||
|
|
||||||
/// Gets the target rate for the given mode.
|
/// Gets the target rate for the given mode.
|
||||||
double getTarget(InjectionSpecification::ControlMode mode);
|
double getTarget(InjectionSpecification::ControlMode mode) const;
|
||||||
|
|
||||||
/// 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.
|
||||||
@ -235,6 +235,18 @@ namespace Opm
|
|||||||
|
|
||||||
virtual void setTargetUpdated(const bool flag) = 0;
|
virtual void setTargetUpdated(const bool flag) = 0;
|
||||||
|
|
||||||
|
// bascially, for the group or wells under group control
|
||||||
|
// they have the potential to adjust their targets to produce more to match the higher level target
|
||||||
|
virtual bool canProduceMore() const = 0;
|
||||||
|
|
||||||
|
// checking wether group production target converged
|
||||||
|
// if the group is producing following the target, then it should be considered okay
|
||||||
|
// if the group is not producing following the target, then we should check wether the group
|
||||||
|
// should be able to produce more to match the target.
|
||||||
|
// if the group can not produce more, we also consider the effort to match the group target is
|
||||||
|
// also done and the group target converged while we should give a message
|
||||||
|
virtual bool groupProdTargetConverged(const std::vector<double>& well_rates) const = 0;
|
||||||
|
|
||||||
double efficiencyFactor() const;
|
double efficiencyFactor() const;
|
||||||
|
|
||||||
void setEfficiencyFactor(const double efficiency_factor);
|
void setEfficiencyFactor(const double efficiency_factor);
|
||||||
@ -369,6 +381,10 @@ namespace Opm
|
|||||||
virtual double getProductionRate(const std::vector<double>& well_rates,
|
virtual double getProductionRate(const std::vector<double>& well_rates,
|
||||||
const ProductionSpecification::ControlMode prod_mode) const;
|
const ProductionSpecification::ControlMode prod_mode) const;
|
||||||
|
|
||||||
|
virtual bool canProduceMore() const;
|
||||||
|
|
||||||
|
virtual bool groupProdTargetConverged(const std::vector<double>& well_rates) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<WellsGroupInterface> > children_;
|
std::vector<std::shared_ptr<WellsGroupInterface> > children_;
|
||||||
};
|
};
|
||||||
@ -497,6 +513,10 @@ namespace Opm
|
|||||||
|
|
||||||
virtual void setTargetUpdated(const bool flag);
|
virtual void setTargetUpdated(const bool flag);
|
||||||
|
|
||||||
|
virtual bool canProduceMore() const;
|
||||||
|
|
||||||
|
virtual bool groupProdTargetConverged(const std::vector<double>& well_rates) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Wells* wells_;
|
Wells* wells_;
|
||||||
int self_index_;
|
int self_index_;
|
||||||
|
Loading…
Reference in New Issue
Block a user