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/action1.py
|
||||||
tests/msim/action2.py
|
tests/msim/action2.py
|
||||||
tests/msim/action3.py
|
tests/msim/action3.py
|
||||||
|
tests/msim/action_count.py
|
||||||
tests/VFP_CASE.DATA)
|
tests/VFP_CASE.DATA)
|
||||||
endif()
|
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(), {});
|
this->schedule.applyAction(report_step, *action, result.wells(), {});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& pyaction : actions.pending_python())
|
for (const auto& pyaction : actions.pending_python(this->action_state))
|
||||||
this->schedule.runPyAction(report_step, *pyaction, this->state, this->st);
|
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[](const std::string& name) const;
|
||||||
const ActionX& operator[](std::size_t index) 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 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;
|
bool has(const std::string& name) const;
|
||||||
std::vector<ActionX>::const_iterator begin() const;
|
std::vector<ActionX>::const_iterator begin() const;
|
||||||
|
@ -36,6 +36,7 @@ class SummaryState;
|
|||||||
class PyRunModule;
|
class PyRunModule;
|
||||||
|
|
||||||
namespace Action {
|
namespace Action {
|
||||||
|
class State;
|
||||||
|
|
||||||
class PyAction {
|
class PyAction {
|
||||||
public:
|
public:
|
||||||
@ -53,7 +54,7 @@ public:
|
|||||||
bool run(EclipseState& ecl_state, Schedule& schedule, std::size_t report_step, SummaryState& st,
|
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::function<void(const std::string&, const std::vector<std::string>&)>& actionx_callback) const;
|
||||||
const std::string& name() const;
|
const std::string& name() const;
|
||||||
bool active() const;
|
bool ready(const State& state) const;
|
||||||
bool operator==(const PyAction& other) const;
|
bool operator==(const PyAction& other) const;
|
||||||
|
|
||||||
template<class Serializer>
|
template<class Serializer>
|
||||||
|
@ -35,6 +35,8 @@ namespace Action {
|
|||||||
|
|
||||||
class ActionX;
|
class ActionX;
|
||||||
class Actions;
|
class Actions;
|
||||||
|
class PyAction;
|
||||||
|
|
||||||
class State {
|
class State {
|
||||||
|
|
||||||
struct RunState {
|
struct RunState {
|
||||||
@ -79,9 +81,11 @@ struct RunState {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
void add_run(const ActionX& action, std::time_t sim_time, Result result);
|
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::size_t run_count(const ActionX& action) const;
|
||||||
std::time_t run_time(const ActionX& action) const;
|
std::time_t run_time(const ActionX& action) const;
|
||||||
std::optional<Result> result(const std::string& 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);
|
void load_rst(const Actions& action_config, const RestartIO::RstState& rst_state);
|
||||||
|
|
||||||
template<class Serializer>
|
template<class Serializer>
|
||||||
@ -89,6 +93,7 @@ public:
|
|||||||
{
|
{
|
||||||
serializer.map(this->run_state);
|
serializer.map(this->run_state);
|
||||||
serializer.map(this->last_result);
|
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);
|
static action_id make_id(const ActionX& action);
|
||||||
std::map<action_id, RunState> run_state;
|
std::map<action_id, RunState> run_state;
|
||||||
std::map<std::string, Result> last_result;
|
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
|
Python code. he return value from runPyAction() comes from such a
|
||||||
internal ACTIONX.
|
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;
|
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;
|
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;
|
std::vector<const PyAction *> pyaction_vector;
|
||||||
for (const auto& pyaction : this->pyactions) {
|
for (const auto& pyaction : this->pyactions) {
|
||||||
if (pyaction.active())
|
if (pyaction.ready(state))
|
||||||
pyaction_vector.push_back( &pyaction );
|
pyaction_vector.push_back( &pyaction );
|
||||||
}
|
}
|
||||||
return pyaction_vector;
|
return pyaction_vector;
|
||||||
|
@ -31,6 +31,7 @@ namespace py = pybind11;
|
|||||||
#include <opm/input/eclipse/Python/Python.hpp>
|
#include <opm/input/eclipse/Python/Python.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Action/PyAction.hpp>
|
#include <opm/input/eclipse/Schedule/Action/PyAction.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/Action/State.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||||
|
|
||||||
|
|
||||||
@ -64,8 +65,18 @@ PyAction PyAction::serializeObject()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PyAction::active() const {
|
bool PyAction::ready(const State& state) const {
|
||||||
return this->m_active;
|
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;
|
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 {
|
bool PyAction::operator==(const PyAction& other) const {
|
||||||
return this->m_name == other.m_name &&
|
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));
|
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 {
|
std::optional<Result> State::result(const std::string& action) const {
|
||||||
auto iter = this->last_result.find(action);
|
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
|
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
|
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 {
|
bool State::operator==(const State& other) const {
|
||||||
return this->run_state == other.run_state &&
|
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;
|
State st;
|
||||||
st.run_state.insert(std::make_pair( std::make_pair("ACTION", 100), RunState::serializeObject()));
|
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.last_result.insert( std::make_pair("ACTION", Result::serializeObject()));
|
||||||
|
st.m_python_result.insert( std::make_pair("PYACTION", false) );
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
|
|
||||||
#include <opm/input/eclipse/EclipseState/TracerConfig.hpp>
|
#include <opm/input/eclipse/EclipseState/TracerConfig.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/EclipseState.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/ActionX.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Action/ActionResult.hpp>
|
#include <opm/input/eclipse/Schedule/Action/ActionResult.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/MSW/SICD.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;
|
SimulatorUpdate sim_update;
|
||||||
|
|
||||||
auto apply_action_callback = [&sim_update, &reportStep, this](const std::string& action_name, const std::vector<std::string>& matching_wells) {
|
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);
|
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;
|
return sim_update;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,18 @@ PYACTION
|
|||||||
WCLOSE UNLIMITED /
|
WCLOSE UNLIMITED /
|
||||||
'wclose.py' /
|
'wclose.py' /
|
||||||
|
|
||||||
|
PYACTION
|
||||||
|
UNLIMITED UNLIMITED /
|
||||||
|
'wclose.py' /
|
||||||
|
|
||||||
|
PYACTION
|
||||||
|
SINGLE SINGLE /
|
||||||
|
'wclose.py' /
|
||||||
|
|
||||||
|
PYACTION
|
||||||
|
FIRST_TRUE FIRST_TRUE /
|
||||||
|
'wclose.py' /
|
||||||
|
|
||||||
WELSPECS
|
WELSPECS
|
||||||
'PROD1' 'G1' 10 10 8400 'OIL' /
|
'PROD1' 'G1' 10 10 8400 'OIL' /
|
||||||
'PROD2' 'G1' 5 5 8400 'OIL' /
|
'PROD2' 'G1' 5 5 8400 'OIL' /
|
||||||
|
@ -447,7 +447,7 @@ PYACTION
|
|||||||
|
|
||||||
PYACTION
|
PYACTION
|
||||||
ACTION3 FIRST_TRUE /
|
ACTION3 FIRST_TRUE /
|
||||||
'action2.py' /
|
'action_count.py' /
|
||||||
|
|
||||||
DATES
|
DATES
|
||||||
1 'JAN' 2015 /
|
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(w4_11.getStatus() == Well::Status::SHUT );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BOOST_CHECK_EQUAL( sim.st.get("run_count"), 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(PYTHON_ACTIONX) {
|
BOOST_AUTO_TEST_CASE(PYTHON_ACTIONX) {
|
||||||
|
@ -276,7 +276,7 @@ BOOST_AUTO_TEST_CASE(TestActions) {
|
|||||||
BOOST_CHECK(!action2.eval(context));
|
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);
|
BOOST_CHECK_EQUAL(python_actions.size(), 2U);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -977,6 +977,7 @@ BOOST_AUTO_TEST_CASE(ActionState) {
|
|||||||
|
|
||||||
auto res = st.result("NAME-HIDDEN");
|
auto res = st.result("NAME-HIDDEN");
|
||||||
BOOST_CHECK(!res.has_value());
|
BOOST_CHECK(!res.has_value());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(MANUAL4_QUOTE) {
|
BOOST_AUTO_TEST_CASE(MANUAL4_QUOTE) {
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||||
#include <opm/common/utility/TimeService.hpp>
|
#include <opm/common/utility/TimeService.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/Action/State.hpp>
|
||||||
|
|
||||||
using namespace Opm;
|
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);
|
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));
|
Action::PyAction py_action(python, "WCLOSE", Action::PyAction::RunCount::unlimited, deck.makeDeckPath(fname));
|
||||||
auto actionx_callback = [] (const std::string&, const std::vector<std::string>&) { ;};
|
auto actionx_callback = [] (const std::string&, const std::vector<std::string>&) { ;};
|
||||||
|
Action::State action_state;
|
||||||
|
|
||||||
st.update_well_var("PROD1", "WWCT", 0);
|
st.update_well_var("PROD1", "WWCT", 0);
|
||||||
py_action.run(ecl_state, schedule, 10, st, actionx_callback);
|
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( well1.getStatus() == Well::Status::SHUT );
|
||||||
BOOST_CHECK( well2.getStatus() == Well::Status::OPEN );
|
BOOST_CHECK( well2.getStatus() == Well::Status::OPEN );
|
||||||
BOOST_CHECK( st.has("RUN_COUNT") );
|
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