mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #749 from GitPaean/support_WECON
Support of Keyword WECON.
This commit is contained in:
@@ -132,7 +132,7 @@ if (HAVE_OPM_DATA)
|
||||
add_test( NAME flow_SPE1CASE2 COMMAND flow ${OPM_DATA_ROOT}/spe1/SPE1CASE2.DATA )
|
||||
add_test( NAME flow_SPE1CASE2_restart COMMAND flow ${OPM_DATA_ROOT}/spe1/SPE1CASE2_RESTART.DATA )
|
||||
|
||||
add_test( NAME flow_MSW2DH__ COMMAND flow_multisegment ${OPM_DATA_ROOT}/multisegment_wells_test_suite/2D_H__/2D_H__.DATA)
|
||||
add_test( NAME flow_MSW2DH__ COMMAND flow_multisegment ${OPM_DATA_ROOT}/wells_test_suite/MSW/2D_H__/2D_H__.DATA)
|
||||
|
||||
set_tests_properties(flow_SPE1CASE2_restart PROPERTIES DEPENDS flow_SPE1CASE2) # Dependes on the restart file from test flow_SPE1CASE2
|
||||
|
||||
|
||||
@@ -255,6 +255,10 @@ namespace Opm {
|
||||
/// Update the scaling factors for mass balance equations
|
||||
void updateEquationsScaling();
|
||||
|
||||
/// return the WellModel object
|
||||
WellModel& wellModel() { return well_model_; }
|
||||
const WellModel& wellModel() const { return well_model_; }
|
||||
|
||||
protected:
|
||||
|
||||
// --------- Types and enums ---------
|
||||
@@ -333,10 +337,6 @@ namespace Opm {
|
||||
return static_cast<const Implementation&>(*this);
|
||||
}
|
||||
|
||||
/// return the WellModel object
|
||||
WellModel& wellModel() { return well_model_; }
|
||||
const WellModel& wellModel() const { return well_model_; }
|
||||
|
||||
/// return the Well struct in the WellModel
|
||||
const Wells& wells() const { return well_model_.wells(); }
|
||||
|
||||
|
||||
@@ -129,6 +129,7 @@ namespace Opm {
|
||||
|
||||
using Base::numPhases;
|
||||
using Base::numMaterials;
|
||||
using Base::wellModel;
|
||||
|
||||
protected:
|
||||
using Base::asImpl;
|
||||
|
||||
@@ -239,6 +239,13 @@ namespace Opm {
|
||||
transport_solver_.model().relativeChange(previous, current));
|
||||
}
|
||||
|
||||
/// Return the well model
|
||||
const WellModel& wellModel() const
|
||||
{
|
||||
return pressure_model_->wellModel();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -88,6 +88,8 @@ namespace Opm {
|
||||
ReservoirState& reservoir_state,
|
||||
WellState& well_state);
|
||||
|
||||
using Base::wellModel;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
@@ -129,7 +131,6 @@ namespace Opm {
|
||||
// --------- Protected methods ---------
|
||||
|
||||
// Need to declare Base members we want to use here.
|
||||
using Base::wellModel;
|
||||
using Base::wells;
|
||||
using Base::variableState;
|
||||
using Base::computeGasPressure;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <opm/autodiff/WellStateFullyImplicitBlackoil.hpp>
|
||||
#include <opm/autodiff/WellStateFullyImplicitBlackoil.hpp>
|
||||
#include <opm/core/wells/DynamicListEconLimited.hpp>
|
||||
|
||||
#if HAVE_OPM_GRID
|
||||
#include <dune/grid/common/p2pcommunicator.hh>
|
||||
@@ -523,6 +524,10 @@ namespace Opm
|
||||
if( isIORank() )
|
||||
{
|
||||
Dune::CpGrid& globalGrid = *grid_;
|
||||
// TODO: make a dummy DynamicListEconLimited here for NOW for compilation and development
|
||||
// TODO: NOT SURE whether it will cause problem for parallel running
|
||||
// TODO: TO BE TESTED AND IMPROVED
|
||||
const DynamicListEconLimited dynamic_list_econ_limited;
|
||||
// Create wells and well state.
|
||||
WellsManager wells_manager(eclipseState_,
|
||||
reportStep,
|
||||
@@ -533,6 +538,7 @@ namespace Opm
|
||||
Opm::UgGridHelpers::cell2Faces( globalGrid ),
|
||||
Opm::UgGridHelpers::beginFaceCentroids( globalGrid ),
|
||||
permeability_,
|
||||
dynamic_list_econ_limited,
|
||||
false);
|
||||
|
||||
const Wells* wells = wells_manager.c_wells();
|
||||
|
||||
@@ -162,6 +162,13 @@ namespace Opm
|
||||
const WellState& xw,
|
||||
std::vector<double>& well_potentials);
|
||||
|
||||
void updateListEconLimited(const std::unique_ptr<Solver>& solver,
|
||||
ScheduleConstPtr schedule,
|
||||
const int current_step,
|
||||
const Wells* wells,
|
||||
const WellState& well_state,
|
||||
DynamicListEconLimited& list_econ_limited) const;
|
||||
|
||||
|
||||
// Data.
|
||||
typedef RateConverter::
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Events.hpp>
|
||||
#include <opm/core/utility/initHydroCarbonState.hpp>
|
||||
#include <opm/core/well_controls.h>
|
||||
#include <opm/core/wells/DynamicListEconLimited.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
@@ -131,6 +132,7 @@ namespace Opm
|
||||
unsigned int totalLinearIterations = 0;
|
||||
bool is_well_potentials_computed = param_.getDefault("compute_well_potentials", false );
|
||||
std::vector<double> well_potentials;
|
||||
DynamicListEconLimited dynamic_list_econ_limited;
|
||||
|
||||
// Main simulation loop.
|
||||
while (!timer.done()) {
|
||||
@@ -153,6 +155,7 @@ namespace Opm
|
||||
Opm::UgGridHelpers::cell2Faces(grid_),
|
||||
Opm::UgGridHelpers::beginFaceCentroids(grid_),
|
||||
props_.permeability(),
|
||||
dynamic_list_econ_limited,
|
||||
is_parallel_run_,
|
||||
well_potentials);
|
||||
const Wells* wells = wells_manager.c_wells();
|
||||
@@ -162,9 +165,10 @@ namespace Opm
|
||||
// give the polymer and surfactant simulators the chance to do their stuff
|
||||
asImpl().handleAdditionalWellInflow(timer, wells_manager, well_state, wells);
|
||||
|
||||
// write simulation state at the report stage
|
||||
output_writer_.writeTimeStep( timer, state, well_state );
|
||||
|
||||
// write the inital state at the report stage
|
||||
if (timer.initialStep()) {
|
||||
output_writer_.writeTimeStep( timer, state, well_state );
|
||||
}
|
||||
|
||||
// Max oil saturation (for VPPARS), hysteresis update.
|
||||
props_.updateSatOilMax(state.saturation());
|
||||
@@ -262,6 +266,10 @@ namespace Opm
|
||||
|
||||
// Increment timer, remember well state.
|
||||
++timer;
|
||||
|
||||
// write simulation state at the report stage
|
||||
output_writer_.writeTimeStep( timer, state, well_state );
|
||||
|
||||
prev_well_state = well_state;
|
||||
// The well potentials are only computed if they are needed
|
||||
// For now thay are only used to determine default guide rates for group controlled wells
|
||||
@@ -269,9 +277,9 @@ namespace Opm
|
||||
asImpl().computeWellPotentials(wells, well_state, well_potentials);
|
||||
}
|
||||
|
||||
asImpl().updateListEconLimited(solver, eclipse_state_->getSchedule(), timer.currentStepNum(), wells,
|
||||
well_state, dynamic_list_econ_limited);
|
||||
}
|
||||
// Write final simulation state.
|
||||
output_writer_.writeTimeStep( timer, state, prev_well_state );
|
||||
|
||||
// Stop timer and create timing report
|
||||
total_timer.stop();
|
||||
@@ -613,4 +621,24 @@ namespace Opm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class Implementation>
|
||||
void
|
||||
SimulatorBase<Implementation>::
|
||||
updateListEconLimited(const std::unique_ptr<Solver>& solver,
|
||||
ScheduleConstPtr schedule,
|
||||
const int current_step,
|
||||
const Wells* wells,
|
||||
const WellState& well_state,
|
||||
DynamicListEconLimited& list_econ_limited) const
|
||||
{
|
||||
|
||||
solver->model().wellModel().updateListEconLimited(schedule, current_step, wells,
|
||||
well_state, list_econ_limited);
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
@@ -89,6 +89,7 @@ namespace Opm
|
||||
|
||||
unsigned int totalNonlinearIterations = 0;
|
||||
unsigned int totalLinearIterations = 0;
|
||||
DynamicListEconLimited dynamic_list_econ_limited;
|
||||
|
||||
// Main simulation loop.
|
||||
while (!timer.done()) {
|
||||
@@ -109,6 +110,7 @@ namespace Opm
|
||||
Opm::UgGridHelpers::cell2Faces(grid_),
|
||||
Opm::UgGridHelpers::beginFaceCentroids(grid_),
|
||||
props_.permeability(),
|
||||
dynamic_list_econ_limited,
|
||||
is_parallel_run_);
|
||||
const Wells* wells = wells_manager.c_wells();
|
||||
WellState well_state;
|
||||
@@ -124,8 +126,10 @@ namespace Opm
|
||||
// give the polymer and surfactant simulators the chance to do their stuff
|
||||
Base::asImpl().handleAdditionalWellInflow(timer, wells_manager, well_state, wells);
|
||||
|
||||
// write simulation state at the report stage
|
||||
output_writer_.writeTimeStep( timer, state, well_state );
|
||||
// write the inital state at the report stage
|
||||
if (timer.initialStep()) {
|
||||
output_writer_.writeTimeStep( timer, state, well_state );
|
||||
}
|
||||
|
||||
// Max oil saturation (for VPPARS), hysteresis update.
|
||||
props_.updateSatOilMax(state.saturation());
|
||||
@@ -177,12 +181,13 @@ namespace Opm
|
||||
|
||||
// Increment timer, remember well state.
|
||||
++timer;
|
||||
|
||||
// write simulation state at the report stage
|
||||
output_writer_.writeTimeStep( timer, state, well_state );
|
||||
|
||||
prev_well_state = well_state;
|
||||
}
|
||||
|
||||
// Write final simulation state.
|
||||
output_writer_.writeTimeStep( timer, state, prev_well_state );
|
||||
|
||||
// Stop timer and create timing report
|
||||
total_timer.stop();
|
||||
SimulatorReport report;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <opm/output/eclipse/EclipseReader.hpp>
|
||||
#include <opm/core/utility/miscUtilities.hpp>
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
#include <opm/core/wells/DynamicListEconLimited.hpp>
|
||||
|
||||
#include <opm/output/Cells.hpp>
|
||||
#include <opm/output/OutputWriter.hpp>
|
||||
@@ -352,6 +353,8 @@ namespace Opm
|
||||
SimulationDataContainer& simulatorstate,
|
||||
WellStateFullyImplicitBlackoil& wellstate)
|
||||
{
|
||||
// gives a dummy dynamic_list_econ_limited
|
||||
DynamicListEconLimited dummy_list_econ_limited;
|
||||
WellsManager wellsmanager(eclipseState_,
|
||||
eclipseState_->getInitConfig()->getRestartStep(),
|
||||
Opm::UgGridHelpers::numCells(grid),
|
||||
@@ -360,7 +363,8 @@ namespace Opm
|
||||
Opm::UgGridHelpers::dimensions(grid),
|
||||
Opm::UgGridHelpers::cell2Faces(grid),
|
||||
Opm::UgGridHelpers::beginFaceCentroids(grid),
|
||||
permeability);
|
||||
permeability,
|
||||
dummy_list_econ_limited);
|
||||
|
||||
const Wells* wells = wellsmanager.c_wells();
|
||||
wellstate.resize(wells, simulatorstate); //Resize for restart step
|
||||
|
||||
@@ -22,14 +22,20 @@
|
||||
#ifndef OPM_STANDARDWELLS_HEADER_INCLUDED
|
||||
#define OPM_STANDARDWELLS_HEADER_INCLUDED
|
||||
|
||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||
|
||||
#include <opm/common/utility/platform_dependent/disable_warnings.h>
|
||||
#include <Eigen/Eigen>
|
||||
#include <Eigen/Sparse>
|
||||
#include <opm/common/utility/platform_dependent/reenable_warnings.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <tuple>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
|
||||
#include <opm/core/wells.h>
|
||||
#include <opm/core/wells/DynamicListEconLimited.hpp>
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAdInterface.hpp>
|
||||
@@ -170,6 +176,15 @@ namespace Opm {
|
||||
/// called.
|
||||
const Vector& getStoredWellPerforationFluxes() const;
|
||||
|
||||
/// upate the dynamic lists related to economic limits
|
||||
template<class WellState>
|
||||
void
|
||||
updateListEconLimited(ScheduleConstPtr schedule,
|
||||
const int current_step,
|
||||
const Wells* wells,
|
||||
const WellState& well_state,
|
||||
DynamicListEconLimited& list_econ_limited) const;
|
||||
|
||||
protected:
|
||||
bool wells_active_;
|
||||
const Wells* wells_;
|
||||
@@ -208,6 +223,39 @@ namespace Opm {
|
||||
const std::vector<double>& depth_perf,
|
||||
const double grav);
|
||||
|
||||
|
||||
template <class WellState>
|
||||
bool checkRateEconLimits(const WellEconProductionLimits& econ_production_limits,
|
||||
const WellState& well_state,
|
||||
const int well_number) const;
|
||||
|
||||
using WellMapType = typename WellState::WellMapType;
|
||||
using WellMapEntryType = typename WellState::mapentry_t;
|
||||
|
||||
// a tuple type for ratio limit check.
|
||||
// first value indicates whether ratio limit is violated, when the ratio limit is not violated, the following three
|
||||
// values should not be used.
|
||||
// second value indicates whehter there is only one connection left.
|
||||
// third value indicates the indx of the worst-offending connection.
|
||||
// the last value indicates the extent of the violation for the worst-offending connection, which is defined by
|
||||
// the ratio of the actual value to the value of the violated limit.
|
||||
using RatioCheckTuple = std::tuple<bool, bool, int, double>;
|
||||
|
||||
enum ConnectionIndex {
|
||||
INVALIDCONNECTION = -10000
|
||||
};
|
||||
|
||||
|
||||
template <class WellState>
|
||||
RatioCheckTuple checkRatioEconLimits(const WellEconProductionLimits& econ_production_limits,
|
||||
const WellState& well_state,
|
||||
const WellMapEntryType& map_entry) const;
|
||||
|
||||
template <class WellState>
|
||||
RatioCheckTuple checkMaxWaterCutLimit(const WellEconProductionLimits& econ_production_limits,
|
||||
const WellState& well_state,
|
||||
const WellMapEntryType& map_entry) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1248,4 +1248,301 @@ namespace Opm
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<class WellState>
|
||||
void
|
||||
StandardWells::
|
||||
updateListEconLimited(ScheduleConstPtr schedule,
|
||||
const int current_step,
|
||||
const Wells* wells_struct,
|
||||
const WellState& well_state,
|
||||
DynamicListEconLimited& list_econ_limited) const
|
||||
{
|
||||
const int nw = wells_struct->number_of_wells;
|
||||
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
// flag to check if the mim oil/gas rate limit is violated
|
||||
bool rate_limit_violated = false;
|
||||
const std::string& well_name = wells_struct->name[w];
|
||||
const Well* well_ecl = schedule->getWell(well_name);
|
||||
const WellEconProductionLimits& econ_production_limits = well_ecl->getEconProductionLimits(current_step);
|
||||
|
||||
// economic limits only apply for production wells.
|
||||
if (wells_struct->type[w] != PRODUCER) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if no limit is effective here, then continue to the next well
|
||||
if ( !econ_production_limits.onAnyEffectiveLimit() ) {
|
||||
continue;
|
||||
}
|
||||
// for the moment, we only handle rate limits, not handling potential limits
|
||||
// the potential limits should not be difficult to add
|
||||
const WellEcon::QuantityLimitEnum& quantity_limit = econ_production_limits.quantityLimit();
|
||||
if (quantity_limit == WellEcon::POTN) {
|
||||
const std::string msg = std::string("POTN limit for well ") + well_name + std::string(" is not supported for the moment. \n")
|
||||
+ std::string("All the limits will be evaluated based on RATE. ");
|
||||
OpmLog::warning("NOT_SUPPORTING_POTN", msg);
|
||||
}
|
||||
|
||||
const WellMapType& well_map = well_state.wellMap();
|
||||
const typename WellMapType::const_iterator i_well = well_map.find(well_name);
|
||||
assert(i_well != well_map.end()); // should always be found?
|
||||
const WellMapEntryType& map_entry = i_well->second;
|
||||
const int well_number = map_entry[0];
|
||||
|
||||
if (econ_production_limits.onAnyRateLimit()) {
|
||||
rate_limit_violated = checkRateEconLimits(econ_production_limits, well_state, well_number);
|
||||
}
|
||||
|
||||
if (rate_limit_violated) {
|
||||
if (econ_production_limits.endRun()) {
|
||||
const std::string warning_message = std::string("ending run after well closed due to economic limits is not supported yet \n")
|
||||
+ std::string("the program will keep running after ") + well_name + std::string(" is closed");
|
||||
OpmLog::warning("NOT_SUPPORTING_ENDRUN", warning_message);
|
||||
}
|
||||
|
||||
if (econ_production_limits.validFollowonWell()) {
|
||||
OpmLog::warning("NOT_SUPPORTING_FOLLOWONWELL", "opening following on well after well closed is not supported yet");
|
||||
}
|
||||
|
||||
if (well_ecl->getAutomaticShutIn()) {
|
||||
list_econ_limited.addShutWell(well_name);
|
||||
const std::string msg = std::string("well ") + well_name + std::string(" will be shut in due to economic limit");
|
||||
OpmLog::info(msg);
|
||||
} else {
|
||||
list_econ_limited.addStoppedWell(well_name);
|
||||
const std::string msg = std::string("well ") + well_name + std::string(" will be stopped due to economic limit");
|
||||
OpmLog::info(msg);
|
||||
}
|
||||
// the well is closed, not need to check other limits
|
||||
continue;
|
||||
}
|
||||
|
||||
// checking for ratio related limits, mostly all kinds of ratio.
|
||||
bool ratio_limits_violated = false;
|
||||
RatioCheckTuple ratio_check_return;
|
||||
|
||||
if (econ_production_limits.onAnyRatioLimit()) {
|
||||
ratio_check_return = checkRatioEconLimits(econ_production_limits, well_state, map_entry);
|
||||
ratio_limits_violated = std::get<0>(ratio_check_return);
|
||||
}
|
||||
|
||||
if (ratio_limits_violated) {
|
||||
const bool last_connection = std::get<1>(ratio_check_return);
|
||||
const int worst_offending_connection = std::get<2>(ratio_check_return);
|
||||
|
||||
const int perf_start = map_entry[1];
|
||||
|
||||
assert((worst_offending_connection >= 0) && (worst_offending_connection < map_entry[2]));
|
||||
|
||||
const int cell_worst_offending_connection = wells_struct->well_cells[perf_start + worst_offending_connection];
|
||||
list_econ_limited.addClosedConnectionsForWell(well_name, cell_worst_offending_connection);
|
||||
const std::string msg = std::string("Connection ") + std::to_string(worst_offending_connection) + std::string(" for well ")
|
||||
+ well_name + std::string(" will be closed due to economic limit");
|
||||
OpmLog::info(msg);
|
||||
|
||||
if (last_connection) {
|
||||
list_econ_limited.addShutWell(well_name);
|
||||
const std::string msg2 = well_name + std::string(" will be shut due to the last connection closed");
|
||||
OpmLog::info(msg2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class WellState>
|
||||
bool
|
||||
StandardWells::
|
||||
checkRateEconLimits(const WellEconProductionLimits& econ_production_limits,
|
||||
const WellState& well_state,
|
||||
const int well_number) const
|
||||
{
|
||||
const Opm::PhaseUsage& pu = fluid_->phaseUsage();
|
||||
const int np = well_state.numPhases();
|
||||
|
||||
if (econ_production_limits.onMinOilRate()) {
|
||||
assert((*active_)[Oil]);
|
||||
const double oil_rate = well_state.wellRates()[well_number * np + pu.phase_pos[ Oil ] ];
|
||||
const double min_oil_rate = econ_production_limits.minOilRate();
|
||||
if (std::abs(oil_rate) < min_oil_rate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (econ_production_limits.onMinGasRate() ) {
|
||||
assert((*active_)[Gas]);
|
||||
const double gas_rate = well_state.wellRates()[well_number * np + pu.phase_pos[ Gas ] ];
|
||||
const double min_gas_rate = econ_production_limits.minGasRate();
|
||||
if (std::abs(gas_rate) < min_gas_rate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (econ_production_limits.onMinLiquidRate() ) {
|
||||
assert((*active_)[Oil]);
|
||||
assert((*active_)[Water]);
|
||||
const double oil_rate = well_state.wellRates()[well_number * np + pu.phase_pos[ Oil ] ];
|
||||
const double water_rate = well_state.wellRates()[well_number * np + pu.phase_pos[ Water ] ];
|
||||
const double liquid_rate = oil_rate + water_rate;
|
||||
const double min_liquid_rate = econ_production_limits.minLiquidRate();
|
||||
if (std::abs(liquid_rate) < min_liquid_rate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (econ_production_limits.onMinReservoirFluidRate()) {
|
||||
OpmLog::warning("NOT_SUPPORTING_MIN_RESERVOIR_FLUID_RATE", "Minimum reservoir fluid production rate limit is not supported yet");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class WellState>
|
||||
StandardWells::RatioCheckTuple
|
||||
StandardWells::
|
||||
checkRatioEconLimits(const WellEconProductionLimits& econ_production_limits,
|
||||
const WellState& well_state,
|
||||
const WellMapEntryType& map_entry) const
|
||||
{
|
||||
// TODO: not sure how to define the worst-offending connection when more than one
|
||||
// ratio related limit is violated.
|
||||
// The defintion used here is that we define the violation extent based on the
|
||||
// ratio between the value and the corresponding limit.
|
||||
// For each violated limit, we decide the worst-offending connection separately.
|
||||
// Among the worst-offending connections, we use the one has the biggest violation
|
||||
// extent.
|
||||
|
||||
bool any_limit_violated = false;
|
||||
bool last_connection = false;
|
||||
int worst_offending_connection = INVALIDCONNECTION;
|
||||
double violation_extent = -1.0;
|
||||
|
||||
if (econ_production_limits.onMaxWaterCut()) {
|
||||
const RatioCheckTuple water_cut_return = checkMaxWaterCutLimit(econ_production_limits, well_state, map_entry);
|
||||
bool water_cut_violated = std::get<0>(water_cut_return);
|
||||
if (water_cut_violated) {
|
||||
any_limit_violated = true;
|
||||
const double violation_extent_water_cut = std::get<3>(water_cut_return);
|
||||
if (violation_extent_water_cut > violation_extent) {
|
||||
violation_extent = violation_extent_water_cut;
|
||||
worst_offending_connection = std::get<2>(water_cut_return);
|
||||
last_connection = std::get<1>(water_cut_return);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (econ_production_limits.onMaxGasOilRatio()) {
|
||||
OpmLog::warning("NOT_SUPPORTING_MAX_GOR", "the support for max Gas-Oil ratio is not implemented yet!");
|
||||
}
|
||||
|
||||
if (econ_production_limits.onMaxWaterGasRatio()) {
|
||||
OpmLog::warning("NOT_SUPPORTING_MAX_WGR", "the support for max Water-Gas ratio is not implemented yet!");
|
||||
}
|
||||
|
||||
if (econ_production_limits.onMaxGasLiquidRatio()) {
|
||||
OpmLog::warning("NOT_SUPPORTING_MAX_GLR", "the support for max Gas-Liquid ratio is not implemented yet!");
|
||||
}
|
||||
|
||||
if (any_limit_violated) {
|
||||
assert(worst_offending_connection >=0);
|
||||
assert(violation_extent > 1.);
|
||||
}
|
||||
|
||||
return std::make_tuple(any_limit_violated, last_connection, worst_offending_connection, violation_extent);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class WellState>
|
||||
StandardWells::RatioCheckTuple
|
||||
StandardWells::
|
||||
checkMaxWaterCutLimit(const WellEconProductionLimits& econ_production_limits,
|
||||
const WellState& well_state,
|
||||
const WellMapEntryType& map_entry) const
|
||||
{
|
||||
bool water_cut_limit_violated = false;
|
||||
int worst_offending_connection = INVALIDCONNECTION;
|
||||
bool last_connection = false;
|
||||
double violation_extent = -1.0;
|
||||
|
||||
const int np = well_state.numPhases();
|
||||
const Opm::PhaseUsage& pu = fluid_->phaseUsage();
|
||||
const int well_number = map_entry[0];
|
||||
|
||||
assert((*active_)[Oil]);
|
||||
assert((*active_)[Water]);
|
||||
|
||||
const double oil_rate = well_state.wellRates()[well_number * np + pu.phase_pos[ Oil ] ];
|
||||
const double water_rate = well_state.wellRates()[well_number * np + pu.phase_pos[ Water ] ];
|
||||
const double liquid_rate = oil_rate + water_rate;
|
||||
double water_cut;
|
||||
if (std::abs(liquid_rate) != 0.) {
|
||||
water_cut = water_rate / liquid_rate;
|
||||
} else {
|
||||
water_cut = 0.0;
|
||||
}
|
||||
|
||||
const double max_water_cut_limit = econ_production_limits.maxWaterCut();
|
||||
if (water_cut > max_water_cut_limit) {
|
||||
water_cut_limit_violated = true;
|
||||
}
|
||||
|
||||
if (water_cut_limit_violated) {
|
||||
// need to handle the worst_offending_connection
|
||||
const int perf_start = map_entry[1];
|
||||
const int perf_number = map_entry[2];
|
||||
|
||||
std::vector<double> water_cut_perf(perf_number);
|
||||
for (int perf = 0; perf < perf_number; ++perf) {
|
||||
const int i_perf = perf_start + perf;
|
||||
const double oil_perf_rate = well_state.perfPhaseRates()[i_perf * np + pu.phase_pos[ Oil ] ];
|
||||
const double water_perf_rate = well_state.perfPhaseRates()[i_perf * np + pu.phase_pos[ Water ] ];
|
||||
const double liquid_perf_rate = oil_perf_rate + water_perf_rate;
|
||||
if (std::abs(liquid_perf_rate) != 0.) {
|
||||
water_cut_perf[perf] = water_perf_rate / liquid_perf_rate;
|
||||
} else {
|
||||
water_cut_perf[perf] = 0.;
|
||||
}
|
||||
}
|
||||
|
||||
last_connection = (perf_number == 1);
|
||||
if (last_connection) {
|
||||
worst_offending_connection = 0;
|
||||
violation_extent = water_cut_perf[0] / max_water_cut_limit;
|
||||
return std::make_tuple(water_cut_limit_violated, last_connection, worst_offending_connection, violation_extent);
|
||||
}
|
||||
|
||||
double max_water_cut_perf = 0.;
|
||||
for (int perf = 0; perf < perf_number; ++perf) {
|
||||
if (water_cut_perf[perf] > max_water_cut_perf) {
|
||||
worst_offending_connection = perf;
|
||||
max_water_cut_perf = water_cut_perf[perf];
|
||||
}
|
||||
}
|
||||
|
||||
assert(max_water_cut_perf != 0.);
|
||||
assert((worst_offending_connection >= 0) && (worst_offending_connection < perf_number));
|
||||
|
||||
violation_extent = max_water_cut_perf / max_water_cut_limit;
|
||||
}
|
||||
|
||||
return std::make_tuple(water_cut_limit_violated, last_connection, worst_offending_connection, violation_extent);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
@@ -125,6 +125,7 @@ namespace Opm {
|
||||
WellState& well_state,
|
||||
const bool initial_assembly);
|
||||
|
||||
using Base::wellModel;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -180,7 +181,6 @@ namespace Opm {
|
||||
// --------- Protected methods ---------
|
||||
|
||||
// Need to declare Base members we want to use here.
|
||||
using Base::wellModel;
|
||||
using Base::wells;
|
||||
using Base::wellsActive;
|
||||
using Base::variableState;
|
||||
|
||||
@@ -119,9 +119,17 @@ namespace Opm
|
||||
WellsManager& wells_manager,
|
||||
typename BaseType::WellState& well_state,
|
||||
const Wells* wells);
|
||||
|
||||
void updateListEconLimited(const std::unique_ptr<Solver>& solver,
|
||||
ScheduleConstPtr schedule,
|
||||
const int current_step,
|
||||
const Wells* wells,
|
||||
const WellState& well_state,
|
||||
DynamicListEconLimited& list_econ_limited) const;
|
||||
private:
|
||||
Opm::DeckConstPtr deck_;
|
||||
const PolymerPropsAd& polymer_props_;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
@@ -98,6 +98,23 @@ handleAdditionalWellInflow(SimulatorTimer& timer,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class GridT>
|
||||
void
|
||||
SimulatorFullyImplicitCompressiblePolymer<GridT>::
|
||||
updateListEconLimited(const std::unique_ptr<Solver>& /*solver*/,
|
||||
ScheduleConstPtr /*schedule*/,
|
||||
const int /*current_step*/,
|
||||
const Wells* /*wells*/,
|
||||
const WellState& /*well_state*/,
|
||||
DynamicListEconLimited& /*list_econ_limited*/) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_SIMULATORFULLYIMPLICITCOMPRESSIBLEPOLYMER_HEADER_INCLUDED
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
#include <opm/core/wells/WellsManager.hpp>
|
||||
#include <opm/core/wells.h>
|
||||
#include <opm/core/wells/DynamicListEconLimited.hpp>
|
||||
|
||||
#include <opm/material/fluidmatrixinteractions/EclMaterialLawManager.hpp>
|
||||
#include <opm/autodiff/GridHelpers.hpp>
|
||||
@@ -91,6 +92,9 @@ struct SetupMSW {
|
||||
|
||||
const size_t current_timestep = 0;
|
||||
|
||||
// dummy_dynamic_list_econ_lmited
|
||||
const Opm::DynamicListEconLimited dummy_dynamic_list;
|
||||
|
||||
// Create wells.
|
||||
Opm::WellsManager wells_manager(ecl_state,
|
||||
current_timestep,
|
||||
@@ -101,6 +105,7 @@ struct SetupMSW {
|
||||
Opm::UgGridHelpers::cell2Faces(grid),
|
||||
Opm::UgGridHelpers::beginFaceCentroids(grid),
|
||||
fluidprops->permeability(),
|
||||
dummy_dynamic_list,
|
||||
false);
|
||||
|
||||
const Wells* wells = wells_manager.c_wells();
|
||||
|
||||
Reference in New Issue
Block a user