Implement extended network model.

This commit is contained in:
Atgeirr Flø Rasmussen 2020-05-15 11:21:32 +02:00
parent f8c276d023
commit 52c695937b
10 changed files with 332 additions and 22 deletions

View File

@ -93,10 +93,11 @@ int main(int argc, char** argv)
} }
Setup setup(argv[1]); Setup setup(argv[1]);
// const int table_id = 1; // const int table_id = 1;
const int table_id = 4; const int table_id = 4;
const double wct = 0.0; const double wct = 0.0;
const double gor = 35.2743; // const double gor = 35.2743;
const double gor = 0.0;
const double alq = 0.0; const double alq = 0.0;
const int n = 51; const int n = 51;
const double m3pd = unit::cubic(unit::meter)/unit::day; const double m3pd = unit::cubic(unit::meter)/unit::day;

View File

@ -196,8 +196,8 @@ namespace Opm {
{ {
auto grp_nwrk_values = ::Opm::data::GroupAndNetworkValues{}; auto grp_nwrk_values = ::Opm::data::GroupAndNetworkValues{};
this->assignGroupValues(reportStepIdx, sched, this->assignGroupValues(reportStepIdx, sched, grp_nwrk_values.groupData);
grp_nwrk_values.groupData); this->assignNodeValues(reportStepIdx, sched, grp_nwrk_values.nodeData);
return grp_nwrk_values; return grp_nwrk_values;
} }
@ -315,6 +315,8 @@ namespace Opm {
WellTestState wellTestState_; WellTestState wellTestState_;
std::unique_ptr<GuideRate> guideRate_; std::unique_ptr<GuideRate> guideRate_;
std::map<std::string, double> node_pressures_; // Storing network pressures for output.
// used to better efficiency of calcuation // used to better efficiency of calcuation
mutable BVector scaleAddRes_; mutable BVector scaleAddRes_;
@ -355,6 +357,7 @@ namespace Opm {
void updateWellControls(Opm::DeferredLogger& deferred_logger, const bool checkGroupControls); void updateWellControls(Opm::DeferredLogger& deferred_logger, const bool checkGroupControls);
void updateAndCommunicateGroupData(); void updateAndCommunicateGroupData();
void updateNetworkPressures();
// setting the well_solutions_ based on well_state. // setting the well_solutions_ based on well_state.
void updatePrimaryVariables(Opm::DeferredLogger& deferred_logger); void updatePrimaryVariables(Opm::DeferredLogger& deferred_logger);
@ -452,6 +455,10 @@ namespace Opm {
const Schedule& sched, const Schedule& sched,
std::map<std::string, data::GroupData>& gvalues) const; std::map<std::string, data::GroupData>& gvalues) const;
void assignNodeValues(const int reportStepIdx,
const Schedule& sched,
std::map<std::string, data::NodeData>& gvalues) const;
std::unordered_map<std::string, data::GroupGuideRates> std::unordered_map<std::string, data::GroupGuideRates>
calculateAllGroupGuiderates(const int reportStepIdx, const Schedule& sched) const; calculateAllGroupGuiderates(const int reportStepIdx, const Schedule& sched) const;

View File

@ -329,6 +329,8 @@ namespace Opm {
BlackoilWellModel<TypeTag>:: BlackoilWellModel<TypeTag>::
beginTimeStep() { beginTimeStep() {
updatePerforationIntensiveQuantities();
Opm::DeferredLogger local_deferredLogger; Opm::DeferredLogger local_deferredLogger;
well_state_ = previous_well_state_; well_state_ = previous_well_state_;
@ -392,6 +394,11 @@ namespace Opm {
local_deferredLogger.warning("WELL_POTENTIAL_CALCULATION_FAILED", msg); local_deferredLogger.warning("WELL_POTENTIAL_CALCULATION_FAILED", msg);
} }
// Update the well rates to match state, if only single-phase rates.
for (auto& well : well_container_) {
well->updateWellStateRates(ebosSimulator_, well_state_, local_deferredLogger);
}
//compute well guideRates //compute well guideRates
const auto& comm = ebosSimulator_.vanguard().grid().comm(); const auto& comm = ebosSimulator_.vanguard().grid().comm();
WellGroupHelpers::updateGuideRatesForWells(schedule(), phase_usage_, reportStepIdx, simulationTime, well_state_, comm, guideRate_.get()); WellGroupHelpers::updateGuideRatesForWells(schedule(), phase_usage_, reportStepIdx, simulationTime, well_state_, comm, guideRate_.get());
@ -1219,6 +1226,8 @@ namespace Opm {
updateAndCommunicateGroupData(); updateAndCommunicateGroupData();
updateNetworkPressures();
std::set<std::string> switched_wells; std::set<std::string> switched_wells;
std::set<std::string> switched_groups; std::set<std::string> switched_groups;
@ -1257,6 +1266,44 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
updateNetworkPressures()
{
// Get the network and return if inactive.
const int reportStepIdx = ebosSimulator_.episodeIndex();
const auto& network = schedule().network(reportStepIdx);
if (!network.active()) {
return;
}
node_pressures_ = WellGroupHelpers::computeNetworkPressures(network, well_state_, *(vfp_properties_->getProd()));
// Set the thp limits of wells (producers only, TODO address injectors).
for (auto& well : well_container_) {
if (well->isProducer()) {
const auto it = node_pressures_.find(well->wellEcl().groupName());
if (it != node_pressures_.end()) {
// The well belongs to a group with has a network pressure constraint,
// set the dynamic THP constraint of the well accordingly.
well->setDynamicThpLimit(it->second);
}
}
}
// Output debug info.
if (terminal_output_) {
std::ostringstream oss;
oss << "Node pressures in network nodes, in bar:\n";
for (const auto& [name, pressure] : node_pressures_) {
oss << name << " " << unit::convert::to(pressure, unit::barsa) << '\n';
}
OpmLog::debug(oss.str());
}
}
template<typename TypeTag> template<typename TypeTag>
void void
@ -2503,6 +2550,19 @@ namespace Opm {
} }
} }
template <typename TypeTag>
void
BlackoilWellModel<TypeTag>::
assignNodeValues(const int reportStepIdx,
const Schedule& sched,
std::map<std::string, data::NodeData>& nodevalues) const
{
nodevalues.clear();
for (const auto& [node, pressure] : node_pressures_) {
nodevalues.emplace(node, data::NodeData{pressure});
}
}
template<typename TypeTag> template<typename TypeTag>
std::unordered_map<std::string, data::GroupGuideRates> std::unordered_map<std::string, data::GroupGuideRates>
BlackoilWellModel<TypeTag>:: BlackoilWellModel<TypeTag>::

View File

@ -2026,13 +2026,13 @@ namespace Opm
const auto& controls = well.injectionControls(summaryState); const auto& controls = well.injectionControls(summaryState);
const double vfp_ref_depth = vfp_properties_->getInj()->getTable(controls.vfp_table_number)->getDatumDepth(); const double vfp_ref_depth = vfp_properties_->getInj()->getTable(controls.vfp_table_number)->getDatumDepth();
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_); const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
return vfp_properties_->getInj()->bhp(controls.vfp_table_number, aqua, liquid, vapour, controls.thp_limit) - dp; return vfp_properties_->getInj()->bhp(controls.vfp_table_number, aqua, liquid, vapour, this->getTHPConstraint(summaryState)) - dp;
} }
else if (well.isProducer()) { else if (well.isProducer()) {
const auto& controls = well.productionControls(summaryState); const auto& controls = well.productionControls(summaryState);
const double vfp_ref_depth = vfp_properties_->getProd()->getTable(controls.vfp_table_number)->getDatumDepth(); const double vfp_ref_depth = vfp_properties_->getProd()->getTable(controls.vfp_table_number)->getDatumDepth();
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_); const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
return vfp_properties_->getProd()->bhp(controls.vfp_table_number, aqua, liquid, vapour, controls.thp_limit, controls.alq_value) - dp; return vfp_properties_->getProd()->bhp(controls.vfp_table_number, aqua, liquid, vapour, this->getTHPConstraint(summaryState), controls.alq_value) - dp;
} }
else { else {
OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well", deferred_logger); OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well", deferred_logger);
@ -3306,11 +3306,12 @@ namespace Opm
const auto& table = *(vfp_properties_->getProd()->getTable(controls.vfp_table_number)); const auto& table = *(vfp_properties_->getProd()->getTable(controls.vfp_table_number));
const double vfp_ref_depth = table.getDatumDepth(); const double vfp_ref_depth = table.getDatumDepth();
const double rho = segment_densities_[0].value(); // Use the density at the top perforation. const double rho = segment_densities_[0].value(); // Use the density at the top perforation.
const double thp_limit = this->getTHPConstraint(summary_state);
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_); const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
auto fbhp = [this, &controls, dp](const std::vector<double>& rates) { auto fbhp = [this, &controls, thp_limit, dp](const std::vector<double>& rates) {
assert(rates.size() == 3); assert(rates.size() == 3);
return this->vfp_properties_->getProd() return this->vfp_properties_->getProd()
->bhp(controls.vfp_table_number, rates[Water], rates[Oil], rates[Gas], controls.thp_limit, controls.alq_value) - dp; ->bhp(controls.vfp_table_number, rates[Water], rates[Oil], rates[Gas], thp_limit, controls.alq_value) - dp;
}; };
// Make the flo() function. // Make the flo() function.
@ -3529,11 +3530,12 @@ namespace Opm
const auto& table = *(vfp_properties_->getInj()->getTable(controls.vfp_table_number)); const auto& table = *(vfp_properties_->getInj()->getTable(controls.vfp_table_number));
const double vfp_ref_depth = table.getDatumDepth(); const double vfp_ref_depth = table.getDatumDepth();
const double rho = segment_densities_[0].value(); // Use the density at the top perforation. const double rho = segment_densities_[0].value(); // Use the density at the top perforation.
const double thp_limit = this->getTHPConstraint(summary_state);
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_); const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
auto fbhp = [this, &controls, dp](const std::vector<double>& rates) { auto fbhp = [this, &controls, thp_limit, dp](const std::vector<double>& rates) {
assert(rates.size() == 3); assert(rates.size() == 3);
return this->vfp_properties_->getInj() return this->vfp_properties_->getInj()
->bhp(controls.vfp_table_number, rates[Water], rates[Oil], rates[Gas], controls.thp_limit) - dp; ->bhp(controls.vfp_table_number, rates[Water], rates[Oil], rates[Gas], thp_limit) - dp;
}; };
// Make the flo() function. // Make the flo() function.

View File

@ -296,6 +296,10 @@ namespace Opm
using Base::phaseUsage; using Base::phaseUsage;
using Base::vfp_properties_; using Base::vfp_properties_;
virtual void updateWellStateRates(const Simulator& ebosSimulator,
WellState& well_state,
DeferredLogger& deferred_logger) const override;
protected: protected:
// protected functions from the Base class // protected functions from the Base class

View File

@ -1441,7 +1441,7 @@ namespace Opm
} }
case Well::ProducerCMode::THP: case Well::ProducerCMode::THP:
{ {
well_state.thp()[well_index] = controls.thp_limit; well_state.thp()[well_index] = this->getTHPConstraint(summaryState);
gliftDebug( gliftDebug(
"computing BHP from THP to update well state", "computing BHP from THP to update well state",
deferred_logger); deferred_logger);
@ -2900,13 +2900,13 @@ namespace Opm
const auto& controls = well.injectionControls(summaryState); const auto& controls = well.injectionControls(summaryState);
const double vfp_ref_depth = vfp_properties_->getInj()->getTable(controls.vfp_table_number)->getDatumDepth(); const double vfp_ref_depth = vfp_properties_->getInj()->getTable(controls.vfp_table_number)->getDatumDepth();
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_); const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
return vfp_properties_->getInj()->bhp(controls.vfp_table_number, aqua, liquid, vapour, controls.thp_limit) - dp; return vfp_properties_->getInj()->bhp(controls.vfp_table_number, aqua, liquid, vapour, this->getTHPConstraint(summaryState)) - dp;
} }
else if (this->isProducer()) { else if (this->isProducer()) {
const auto& controls = well.productionControls(summaryState); const auto& controls = well.productionControls(summaryState);
const double vfp_ref_depth = vfp_properties_->getProd()->getTable(controls.vfp_table_number)->getDatumDepth(); const double vfp_ref_depth = vfp_properties_->getProd()->getTable(controls.vfp_table_number)->getDatumDepth();
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_); const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
return vfp_properties_->getProd()->bhp(controls.vfp_table_number, aqua, liquid, vapour, controls.thp_limit, getALQ(well_state)) - dp; return vfp_properties_->getProd()->bhp(controls.vfp_table_number, aqua, liquid, vapour, this->getTHPConstraint(summaryState), getALQ(well_state)) - dp;
} }
else { else {
OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well", deferred_logger); OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well", deferred_logger);
@ -3585,9 +3585,9 @@ namespace Opm
std::optional<double> std::optional<double>
StandardWell<TypeTag>:: StandardWell<TypeTag>::
computeBhpAtThpLimitProdWithAlq(const Simulator& ebos_simulator, computeBhpAtThpLimitProdWithAlq(const Simulator& ebos_simulator,
const SummaryState& summary_state, const SummaryState& summary_state,
DeferredLogger& deferred_logger, DeferredLogger& deferred_logger,
double alq_value) const double alq_value) const
{ {
// Given a VFP function returning bhp as a function of phase // Given a VFP function returning bhp as a function of phase
// rates and thp: // rates and thp:
@ -3633,11 +3633,12 @@ namespace Opm
const auto& table = *(vfp_properties_->getProd()->getTable(controls.vfp_table_number)); const auto& table = *(vfp_properties_->getProd()->getTable(controls.vfp_table_number));
const double vfp_ref_depth = table.getDatumDepth(); const double vfp_ref_depth = table.getDatumDepth();
const double rho = perf_densities_[0]; // Use the density at the top perforation. const double rho = perf_densities_[0]; // Use the density at the top perforation.
const double thp_limit = this->getTHPConstraint(summary_state);
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_); const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
auto fbhp = [this, &controls, dp, alq_value](const std::vector<double>& rates) { auto fbhp = [this, &controls, thp_limit, dp, alq_value](const std::vector<double>& rates) {
assert(rates.size() == 3); assert(rates.size() == 3);
return this->vfp_properties_->getProd() return this->vfp_properties_->getProd()
->bhp(controls.vfp_table_number, rates[Water], rates[Oil], rates[Gas], controls.thp_limit, alq_value) - dp; ->bhp(controls.vfp_table_number, rates[Water], rates[Oil], rates[Gas], thp_limit, alq_value) - dp;
}; };
// Make the flo() function. // Make the flo() function.
@ -3838,11 +3839,12 @@ namespace Opm
const auto& table = *(vfp_properties_->getInj()->getTable(controls.vfp_table_number)); const auto& table = *(vfp_properties_->getInj()->getTable(controls.vfp_table_number));
const double vfp_ref_depth = table.getDatumDepth(); const double vfp_ref_depth = table.getDatumDepth();
const double rho = perf_densities_[0]; // Use the density at the top perforation. const double rho = perf_densities_[0]; // Use the density at the top perforation.
const double thp_limit = this->getTHPConstraint(summary_state);
const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_); const double dp = wellhelpers::computeHydrostaticCorrection(ref_depth_, vfp_ref_depth, rho, gravity_);
auto fbhp = [this, &controls, dp](const std::vector<double>& rates) { auto fbhp = [this, &controls, thp_limit, dp](const std::vector<double>& rates) {
assert(rates.size() == 3); assert(rates.size() == 3);
return this->vfp_properties_->getInj() return this->vfp_properties_->getInj()
->bhp(controls.vfp_table_number, rates[Water], rates[Oil], rates[Gas], controls.thp_limit) - dp; ->bhp(controls.vfp_table_number, rates[Water], rates[Oil], rates[Gas], thp_limit) - dp;
}; };
// Make the flo() function. // Make the flo() function.
@ -4028,4 +4030,85 @@ namespace Opm
} }
template<typename TypeTag>
void
StandardWell<TypeTag>::
updateWellStateRates(const Simulator& ebosSimulator,
WellState& well_state,
DeferredLogger& deferred_logger) const
{
// Check if the rates of this well only are single-phase, do nothing
// if more than one nonzero rate.
int nonzero_rate_index = -1;
for (int p = 0; p < number_of_phases_; ++p) {
if (well_state.wellRates()[index_of_well_ * number_of_phases_ + p] != 0.0) {
if (nonzero_rate_index == -1) {
nonzero_rate_index = p;
} else {
// More than one nonzero rate.
return;
}
}
}
if (nonzero_rate_index == -1) {
// No nonzero rates.
return;
}
// Calculate the rates that follow from the current primary variables.
std::vector<EvalWell> well_q_s(num_components_, {numWellEq_ + numEq, 0.});
const EvalWell& bhp = getBhp();
const bool allow_cf = getAllowCrossFlow() || openCrossFlowAvoidSingularity(ebosSimulator);
for (int perf = 0; perf < number_of_perforations_; ++perf) {
const int cell_idx = well_cells_[perf];
const auto& intQuants = *(ebosSimulator.model().cachedIntensiveQuantities(cell_idx, /*timeIdx=*/ 0));
std::vector<EvalWell> mob(num_components_, {numWellEq_ + numEq, 0.});
getMobility(ebosSimulator, perf, mob, deferred_logger);
std::vector<EvalWell> cq_s(num_components_, {numWellEq_ + numEq, 0.});
double perf_dis_gas_rate = 0.;
double perf_vap_oil_rate = 0.;
double trans_mult = ebosSimulator.problem().template rockCompTransMultiplier<double>(intQuants, cell_idx);
const double Tw = well_index_[perf] * trans_mult;
computePerfRate(intQuants, mob, bhp, Tw, perf, allow_cf,
cq_s, perf_dis_gas_rate, perf_vap_oil_rate, deferred_logger);
for (int comp = 0; comp < num_components_; ++comp) {
well_q_s[comp] += cq_s[comp];
}
}
// We must keep in mind that component and phase indices are different here.
// Therefore we set up a mapping to make the last code block simpler.
const auto& pu = phaseUsage();
const int wpi = Water;
const int opi = Oil;
const int gpi = Gas;
const unsigned int wci = FluidSystem::waterCompIdx;
const unsigned int oci = FluidSystem::oilCompIdx;
const unsigned int gci = FluidSystem::gasCompIdx;
std::pair<int, unsigned int> phase_comp[3] = { {wpi, wci},
{opi, oci},
{gpi, gci} };
std::vector<int> phase_to_comp(number_of_phases_, -1);
for (const auto& pc : phase_comp) {
if (pu.phase_used[pc.first]) {
const int phase_idx = pu.phase_pos[pc.first];
const int comp_idx = Indices::canonicalToActiveComponentIndex(pc.second);
phase_to_comp[phase_idx] = comp_idx;
}
}
// Set the currently-zero phase flows to be nonzero in proportion to well_q_s.
const double initial_nonzero_rate = well_state.wellRates()[index_of_well_ * number_of_phases_ + nonzero_rate_index];
const int comp_idx_nz = phase_to_comp[nonzero_rate_index];
for (int p = 0; p < number_of_phases_; ++p) {
if (p != nonzero_rate_index) {
const int comp_idx = phase_to_comp[p];
double& rate = well_state.wellRates()[index_of_well_ * number_of_phases_ + p];
rate = (initial_nonzero_rate/well_q_s[comp_idx_nz].value()) * (well_q_s[comp_idx].value());
}
}
}
} // namespace Opm } // namespace Opm

View File

@ -22,6 +22,7 @@
#include <opm/simulators/wells/TargetCalculator.hpp> #include <opm/simulators/wells/TargetCalculator.hpp>
#include <algorithm> #include <algorithm>
#include <stack>
#include <vector> #include <vector>
namespace { namespace {
@ -585,6 +586,120 @@ namespace WellGroupHelpers
wellState.setCurrentInjectionREINRates(group.name(), rein); wellState.setCurrentInjectionREINRates(group.name(), rein);
} }
std::map<std::string, double>
computeNetworkPressures(const Opm::Network::ExtNetwork& network,
const WellStateFullyImplicitBlackoil& well_state,
const VFPProdProperties& vfp_prod_props)
{
// TODO: Only dealing with production networks for now.
if (!network.active()) {
return {};
}
// Fixed pressure nodes of the network are the roots of trees.
// Leaf nodes must correspond to groups in the group structure.
// Let us first find all leaf nodes of the network. We also
// create a vector of all nodes, ordered so that a child is
// always after its parent.
std::stack<std::string> children;
std::set<std::string> leaf_nodes;
std::vector<std::string> root_to_child_nodes;
children.push(network.root().name());
while (!children.empty()) {
const auto node = children.top();
children.pop();
root_to_child_nodes.push_back(node);
auto branches = network.downtree_branches(node);
if (branches.empty()) {
leaf_nodes.insert(node);
}
for (const auto& branch : branches) {
children.push(branch.downtree_node());
}
}
assert(children.empty());
// Starting with the leaf nodes of the network, get the flow rates
// from the corresponding groups.
std::map<std::string, std::vector<double>> node_inflows;
for (const auto& node : leaf_nodes) {
node_inflows[node] = well_state.currentProductionGroupRates(node);
}
// Accumulate in the network, towards the roots. Note that a
// root (i.e. fixed pressure node) can still be contributing
// flow towards other nodes in the network, i.e. a node is
// the root of a subtree.
auto child_to_root_nodes = root_to_child_nodes;
std::reverse(child_to_root_nodes.begin(), child_to_root_nodes.end());
for (const auto& node : child_to_root_nodes) {
const auto upbranch = network.uptree_branch(node);
if (upbranch) {
// Add downbranch rates to upbranch.
std::vector<double>& up = node_inflows[(*upbranch).uptree_node()];
const std::vector<double>& down = node_inflows[node];
if (up.empty()) {
up = down;
} else {
assert (up.size() == down.size());
for (size_t ii = 0; ii < up.size(); ++ii) {
up[ii] += down[ii];
}
}
}
}
// Going the other way (from roots to leafs), calculate the pressure
// at each node using VFP tables and rates.
std::map<std::string, double> node_pressures;
for (const auto& node : root_to_child_nodes) {
auto press = network.node(node).terminal_pressure();
if (press) {
node_pressures[node] = *press;
} else {
const auto upbranch = network.uptree_branch(node);
assert(upbranch);
const double up_press = node_pressures[(*upbranch).uptree_node()];
const auto vfp_table = (*upbranch).vfp_table();
if (vfp_table) {
// The rates are here positive, but the VFP code expects the
// convention that production rates are negative, so we must
// take a copy and flip signs.
auto rates = node_inflows[node];
for (auto& r : rates) { r *= -1.0; }
assert(rates.size() == 3);
const double alq = 0.0; // TODO: Do not ignore ALQ
node_pressures[node] = vfp_prod_props.bhp(*vfp_table,
rates[BlackoilPhases::Aqua],
rates[BlackoilPhases::Liquid],
rates[BlackoilPhases::Vapour],
up_press,
alq);
#define EXTRA_DEBUG_NETWORK 1
#if EXTRA_DEBUG_NETWORK
std::ostringstream oss;
oss << "parent: " << (*upbranch).uptree_node() << " child: " << node
<< " rates = [ " << rates[0]*86400 << ", " << rates[1]*86400 << ", " << rates[2]*86400 << " ]"
<< " p(parent) = " << up_press/1e5 << " p(child) = " << node_pressures[node]/1e5 << std::endl;
OpmLog::debug(oss.str());
#endif
} else {
// Table number specified as 9999 in the deck, no pressure loss.
node_pressures[node] = up_press;
}
}
}
return node_pressures;
}
GuideRate::RateVector GuideRate::RateVector
getRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& name) getRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& name)
{ {

View File

@ -26,10 +26,13 @@
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp> #include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/simulators/utils/DeferredLogger.hpp> #include <opm/simulators/utils/DeferredLogger.hpp>
#include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp> #include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
#include <opm/simulators/wells/VFPProdProperties.hpp>
#include <opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp> #include <opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp>
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <map>
#include <string>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
@ -258,6 +261,11 @@ namespace WellGroupHelpers
const WellStateFullyImplicitBlackoil& wellStateNupcol, const WellStateFullyImplicitBlackoil& wellStateNupcol,
WellStateFullyImplicitBlackoil& wellState); WellStateFullyImplicitBlackoil& wellState);
std::map<std::string, double>
computeNetworkPressures(const Opm::Network::ExtNetwork& network,
const WellStateFullyImplicitBlackoil& well_state,
const VFPProdProperties& vfp_prod_props);
GuideRate::RateVector GuideRate::RateVector
getRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& name); getRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& name);

View File

@ -275,6 +275,14 @@ namespace Opm
// update perforation water throughput based on solved water rate // update perforation water throughput based on solved water rate
virtual void updateWaterThroughput(const double dt, WellState& well_state) const = 0; virtual void updateWaterThroughput(const double dt, WellState& well_state) const = 0;
virtual void updateWellStateRates(const Simulator& ebosSimulator,
WellState& well_state,
DeferredLogger& deferred_logger) const
{
// Default: do nothing.
// TODO: make this a pure virtual.
}
void stopWell() { void stopWell() {
wellIsStopped_ = true; wellIsStopped_ = true;
} }
@ -288,6 +296,7 @@ namespace Opm
void setWsolvent(const double wsolvent); void setWsolvent(const double wsolvent);
void setDynamicThpLimit(const double thp_limit);
protected: protected:
@ -384,6 +393,8 @@ namespace Opm
double wsolvent_; double wsolvent_;
std::optional<double> dynamic_thp_limit_;
const PhaseUsage& phaseUsage() const; const PhaseUsage& phaseUsage() const;
int flowPhaseToEbosCompIdx( const int phaseIdx ) const; int flowPhaseToEbosCompIdx( const int phaseIdx ) const;

View File

@ -328,6 +328,18 @@ namespace Opm
template<typename TypeTag>
void
WellInterface<TypeTag>::
setDynamicThpLimit(const double thp_limit)
{
dynamic_thp_limit_ = thp_limit;
}
template<typename TypeTag> template<typename TypeTag>
double double
WellInterface<TypeTag>:: WellInterface<TypeTag>::
@ -403,6 +415,10 @@ namespace Opm
WellInterface<TypeTag>:: WellInterface<TypeTag>::
wellHasTHPConstraints(const SummaryState& summaryState) const wellHasTHPConstraints(const SummaryState& summaryState) const
{ {
if (dynamic_thp_limit_) {
return true;
}
if (well_ecl_.isInjector()) { if (well_ecl_.isInjector()) {
const auto controls = well_ecl_.injectionControls(summaryState); const auto controls = well_ecl_.injectionControls(summaryState);
if (controls.hasControl(Well::InjectorCMode::THP)) if (controls.hasControl(Well::InjectorCMode::THP))
@ -442,6 +458,9 @@ namespace Opm
WellInterface<TypeTag>:: WellInterface<TypeTag>::
getTHPConstraint(const SummaryState& summaryState) const getTHPConstraint(const SummaryState& summaryState) const
{ {
if (dynamic_thp_limit_) {
return *dynamic_thp_limit_;
}
if (well_ecl_.isInjector()) { if (well_ecl_.isInjector()) {
const auto& controls = well_ecl_.injectionControls(summaryState); const auto& controls = well_ecl_.injectionControls(summaryState);
return controls.thp_limit; return controls.thp_limit;
@ -1531,7 +1550,7 @@ namespace Opm
if (controls.hasControl(Well::InjectorCMode::THP) && currentControl != Well::InjectorCMode::THP) if (controls.hasControl(Well::InjectorCMode::THP) && currentControl != Well::InjectorCMode::THP)
{ {
const auto& thp = controls.thp_limit; const auto& thp = this->getTHPConstraint(summaryState);
double current_thp = well_state.thp()[well_index]; double current_thp = well_state.thp()[well_index];
if (thp < current_thp) { if (thp < current_thp) {
currentControl = Well::InjectorCMode::THP; currentControl = Well::InjectorCMode::THP;
@ -1633,7 +1652,7 @@ namespace Opm
if (controls.hasControl(Well::ProducerCMode::THP) && currentControl != Well::ProducerCMode::THP) if (controls.hasControl(Well::ProducerCMode::THP) && currentControl != Well::ProducerCMode::THP)
{ {
const auto& thp = controls.thp_limit; const auto& thp = this->getTHPConstraint(summaryState);
double current_thp = well_state.thp()[well_index]; double current_thp = well_state.thp()[well_index];
if (thp > current_thp) { if (thp > current_thp) {
currentControl = Well::ProducerCMode::THP; currentControl = Well::ProducerCMode::THP;