Completly revamped the way group control is checked

This commit is contained in:
Kjetil Olsen Lye 2012-04-25 16:14:40 +02:00
parent 3fe04afa8d
commit 7d25e9c6a0
6 changed files with 191 additions and 235 deletions

View File

@ -93,15 +93,17 @@ namespace Opm
return NULL;
}
void WellCollection::conditionsMet(const std::vector<double>& well_bhp,
bool WellCollection::conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_rate,
const UnstructuredGrid& grid,
WellControlResult& result,
double epsilon) const
double epsilon)
{
for (size_t i = 0; i < leaf_nodes_.size(); i++) {
leaf_nodes_[i]->conditionsMet(well_bhp, well_rate, grid, result, epsilon);
}
for (size_t i = 0; i < roots_.size(); i++) {
WellPhasesSummed phases;
if(!roots_[i]->conditionsMet(well_bhp, well_rate, phases, epsilon)) {
return false;
}
}
return true;
}
void WellCollection::calculateGuideRates()
@ -111,7 +113,7 @@ namespace Opm
}
}
void WellCollection::setWellsPointer(const Wells* wells) {
void WellCollection::setWellsPointer(Wells* wells) {
for(size_t i = 0; i < leaf_nodes_.size(); i++) {
leaf_nodes_[i]->setWellsPointer(wells, i);
}

View File

@ -43,14 +43,12 @@ namespace Opm
const std::string& parent,
const EclipseGridParser& deck);
/// Builds the WellControlResult object for the current well group hierachy.
void conditionsMet(const std::vector<double>& well_bhp,
bool conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_rate,
const UnstructuredGrid& grid,
WellControlResult& result,
const double epsilon=1e-8) const;
const double epsilon=1e-8);
/// Adds the well pointer to each leaf node (does not take ownership).
void setWellsPointer(const Wells* wells);
void setWellsPointer(Wells* wells);
const std::vector<WellNode*>& getLeafNodes() const;

View File

@ -12,6 +12,18 @@
namespace Opm
{
WellPhasesSummed::WellPhasesSummed()
: bhp_sum(0.0), rate_sum(0.0)
{
}
void WellPhasesSummed::operator+=(const WellPhasesSummed& other)
{
rate_sum += other.rate_sum;
bhp_sum += other.bhp_sum;
}
WellsGroupInterface::WellsGroupInterface(const std::string& myname,
ProductionSpecification prod_spec,
InjectionSpecification inje_spec)
@ -114,65 +126,80 @@ namespace Opm
}
}
}
void WellsGroup::applyControl(const WellControlType type)
{
for (size_t i = 0; i < children_.size(); ++i) {
children_[i]->applyControl(type);
}
}
void WellsGroup::conditionsMet(const std::vector<double>& well_bhp,
bool WellsGroup::conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_rate,
const UnstructuredGrid& grid,
const struct Wells* wells,
int index_of_well,
WellControlResult& result,
WellPhasesSummed& summed_phases,
const double epsilon)
{
if (parent_ != NULL) {
(static_cast<WellsGroup*> (parent_))->conditionsMet(well_bhp,
well_rate,grid, wells, index_of_well, result, epsilon);
WellPhasesSummed child_phases_summed;
for(size_t i = 0; i < children_.size(); ++i) {
WellPhasesSummed current_child_phases_summed;
if(!children_[i]->conditionsMet(well_bhp, well_rate,
current_child_phases_summed, epsilon)) {
return false;
}
child_phases_summed += current_child_phases_summed;
}
int number_of_leaf_nodes = numberOfLeafNodes();
double bhp_target = 1e100;
double rate_target = 1e100;
switch(wells->type[index_of_well]) {
case INJECTOR:
{
const InjectionSpecification& inje_spec = injSpec();
bhp_target = inje_spec.BHP_limit_ / number_of_leaf_nodes;
rate_target = inje_spec.fluid_volume_max_rate_ / number_of_leaf_nodes;
break;
}
case PRODUCER:
{
const ProductionSpecification& prod_spec = prodSpec();
bhp_target = prod_spec.BHP_limit_ / number_of_leaf_nodes;
rate_target = prod_spec.fluid_volume_max_rate_ / number_of_leaf_nodes;
break;
}
}
double bhp_target = std::min(injSpec().BHP_limit_, prodSpec().BHP_limit_);
double rate_target = std::min(injSpec().fluid_volume_max_rate_,
prodSpec().fluid_volume_max_rate_);
if (well_bhp[index_of_well] - bhp_target > epsilon) {
double bhp_sum = child_phases_summed.bhp_sum;
double rate_sum = child_phases_summed.rate_sum;
if (bhp_sum - bhp_target > epsilon) {
std::cout << "BHP not met" << std::endl;
std::cout << "BHP limit was " << bhp_target << std::endl;
std::cout << "Actual bhp was " << well_bhp[index_of_well] << std::endl;
ExceedInformation info;
info.group_name_ = name();
info.surplus_ = well_bhp[index_of_well] - bhp_target;
info.well_index_ = index_of_well;
result.bhp_.push_back(info);
std::cout << "Actual bhp was " << bhp_sum << std::endl;
switch(prodSpec().procedure_) {
case ProductionSpecification::WELL:
getWorstOffending(well_bhp).first->shutWell();
return false;
break;
case ProductionSpecification::RATE:
applyControl(BHP);
return false;
break;
default:
// Nothing do to;
break;
}
}
if(well_rate[index_of_well] - rate_target > epsilon) {
if(rate_sum - rate_target > epsilon) {
std::cout << "well_rate not met" << std::endl;
std::cout << "target = " << rate_target << ", well_rate[index_of_well] = " << well_rate[index_of_well] << std::endl;
std::cout << "target = " << rate_target
<< ", well_rate[index_of_well] = "
<< rate_sum << std::endl;
std::cout << "Group name = " << name() << std::endl;
ExceedInformation info;
info.group_name_ = name();
info.surplus_ = well_rate[index_of_well] - rate_target;
info.well_index_ = index_of_well;
result.fluid_rate_.push_back(info);
switch(prodSpec().procedure_) {
case ProductionSpecification::WELL:
getWorstOffending(well_rate).first->shutWell();
return false;
break;
case ProductionSpecification::RATE:
applyControl(RATE);
return false;
break;
default:
// Nothing do to;
break;
}
}
summed_phases += child_phases_summed;
return true;
}
void WellsGroup::addChild(std::tr1::shared_ptr<WellsGroupInterface> child)
@ -193,6 +220,18 @@ namespace Opm
return sum;
}
std::pair<WellNode*, double> WellsGroup::getWorstOffending(const std::vector<double>& values)
{
std::pair<WellNode*, double> max;
for (size_t i = 0; i < children_.size(); i++) {
std::pair<WellNode*, double> child_max = children_[i]->getWorstOffending(values);
if (i == 0 || max.second < child_max.second) {
max = child_max;
}
}
return max;
}
WellNode::WellNode(const std::string& myname,
ProductionSpecification prod_spec,
InjectionSpecification inj_spec)
@ -200,19 +239,13 @@ namespace Opm
{
}
void WellNode::conditionsMet(const std::vector<double>& well_bhp,
bool WellNode::conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_rate,
const UnstructuredGrid& grid,
WellControlResult& result,
WellPhasesSummed& summed_phases,
const double epsilon)
{
if (parent_ != NULL) {
(static_cast<WellsGroup*> (parent_))
->conditionsMet(well_bhp, well_rate, grid, wells_,
self_index_, result, epsilon);
}
// Check for self:
if (wells_->type[self_index_] == PRODUCER) {
double bhp_diff = well_bhp[self_index_] - prodSpec().BHP_limit_;
@ -223,21 +256,14 @@ namespace Opm
std::cout << "BHP exceeded, bhp_diff = " << bhp_diff << std::endl;
std::cout << "BHP_limit = " << prodSpec().BHP_limit_ << std::endl;
std::cout << "BHP = " << well_bhp[self_index_] << std::endl;
ExceedInformation info;
info.group_name_ = name();
info.surplus_ = bhp_diff;
info.well_index_ = self_index_;
result.bhp_.push_back(info);
shutWell();
return false;
}
if (rate_diff > epsilon) {
ExceedInformation info;
info.group_name_ = name();
info.surplus_ = rate_diff;
info.well_index_ = self_index_;
result.fluid_rate_.push_back(info);
std::cout << "Rate exceeded, rate_diff = " << rate_diff << std::endl;
shutWell();
return false;
}
} else {
double bhp_diff = well_bhp[self_index_] - injSpec().BHP_limit_;
@ -246,22 +272,20 @@ namespace Opm
if (bhp_diff > epsilon) {
std::cout << "BHP exceeded, bhp_diff = " << bhp_diff<<std::endl;
ExceedInformation info;
info.group_name_ = name();
info.surplus_ = bhp_diff;
info.well_index_ = self_index_;
result.bhp_.push_back(info);
shutWell();
return false;
}
if (rate_diff > epsilon) {
std::cout << "Flow diff exceeded, flow_diff = " << rate_diff << std::endl;
ExceedInformation info;
info.group_name_ = name();
info.surplus_ = rate_diff;
info.well_index_ = self_index_;
result.fluid_rate_.push_back(info);
shutWell();
return false;
}
}
summed_phases.bhp_sum = well_bhp[self_index_];
summed_phases.rate_sum = well_rate[self_index_];
return true;
}
WellsGroupInterface* WellNode::findGroup(std::string name_of_node)
@ -279,7 +303,7 @@ namespace Opm
return true;
}
void WellNode::setWellsPointer(const struct Wells* wells, int self_index)
void WellNode::setWellsPointer(Wells* wells, int self_index)
{
wells_ = wells;
self_index_ = self_index;
@ -294,6 +318,40 @@ namespace Opm
{
return 1;
}
void WellNode::shutWell()
{
wells_->ctrls[self_index_]->target[0] = 0.0;
}
std::pair<WellNode*, double> WellNode::getWorstOffending(const std::vector<double>& values) {
return std::make_pair<WellNode*, double>(this, values[self_index_]);
}
void WellNode::applyControl(const WellControlType type)
{
wells_->ctrls[self_index_]->type[0] = type;
double target = 0.0;
switch(type) {
case BHP:
if(wells_->type[self_index_] == INJECTOR) {
target = injSpec().BHP_limit_;
}
else {
target = prodSpec().BHP_limit_;
}
break;
case RATE:
if(wells_->type[self_index_] == INJECTOR) {
target = injSpec().fluid_volume_max_rate_;
}
else {
target = prodSpec().fluid_volume_max_rate_;
}
break;
}
wells_->ctrls[self_index_]->target[0] = target;
}
namespace
{

View File

@ -10,17 +10,13 @@
namespace Opm
{
struct ExceedInformation {
std::string group_name_;
int well_index_;
double surplus_;
};
struct WellControlResult {
std::vector<ExceedInformation> oil_rate_;
std::vector<ExceedInformation> fluid_rate_;
std::vector<ExceedInformation> bhp_;
class WellNode;
struct WellPhasesSummed {
WellPhasesSummed();
double bhp_sum;
double rate_sum;
void operator+=(const WellPhasesSummed& other);
};
class WellsGroupInterface
@ -64,6 +60,17 @@ namespace Opm
/// Calculates the number of leaf nodes in the given group.
/// A leaf node is defined to have one leaf node in its group.
virtual int numberOfLeafNodes() = 0;
/// Fills the WellControlResult parameter with all exceed information
virtual bool conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_rate,
WellPhasesSummed& summed_phases,
const double epsilon = 1e-8) = 0;
virtual void applyControl(const WellControlType type) = 0;
virtual std::pair<WellNode*, double> getWorstOffending(const std::vector<double>& values) = 0;
protected:
WellsGroupInterface* parent_;
@ -86,17 +93,18 @@ namespace Opm
void addChild(std::tr1::shared_ptr<WellsGroupInterface> child);
void conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_rate,
const UnstructuredGrid& grid,
const struct Wells* wells,
int index_of_well,
WellControlResult& result,
double epsilon = 1e-8);
virtual bool conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_rate,
WellPhasesSummed& summed_phases,
const double epsilon = 1e-8);
virtual void calculateGuideRates();
virtual int numberOfLeafNodes();
virtual std::pair<WellNode*, double> getWorstOffending(const std::vector<double>& values);
virtual void applyControl(const WellControlType type);
private:
std::vector<std::tr1::shared_ptr<WellsGroupInterface> > children_;
};
@ -111,19 +119,25 @@ namespace Opm
InjectionSpecification inj_spec);
virtual WellsGroupInterface* findGroup(std::string name_of_node);
virtual void conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_rate,
const UnstructuredGrid& grid,
WellControlResult& result,
double epsilon=1e-8);
virtual bool conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_rate,
WellPhasesSummed& summed_phases,
const double epsilon = 1e-8);
virtual bool isLeafNode() const;
void setWellsPointer(const struct Wells* wells, int self_index);
void setWellsPointer(Wells* wells, int self_index);
virtual void calculateGuideRates();
virtual int numberOfLeafNodes();
void shutWell();
virtual std::pair<WellNode*, double> getWorstOffending(const std::vector<double>& values);
virtual void applyControl(const WellControlType type);
private:
const struct Wells* wells_;
Wells* wells_;
int self_index_;
};

View File

@ -637,120 +637,10 @@ namespace Opm
return well_collection_;
}
/// Apply control results
/// \param[in] result The result of a run to conditionsMet on WellCollection
/// \param[in] wellCollection The WellCollection on which the control is to be issued on
void WellsManager::applyControl(const WellControlResult& result)
bool WellsManager::conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_rate)
{
// Check oil
std::map<std::string, std::vector<ExceedInformation> > oil_exceed;
for(size_t i = 0; i < result.oil_rate_.size(); i++) {
oil_exceed[result.oil_rate_[i].group_name_].push_back(result.oil_rate_[i]);
}
applyControl(oil_exceed, ProductionSpecification::ORAT);
// Check fluid
std::map<std::string, std::vector<ExceedInformation> > fluid_exceed;
for(size_t i = 0; i < result.fluid_rate_.size(); i++) {
fluid_exceed[result.oil_rate_[i].group_name_].push_back(result.fluid_rate_[i]);
}
applyControl(fluid_exceed, ProductionSpecification::LRAT);
// Check BHP
std::map<std::string, std::vector<ExceedInformation> > bhp_exceed;
for(size_t i = 0; i < result.bhp_.size(); i++) {
bhp_exceed[result.oil_rate_[i].group_name_].push_back(result.bhp_[i]);
}
applyControl(fluid_exceed, ProductionSpecification::BHP);
// Apply guide rates:
for (int i = 0; i < w_->number_of_wells; i++) {
if (well_collection_.getLeafNodes()[i]->prodSpec().control_mode_ == ProductionSpecification::GRUP) {
switch (well_collection_.getLeafNodes()[i]->prodSpec().guide_rate_type_) {
case ProductionSpecification::OIL:
{
// Not handled at the moment
}
case ProductionSpecification::NONE_GRT:
{
// Will use the group control type:
const ProductionSpecification& parent_prod_spec =
well_collection_.getLeafNodes()[i]->getParent()->prodSpec();
double guide_rate = well_collection_.getLeafNodes()[i]->prodSpec().guide_rate_;
if (parent_prod_spec.control_mode_ == ProductionSpecification::LRAT) {
w_->ctrls[i]->target[0] = guide_rate * parent_prod_spec.liquid_max_rate_;
w_->ctrls[i]->type[0] = RATE;
} else {
THROW("Unhandled group control mode " << parent_prod_spec.control_mode_);
}
}
default:
// Do nothing
break;
}
}
}
}
/// Apply control results for a specific target (OIL, WATER, etc)
/// \param[in] exceed_info will for each group name contain all the
/// exceed informations for the given mode.
/// \param[in] well_collection The associated well_collection.
/// \param[in] mode The ControlMode to which the violations apply.
void WellsManager::applyControl(const std::map<std::string, std::vector<ExceedInformation> >& exceed_info,
ProductionSpecification::ControlMode mode)
{
std::map<std::string, std::vector<ExceedInformation> >::const_iterator it;
for(it = exceed_info.begin(); it != exceed_info.end(); ++it) {
std::string group_name = it->first;
WellsGroupInterface* group = well_collection_.findNode(group_name);
if(group->isLeafNode()) {
// Just shut the well
int well_index = it->second[0].well_index_;
w_->ctrls[well_index]->target[0] = 0.0;
}
else {
switch(group->prodSpec().procedure_) {
case ProductionSpecification::WELL:
{
// Shut the worst offending well
double max_exceed = 0.0;
int exceed_index = -1;
for(size_t i = 0; i < it->second.size(); i++) {
if(max_exceed <= it->second[i].surplus_) {
exceed_index = it->second[i].well_index_;
max_exceed = it->second[i].surplus_;
}
}
w_->ctrls[exceed_index]->target[0] = 0.0;
break;
}
case ProductionSpecification::RATE:
{
// Now we need to set the group control mode to the active one
group->prodSpec().control_mode_ = mode;
break;
}
default:
// Do nothing for now
break;
}
}
}
return well_collection_.conditionsMet(well_bhp, well_rate);
}
} // namespace Opm

View File

@ -51,9 +51,6 @@ namespace Opm
/// Destructor.
~WellsManager();
/// Apply control results
/// \param[in] result The result of a run to conditionsMet on WellCollection
void applyControl(const WellControlResult& result);
/// Access the managed Wells.
/// The method is named similarly to c_str() in std::string,
@ -62,6 +59,9 @@ namespace Opm
/// Access the well group hierarchy.
const WellCollection& wellCollection() const;
bool conditionsMet(const std::vector<double>& well_bhp,
const std::vector<double>& well_rate);
private:
// Disable copying and assignment.
@ -72,13 +72,7 @@ namespace Opm
Wells* w_;
WellCollection well_collection_;
/// Apply control results for a specific target (OIL, WATER, etc)
/// \param[in] exceed_info will for each group name contain all the
/// exceed informations for the given mode.
/// \param[in] well_collection The associated well_collection.
/// \param[in] mode The ControlMode to which the violations apply.
void applyControl(const std::map<std::string, std::vector<ExceedInformation> >& exceed_info,
ProductionSpecification::ControlMode mode);
};