Loading...
Searching...
No Matches
Schedule.hpp
/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SCHEDULE_HPP
#define SCHEDULE_HPP
#include <cstddef>
#include <ctime>
#include <functional>
#include <iosfwd>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <opm/input/eclipse/Schedule/Action/ActionResult.hpp>
#include <opm/input/eclipse/Schedule/Action/SimulatorUpdate.hpp>
#include <opm/input/eclipse/Schedule/Action/WGNames.hpp>
#include <opm/input/eclipse/Schedule/CompletedCells.hpp>
#include <opm/input/eclipse/Schedule/Group/Group.hpp>
#include <opm/input/eclipse/Schedule/ScheduleDeck.hpp>
#include <opm/input/eclipse/Schedule/ScheduleState.hpp>
#include <opm/input/eclipse/Schedule/ScheduleStatic.hpp>
#include <opm/input/eclipse/Schedule/Well/PAvg.hpp>
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
#include <opm/input/eclipse/Schedule/WriteRestartFileEvents.hpp>
#include <opm/input/eclipse/Units/UnitSystem.hpp>
namespace Opm {
class ActiveGridCells;
class Deck;
class DeckKeyword;
class DeckRecord;
enum class ConnectionOrder;
class EclipseGrid;
class EclipseState;
class ErrorGuard;
class FieldPropsManager;
class GasLiftOpt;
class GTNode;
class GuideRateConfig;
class GuideRateModel;
class HandlerContext;
enum class InputErrorAction;
class NumericalAquifers;
class ParseContext;
class Python;
class Runspec;
class RPTConfig;
class ScheduleGrid;
class SCHEDULESection;
class SegmentMatcher;
class SummaryState;
class TracerConfig;
class UDQConfig;
class Well;
enum class WellGasInflowEquation : std::uint8_t;
class WellMatcher;
enum class WellProducerCMode : std::uint16_t;
enum class WellStatus : std::uint8_t;
class WelSegsSet;
class WellTestConfig;
} // namespace Opm
namespace Opm::ReservoirCoupling {
class CouplingInfo;
} // namespace Opm::ReservoirCoupling
namespace Opm::Action {
class ActionX;
class PyAction;
class State;
} // namespace Opm::Action
namespace Opm::RestartIO {
struct RstState;
} // namespace Opm::RestartIO
namespace Opm {
class Schedule
{
public:
Schedule() = default;
explicit Schedule(std::shared_ptr<const Python> python_handle);
Schedule(const Deck& deck,
const EclipseGrid& grid,
const FieldPropsManager& fp,
const NumericalAquifers& numAquifers,
const Runspec& runspec,
const ParseContext& parseContext,
ErrorGuard& errors,
std::shared_ptr<const Python> python,
const bool lowActionParsingStrictness = false,
const bool slave_mode = false,
const bool keepKeywords = true,
const std::optional<int>& output_interval = {},
const RestartIO::RstState* rst = nullptr,
const TracerConfig* tracer_config = nullptr);
template<typename T>
Schedule(const Deck& deck,
const EclipseGrid& grid,
const FieldPropsManager& fp,
const NumericalAquifers& numAquifers,
const Runspec &runspec,
const ParseContext& parseContext,
T&& errors,
std::shared_ptr<const Python> python,
const bool lowActionParsingStrictness = false,
const bool slave_mode = false,
const bool keepKeywords = true,
const std::optional<int>& output_interval = {},
const RestartIO::RstState* rst = nullptr,
const TracerConfig* tracer_config = nullptr);
Schedule(const Deck& deck,
const EclipseGrid& grid,
const FieldPropsManager& fp,
const NumericalAquifers& numAquifers,
const Runspec &runspec,
std::shared_ptr<const Python> python,
const bool lowActionParsingStrictness = false,
const bool slave_mode = false,
const bool keepKeywords = true,
const std::optional<int>& output_interval = {},
const RestartIO::RstState* rst = nullptr,
const TracerConfig* tracer_config = nullptr);
Schedule(const Deck& deck,
const EclipseState& es,
const ParseContext& parseContext,
ErrorGuard& errors,
std::shared_ptr<const Python> python,
const bool lowActionParsingStrictness = false,
const bool slave_mode = false,
const bool keepKeywords = true,
const std::optional<int>& output_interval = {},
const RestartIO::RstState* rst = nullptr);
template <typename T>
Schedule(const Deck& deck,
const EclipseState& es,
const ParseContext& parseContext,
T&& errors,
std::shared_ptr<const Python> python,
const bool lowActionParsingStrictness = false,
const bool slave_mode = false,
const bool keepKeywords = true,
const std::optional<int>& output_interval = {},
const RestartIO::RstState* rst = nullptr);
Schedule(const Deck& deck,
const EclipseState& es,
std::shared_ptr<const Python> python,
const bool lowActionParsingStrictness = false,
const bool slave_mode = false,
const bool keepKeywords = true,
const std::optional<int>& output_interval = {},
const RestartIO::RstState* rst = nullptr);
// The constructor *without* the Python arg should really only be used from Python itself
Schedule(const Deck& deck,
const EclipseState& es,
const std::optional<int>& output_interval = {},
const RestartIO::RstState* rst = nullptr);
~Schedule() = default;
static Schedule serializationTestObject();
/*
* If the input deck does not specify a start time, Eclipse's 1. Jan
* 1983 is defaulted
*/
std::time_t getStartTime() const;
std::time_t posixStartTime() const;
std::time_t posixEndTime() const;
std::time_t simTime(std::size_t timeStep) const;
double seconds(std::size_t timeStep) const;
double stepLength(std::size_t timeStep) const;
std::optional<int> exitStatus() const;
const UnitSystem& getUnits() const { return this->m_static.m_unit_system; }
const Runspec& runspec() const { return this->m_static.m_runspec; }
std::size_t numWells() const;
std::size_t numWells(std::size_t timestep) const;
bool hasWell(const std::string& wellName) const;
bool hasWell(const std::string& wellName, std::size_t timeStep) const;
WellMatcher wellMatcher(std::size_t report_step) const;
std::function<std::unique_ptr<SegmentMatcher>()> segmentMatcherFactory(std::size_t report_step) const;
std::vector<std::string> wellNames(const std::string& pattern, std::size_t timeStep, const std::vector<std::string>& matching_wells = {}) const;
std::vector<std::string> wellNames(const std::string& pattern) const;
std::vector<std::string> wellNames(std::size_t timeStep) const;
std::vector<std::string> wellNames() const;
bool hasGroup(const std::string& groupName, std::size_t timeStep) const;
std::vector<std::string>
groupNames(const std::string& pattern, std::size_t timeStep) const;
const std::vector<std::string>& groupNames(std::size_t timeStep) const;
std::vector<std::string> groupNames(const std::string& pattern) const;
const std::vector<std::string>& groupNames() const;
std::vector<const Group*> restart_groups(std::size_t timeStep) const;
std::vector<std::string>
changed_wells(std::size_t reportStep,
std::size_t initialStep = 0) const;
const Well& getWell(std::size_t well_index, std::size_t timeStep) const;
const Well& getWell(const std::string& wellName, std::size_t timeStep) const;
const Well& getWellatEnd(const std::string& well_name) const;
// get the list of the constant flux aquifer specified in the whole schedule
std::unordered_set<int> getAquiferFluxSchedule() const;
std::vector<Well> getWells(std::size_t timeStep) const;
std::vector<Well> getWellsatEnd() const;
// Get wells that have been active any time during simulation
std::vector<Well> getActiveWellsAtEnd() const;
// Get well names of wells that have never been active
std::vector<std::string> getInactiveWellNamesAtEnd() const;
const std::unordered_map<std::string, std::set<int>>&
getPossibleFutureConnections() const;
void shut_well(const std::string& well_name, std::size_t report_step);
void shut_well(const std::string& well_name);
void stop_well(const std::string& well_name, std::size_t report_step);
void stop_well(const std::string& well_name);
void open_well(const std::string& well_name, std::size_t report_step);
void open_well(const std::string& well_name);
void clear_event(ScheduleEvents::Events, std::size_t report_step);
void add_event(ScheduleEvents::Events, std::size_t report_step);
void applyWellProdIndexScaling(const std::string& well_name, const std::size_t reportStep, const double scalingFactor);
void clearEvents(const std::size_t report_step);
WellProducerCMode getGlobalWhistctlMmode(std::size_t timestep) const;
const UDQConfig& getUDQConfig(std::size_t timeStep) const;
GTNode groupTree(std::size_t report_step) const;
GTNode groupTree(const std::string& root_node, std::size_t report_step) const;
const Group& getGroup(const std::string& groupName, std::size_t timeStep) const;
std::optional<std::size_t> first_RFT() const;
/*
Will remove all completions which are connected to cell which is not
active. Will scan through all wells and all timesteps.
*/
void filterConnections(const ActiveGridCells& grid);
std::size_t size() const;
bool write_rst_file(std::size_t report_step) const;
const std::map< std::string, int >& rst_keywords( size_t timestep ) const;
// The applyAction() member function is invoked from the simulator
// *after* an ACTIONX has triggered. Its return value is a small
// structure with 'information' which the simulator should take into
// account when updating internal datastructures after the ACTIONX
// keywords have been applied.
SimulatorUpdate applyAction(std::size_t reportStep,
const Action::ActionX& action,
const Action::Result::MatchingEntities& matches,
const std::unordered_map<std::string, double>& wellpi,
const bool iterateSchedule);
SimulatorUpdate applyAction(std::size_t reportStep,
const Action::ActionX& action,
const Action::Result::MatchingEntities& matches,
const std::unordered_map<std::string, float>& wellpi,
const bool iterateSchedule);
/*
The runPyAction() will run the Python script in a PYACTION keyword. In
the case of Schedule updates the recommended way of doing that from
PYACTION is to invoke a "normal" ACTIONX keyword internally from the
Python code. he return value from runPyAction() comes from such a
internal ACTIONX.
*/
SimulatorUpdate runPyAction(std::size_t reportStep,
const Action::PyAction& pyaction,
Action::State& action_state,
EclipseState& ecl_state,
SummaryState& summary_state);
SimulatorUpdate runPyAction(std::size_t reportStep,
const Action::PyAction& pyaction,
Action::State& action_state,
EclipseState& ecl_state,
SummaryState& summary_state,
const std::unordered_map<std::string, double>& target_wellpi);
SimulatorUpdate runPyAction(std::size_t reportStep,
const Action::PyAction& pyaction,
Action::State& action_state,
EclipseState& ecl_state,
SummaryState& summary_state,
const std::unordered_map<std::string, float>& target_wellpi);
SimulatorUpdate modifyCompletions(const std::size_t reportStep,
const std::map<std::string, std::vector<Connection>>& extraConns);
const GasLiftOpt& glo(std::size_t report_step) const;
bool operator==(const Schedule& data) const;
std::shared_ptr<const Python> python() const;
const std::optional<RPTConfig>& initialReportConfiguration() const;
const ScheduleState& back() const;
const ScheduleState& operator[](std::size_t index) const;
std::vector<ScheduleState>::const_iterator begin() const;
std::vector<ScheduleState>::const_iterator end() const;
void create_next(const time_point& start_time, const std::optional<time_point>& end_time);
void create_next(const ScheduleBlock& block);
void create_first(const time_point& start_time, const std::optional<time_point>& end_time);
void treat_critical_as_non_critical(bool value) { this->m_treat_critical_as_non_critical = value; }
/*
The cmp() function compares two schedule instances in a context aware
manner. Floating point numbers are compared with a tolerance. The
purpose of this comparison function is to implement regression tests
for the schedule instances created by loading a restart file.
*/
static bool cmp(const Schedule& sched1, const Schedule& sched2, std::size_t report_step);
void applyKeywords(std::vector<std::unique_ptr<DeckKeyword>>& keywords, std::unordered_map<std::string, double>& target_wellpi, bool action_mode, std::size_t report_step);
void applyKeywords(std::vector<std::unique_ptr<DeckKeyword>>& keywords, std::unordered_map<std::string, double>& target_wellpi, bool action_mode);
template<class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(this->m_static);
serializer(this->m_sched_deck);
serializer(this->action_wgnames);
serializer(this->potential_wellopen_patterns);
serializer(this->exit_status);
serializer(this->snapshots);
serializer(this->restart_output);
serializer(this->completed_cells);
serializer(this->completed_cells_lgr);
serializer(this->completed_cells_lgr_map);
serializer(this->m_treat_critical_as_non_critical);
serializer(this->current_report_step);
serializer(this->m_lowActionParsingStrictness);
serializer(this->simUpdateFromPython);
// If we are deserializing we need to setup the pointer to the
// unit system since this is process specific. This is safe
// because we set the same value in all well instances.
// We do some redundant assignments as these are shared_ptr's
// with multiple pointers to any given instance, but it is not
// significant so let's keep it simple.
if (!serializer.isSerializing()) {
for (auto& snapshot : snapshots) {
for (auto& well : snapshot.wells) {
well.second->updateUnitSystem(&m_static.m_unit_system);
}
}
}
}
template <typename T>
std::vector<std::pair<std::size_t, T>> unique() const
{
std::vector<std::pair<std::size_t, T>> values;
for (std::size_t index = 0; index < this->snapshots.size(); index++) {
const auto& member = this->snapshots[index].get<T>();
const auto& value = member.get();
if (values.empty() || !(value == values.back().second))
values.push_back( std::make_pair(index, value));
}
return values;
}
friend std::ostream& operator<<(std::ostream& os, const Schedule& sched);
void dump_deck(std::ostream& os) const;
private:
friend class HandlerContext;
// Please update the member functions
// - operator==(const Schedule&) const
// - serializationTestObject()
// - serializeOp(Serializer&)
// when you update/change this list of data members.
bool m_treat_critical_as_non_critical = false;
ScheduleStatic m_static{};
ScheduleDeck m_sched_deck{};
Action::WGNames action_wgnames{};
std::unordered_set<std::string> potential_wellopen_patterns{}; // Set of well name patterns that potentially can open
std::optional<int> exit_status{};
std::vector<ScheduleState> snapshots{};
WriteRestartFileEvents restart_output{};
CompletedCells completed_cells{};
std::vector<CompletedCells> completed_cells_lgr{};
std::unordered_map<std::string, std::size_t> completed_cells_lgr_map;
// Boolean indicating the strictness of parsing process for ActionX and PyAction.
// If lowActionParsingStrictness is true, the simulator tries to apply unsupported
// keywords, if lowActionParsingStrictness is false, the simulator only applies
// supported keywords.
bool m_lowActionParsingStrictness = false;
// This unordered_map contains possible future connections of wells that might get added through an ACTIONX.
// For parallel runs, this unordered_map is retrieved by the grid partitioner to ensure these connections
// end up on the same partition.
std::unordered_map<std::string, std::set<int>> possibleFutureConnections;
// The current_report_step is set to the current report step when a PYACTION call is executed.
// This is needed since the Schedule object does not know the current report step of the simulator and
// we only allow PYACTIONS for the current and future report steps.
std::size_t current_report_step = 0;
// The simUpdateFromPython points to a SimulatorUpdate collecting all updates from one PYACTION call.
// The SimulatorUpdate is reset before a new PYACTION call is executed.
// It is a shared_ptr, so a Schedule can be constructed using the copy constructor sharing the simUpdateFromPython.
// The copy constructor is needed for creating a mocked simulator (msim).
std::shared_ptr<SimulatorUpdate> simUpdateFromPython{};
void init_completed_cells_lgr(const EclipseGrid& ecl_grid);
void init_completed_cells_lgr_map(const EclipseGrid& ecl_grid);
void load_rst(const RestartIO::RstState& rst,
const TracerConfig& tracer_config,
const ScheduleGrid& grid,
const FieldPropsManager& fp);
void addWell(Well well);
void addWell(const std::string& wellName,
const std::string& group,
int headI,
int headJ,
Phase preferredPhase,
const std::optional<double>& refDepth,
double drainageRadius,
bool allowCrossFlow,
bool automaticShutIn,
int pvt_table,
WellGasInflowEquation gas_inflow,
std::size_t timeStep,
ConnectionOrder wellConnectionOrder);
bool updateWPAVE(const std::string& wname, std::size_t report_step, const PAvg& pavg);
void updateGuideRateModel(const GuideRateModel& new_model, std::size_t report_step);
GTNode groupTree(const std::string& root_node, std::size_t report_step, std::size_t level, const std::optional<std::string>& parent_name) const;
bool updateWellStatus( const std::string& well, std::size_t reportStep, WellStatus status, std::optional<KeywordLocation> = {});
void addWellToGroup( const std::string& group_name, const std::string& well_name , std::size_t timeStep);
void iterateScheduleSection(std::size_t load_start,
std::size_t load_end,
const ParseContext& parseContext,
ErrorGuard& errors,
const ScheduleGrid& grid,
const std::unordered_map<std::string, double> * target_wellpi,
const std::string& prefix,
const bool keepKeywords,
const bool log_to_debug = false);
void addACTIONX(const Action::ActionX& action);
void addGroupToGroup( const std::string& parent_group, const std::string& child_group);
void addGroup(const std::string& groupName , std::size_t timeStep);
void addGroup(Group group);
void addGroup(const RestartIO::RstGroup& rst_group, std::size_t timeStep);
void addWell(const std::string& wellName, const DeckRecord& record,
std::size_t timeStep, ConnectionOrder connection_order);
void checkIfAllConnectionsIsShut(std::size_t reportStep);
void end_report(std::size_t report_step);
void handleKeyword(std::size_t currentStep,
const ScheduleBlock& block,
const DeckKeyword& keyword,
const ParseContext& parseContext,
ErrorGuard& errors,
const ScheduleGrid& grid,
const Action::Result::MatchingEntities& matches,
bool action_mode,
SimulatorUpdate* sim_update,
const std::unordered_map<std::string, double>* target_wellpi,
std::unordered_map<std::string, double>& wpimult_global_factor,
WelSegsSet* welsegs_wells = nullptr,
std::set<std::string>* compsegs_wells = nullptr);
void internalWELLSTATUSACTIONXFromPYACTION(const std::string& well_name, std::size_t report_step, const std::string& wellStatus);
void prefetchPossibleFutureConnections(const ScheduleGrid& grid, const DeckKeyword& keyword,
const ParseContext& parseContext, ErrorGuard& errors);
void store_wgnames(const DeckKeyword& keyword);
std::vector<std::string> wellNames(const std::string& pattern,
const HandlerContext& context,
bool allowEmpty = false);
static std::string formatDate(std::time_t t);
void applyGlobalWPIMULT( const std::unordered_map<std::string, double>& wpimult_global_factor);
bool must_write_rst_file(std::size_t report_step) const;
bool isWList(std::size_t report_step, const std::string& pattern) const;
SimulatorUpdate applyAction(std::size_t reportStep, const std::string& action_name, const std::vector<std::string>& matching_wells);
};
}
#endif
Opm::Action::ActionX
Definition ActionX.hpp:72
Opm::Action::PyAction
Definition PyAction.hpp:40
Opm::Action::Result::MatchingEntities
Container of matching entities.
Definition ActionResult.hpp:174
Opm::Action::State
Management information about the current run's ACTION system, especially concerning the number of tim...
Definition State.hpp:51
Opm::Action::WGNames
Definition WGNames.hpp:29
Opm::ActiveGridCells
Simple class capturing active cells of a grid.
Definition ActiveGridCells.hpp:36
Opm::CompletedCells
Sparse collection of cells, and their properties, intersected by one or more well connections.
Definition CompletedCells.hpp:36
Opm::DeckKeyword
Definition DeckKeyword.hpp:36
Opm::DeckRecord
Definition DeckRecord.hpp:32
Opm::Deck
Definition Deck.hpp:46
Opm::EclipseGrid
About cell information and dimension: The actual grid information is held in a pointer to an ERT ecl_...
Definition EclipseGrid.hpp:61
Opm::EclipseState
Definition EclipseState.hpp:62
Opm::ErrorGuard
Definition ErrorGuard.hpp:30
Opm::FieldPropsManager
Definition FieldPropsManager.hpp:42
Opm::GTNode
Definition GTNode.hpp:34
Opm::GasLiftOpt
Gas lift optimisation parameters for all wells and groups.
Definition GasLiftOpt.hpp:356
Opm::Group
Definition Group.hpp:50
Opm::GuideRateConfig
Definition GuideRateConfig.hpp:36
Opm::GuideRateModel
Definition GuideRateModel.hpp:30
Opm::HandlerContext
Definition HandlerContext.hpp:55
Opm::NumericalAquifers
Definition NumericalAquifers.hpp:38
Opm::PAvg
Definition PAvg.hpp:30
Opm::ParseContext
Definition ParseContext.hpp:84
Opm::Python
Definition Python.hpp:116
Opm::RPTConfig
Configuration manager for RPTSCHED and RPTSOL keywords.
Definition RPTConfig.hpp:40
Opm::ReservoirCoupling::CouplingInfo
Definition ReservoirCouplingInfo.hpp:34
Opm::Runspec
Definition Runspec.hpp:489
Opm::SCHEDULESection
Definition DeckSection.hpp:145
Opm::ScheduleBlock
Definition ScheduleBlock.hpp:52
Opm::ScheduleDeck
Definition ScheduleDeck.hpp:53
Opm::ScheduleGrid
Collection of intersected cells and associate properties for all simulation grids,...
Definition ScheduleGrid.hpp:50
Opm::ScheduleState
Definition ScheduleState.hpp:101
Opm::Schedule::hasGroup
bool hasGroup(const std::string &groupName, std::size_t timeStep) const
Query for group existence at particular time.
Definition Schedule.cpp:1208
Opm::Schedule::initialReportConfiguration
const std::optional< RPTConfig > & initialReportConfiguration() const
Retrieve initial report configuration object.
Definition Schedule.cpp:2683
Opm::Schedule::clearEvents
void clearEvents(const std::size_t report_step)
Clear out all registered events at a given report step.
Definition Schedule.cpp:1023
Opm::Schedule::groupNames
const std::vector< std::string > & groupNames() const
Retrieve names of all groups in model.
Definition Schedule.cpp:1461
Opm::Schedule::restart_groups
std::vector< const Group * > restart_groups(std::size_t timeStep) const
Retrieve collection of group objects suiteable for restart file output.
Definition Schedule.cpp:1466
Opm::Serializer
Class for (de-)serializing.
Definition Serializer.hpp:94
Opm::Serializer::isSerializing
bool isSerializing() const
Returns true if we are currently doing a serialization operation.
Definition Serializer.hpp:207
Opm::SummaryState
Definition SummaryState.hpp:72
Opm::TracerConfig
Definition TracerConfig.hpp:33
Opm::UDQConfig
Collection of all user-defined quantities in the current simulation run.
Definition UDQConfig.hpp:69
Opm::UnitSystem
Definition UnitSystem.hpp:34
Opm::WelSegsSet
Definition WelSegsSet.hpp:34
Opm::WellTestConfig
Definition WellTestConfig.hpp:67
Opm::Well
Definition Well.hpp:77
Opm::WriteRestartFileEvents
Definition WriteRestartFileEvents.hpp:31
Opm::prefix
Conversion prefix for units.
Definition Units.hpp:59
Opm
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition Exceptions.hpp:30
Opm::RestartIO::RstGroup
Definition group.hpp:38
Opm::RestartIO::RstState
Definition state.hpp:57
Opm::ScheduleStatic
Initial state of Schedule object created from information in SOLUTION section.
Definition ScheduleStatic.hpp:48
Opm::SimulatorUpdate
This struct is used to communicate back from the Schedule::applyAction() what needs to be updated in ...
Definition SimulatorUpdate.hpp:33