Files
opm-common/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp
2021-01-15 09:19:33 +01:00

566 lines
28 KiB
C++

/*
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 <map>
#include <memory>
#include <optional>
#include <unordered_set>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Python/Python.hpp>
#include <opm/parser/eclipse/EclipseState/IOConfig/RestartConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/DynamicVector.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GTNode.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Util/OrderedMap.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/MessageLimits.hpp>
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/RFTConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Network/ExtNetwork.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/PAvg.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/PAvgCalculatorCollection.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellTestConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Well/WellMatcher.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleDeck.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/RPTConfig.hpp>
#include <opm/common/utility/ActiveGridCells.hpp>
#include <opm/io/eclipse/rst/state.hpp>
/*
The DynamicState<std::shared_ptr<T>> pattern: The quantities in the Schedule
section like e.g. wellrates and completion properties are typically
characterized by the following behaviour:
1. They can be updated repeatedly at arbitrary points in the Schedule
section.
2. The value set at one timestep will apply until is explicitly set again at
a later timestep.
These properties are typically stored in a DynamicState<T> container; the
DynamicState<T> class is a container which implements this semantics:
1. It is legitimate to ask for an out-of-range value, you will then get the
last value which has been set.
2. When assigning an out-of-bounds value the container will append the
currently set value until correct length has been reached, and then the
new value will be assigned.
3. The DynamicState<T> has an awareness of the total length of the time
axis, trying to access values beyound that is illegal.
For many of the non-trival objects like eg Well and Group the DynamicState<>
contains a shared pointer to an underlying object, that way the fill operation
when the vector is resized is quite fast. The following pattern is quite
common for the Schedule implementation:
// Create a new well object.
std::shared_ptr<Well> new_well = this->getWell( well_name, time_step );
// Update the new well object with new settings from the deck, the
// updateXXXX() method will return true if the well object was actually
// updated:
if (new_well->updateRate( new_rate ))
this->dynamic_state.update( time_step, new_well);
*/
namespace Opm
{
class Deck;
class DeckKeyword;
class DeckRecord;
class EclipseGrid;
class EclipseState;
class FieldPropsManager;
class Runspec;
class SCHEDULESection;
class SummaryState;
class TimeMap;
class ErrorGuard;
class UDQConfig;
struct ScheduleStatic {
std::shared_ptr<const Python> m_python_handle;
std::string m_input_path;
MessageLimits m_deck_message_limits;
UnitSystem m_unit_system;
Runspec m_runspec;
ScheduleStatic() = default;
explicit ScheduleStatic(std::shared_ptr<const Python> python_handle) :
m_python_handle(python_handle)
{}
ScheduleStatic(std::shared_ptr<const Python> python_handle,
const Deck& deck,
const Runspec& runspec) :
m_python_handle(python_handle),
m_input_path(deck.getInputPath()),
m_deck_message_limits( deck ),
m_unit_system( deck.getActiveUnitSystem() ),
m_runspec( runspec )
{}
template<class Serializer>
void serializeOp(Serializer& serializer)
{
m_deck_message_limits.serializeOp(serializer);
m_runspec.serializeOp(serializer);
m_unit_system.serializeOp(serializer);
serializer(this->m_input_path);
}
static ScheduleStatic serializeObject() {
auto python = std::make_shared<Python>(Python::Enable::OFF);
ScheduleStatic st(python);
st.m_deck_message_limits = MessageLimits::serializeObject();
st.m_runspec = Runspec::serializeObject();
st.m_unit_system = UnitSystem::newFIELD();
st.m_input_path = "Some/funny/path";
return st;
}
bool operator==(const ScheduleStatic& other) const {
return this->m_input_path == other.m_input_path &&
this->m_deck_message_limits == other.m_deck_message_limits &&
this->m_unit_system == other.m_unit_system &&
this->m_runspec == other.m_runspec;
}
};
class Schedule {
public:
using WellMap = OrderedMap<std::string, DynamicState<std::shared_ptr<Well>>>;
using GroupMap = OrderedMap<std::string, DynamicState<std::shared_ptr<Group>>>;
Schedule() = default;
explicit Schedule(std::shared_ptr<const Python> python_handle);
Schedule(const Deck& deck,
const EclipseGrid& grid,
const FieldPropsManager& fp,
const Runspec &runspec,
const ParseContext& parseContext,
ErrorGuard& errors,
std::shared_ptr<const Python> python,
const RestartIO::RstState* rst = nullptr);
template<typename T>
Schedule(const Deck& deck,
const EclipseGrid& grid,
const FieldPropsManager& fp,
const Runspec &runspec,
const ParseContext& parseContext,
T&& errors,
std::shared_ptr<const Python> python,
const RestartIO::RstState* rst = nullptr);
Schedule(const Deck& deck,
const EclipseGrid& grid,
const FieldPropsManager& fp,
const Runspec &runspec,
std::shared_ptr<const Python> python,
const RestartIO::RstState* rst = nullptr);
Schedule(const Deck& deck,
const EclipseState& es,
const ParseContext& parseContext,
ErrorGuard& errors,
std::shared_ptr<const Python> python,
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 RestartIO::RstState* rst = nullptr);
Schedule(const Deck& deck,
const EclipseState& es,
std::shared_ptr<const Python> python,
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 RestartIO::RstState* rst = nullptr);
static Schedule serializeObject();
/*
* If the input deck does not specify a start time, Eclipse's 1. Jan
* 1983 is defaulted
*/
time_t getStartTime() const;
time_t posixStartTime() const;
time_t posixEndTime() const;
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 TimeMap& getTimeMap() const;
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::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;
std::vector<std::string> groupNames(const std::string& pattern, std::size_t timeStep) const;
std::vector<std::string> groupNames(std::size_t timeStep) const;
std::vector<std::string> groupNames(const std::string& pattern) const;
std::vector<std::string> groupNames() const;
/*
The restart_groups function returns a vector of groups pointers which
is organized as follows:
1. The number of elements is WELLDIMS::MAXGROUPS + 1
2. The elements are sorted according to group.insert_index().
3. If there are less than WELLDIMS::MAXGROUPS nullptr is used.
4. The very last element corresponds to the FIELD group.
*/
std::vector<const Group*> restart_groups(std::size_t timeStep) const;
void updateWell(std::shared_ptr<Well> well, std::size_t reportStep);
std::vector<std::string> changed_wells(std::size_t reportStep) const;
const Well& getWell(const std::string& wellName, std::size_t timeStep) const;
const Well& getWellatEnd(const std::string& well_name) const;
std::vector<Well> getWells(std::size_t timeStep) const;
std::vector<Well> getWellsatEnd() const;
void shut_well(const std::string& well_name, std::size_t report_step);
void stop_well(const std::string& well_name, std::size_t report_step);
void open_well(const std::string& well_name, std::size_t report_step);
std::vector<const Group*> getChildGroups2(const std::string& group_name, std::size_t timeStep) const;
std::vector<Well> getChildWells2(const std::string& group_name, std::size_t timeStep) const;
Well::ProducerCMode getGlobalWhistctlMmode(std::size_t timestep) const;
const UDQConfig& getUDQConfig(std::size_t timeStep) const;
std::vector<const UDQConfig*> udqConfigList() const;
void evalAction(const SummaryState& summary_state, std::size_t timeStep);
GTNode groupTree(std::size_t report_step) const;
GTNode groupTree(const std::string& root_node, std::size_t report_step) const;
std::size_t numGroups() const;
std::size_t numGroups(std::size_t timeStep) const;
bool hasGroup(const std::string& groupName) const;
bool hasGroup(const std::string& groupName, std::size_t timeStep) const;
const Group& getGroup(const std::string& groupName, std::size_t timeStep) const;
void invalidNamePattern (const std::string& namePattern, std::size_t report_step, const ParseContext& parseContext, ErrorGuard& errors, const DeckKeyword& keyword) const;
const GuideRateConfig& guideRateConfig(std::size_t timeStep) const;
const RFTConfig& rftConfig() 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;
const RestartConfig& restart() const;
RestartConfig& restart();
void applyAction(std::size_t reportStep, const Action::ActionX& action, const Action::Result& result);
void applyWellProdIndexScaling(const std::string& well_name, const std::size_t reportStep, const double scalingFactor);
const GasLiftOpt& glo(std::size_t report_step) const;
bool operator==(const Schedule& data) const;
std::shared_ptr<const Python> python() 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 std::chrono::system_clock::time_point& start_time, const std::optional<std::chrono::system_clock::time_point>& end_time);
void create_next(const ScheduleBlock& block);
void create_first(const std::chrono::system_clock::time_point& start_time, const std::optional<std::chrono::system_clock::time_point>& end_time);
/*
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);
template<class Serializer>
void serializeOp(Serializer& serializer)
{
m_sched_deck.serializeOp(serializer);
m_timeMap.serializeOp(serializer);
auto splitWells = splitDynMap(wells_static);
serializer.vector(splitWells.first);
serializer(splitWells.second);
auto splitGroups = splitDynMap(groups);
serializer.vector(splitGroups.first);
serializer(splitGroups.second);
udq_config.serializeOp(serializer);
guide_rate_config.serializeOp(serializer);
m_glo.serializeOp(serializer);
rft_config.serializeOp(serializer);
restart_config.serializeOp(serializer);
if (!serializer.isSerializing()) {
reconstructDynMap(splitWells.first, splitWells.second, wells_static);
reconstructDynMap(splitGroups.first, splitGroups.second, groups);
}
serializer.vector(snapshots);
m_static.serializeOp(serializer);
}
private:
template<class Key, class Value> using Map2 = std::map<Key,Value>;
ScheduleStatic m_static;
ScheduleDeck m_sched_deck;
TimeMap m_timeMap;
WellMap wells_static;
GroupMap groups;
DynamicState<std::shared_ptr<UDQConfig>> udq_config;
DynamicState<std::shared_ptr<GuideRateConfig>> guide_rate_config;
DynamicState<std::shared_ptr<GasLiftOpt>> m_glo;
RFTConfig rft_config;
RestartConfig restart_config;
std::optional<int> exit_status;
std::vector<ScheduleState> snapshots;
void load_rst(const RestartIO::RstState& rst,
const EclipseGrid& grid,
const FieldPropsManager& fp);
void addWell(Well well, std::size_t report_step);
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,
Well::GasInflowEquation gas_inflow,
std::size_t timeStep,
Connection::Order 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;
void updateGroup(std::shared_ptr<Group> group, std::size_t reportStep);
bool checkGroups(const ParseContext& parseContext, ErrorGuard& errors);
bool updateWellStatus( const std::string& well, std::size_t reportStep, bool runtime, Well::Status 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 EclipseGrid& grid,
const FieldPropsManager& fp);
void addACTIONX(const Action::ActionX& action);
void addGroupToGroup( const std::string& parent_group, const std::string& child_group, std::size_t timeStep);
void addGroupToGroup( const std::string& parent_group, const Group& child_group, std::size_t timeStep);
void addGroup(const std::string& groupName , std::size_t timeStep);
void addGroup(const Group& group, std::size_t timeStep);
void addWell(const std::string& wellName, const DeckRecord& record, std::size_t timeStep, Connection::Order connection_order);
void checkIfAllConnectionsIsShut(std::size_t currentStep);
void updateUDQ(const DeckKeyword& keyword, std::size_t current_step);
void handleKeyword(std::size_t currentStep,
const ScheduleBlock& block,
const DeckKeyword& keyword,
const ParseContext& parseContext, ErrorGuard& errors,
const EclipseGrid& grid,
const FieldPropsManager& fp,
std::vector<std::pair<const DeckKeyword*, std::size_t > >& rftProperties);
template<template<class, class> class Map, class Type, class Key>
std::pair<std::vector<Type>, std::vector<std::pair<Key, std::vector<std::size_t>>>>
splitDynMap(const Map<Key, Opm::DynamicState<Type>>& map)
{
// we have to pack the unique ptrs separately, and use an index map
// to allow reconstructing the appropriate structures.
std::vector<std::pair<Key, std::vector<std::size_t>>> asMap;
std::vector<Type> unique;
for (const auto& it : map) {
auto indices = it.second.split(unique);
asMap.push_back(std::make_pair(it.first, indices));
}
return std::make_pair(unique, asMap);
}
template<template<class, class> class Map, class Type, class Key>
void reconstructDynMap(const std::vector<Type>& unique,
const std::vector<std::pair<Key, std::vector<std::size_t>>>& asMap,
Map<Key, Opm::DynamicState<Type>>& result)
{
for (const auto& it : asMap) {
result[it.first].reconstruct(unique, it.second);
}
}
static std::string formatDate(std::time_t t);
std::string simulationDays(std::size_t currentStep) const;
void applyEXIT(const DeckKeyword&, std::size_t currentStep);
void applyWELOPEN(const DeckKeyword&, std::size_t currentStep, bool runtime, const ParseContext&, ErrorGuard&, const std::vector<std::string>& matching_wells = {});
void applyWRFT(const DeckKeyword&, std::size_t currentStep);
void applyWRFTPLT(const DeckKeyword&, std::size_t currentStep);
struct HandlerContext {
const ScheduleBlock& block;
const DeckKeyword& keyword;
const std::size_t currentStep;
const EclipseGrid* grid_ptr;
const FieldPropsManager* fp_ptr;
HandlerContext(const ScheduleBlock& block_,
const DeckKeyword& keyword_,
const std::size_t currentStep_):
block(block_),
keyword(keyword_),
currentStep(currentStep_),
grid_ptr(nullptr),
fp_ptr(nullptr)
{}
};
/**
* Handles a "normal" keyword. A normal keyword is one that can be handled by a function with the standard set of arguments (the ones that are passed to this function).
*
* Normal keywords are found in the file KeywordHandlers.cpp; to add a new keyword handler to the file, add its signature in the list below,
* add the implementation to KeywordHandlers.cpp, and add a pointer to the handler in the dispatch registry in the implementation of this method, found at the bottom of
* KeywordHandlers.cpp.
*
* For the benefit of automatic cross-checking of the lists, all of these are in alphabetical order.
*
* @param handlerContext context object containing the environment in which the handler was invoked
* @param parseContext context object containing the parsing environment
* @param errors the error handling object for the current parsing process
*
* @return `true` if the keyword was handled
*/
bool handleNormalKeyword(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors);
// Keyword Handlers
void handlePYACTION(const DeckKeyword&);
void handleGCONPROD(const DeckKeyword& keyword, std::size_t current_step, const ParseContext& parseContext, ErrorGuard& errors);
void handleGCONINJE(const DeckKeyword& keyword, std::size_t current_step, const ParseContext& parseContext, ErrorGuard& errors);
void handleGLIFTOPT(const DeckKeyword& keyword, std::size_t report_step, const ParseContext& parseContext, ErrorGuard& errors);
void handleWELPI (const DeckKeyword& keyword, std::size_t report_step, const ParseContext& parseContext, ErrorGuard& errors, bool actionx_mode = false, const std::vector<std::string>& matching_wells = {});
// Normal keyword handlers -- in KeywordHandlers.cpp
void handleBRANPROP (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleCOMPDAT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleCOMPLUMP (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleCOMPORD (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleCOMPSEGS (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleDRSDT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleDRSDTR (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleDRVDT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleDRVDTR (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleGCONINJE (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleGCONPROD (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleGCONSALE (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleGCONSUMP (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleGEFAC (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleGLIFTOPT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleGPMAINT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleGRUPNET (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleGRUPTREE (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleGUIDERAT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleLIFTOPT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleLINCOM (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleMESSAGES (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleMULTFLT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleMXUNSUPP (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleNODEPROP (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleNUPCOL (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleRPTSCHED (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleTUNING (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleUDQ (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleVAPPARS (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleVFPINJ (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleVFPPROD (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWCONHIST (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWCONINJE (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWCONINJH (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWCONPROD (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWECON (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWEFAC (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWELOPEN (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWELPI (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWELSEGS (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWELSPECS (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWELTARG (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWFOAM (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWGRUPCON (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWHISTCTL (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWINJTEMP (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWLIFTOPT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWLIST (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWPAVE (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWPAVEDEP (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWWPAVE (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWPIMULT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWPMITAB (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWPOLYMER (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWSALT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWSEGITER (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWSEGSICD (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWSEGAICD (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWSEGVALV (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWSKPTAB (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWSOLVENT (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWTEMP (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWTEST (const HandlerContext&, const ParseContext&, ErrorGuard&);
void handleWTRACER (const HandlerContext&, const ParseContext&, ErrorGuard&);
};
}
#endif