Merge pull request #1152 from GitPaean/fixing_updating_well_petentials_2

[WIP] changes needed to compute well potentials each time step.
This commit is contained in:
Andreas Lauser 2017-04-12 10:34:24 +02:00 committed by GitHub
commit 2e9b04fc37
9 changed files with 279 additions and 161 deletions

View File

@ -34,7 +34,7 @@ namespace Opm
BHP_limit_(-1e100),
reinjection_fraction_target_(1),
voidage_replacment_fraction_(1),
guide_rate_(1.0),
guide_rate_(-1.0),
guide_rate_type_(NONE_GRT)
{

View File

@ -36,7 +36,7 @@ namespace Opm
liquid_max_rate_(-1e100),
reservoir_flow_max_rate_(-1e100),
BHP_limit_(-1e100),
guide_rate_(1.0),
guide_rate_(-1.0),
guide_rate_type_(NONE_GRT)
{
}

View File

@ -194,6 +194,8 @@ namespace Opm
roots_[i]->applyProdGroupControls();
roots_[i]->applyInjGroupControls();
}
group_control_applied_ = true;
}
/// Applies explicit reinjection controls. This must be called at each timestep to be correct.
@ -282,9 +284,8 @@ namespace Opm
void WellCollection::updateWellTargets(const std::vector<double>& well_rates)
{
if ( !needUpdateWellTargets() && groupTargetConverged(well_rates)) {
return;
}
// TODO: if it gets converged, should we still update targets?
// set the target_updated to be false
for (WellNode* well_node : leaf_nodes_) {
@ -296,8 +297,7 @@ namespace Opm
// 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()) {
if (!leaf_nodes_[i]->targetUpdated()) {
WellsGroupInterface* parent_node = leaf_nodes_[i]->getParent();
// update the target within this group.
if (leaf_nodes_[i]->isProducer()) {
@ -324,6 +324,13 @@ namespace Opm
}
bool WellCollection::groupControlApplied() const
{
return group_control_applied_;
}
bool WellCollection::groupTargetConverged(const std::vector<double>& well_rates) const
{
// TODO: eventually, there should be only one root node
@ -336,4 +343,154 @@ namespace Opm
return true;
}
void WellCollection::
setGuideRatesWithPotentials(const Wells* wells,
const PhaseUsage& phase_usage,
const std::vector<double>& well_potentials) const
{
// TODO: assuming the order of well_potentials is the same with the order in wells struct
// TODO: it will overwrite the well potentials from other means. It should be changed after
// fixing the other part of the code. It makes the current flow only support guide rates based on
// well potentials.
const int np = wells->number_of_phases;
const int nw = wells->number_of_wells;
for (int w = 0; w < nw; ++w) {
const std::string well_name = wells->name[w];
WellNode& well_node = findWellNode(well_name);
const WellType well_type = wells->type[w];
// TODO: eventually the following standard will be wrong, it will belong to FIELD group
if (well_node.getParent() != nullptr) { // If it does not belong a group, will it belong to FIELD?
const WellsGroupInterface* group = well_node.getParent();
if (well_type == PRODUCER) {
// The guide rates is calculated based on the group control
// Currently only supporting WRAT, ORAT and GRAT.
ProductionSpecification::ControlMode control_mode = group->prodSpec().control_mode_;
if (control_mode == ProductionSpecification::FLD) {
if (group->getParent() != nullptr) {
// TODO: only handle one level FLD control
const WellsGroupInterface* higher_group = group->getParent();
control_mode = higher_group->prodSpec().control_mode_;
} else {
OPM_THROW(std::runtime_error, "Group " << group->name() << " is under FLD control while no higher level of group is specified.");
}
}
switch (control_mode) {
case ProductionSpecification::WRAT: {
if (!phase_usage.phase_used[BlackoilPhases::Aqua]) {
OPM_THROW(std::runtime_error, "Water phase not used, yet found water rate controlled well.");
}
const int water_index = phase_usage.phase_pos[BlackoilPhases::Aqua];
well_node.prodSpec().guide_rate_ = well_potentials[np * w + water_index];
well_node.prodSpec().guide_rate_type_ = ProductionSpecification::WATER;
break;
}
case ProductionSpecification::ORAT: {
if (!phase_usage.phase_used[BlackoilPhases::Liquid]) {
OPM_THROW(std::runtime_error, "Oil phase not used, yet found oil rate controlled well.");
}
const int oil_index = phase_usage.phase_pos[BlackoilPhases::Liquid];
well_node.prodSpec().guide_rate_ = well_potentials[np * w + oil_index];
well_node.prodSpec().guide_rate_type_ = ProductionSpecification::OIL;
break;
}
case ProductionSpecification::GRAT: {
if (!phase_usage.phase_used[BlackoilPhases::Vapour]) {
OPM_THROW(std::runtime_error, "Gas phase not used, yet found gas rate controlled well.");
}
const int gas_index = phase_usage.phase_pos[BlackoilPhases::Vapour];
well_node.prodSpec().guide_rate_ = well_potentials[np * w + gas_index];
well_node.prodSpec().guide_rate_type_ = ProductionSpecification::GAS;
break;
}
case ProductionSpecification::FLD: {
OPM_THROW(std::logic_error, "Not support more than one continous level of FLD control");
}
case ProductionSpecification::LRAT: {
double guide_rate = 0;
if (phase_usage.phase_used[BlackoilPhases::Liquid]) {
const int oil_index = phase_usage.phase_pos[BlackoilPhases::Liquid];
const double potential_oil = well_potentials[np * w + oil_index];
guide_rate += potential_oil;
}
if (phase_usage.phase_used[BlackoilPhases::Aqua]) {
const int water_index = phase_usage.phase_pos[BlackoilPhases::Aqua];
const double potential_water = well_potentials[np * w + water_index];
guide_rate += potential_water;
}
// not sure if no water and no oil, what will happen here, zero guide_rate?
well_node.prodSpec().guide_rate_ = guide_rate;
well_node.prodSpec().guide_rate_type_ = ProductionSpecification::LIQ;
break;
}
case ProductionSpecification::NONE: {
// Group control is not in use for this group.
break;
}
default:
OPM_THROW(std::logic_error, "Not supported control_mode for guide rate computed" <<
" from well potentials: " << ProductionSpecification::toString(group->prodSpec().control_mode_) );
}
} else if (well_type == INJECTOR) {
// The guide rates is calculated based on the group injector type
switch (group->injSpec().injector_type_) {
case InjectionSpecification::WATER: {
if (!phase_usage.phase_used[BlackoilPhases::Aqua]) {
OPM_THROW(std::runtime_error, "Water phase not used, yet found water injecting well.");
}
const int water_index = phase_usage.phase_pos[BlackoilPhases::Aqua];
well_node.injSpec().guide_rate_ = well_potentials[np * w + water_index];
// Guide rates applies to the phase that the well is injecting i.e water
well_node.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
break;
}
case InjectionSpecification::OIL: {
if (!phase_usage.phase_used[BlackoilPhases::Liquid]) {
OPM_THROW(std::runtime_error, "Oil phase not used, yet found oil injecting well.");
}
const int oil_index = phase_usage.phase_pos[BlackoilPhases::Liquid];
well_node.injSpec().guide_rate_ = well_potentials[np * w + oil_index];
// Guide rates applies to the phase that the well is injecting i.e. oil
well_node.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
break;
}
case InjectionSpecification::GAS: {
if (!phase_usage.phase_used[BlackoilPhases::Vapour]) {
OPM_THROW(std::runtime_error, "Gas phase not used, yet found gas injecting well.");
}
const int gas_index = phase_usage.phase_pos[BlackoilPhases::Vapour];
well_node.injSpec().guide_rate_ = well_potentials[np * w + gas_index];
// Guide rates applies to the phase that the well is injecting i.e gas
well_node.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
break;
}
default:
OPM_THROW(std::logic_error, "Not supported injector type for guide rate computed" <<
" from well potentials: " << InjectionSpecification::toString(group->injSpec().injector_type_) );
}
} else { // neither injector nor producer
OPM_THROW(std::logic_error, "Expected well type to be either INJECTOR or PRODUCER for well " << well_node.name() );
}
} // end of if (well_node.getParent() != nullptr)
} // end of for (int w = 0; w < nw; ++w)
}
bool WellCollection::requireWellPotentials() const
{
for (const auto& well_node : leaf_nodes_) {
if (well_node->isGuideRateWellPotential()) {
return true;
}
}
return false;
}
}

View File

@ -139,6 +139,9 @@ namespace Opm
/// Whether we have active group control
bool groupControlActive() const;
/// Whether we have applied the group control
bool groupControlApplied() 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
@ -146,6 +149,15 @@ namespace Opm
// 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;
/// Setting the guide rates with well potentials
void setGuideRatesWithPotentials(const Wells* wells,
const PhaseUsage& phase_usage,
const std::vector<double>& well_potentials) const;
bool requireWellPotentials() const;
private:
// To account for the possibility of a forest
std::vector<std::shared_ptr<WellsGroupInterface> > roots_;
@ -157,7 +169,8 @@ namespace Opm
bool group_control_active_ = false;
// This is used to mark whether apply or update the group control
bool group_control_applied_ = false;
};
} // namespace Opm

View File

@ -694,14 +694,17 @@ namespace Opm
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);
const InjectionSpecification::InjectorType injector_type = injSpec().injector_type_;
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);
children_[i]->applyVREPGroupControl(child_target, injector_type, well_voidage_rates, conversion_coeffs, false);
}
}
break;
// TODO: It should not be put under default case. It should always perform, since there can be multi VREP controls
// for different group levels. The same applies to other different types apply**Controls
default:
{
for (size_t i = 0; i < children_.size(); ++i ) {
@ -714,6 +717,7 @@ namespace Opm
// TODO: actually, it is not tested since it never get into this function.
void WellsGroup::applyVREPGroupControl(const double target,
const InjectionSpecification::InjectorType injector_type,
const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs,
const bool only_group)
@ -734,7 +738,7 @@ namespace Opm
}
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);
children_[i]->applyVREPGroupControl(child_target, injector_type, well_voidage_rates, conversion_coeffs, false);
}
// I do not know why here.
injSpec().control_mode_ = InjectionSpecification::FLD;
@ -784,7 +788,7 @@ namespace Opm
}
// the rates left for the wells under group control to split
const double rate_for_group_control = target_rate - rate_individual_control;
const double rate_for_group_control = std::max(target_rate - rate_individual_control, 0.0);
const double my_guide_rate = productionGuideRate(true);
@ -859,13 +863,22 @@ namespace Opm
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()) {
if (production_rate < production_target) {
// 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!");
return true;
}
} else { // overproducing the target, the only possibility is that all the wells/groups are under individual control
// while somehow our algorithms did not make the wells/groups return group controls
// either we should fix the algorithm of determining the target for well to return group controls
// or we should do something here
OpmLog::info("group " + name() + " is overproducing its target!");
return false;
} else {
// can not produce more to meet the target
OpmLog::info("group " + name() + " can not meet its target!");
}
}
}
@ -908,7 +921,8 @@ namespace Opm
self_index_(-1),
group_control_index_(-1),
shut_well_(true), // This is default for now
target_updated_(false) // This is default for now, not sure whether to use the default value
target_updated_(false), // This is default for now, not sure whether to use the default value
is_guiderate_wellpotential_(false)
{
}
@ -1071,7 +1085,7 @@ namespace Opm
const bool only_group)
{
if ( !isInjector() ) {
// assert(target == 0.0);
assert(target == 0.0 || std::isnan(target));
return;
}
@ -1127,6 +1141,7 @@ namespace Opm
// Put the well under group control immediately when GRUP control mdoe is specified
if (injSpec().control_mode_ == InjectionSpecification::GRUP) {
set_current_control(self_index_, group_control_index_, wells_);
individual_control_ = false;
}
} else {
// We will now modify the last control, that
@ -1190,6 +1205,7 @@ namespace Opm
}
void WellNode::applyVREPGroupControl(const double target,
const InjectionSpecification::InjectorType injector_type,
const std::vector<double>& /*well_voidage_rates*/,
const std::vector<double>& conversion_coeffs,
const bool only_group)
@ -1209,11 +1225,37 @@ namespace Opm
// 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 int* phase_pos = phaseUsage().phase_pos;
const int* phase_used = phaseUsage().phase_used;
std::vector<double> distr(np, 0.0);
switch(injector_type) {
case InjectionSpecification::WATER: {
if (!phase_used[BlackoilPhases::Aqua]) {
OPM_THROW(std::runtime_error, "Water phase not active and Water VREP injection control specified.");
}
const int phase_position = phase_pos[BlackoilPhases::Aqua];
distr[phase_position] = conversion_coeffs[np * self_index_ + phase_position];
break;
}
case InjectionSpecification::OIL: {
if (!phase_used[BlackoilPhases::Liquid]) {
OPM_THROW(std::runtime_error, "Oil phase not active and Oil VREP injection control specified.");
}
const int phase_position = phase_pos[BlackoilPhases::Liquid];
distr[phase_position] = conversion_coeffs[np * self_index_ + phase_position];
break;
}
case InjectionSpecification::GAS: {
if (!phase_used[BlackoilPhases::Vapour]) {
OPM_THROW(std::runtime_error, "Gas phase not active and Gas VREP injection control specified.");
}
const int phase_position = phase_pos[BlackoilPhases::Vapour];
distr[phase_position] = conversion_coeffs[np * self_index_ + phase_position];
break;
}
default:
OPM_THROW(std::runtime_error, "Group VREP injection type not handled: " << InjectionSpecification::toString(injector_type));
}
const double invalid_alq = -std::numeric_limits<double>::max();
const int invalid_vfp = -std::numeric_limits<int>::max();
@ -1223,9 +1265,11 @@ namespace Opm
// 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;
set_current_control(self_index_, group_control_index_, wells_);
// Put the well under group control immediately when GRUP control mdoe is specified
if (injSpec().control_mode_ == InjectionSpecification::GRUP) {
set_current_control(self_index_, group_control_index_, wells_);
individual_control_ = false;
}
} else {
well_controls_iset_type(wells_->ctrls[self_index_] , group_control_index_ , RESERVOIR_RATE);
well_controls_iset_target(wells_->ctrls[self_index_] , group_control_index_ , ntarget);
@ -1249,7 +1293,7 @@ namespace Opm
const bool only_group)
{
if ( !isProducer() ) {
assert(target == 0.0);
assert(target == 0.0 || std::isnan(target));
return;
}
@ -1312,6 +1356,7 @@ namespace Opm
// Put the well under group control immediately when GRUP control mdoe is specified
if (prodSpec().control_mode_ == ProductionSpecification::GRUP) {
set_current_control(self_index_, group_control_index_, wells_);
individual_control_ = false;
}
} else {
// We will now modify the last control, that
@ -1607,6 +1652,18 @@ namespace Opm
}
bool WellNode::isGuideRateWellPotential() const
{
return is_guiderate_wellpotential_;
}
void WellNode::setIsGuideRateWellPotential(const bool flag)
{
is_guiderate_wellpotential_ = flag;
}
bool WellNode::canProduceMore() const
{
return (isProducer() && !individualControl());

View File

@ -211,6 +211,7 @@ namespace Opm
const std::vector<double>& conversion_coeffs) = 0;
virtual void applyVREPGroupControl(const double target,
const InjectionSpecification::InjectorType injector_type,
const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs,
const bool only_group) = 0;
@ -366,6 +367,7 @@ namespace Opm
const std::vector<double>& conversion_coeffs);
virtual void applyVREPGroupControl(const double target,
const InjectionSpecification::InjectorType injector_type,
const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs,
const bool only_group);
@ -484,6 +486,7 @@ namespace Opm
const std::vector<double>& conversion_coeffs);
virtual void applyVREPGroupControl(const double target,
const InjectionSpecification::InjectorType injector_type,
const std::vector<double>& well_voidage_rates,
const std::vector<double>& conversion_coeffs,
const bool only_group);
@ -511,6 +514,10 @@ namespace Opm
bool targetUpdated() const;
bool isGuideRateWellPotential() const;
void setIsGuideRateWellPotential(const bool flag);
virtual void setTargetUpdated(const bool flag);
virtual bool canProduceMore() const;
@ -524,6 +531,10 @@ namespace Opm
bool shut_well_;
// TODO: used when updating well targets
bool target_updated_;
// whether the guide rate is specified with well potential
// TODO: we have never handle the guide rates for groups, maybe this
// is something will go to WellsGroupInterface later
bool is_guiderate_wellpotential_;
};
/// Creates the WellsGroupInterface for the given well

View File

@ -331,7 +331,6 @@ namespace Opm
const UnstructuredGrid& grid)
: w_(0), is_parallel_run_(false)
{
std::vector<double> dummy_well_potentials;
// TODO: not sure about the usage of this WellsManager constructor
// TODO: not sure whether this is the correct thing to do here.
DynamicListEconLimited dummy_list_econ_limited;
@ -339,7 +338,7 @@ namespace Opm
UgGridHelpers::globalCell(grid), UgGridHelpers::cartDims(grid),
UgGridHelpers::dimensions(grid),
UgGridHelpers::cell2Faces(grid), UgGridHelpers::beginFaceCentroids(grid),
dummy_list_econ_limited, dummy_well_potentials,
dummy_list_econ_limited,
std::unordered_set<std::string>());
}
@ -734,10 +733,9 @@ namespace Opm
}
void WellsManager::setupGuideRates(std::vector< const Well* >& wells, const size_t timeStep, std::vector<WellData>& well_data, std::map<std::string, int>& well_names_to_index,
const PhaseUsage& phaseUsage, const std::vector<double>& well_potentials)
// only handle the guide rates from the keyword WGRUPCON
void WellsManager::setupGuideRates(std::vector< const Well* >& wells, const size_t timeStep, std::vector<WellData>& well_data, std::map<std::string, int>& well_names_to_index)
{
const int np = phaseUsage.num_phases;
for (auto wellIter = wells.begin(); wellIter != wells.end(); ++wellIter ) {
const auto* well = *wellIter;
@ -749,7 +747,8 @@ namespace Opm
const int wix = well_names_to_index[well->name()];
WellNode& wellnode = *well_collection_.getLeafNodes()[wix];
if (well->getGuideRatePhase(timeStep) != GuideRate::UNDEFINED) {
// TODO: looks like only handling OIL phase guide rate for producers
if (well->getGuideRatePhase(timeStep) != GuideRate::UNDEFINED && well->getGuideRate(timeStep) >= 0.) {
if (well_data[wix].type == PRODUCER) {
wellnode.prodSpec().guide_rate_ = well->getGuideRate(timeStep);
if (well->getGuideRatePhase(timeStep) == GuideRate::OIL) {
@ -769,125 +768,10 @@ namespace Opm
} else {
OPM_THROW(std::runtime_error, "Unknown well type " << well_data[wix].type << " for well " << well->name());
}
} else if (well_potentials.size() > 0) { // default: calculate guide rates from well potentials
// Note: Modification of the guide rate using GUIDERAT is not supported
// only set the guide rates if there is a parent group with valied control
if (wellnode.getParent() != nullptr) {
const WellsGroupInterface& group = *wellnode.getParent();
if ( well->isProducer(timeStep) ) {
// The guide rates is calculated based on the group control
// Currently only supporting WRAT, ORAT and GRAT.
ProductionSpecification::ControlMode control_mode = group.prodSpec().control_mode_;
if (control_mode == ProductionSpecification::FLD) {
if (group.getParent() != nullptr) {
const WellsGroupInterface& higher_group = *(group.getParent());
control_mode = higher_group.prodSpec().control_mode_;
} else {
OPM_THROW(std::runtime_error, "Group " << group.name() << " is under FLD control while no higher level of group is specified.");
}
}
switch (control_mode) {
case ProductionSpecification::WRAT: {
if (!phaseUsage.phase_used[BlackoilPhases::Aqua]) {
OPM_THROW(std::runtime_error, "Water phase not used, yet found water rate controlled well.");
}
const int water_index = phaseUsage.phase_pos[BlackoilPhases::Aqua];
wellnode.prodSpec().guide_rate_ = well_potentials[np*wix + water_index];
wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::WATER;
break;
}
case ProductionSpecification::ORAT: {
if (!phaseUsage.phase_used[BlackoilPhases::Liquid]) {
OPM_THROW(std::runtime_error, "Oil phase not used, yet found oil rate controlled well.");
}
const int oil_index = phaseUsage.phase_pos[BlackoilPhases::Liquid];
wellnode.prodSpec().guide_rate_ = well_potentials[np*wix + oil_index];
wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::OIL;
break;
}
case ProductionSpecification::GRAT: {
if (!phaseUsage.phase_used[BlackoilPhases::Vapour]) {
OPM_THROW(std::runtime_error, "Gas phase not used, yet found gas rate controlled well.");
}
const int gas_index = phaseUsage.phase_pos[BlackoilPhases::Vapour];
wellnode.prodSpec().guide_rate_ = well_potentials[np*wix + gas_index];
wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::GAS;
break;
}
case ProductionSpecification::FLD: {
OPM_THROW(std::logic_error, "Not support more than one continous level of FLD control");
}
case ProductionSpecification::LRAT: {
double guide_rate = 0;
if (phaseUsage.phase_used[BlackoilPhases::Liquid]) {
const int oil_index = phaseUsage.phase_pos[BlackoilPhases::Liquid];
const double potential_oil = well_potentials[np*wix + oil_index];
guide_rate += potential_oil;
}
if (phaseUsage.phase_used[BlackoilPhases::Aqua]) {
const int water_index = phaseUsage.phase_pos[BlackoilPhases::Aqua];
const double potential_water = well_potentials[np*wix + water_index];
guide_rate += potential_water;
}
// not sure if no water and no oil, what will happen here, zero guide_rate?
wellnode.prodSpec().guide_rate_ = guide_rate;
wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::LIQ;
}
case ProductionSpecification::NONE: {
// Group control is not in use for this group.
break;
}
default:
OPM_THROW(std::logic_error, "Not supported control_mode for guide rate computed" <<
" from well potentials: " << group.prodSpec().control_mode_);
}
} else {
// The guide rates is calculated based on the group injector type
switch (group.injSpec().injector_type_) {
case InjectionSpecification::WATER: {
if (!phaseUsage.phase_used[BlackoilPhases::Aqua]) {
OPM_THROW(std::runtime_error, "Water phase not used, yet found water injecting well.");
}
const int water_index = phaseUsage.phase_pos[BlackoilPhases::Aqua];
wellnode.injSpec().guide_rate_ = well_potentials[np*wix + water_index];
// Guide rates applies to the phase that the well is injecting i.e water
wellnode.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
break;
}
case InjectionSpecification::OIL: {
if (!phaseUsage.phase_used[BlackoilPhases::Liquid]) {
OPM_THROW(std::runtime_error, "Oil phase not used, yet found oil injecting well.");
}
const int oil_index = phaseUsage.phase_pos[BlackoilPhases::Liquid];
wellnode.injSpec().guide_rate_ = well_potentials[np*wix + oil_index];
// Guide rates applies to the phase that the well is injecting i.e. oil
wellnode.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
break;
}
case InjectionSpecification::GAS: {
if (!phaseUsage.phase_used[BlackoilPhases::Vapour]) {
OPM_THROW(std::runtime_error, "Gas phase not used, yet found gas injecting well.");
}
const int gas_index = phaseUsage.phase_pos[BlackoilPhases::Vapour];
wellnode.injSpec().guide_rate_ = well_potentials[np*wix + gas_index];
// Guide rates applies to the phase that the well is injecting i.e gas
wellnode.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
break;
}
default:
OPM_THROW(std::logic_error, "Not supported injector type for guide rate computed" <<
" from well potentials: " << group.injSpec().injector_type_);
}
}
}
} // if neither WGRUPCON nor well_potentials is given, distribute the flow equaly
} else {
wellnode.setIsGuideRateWellPotential(true);
}
}
}
} // namespace Opm

View File

@ -94,7 +94,6 @@ namespace Opm
FC begin_face_centroids,
const DynamicListEconLimited& list_econ_limited,
bool is_parallel_run=false,
const std::vector<double>& well_potentials=std::vector<double>(),
const std::unordered_set<std::string>& deactivated_wells = std::unordered_set<std::string> ());
WellsManager(const Opm::EclipseState& eclipseState,
@ -163,7 +162,6 @@ namespace Opm
const C2F& cell_to_faces,
FC begin_face_centroids,
const DynamicListEconLimited& list_econ_limited,
const std::vector<double>& well_potentials,
const std::unordered_set<std::string>& deactivated_wells);
// Disable copying and assignment.
WellsManager(const WellsManager& other);
@ -192,8 +190,8 @@ namespace Opm
const std::unordered_set<std::string>& deactivated_wells,
const DynamicListEconLimited& list_econ_limited);
void setupGuideRates(std::vector<const Well*>& wells, const size_t timeStep, std::vector<WellData>& well_data, std::map<std::string, int>& well_names_to_index,
const PhaseUsage& phaseUsage, const std::vector<double>& well_potentials);
void setupGuideRates(std::vector<const Well*>& wells, const size_t timeStep, std::vector<WellData>& well_data, std::map<std::string, int>& well_names_to_index);
// Data
Wells* w_;
WellCollection well_collection_;

View File

@ -318,13 +318,12 @@ WellsManager(const Opm::EclipseState& eclipseState,
FC begin_face_centroids,
const DynamicListEconLimited& list_econ_limited,
bool is_parallel_run,
const std::vector<double>& well_potentials,
const std::unordered_set<std::string>& deactivated_wells)
: w_(0), is_parallel_run_(is_parallel_run)
{
init(eclipseState, timeStep, number_of_cells, global_cell,
cart_dims, dimensions,
cell_to_faces, begin_face_centroids, list_econ_limited, well_potentials, deactivated_wells);
cell_to_faces, begin_face_centroids, list_econ_limited, deactivated_wells);
}
/// Construct wells from deck.
@ -339,7 +338,6 @@ WellsManager::init(const Opm::EclipseState& eclipseState,
const C2F& cell_to_faces,
FC begin_face_centroids,
const DynamicListEconLimited& list_econ_limited,
const std::vector<double>& well_potentials,
const std::unordered_set<std::string>& deactivated_wells)
{
if (dimensions != 3) {
@ -445,8 +443,8 @@ WellsManager::init(const Opm::EclipseState& eclipseState,
well_collection_.setWellsPointer(w_);
if (well_collection_.groupControlActive()) {
setupGuideRates(wells, timeStep, well_data, well_names_to_index, pu, well_potentials);
well_collection_.applyGroupControls();
// here does not consider the well potentials related guide rate setting
setupGuideRates(wells, timeStep, well_data, well_names_to_index);
}
// Debug output.