2019-09-02 18:27:22 +02:00
/*
Copyright 2019 Equinor 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/>.
*/
# define BOOST_TEST_MODULE EMBEDDED_PYTHON
# include <boost/test/unit_test.hpp>
2021-12-14 08:06:42 +01:00
# include <opm/input/eclipse/Python/Python.hpp>
2023-06-08 09:19:32 +02:00
2022-07-26 15:00:59 +02:00
# include <opm/input/eclipse/EclipseState/EclipseState.hpp>
2023-06-08 09:19:32 +02:00
2023-01-10 12:55:58 +01:00
# include <opm/input/eclipse/Schedule/Action/Actions.hpp>
2022-01-28 09:28:07 +01:00
# include <opm/input/eclipse/Schedule/Action/State.hpp>
2023-06-08 09:19:32 +02:00
# include <opm/input/eclipse/Schedule/Schedule.hpp>
# include <opm/input/eclipse/Schedule/SummaryState.hpp>
2023-01-18 10:52:39 +01:00
# include <opm/input/eclipse/Schedule/Well/Well.hpp>
2019-09-02 18:27:22 +02:00
2023-06-08 09:19:32 +02:00
# include <opm/common/utility/TimeService.hpp>
# include <opm/input/eclipse/Deck/Deck.hpp>
# include <opm/input/eclipse/Parser/Parser.hpp>
# include <opm/input/eclipse/Parser/ParserKeywords/P.hpp>
# include <map>
# include <memory>
# include <stdexcept>
# include <string>
# include <vector>
2019-11-07 14:48:49 +01:00
using namespace Opm ;
2019-09-02 18:27:22 +02:00
# ifndef EMBEDDED_PYTHON
2023-06-08 09:19:32 +02:00
BOOST_AUTO_TEST_CASE ( INSTANTIATE )
{
2020-03-31 16:56:44 +02:00
Python python ;
2020-03-26 16:58:00 +01:00
BOOST_CHECK ( ! python . enabled ( ) ) ;
BOOST_CHECK_THROW ( python . exec ( " print('Hello world') " ) , std : : logic_error ) ;
BOOST_CHECK ( ! Python : : supported ( ) ) ;
2020-03-26 12:00:59 +01:00
2020-03-27 10:08:36 +01:00
BOOST_CHECK_THROW ( Python { Python : : Enable : : ON } , std : : logic_error ) ;
2020-03-26 16:58:00 +01:00
Python python_cond ( Python : : Enable : : TRY ) ;
BOOST_CHECK ( ! python_cond . enabled ( ) ) ;
2020-03-26 12:00:59 +01:00
Python python_off ( Python : : Enable : : OFF ) ;
2020-03-26 16:58:00 +01:00
BOOST_CHECK ( ! python_off . enabled ( ) ) ;
2019-09-02 18:27:22 +02:00
}
2023-06-08 09:19:32 +02:00
# else // EMBEDDED_PYTHON
2019-09-02 18:27:22 +02:00
2023-06-08 09:19:32 +02:00
BOOST_AUTO_TEST_CASE ( INSTANTIATE )
{
2020-03-31 10:26:55 +02:00
auto python = std : : make_shared < Python > ( ) ;
2023-06-08 09:19:32 +02:00
BOOST_CHECK_MESSAGE ( Python : : supported ( ) , " Python interpreter must be available when we have Embedded Python support " ) ;
BOOST_CHECK_MESSAGE ( python - > enabled ( ) , " Python interpreter must be enabled in a default-constructed Python object when we have Embedded Python support " ) ;
2020-03-22 21:02:32 +01:00
BOOST_CHECK_NO_THROW ( python - > exec ( " import sys " ) ) ;
2019-09-12 16:34:37 +02:00
2019-11-07 14:48:49 +01:00
Parser parser ;
Deck deck ;
2023-06-08 09:19:32 +02:00
const std : : string python_code = R " (
2019-09-12 16:34:37 +02:00
print ( ' Parser : { } ' . format ( context . parser ) )
print ( ' Deck : { } ' . format ( context . deck ) )
2019-10-25 17:15:56 +02:00
kw = context . DeckKeyword ( context . parser [ ' FIELD ' ] )
context . deck . add ( kw )
2019-09-12 16:34:37 +02:00
) " ;
2023-06-08 09:19:32 +02:00
BOOST_CHECK_NO_THROW ( python - > exec ( python_code , parser , deck ) ) ;
BOOST_CHECK ( deck . hasKeyword ( " FIELD " ) ) ;
2019-09-02 18:27:22 +02:00
}
2020-03-22 21:02:32 +01:00
2019-11-07 14:48:49 +01:00
BOOST_AUTO_TEST_CASE ( PYINPUT_BASIC ) {
Parser parser ;
std : : string input = R " (
START - - 0
31 AUG 1993 /
RUNSPEC
PYINPUT
kw = context . DeckKeyword ( context . parser [ ' FIELD ' ] )
context . deck . add ( kw )
2020-01-09 08:21:59 +01:00
PYEND
2019-11-07 14:48:49 +01:00
DIMENS
2 2 1 /
PYINPUT
import numpy as np
dx = np . array ( [ 0.25 , 0.25 , 0.25 , 0.25 ] )
active_unit_system = context . deck . active_unit_system ( )
2020-01-09 08:21:59 +01:00
default_unit_system = context . deck . default_unit_system ( )
2019-11-07 14:48:49 +01:00
kw = context . DeckKeyword ( context . parser [ ' DX ' ] , dx , active_unit_system , default_unit_system )
context . deck . add ( kw )
2020-01-09 08:21:59 +01:00
PYEND
2019-11-07 14:48:49 +01:00
DY
4 * 0.25 /
) " ;
Deck deck = parser . parseString ( input ) ;
BOOST_CHECK ( deck . hasKeyword ( " START " ) ) ;
BOOST_CHECK ( deck . hasKeyword ( " FIELD " ) ) ;
BOOST_CHECK ( deck . hasKeyword ( " DIMENS " ) ) ;
BOOST_CHECK ( deck . hasKeyword ( " DX " ) ) ;
2021-11-16 14:26:04 +01:00
auto DX = deck [ " DX " ] . back ( ) ;
2019-11-07 14:48:49 +01:00
std : : vector < double > dx_data = DX . getSIDoubleData ( ) ;
BOOST_CHECK_EQUAL ( dx_data . size ( ) , 4 ) ;
BOOST_CHECK_EQUAL ( dx_data [ 2 ] , 0.25 * 0.3048 ) ;
BOOST_CHECK ( deck . hasKeyword ( " DY " ) ) ;
}
2023-06-08 09:19:32 +02:00
BOOST_AUTO_TEST_CASE ( PYACTION )
{
2020-01-08 10:35:39 +01:00
Parser parser ;
2020-03-22 21:02:32 +01:00
auto python = std : : make_shared < Python > ( Python : : Enable : : ON ) ;
2020-03-16 11:34:12 +01:00
auto deck = parser . parseFile ( " EMBEDDED_PYTHON.DATA " ) ;
2020-01-08 10:35:39 +01:00
auto ecl_state = EclipseState ( deck ) ;
2020-03-26 15:31:21 +01:00
auto schedule = Schedule ( deck , ecl_state , python ) ;
2020-01-08 10:35:39 +01:00
2021-02-28 17:04:35 +01:00
SummaryState st ( TimeService : : now ( ) ) ;
2021-11-18 10:34:22 +01:00
const auto & pyaction_kw = deck . get < ParserKeywords : : PYACTION > ( ) . front ( ) ;
2020-03-16 11:34:12 +01:00
const std : : string & fname = pyaction_kw . getRecord ( 1 ) . getItem ( 0 ) . get < std : : string > ( 0 ) ;
2020-03-22 21:02:32 +01:00
Action : : PyAction py_action ( python , " WCLOSE " , Action : : PyAction : : RunCount : : unlimited , deck . makeDeckPath ( fname ) ) ;
2022-01-24 13:47:05 +01:00
auto actionx_callback = [ ] ( const std : : string & , const std : : vector < std : : string > & ) { ; } ;
2022-01-28 09:28:07 +01:00
Action : : State action_state ;
2022-01-24 13:47:05 +01:00
2020-01-08 10:35:39 +01:00
st . update_well_var ( " PROD1 " , " WWCT " , 0 ) ;
2022-01-24 13:47:05 +01:00
py_action . run ( ecl_state , schedule , 10 , st , actionx_callback ) ;
2020-01-08 10:35:39 +01:00
st . update ( " FOPR " , 0 ) ;
2022-01-24 13:47:05 +01:00
py_action . run ( ecl_state , schedule , 10 , st , actionx_callback ) ;
2020-01-08 10:35:39 +01:00
st . update ( " FOPR " , 100 ) ;
st . update_well_var ( " PROD1 " , " WWCT " , 0.90 ) ;
2022-01-24 13:47:05 +01:00
py_action . run ( ecl_state , schedule , 10 , st , actionx_callback ) ;
2020-03-22 21:02:32 +01:00
2020-01-08 10:35:39 +01:00
const auto & well1 = schedule . getWell ( " PROD1 " , 10 ) ;
const auto & well2 = schedule . getWell ( " PROD2 " , 10 ) ;
BOOST_CHECK ( well1 . getStatus ( ) = = Well : : Status : : SHUT ) ;
BOOST_CHECK ( well2 . getStatus ( ) = = Well : : Status : : OPEN ) ;
BOOST_CHECK ( st . has ( " RUN_COUNT " ) ) ;
2022-01-28 09:28:07 +01:00
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 ) ;
2020-01-08 10:35:39 +01:00
}
2023-06-08 09:19:32 +02:00
BOOST_AUTO_TEST_CASE ( Python_Constructor )
{
2020-03-26 12:00:59 +01:00
Python python_off ( Python : : Enable : : OFF ) ;
2020-03-26 16:58:00 +01:00
BOOST_CHECK ( ! python_off . enabled ( ) ) ;
2020-03-26 12:00:59 +01:00
Python python_on ( Python : : Enable : : ON ) ;
2020-03-26 16:58:00 +01:00
BOOST_CHECK ( python_on . enabled ( ) ) ;
2020-03-26 12:00:59 +01:00
2020-03-26 16:58:00 +01:00
//.enabled() Can only have one Python interpreter active at any time
2022-09-09 07:46:45 +02:00
BOOST_CHECK_THROW ( Python python_throw ( Python : : Enable : : ON ) , std : : logic_error ) ;
2020-03-26 12:00:59 +01:00
}
2023-06-08 09:19:32 +02:00
BOOST_AUTO_TEST_CASE ( Python_Constructor2 )
{
2020-03-26 16:58:00 +01:00
Python python_cond1 ( Python : : Enable : : TRY ) ;
BOOST_CHECK ( python_cond1 . enabled ( ) ) ;
2020-03-26 12:00:59 +01:00
2020-03-26 16:58:00 +01:00
Python python_cond2 ( Python : : Enable : : TRY ) ;
BOOST_CHECK ( ! python_cond2 . enabled ( ) ) ;
2020-03-26 12:00:59 +01:00
}
2023-06-08 09:19:32 +02:00
# endif // EMBEDDED_PYTHON