Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support instantaneous flow rates in extended network (WEFAC and GEFAC item 3) #4094

Merged
merged 3 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions opm/input/eclipse/Schedule/Group/Group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ Group::Group(const std::string& name, std::size_t insert_index_arg, double udq_u
unit_system(unit_system_arg),
group_type(GroupType::NONE),
gefac(1),
transfer_gefac(true),
use_efficiency_in_network(true),
production_properties(unit_system, name)
{
// All groups are initially created as children of the "FIELD" group.
Expand Down Expand Up @@ -267,7 +267,7 @@ Group Group::serializationTestObject()
result.unit_system = UnitSystem::serializationTestObject();
result.group_type = GroupType::PRODUCTION;
result.gefac = 4.0;
result.transfer_gefac = true;
result.use_efficiency_in_network = true;
result.parent_group = "test2";
result.m_wells = {{"test3", "test4"}, {"test5", "test6"}};
result.m_groups = {{"test7", "test8"}, {"test9", "test10"}};
Expand Down Expand Up @@ -698,27 +698,31 @@ void Group::delGroup(const std::string& group_name) {
};
}

bool Group::update_gefac(double gf, bool transfer_gf) {
bool Group::update_gefac(double gf, bool use_efficiency_in_network_arg) {
bool update = false;
if (this->gefac != gf) {
this->gefac = gf;
update = true;
}

if (this->transfer_gefac != transfer_gf) {
this->transfer_gefac = transfer_gf;
if (this->use_efficiency_in_network != use_efficiency_in_network_arg) {
this->use_efficiency_in_network = use_efficiency_in_network_arg;
update = true;
}

return update;
}

double Group::getGroupEfficiencyFactor() const {
double Group::getGroupEfficiencyFactor(bool network) const {
if (network && !(this->use_efficiency_in_network)) {
return 1.0;
}

return this->gefac;
}

bool Group::getTransferGroupEfficiencyFactor() const {
return this->transfer_gefac;
bool Group::useEfficiencyInNetwork() const {
return this->use_efficiency_in_network;
}

const std::string& Group::parent() const {
Expand Down Expand Up @@ -1223,7 +1227,7 @@ bool Group::operator==(const Group& data) const
this->unit_system == data.unit_system &&
this->group_type == data.group_type &&
this->getGroupEfficiencyFactor() == data.getGroupEfficiencyFactor() &&
this->getTransferGroupEfficiencyFactor() == data.getTransferGroupEfficiencyFactor() &&
this->useEfficiencyInNetwork() == data.useEfficiencyInNetwork() &&
this->parent() == data.parent() &&
this->m_wells == data.m_wells &&
this->m_groups == data.m_groups &&
Expand Down
10 changes: 5 additions & 5 deletions opm/input/eclipse/Schedule/Group/Group.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ class Group {
const std::string& name() const;
bool is_field() const;

bool update_gefac(double gefac, bool transfer_gefac);
bool update_gefac(double gefac, bool use_efficiency_in_network);

// [[deprecated("use Group::control_group() or Group::flow_group()")]]
const std::string& parent() const;
Expand All @@ -292,8 +292,8 @@ class Group {
bool isInjectionGroup() const;
void setProductionGroup();
void setInjectionGroup();
double getGroupEfficiencyFactor() const;
bool getTransferGroupEfficiencyFactor() const;
double getGroupEfficiencyFactor(bool network = false) const;
bool useEfficiencyInNetwork() const;

std::size_t numWells() const;
bool addGroup(const std::string& group_name);
Expand Down Expand Up @@ -340,7 +340,7 @@ class Group {
serializer(unit_system);
serializer(group_type);
serializer(gefac);
serializer(transfer_gefac);
serializer(use_efficiency_in_network);
serializer(parent_group);
serializer(m_wells);
serializer(m_groups);
Expand All @@ -360,7 +360,7 @@ class Group {
UnitSystem unit_system;
GroupType group_type;
double gefac;
bool transfer_gefac;
bool use_efficiency_in_network;

std::string parent_group;
IOrderSet<std::string> m_wells;
Expand Down
4 changes: 2 additions & 2 deletions opm/input/eclipse/Schedule/Group/GroupKeywordHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,12 +414,12 @@ void handleGEFAC(HandlerContext& handlerContext)
handlerContext.invalidNamePattern(groupNamePattern);
}

const bool transfer = DeckItem::to_bool(record.getItem("TRANSFER_EXT_NET").getTrimmedString(0));
const bool use_efficiency_in_network = DeckItem::to_bool(record.getItem("USE_GEFAC_IN_NETWORK").getTrimmedString(0));
const auto gefac = record.getItem("EFFICIENCY_FACTOR").get<double>(0);

for (const auto& group_name : group_names) {
auto new_group = handlerContext.state().groups.get(group_name);
if (new_group.update_gefac(gefac, transfer)) {
if (new_group.update_gefac(gefac, use_efficiency_in_network)) {
handlerContext.state().wellgroup_events().addEvent( group_name, ScheduleEvents::WELLGROUP_EFFICIENCY_UPDATE);
handlerContext.state().events().addEvent( ScheduleEvents::WELLGROUP_EFFICIENCY_UPDATE );
handlerContext.state().groups.update(std::move(new_group));
Expand Down
27 changes: 27 additions & 0 deletions opm/input/eclipse/Schedule/Network/ExtNetwork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <cassert>
#include <iterator>
#include <stdexcept>
#include <fmt/format.h>
#include <vector>
#include <stack>
#include <functional>

#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>

namespace Opm {
namespace Network {
Expand Down Expand Up @@ -235,5 +239,28 @@ std::vector<std::string> ExtNetwork::node_names() const
{
return this->insert_indexed_node_names;
}

std::set<std::string> ExtNetwork::leaf_nodes() const
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function looks correct to me. From the usage in the opm-simulators, it looks like it will be called many times. Ideally, it will be nice if we can save the results somehow to avoid repeating the process.

This can be done in a following up PR if it turns out to be costly and needs to be optimized.

{
std::set<std::string> leaf_nodes;
auto roots = this->roots();
for (const auto& root : roots) {
std::stack<std::string> children;
children.push(root.get().name());
while (!children.empty()) {
const auto& node = children.top();
children.pop();
auto branches = this->downtree_branches(node);
if (branches.empty()) {
leaf_nodes.emplace(node);
}
for (const auto& branch : branches) {
children.push(branch.downtree_node());
}
}
}
return leaf_nodes;
}

}
}
4 changes: 4 additions & 0 deletions opm/input/eclipse/Schedule/Network/ExtNetwork.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@
#include <optional>
#include <string>
#include <vector>
#include <set>
#include <functional>

#include <opm/input/eclipse/Schedule/Network/Branch.hpp>
#include <opm/input/eclipse/Schedule/Network/Node.hpp>

namespace Opm {
class Schedule;

namespace Network {


Expand All @@ -51,6 +54,7 @@ class ExtNetwork {
std::vector<const Branch*> branches() const;
std::optional<Branch> uptree_branch(const std::string& node) const;
std::vector<std::string> node_names() const;
std::set<std::string> leaf_nodes() const;
int NoOfBranches() const;
int NoOfNodes() const;

Expand Down
101 changes: 68 additions & 33 deletions opm/input/eclipse/Schedule/Network/NetworkKeywordHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,36 @@ void handleGRUPNET(HandlerContext& handlerContext)
handlerContext.state().network.update( std::move(network));
}

void handleNEFAC(HandlerContext& handlerContext)
{
auto ext_network = handlerContext.state().network.get();
if (!ext_network.active())
return;
if (ext_network.is_standard_network()) {
const std::string& msg = "NEFAC has no effect for a standard network: file {filename} line {lineno}";
OpmLog::warning(handlerContext.keyword.location().format(msg));
return;
}

bool updated = false;
for (const auto& record : handlerContext.keyword) {
const auto& node_name = record.getItem<ParserKeywords::NEFAC::NODE>().get<std::string>(0);
const auto efficiency = record.getItem<ParserKeywords::NEFAC::EFF_FACTOR>().getSIDouble(0);

if (ext_network.has_node(node_name)) {
auto node = ext_network.node(node_name);
if (node.efficiency() != efficiency) {
node.set_efficiency(efficiency);
ext_network.update_node(node);
updated = true;
}
}
}

if (updated)
handlerContext.state().network.update( std::move(ext_network) );
}

void handleNETBALAN(HandlerContext& handlerContext)
{
handlerContext.state().network_balance
Expand Down Expand Up @@ -180,44 +210,48 @@ void handleNODEPROP(HandlerContext& handlerContext)
node.terminal_pressure(pressure_item.getSIDouble(0));
}

if (as_choke) {
if (handlerContext.state().groups.has(name)) {
auto& group = handlerContext.state().groups.get(name);
group.as_choke(name);
if (group.wellgroup()) {
// Wells belong to a group with autochoke enabled are to be run on a common THP and should not have guide rates
for (const std::string& wellName : group.wells()) {
auto well = handlerContext.state().wells.get(wellName);

// Let the wells be operating on a THP Constraint
auto properties = std::make_shared<Well::WellProductionProperties>(well.getProductionProperties());
// The wells are not to be under GRUP control using guide rates but under THP control
properties->addProductionControl(Well::ProducerCMode::THP);
properties->controlMode = Well::ProducerCMode::THP;
well.updateProduction(properties);

// Guide rate availability should be set to false
well.updateAvailableForGroupControl(false);
auto new_config = handlerContext.state().guide_rate();
new_config.update_well(well);
handlerContext.state().guide_rate.update( std::move(new_config) );
handlerContext.state().wells.update( std::move(well) );
}
std::string target_group = name;
const auto& target_item = record.getItem<ParserKeywords::NODEPROP::CHOKE_GROUP>();

if (target_item.hasValue(0)) {
target_group = target_item.get<std::string>(0);
node.set_efficiency(group.getGroupEfficiencyFactor(/*network*/ true));

if (as_choke) {
group.as_choke(name);
if (group.wellgroup()) {
// Wells belong to a group with autochoke enabled are to be run on a common THP and should not have guide rates
for (const std::string& wellName : group.wells()) {
auto well = handlerContext.state().wells.get(wellName);

// Let the wells be operating on a THP Constraint
auto properties = std::make_shared<Well::WellProductionProperties>(well.getProductionProperties());
// The wells are not to be under GRUP control using guide rates but under THP control
properties->addProductionControl(Well::ProducerCMode::THP);
properties->controlMode = Well::ProducerCMode::THP;
well.updateProduction(properties);

// Guide rate availability should be set to false
well.updateAvailableForGroupControl(false);
auto new_config = handlerContext.state().guide_rate();
new_config.update_well(well);
handlerContext.state().guide_rate.update( std::move(new_config) );
handlerContext.state().wells.update( std::move(well) );
}
std::string target_group = name;
const auto& target_item = record.getItem<ParserKeywords::NODEPROP::CHOKE_GROUP>();

if (target_item.hasValue(0)) {
target_group = target_item.get<std::string>(0);
}
if (target_group != name) {
const std::string msg = "A manifold group must respond to its own target.";
throw OpmInputError(msg, handlerContext.keyword.location());
}
node.as_choke(target_group);
}
if (target_group != name) {
const std::string msg = "A manifold group must respond to its own target.";
else {
std::string msg = "The auto-choke option is implemented only for well groups.";
throw OpmInputError(msg, handlerContext.keyword.location());
}
node.as_choke(target_group);
}
else {
std::string msg = "The auto-choke option is implemented only for well groups.";
throw OpmInputError(msg, handlerContext.keyword.location());
}
}

node.add_gas_lift_gas(add_gas_lift_gas);
Expand All @@ -235,6 +269,7 @@ getNetworkHandlers()
return {
{ "BRANPROP", &handleBRANPROP },
{ "GRUPNET", &handleGRUPNET },
{ "NEFAC", &handleNEFAC },
{ "NETBALAN", &handleNETBALAN },
{ "NODEPROP", &handleNODEPROP },
};
Expand Down
21 changes: 15 additions & 6 deletions opm/input/eclipse/Schedule/Network/Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ bool Node::as_choke() const {
return this->m_choke_target_group.has_value();
}

double Node::efficiency() const {
return this->m_efficiency;
}

void Node::terminal_pressure(double pressure) {
this->m_terminal_pressure = pressure;
}
Expand All @@ -59,23 +63,28 @@ void Node::as_choke(const std::string& target_group) {
this->m_choke_target_group = target_group;
}

void Node::set_efficiency(const double efficiency) {
this->m_efficiency = efficiency;
}

bool Node::operator==(const Node& other) const {
return this->m_name == other.m_name &&
this->m_terminal_pressure == other.m_terminal_pressure &&
this->m_add_gas_lift_gas == other.m_add_gas_lift_gas &&
this->m_choke_target_group == other.m_choke_target_group;
this->m_choke_target_group == other.m_choke_target_group &&
this->m_efficiency == other.m_efficiency;
}


Node Node::serializationTestObject()
{
Node result;
result.m_name = "test";
result.m_terminal_pressure = 1.0;
result.m_add_gas_lift_gas = true;
Node result;
result.m_name = "test";
result.m_terminal_pressure = 1.0;
result.m_add_gas_lift_gas = true;
result.m_efficiency = 1.0;

return result;
return result;
}


Expand Down
6 changes: 5 additions & 1 deletion opm/input/eclipse/Schedule/Network/Node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ class Node {
const std::string& name() const;
const std::optional<double>& terminal_pressure() const;
bool as_choke() const;
double efficiency() const;
bool add_gas_lift_gas() const;
const std::optional<std::string>& target_group() const;

void terminal_pressure(double pressure);
void add_gas_lift_gas(bool add_gas);
void as_choke(const std::string& target_group);
void set_efficiency(const double efficiency);

static Node serializationTestObject();
bool operator==(const Node& other) const;
Expand All @@ -52,12 +54,14 @@ class Node {
serializer(m_terminal_pressure);
serializer(m_add_gas_lift_gas);
serializer(m_choke_target_group);
serializer(m_efficiency);
}
private:
std::string m_name;
std::optional<double> m_terminal_pressure;
std::optional<std::string> m_choke_target_group;
bool m_add_gas_lift_gas = false;
bool m_add_gas_lift_gas{false};
double m_efficiency{1.0};
};
}
}
Expand Down
Loading