Record and act on return value from PYACTION
This commit is contained in:
parent
c37c2b2d49
commit
343f14dacf
@ -551,6 +551,7 @@ if(ENABLE_ECL_OUTPUT)
|
||||
tests/msim/action1.py
|
||||
tests/msim/action2.py
|
||||
tests/msim/action3.py
|
||||
tests/msim/action_count.py
|
||||
tests/VFP_CASE.DATA)
|
||||
endif()
|
||||
|
||||
|
@ -89,8 +89,8 @@ void msim::post_step(data::Solution& /* sol */, data::Wells& /* well_data */, da
|
||||
this->schedule.applyAction(report_step, *action, result.wells(), {});
|
||||
}
|
||||
|
||||
for (const auto& pyaction : actions.pending_python())
|
||||
this->schedule.runPyAction(report_step, *pyaction, this->state, this->st);
|
||||
for (const auto& pyaction : actions.pending_python(this->action_state))
|
||||
this->schedule.runPyAction(report_step, *pyaction, this->action_state, this->state, this->st);
|
||||
}
|
||||
|
||||
|
||||
|
@ -55,7 +55,7 @@ public:
|
||||
const ActionX& operator[](const std::string& name) const;
|
||||
const ActionX& operator[](std::size_t index) const;
|
||||
std::vector<const ActionX *> pending(const State& state, std::time_t sim_time) const;
|
||||
std::vector<const PyAction *> pending_python() const;
|
||||
std::vector<const PyAction *> pending_python(const State& state) const;
|
||||
|
||||
bool has(const std::string& name) const;
|
||||
std::vector<ActionX>::const_iterator begin() const;
|
||||
|
@ -36,6 +36,7 @@ class SummaryState;
|
||||
class PyRunModule;
|
||||
|
||||
namespace Action {
|
||||
class State;
|
||||
|
||||
class PyAction {
|
||||
public:
|
||||
@ -53,7 +54,7 @@ public:
|
||||
bool run(EclipseState& ecl_state, Schedule& schedule, std::size_t report_step, SummaryState& st,
|
||||
const std::function<void(const std::string&, const std::vector<std::string>&)>& actionx_callback) const;
|
||||
const std::string& name() const;
|
||||
bool active() const;
|
||||
bool ready(const State& state) const;
|
||||
bool operator==(const PyAction& other) const;
|
||||
|
||||
template<class Serializer>
|
||||
|
@ -35,6 +35,8 @@ namespace Action {
|
||||
|
||||
class ActionX;
|
||||
class Actions;
|
||||
class PyAction;
|
||||
|
||||
class State {
|
||||
|
||||
struct RunState {
|
||||
@ -79,9 +81,11 @@ struct RunState {
|
||||
|
||||
public:
|
||||
void add_run(const ActionX& action, std::time_t sim_time, Result result);
|
||||
void add_run(const PyAction& action, bool result);
|
||||
std::size_t run_count(const ActionX& action) const;
|
||||
std::time_t run_time(const ActionX& action) const;
|
||||
std::optional<Result> result(const std::string& action) const;
|
||||
std::optional<bool> python_result(const std::string& action) const;
|
||||
void load_rst(const Actions& action_config, const RestartIO::RstState& rst_state);
|
||||
|
||||
template<class Serializer>
|
||||
@ -89,6 +93,7 @@ public:
|
||||
{
|
||||
serializer.map(this->run_state);
|
||||
serializer.map(this->last_result);
|
||||
serializer.template map<std::map<std::string,bool>, false>(this->m_python_result);
|
||||
}
|
||||
|
||||
|
||||
@ -100,6 +105,7 @@ private:
|
||||
static action_id make_id(const ActionX& action);
|
||||
std::map<action_id, RunState> run_state;
|
||||
std::map<std::string, Result> last_result;
|
||||
std::map<std::string, bool> m_python_result;
|
||||
};
|
||||
|
||||
|
||||
|
@ -295,7 +295,7 @@ namespace Opm
|
||||
Python code. he return value from runPyAction() comes from such a
|
||||
internal ACTIONX.
|
||||
*/
|
||||
SimulatorUpdate runPyAction(std::size_t reportStep, const Action::PyAction& pyaction, 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 GasLiftOpt& glo(std::size_t report_step) const;
|
||||
|
@ -109,10 +109,10 @@ bool Actions::ready(const State& state, std::time_t sim_time) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<const PyAction *> Actions::pending_python() const {
|
||||
std::vector<const PyAction *> Actions::pending_python(const State& state) const {
|
||||
std::vector<const PyAction *> pyaction_vector;
|
||||
for (const auto& pyaction : this->pyactions) {
|
||||
if (pyaction.active())
|
||||
if (pyaction.ready(state))
|
||||
pyaction_vector.push_back( &pyaction );
|
||||
}
|
||||
return pyaction_vector;
|
||||
|
@ -31,6 +31,7 @@ namespace py = pybind11;
|
||||
#include <opm/input/eclipse/Python/Python.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Action/PyAction.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Action/State.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||
|
||||
|
||||
@ -64,8 +65,18 @@ PyAction PyAction::serializeObject()
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PyAction::active() const {
|
||||
return this->m_active;
|
||||
bool PyAction::ready(const State& state) const {
|
||||
if (this->m_run_count == RunCount::unlimited)
|
||||
return true;
|
||||
|
||||
auto last_result = state.python_result(this->m_name);
|
||||
if (!last_result.has_value())
|
||||
return true;
|
||||
|
||||
if (this->m_run_count == RunCount::first_true && last_result.value() == false)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -73,13 +84,6 @@ const std::string& PyAction::name() const {
|
||||
return this->m_name;
|
||||
}
|
||||
|
||||
void PyAction::update(bool result) const {
|
||||
if (this->m_run_count == RunCount::single)
|
||||
this->m_active = false;
|
||||
|
||||
if (this->m_run_count == RunCount::first_true && result)
|
||||
this->m_active = false;
|
||||
}
|
||||
|
||||
bool PyAction::operator==(const PyAction& other) const {
|
||||
return this->m_name == other.m_name &&
|
||||
|
@ -59,6 +59,10 @@ void State::add_run(const ActionX& action, std::time_t run_time, Result result)
|
||||
this->last_result.insert_or_assign(action.name(), std::move(result));
|
||||
}
|
||||
|
||||
void State::add_run(const PyAction& action, bool result) {
|
||||
this->m_python_result.insert_or_assign( action.name(), result );
|
||||
}
|
||||
|
||||
|
||||
std::optional<Result> State::result(const std::string& action) const {
|
||||
auto iter = this->last_result.find(action);
|
||||
@ -69,6 +73,16 @@ std::optional<Result> State::result(const std::string& action) const {
|
||||
}
|
||||
|
||||
|
||||
std::optional<bool> State::python_result(const std::string& action) const {
|
||||
auto iter = this->m_python_result.find(action);
|
||||
if (iter == this->m_python_result.end())
|
||||
return std::nullopt;
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
When restoring from restart file we initialize the number of times it has run
|
||||
and the last run time. From the evaluation only the 'true' evaluation is
|
||||
@ -86,7 +100,8 @@ void State::load_rst(const Actions& action_config, const RestartIO::RstState& rs
|
||||
|
||||
bool State::operator==(const State& other) const {
|
||||
return this->run_state == other.run_state &&
|
||||
this->last_result == other.last_result;
|
||||
this->last_result == other.last_result &&
|
||||
this->m_python_result == other.m_python_result;
|
||||
}
|
||||
|
||||
|
||||
@ -94,6 +109,7 @@ State State::serializeObject() {
|
||||
State st;
|
||||
st.run_state.insert(std::make_pair( std::make_pair("ACTION", 100), RunState::serializeObject()));
|
||||
st.last_result.insert( std::make_pair("ACTION", Result::serializeObject()));
|
||||
st.m_python_result.insert( std::make_pair("PYACTION", false) );
|
||||
return st;
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,7 @@
|
||||
|
||||
#include <opm/input/eclipse/EclipseState/TracerConfig.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Action/State.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Action/ActionX.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Action/ActionResult.hpp>
|
||||
#include <opm/input/eclipse/Schedule/MSW/SICD.hpp>
|
||||
@ -1428,14 +1429,15 @@ File {} line {}.)", pattern, location.keyword, location.filename, location.linen
|
||||
*/
|
||||
|
||||
|
||||
SimulatorUpdate Schedule::runPyAction(std::size_t reportStep, const Action::PyAction& pyaction, EclipseState& ecl_state, SummaryState& summary_state) {
|
||||
SimulatorUpdate Schedule::runPyAction(std::size_t reportStep, const Action::PyAction& pyaction, Action::State& action_state, EclipseState& ecl_state, SummaryState& summary_state) {
|
||||
SimulatorUpdate sim_update;
|
||||
|
||||
auto apply_action_callback = [&sim_update, &reportStep, this](const std::string& action_name, const std::vector<std::string>& matching_wells) {
|
||||
sim_update = this->applyAction(reportStep, action_name, matching_wells);
|
||||
};
|
||||
|
||||
pyaction.run(ecl_state, *this, reportStep, summary_state, apply_action_callback);
|
||||
auto result = pyaction.run(ecl_state, *this, reportStep, summary_state, apply_action_callback);
|
||||
action_state.add_run(pyaction, result);
|
||||
return sim_update;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,18 @@ PYACTION
|
||||
WCLOSE UNLIMITED /
|
||||
'wclose.py' /
|
||||
|
||||
PYACTION
|
||||
UNLIMITED UNLIMITED /
|
||||
'wclose.py' /
|
||||
|
||||
PYACTION
|
||||
SINGLE SINGLE /
|
||||
'wclose.py' /
|
||||
|
||||
PYACTION
|
||||
FIRST_TRUE FIRST_TRUE /
|
||||
'wclose.py' /
|
||||
|
||||
WELSPECS
|
||||
'PROD1' 'G1' 10 10 8400 'OIL' /
|
||||
'PROD2' 'G1' 5 5 8400 'OIL' /
|
||||
|
@ -447,7 +447,7 @@ PYACTION
|
||||
|
||||
PYACTION
|
||||
ACTION3 FIRST_TRUE /
|
||||
'action2.py' /
|
||||
'action_count.py' /
|
||||
|
||||
DATES
|
||||
1 'JAN' 2015 /
|
||||
|
11
tests/msim/action_count.py
Normal file
11
tests/msim/action_count.py
Normal file
@ -0,0 +1,11 @@
|
||||
import math
|
||||
|
||||
def run(ecl_state, schedule, report_step, summary_state, actionx_callback):
|
||||
if not "run_count" in summary_state:
|
||||
summary_state["run_count"] = 0
|
||||
summary_state["run_count"] += 1
|
||||
|
||||
if summary_state.elapsed() > (365 + 15)*24*3600:
|
||||
return True
|
||||
|
||||
return False
|
@ -524,6 +524,7 @@ BOOST_AUTO_TEST_CASE(PYTHON_WELL_CLOSE_EXAMPLE) {
|
||||
BOOST_CHECK(w4_11.getStatus() == Well::Status::SHUT );
|
||||
}
|
||||
}
|
||||
BOOST_CHECK_EQUAL( sim.st.get("run_count"), 13);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(PYTHON_ACTIONX) {
|
||||
|
@ -276,7 +276,7 @@ BOOST_AUTO_TEST_CASE(TestActions) {
|
||||
BOOST_CHECK(!action2.eval(context));
|
||||
|
||||
|
||||
const auto& python_actions = config.pending_python();
|
||||
const auto& python_actions = config.pending_python(action_state);
|
||||
BOOST_CHECK_EQUAL(python_actions.size(), 2U);
|
||||
}
|
||||
|
||||
@ -977,6 +977,7 @@ BOOST_AUTO_TEST_CASE(ActionState) {
|
||||
|
||||
auto res = st.result("NAME-HIDDEN");
|
||||
BOOST_CHECK(!res.has_value());
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MANUAL4_QUOTE) {
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||
#include <opm/common/utility/TimeService.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Action/State.hpp>
|
||||
|
||||
using namespace Opm;
|
||||
|
||||
@ -124,7 +125,7 @@ BOOST_AUTO_TEST_CASE(PYACTION) {
|
||||
const std::string& fname = pyaction_kw.getRecord(1).getItem(0).get<std::string>(0);
|
||||
Action::PyAction py_action(python, "WCLOSE", Action::PyAction::RunCount::unlimited, deck.makeDeckPath(fname));
|
||||
auto actionx_callback = [] (const std::string&, const std::vector<std::string>&) { ;};
|
||||
|
||||
Action::State action_state;
|
||||
|
||||
st.update_well_var("PROD1", "WWCT", 0);
|
||||
py_action.run(ecl_state, schedule, 10, st, actionx_callback);
|
||||
@ -141,6 +142,32 @@ BOOST_AUTO_TEST_CASE(PYACTION) {
|
||||
BOOST_CHECK( well1.getStatus() == Well::Status::SHUT );
|
||||
BOOST_CHECK( well2.getStatus() == Well::Status::OPEN );
|
||||
BOOST_CHECK( st.has("RUN_COUNT") );
|
||||
|
||||
std::map<std::string, Action::PyAction> action_map;
|
||||
for (const auto * p : schedule[0].actions().pending_python(action_state))
|
||||
action_map.emplace( p->name(), *p );
|
||||
|
||||
const auto& pyaction_unlimited = action_map.at("UNLIMITED");
|
||||
const auto& pyaction_single = action_map.at("SINGLE");
|
||||
const auto& pyaction_first_true = action_map.at("FIRST_TRUE");
|
||||
|
||||
auto actions = schedule[0].actions();
|
||||
BOOST_CHECK( actions.pending_python(action_state).size() == 4);
|
||||
|
||||
action_state.add_run( py_action, true);
|
||||
BOOST_CHECK( actions.pending_python(action_state).size() == 4);
|
||||
|
||||
action_state.add_run( pyaction_unlimited, true);
|
||||
BOOST_CHECK( actions.pending_python(action_state).size() == 4);
|
||||
|
||||
action_state.add_run( pyaction_single, false);
|
||||
BOOST_CHECK( actions.pending_python(action_state).size() == 3);
|
||||
|
||||
action_state.add_run( pyaction_first_true, false);
|
||||
BOOST_CHECK( actions.pending_python(action_state).size() == 3);
|
||||
|
||||
action_state.add_run( pyaction_first_true, true);
|
||||
BOOST_CHECK( actions.pending_python(action_state).size() == 2);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user