Adding python bindings for c++ class ExtESmry

- Used for loading data from summary file ESMRY
 - python class ESmry supporting both SMSPEC/UNSMRY and ESMRY summary files.
This commit is contained in:
Torbjørn Skille
2021-08-21 20:21:00 +02:00
parent 981e977da4
commit 514e3a4a35
4 changed files with 225 additions and 36 deletions

View File

@@ -54,6 +54,8 @@ public:
void loadData();
void loadData(const std::vector<std::string>& stringVect);
time_point startdate() const { return m_startdat; }
bool hasKey(const std::string& key) const;
size_t numberOfTimeSteps() const { return m_nTstep; }

View File

@@ -2,15 +2,18 @@
#include <pybind11/stl.h>
#include <pybind11/numpy.h>
#include <pybind11/chrono.h>
#include <stdexcept>
#include <opm/io/eclipse/EclFile.hpp>
#include <opm/io/eclipse/EclIOdata.hpp>
#include <opm/io/eclipse/ERst.hpp>
#include <opm/io/eclipse/ESmry.hpp>
#include <opm/io/eclipse/ExtESmry.hpp>
#include <opm/io/eclipse/EGrid.hpp>
#include <opm/io/eclipse/ERft.hpp>
#include <opm/io/eclipse/EclOutput.hpp>
#include <opm/common/utility/TimeService.hpp>
#include <opm/common/utility/FileSystem.hpp>
#include <opm/common/utility/numeric/calculateCellVol.hpp>
@@ -25,6 +28,100 @@ namespace {
using npArray = std::tuple<py::array, Opm::EclIO::eclArrType>;
using EclEntry = std::tuple<std::string, Opm::EclIO::eclArrType, int64_t>;
class ESmryBind {
public:
ESmryBind(const std::string& filename, bool loadBaseRunData)
{
filesystem::path m_inputFileName(filename);
if (m_inputFileName.extension() == ".SMSPEC"){
m_esmry = std::make_unique<Opm::EclIO::ESmry>(m_inputFileName, loadBaseRunData);
} else if (m_inputFileName.extension()==".ESMRY") {
m_ext_esmry = std::make_unique<Opm::EclIO::ExtESmry>(m_inputFileName, loadBaseRunData);
} else
throw std::invalid_argument("Input file should have extension .SMSPEC or .ESMRY");
}
bool hasKey(const std::string& key)
{
if (m_esmry != nullptr)
return m_esmry->hasKey(key);
else
return m_ext_esmry->hasKey(key);
}
void make_esmry_file()
{
if (m_esmry == nullptr)
throw std::invalid_argument("make_esmry_file only available for SMSPEC input files");
m_esmry->make_esmry_file();
}
size_t numberOfTimeSteps()
{
if (m_esmry != nullptr)
return m_esmry->numberOfTimeSteps();
else
return m_ext_esmry->numberOfTimeSteps();
}
py::array get_smry_vector(const std::string& key)
{
if (m_esmry != nullptr)
return convert::numpy_array( m_esmry->get(key) );
else
return convert::numpy_array( m_ext_esmry->get(key) );
}
py::array get_smry_vector_at_rsteps(const std::string& key)
{
if (m_esmry != nullptr)
return convert::numpy_array( m_esmry->get_at_rstep(key) );
else
return convert::numpy_array( m_ext_esmry->get_at_rstep(key) );
}
time_point smry_start_date()
{
time_point utc_chrono;
if (m_esmry != nullptr)
utc_chrono = m_esmry->startdate();
else
utc_chrono = m_ext_esmry->startdate();
auto utc_time_t = std::chrono::system_clock::to_time_t( utc_chrono );
auto utc_ts = Opm::TimeStampUTC( utc_time_t );
auto local_time_t = Opm::asLocalTimeT( utc_ts );
return TimeService::from_time_t( local_time_t );
}
const std::vector<std::string>& keywordList() const
{
if (m_esmry != nullptr)
return m_esmry->keywordList();
else
return m_ext_esmry->keywordList();
}
std::vector<std::string> keywordList(const std::string& pattern) const
{
if (m_esmry != nullptr)
return m_esmry->keywordList(pattern);
else
return m_ext_esmry->keywordList(pattern);
}
private:
std::unique_ptr<Opm::EclIO::ESmry> m_esmry;
std::unique_ptr<Opm::EclIO::ExtESmry> m_ext_esmry;
};
class EclOutputBind {
public:
@@ -166,18 +263,6 @@ npArray get_erst_vector(Opm::EclIO::ERst * file_ptr, const std::string& key, siz
}
py::array get_smry_vector(Opm::EclIO::ESmry * file_ptr, const std::string& key)
{
return convert::numpy_array( file_ptr->get(key) );
}
py::array get_smry_vector_at_rsteps(Opm::EclIO::ESmry * file_ptr, const std::string& key)
{
return convert::numpy_array( file_ptr->get_at_rstep(key) );
}
std::tuple<std::array<double,8>, std::array<double,8>, std::array<double,8>>
get_xyz_from_ijk(Opm::EclIO::EGrid * file_ptr,int i, int j, int k)
{
@@ -291,14 +376,6 @@ npArray get_rft_vector_Index(Opm::EclIO::ERft * file_ptr,const std::string& name
the pybind11 conversion.
*/
time_point esmry_start_date(const Opm::EclIO::ESmry * esmry) {
auto utc_chrono = esmry->startdate();
auto utc_time_t = std::chrono::system_clock::to_time_t( utc_chrono );
auto utc_ts = Opm::TimeStampUTC( utc_time_t );
auto local_time_t = Opm::asLocalTimeT( utc_ts );
return TimeService::from_time_t( local_time_t );
}
}
@@ -340,18 +417,19 @@ void python::common::export_IO(py::module& m) {
.def("__get_data", &get_erst_by_index)
.def("__get_data", &get_erst_vector);
py::class_<Opm::EclIO::ESmry>(m, "ESmry")
py::class_<ESmryBind>(m, "ESmry")
.def(py::init<const std::string &, const bool>(), py::arg("filename"), py::arg("load_base_run") = false)
.def("__contains__", &Opm::EclIO::ESmry::hasKey)
.def("__len__", &Opm::EclIO::ESmry::numberOfTimeSteps)
.def("__get_all", &get_smry_vector)
.def("__get_at_rstep", &get_smry_vector_at_rsteps)
.def_property_readonly("start_date", &esmry_start_date)
.def("__contains__", &ESmryBind::hasKey)
.def("make_esmry_file", &ESmryBind::make_esmry_file)
.def("__len__", &ESmryBind::numberOfTimeSteps)
.def("__get_all", &ESmryBind::get_smry_vector)
.def("__get_at_rstep", &ESmryBind::get_smry_vector_at_rsteps)
.def_property_readonly("start_date", &ESmryBind::smry_start_date)
.def("keys", (const std::vector<std::string>& (ESmryBind::*) (void) const)
&ESmryBind::keywordList)
.def("keys", (std::vector<std::string> (ESmryBind::*) (const std::string&) const)
&ESmryBind::keywordList);
.def("keys", (const std::vector<std::string>& (Opm::EclIO::ESmry::*) (void) const)
&Opm::EclIO::ESmry::keywordList)
.def("keys", (std::vector<std::string> (Opm::EclIO::ESmry::*) (const std::string&) const)
&Opm::EclIO::ESmry::keywordList);
py::class_<Opm::EclIO::EGrid>(m, "EGrid")
.def(py::init<const std::string &>())

View File

@@ -29,7 +29,3 @@ from .libopmcommon_python import EclOutput
from .libopmcommon_python import EModel
from .libopmcommon_python import calc_cell_vol
from .libopmcommon_python import SummaryState
#from .schedule import Well, Connection, Schedule
#from .config import EclipseConfig
#from .parser import parse, parse_string

View File

@@ -10,15 +10,20 @@ except ImportError:
from utils import test_path
class TestEclFile(unittest.TestCase):
def test_base_runs(self):
with self.assertRaises(RuntimeError):
with self.assertRaises(ValueError):
ESmry("/file/that/does_not_exists")
smry1 = ESmry(test_path("data/SPE1CASE1.SMSPEC"))
smry1.make_esmry_file()
smry2 = ESmry(test_path("data/SPE1CASE1.ESMRY"))
with self.assertRaises(ValueError):
smry2.make_esmry_file()
self.assertEqual(len(smry1), 67)
self.assertEqual(smry1.start_date, datetime.datetime(2015,1,1) )
@@ -100,6 +105,114 @@ class TestEclFile(unittest.TestCase):
for key, ref in zip(list_of_keys2, ref_keys_pattern):
self.assertEqual(key, ref)
def test_base_runs_ext(self):
smry1 = ESmry(test_path("data/SPE1CASE1.SMSPEC"))
smry1.make_esmry_file()
extsmry1 = ESmry(test_path("data/SPE1CASE1.ESMRY"))
self.assertEqual(len(extsmry1), 67)
self.assertEqual(extsmry1.start_date, datetime.datetime(2015,1,1) )
self.assertEqual(extsmry1.end_date, datetime.datetime(2020,4,29) )
self.assertTrue("TIME" in extsmry1)
self.assertTrue("BPR:10,10,3" in extsmry1)
self.assertFalse("XXXX" in extsmry1)
with self.assertRaises(ValueError):
test = extsmry1["XXX"]
time1a = extsmry1["TIME"]
self.assertEqual(len(time1a), len(extsmry1))
time1b = extsmry1["TIME", True]
self.assertEqual(len(time1b), 64)
def test_restart_runs_ext(self):
base_smry = ESmry(test_path("data/SPE1CASE1.SMSPEC"))
base_smry.make_esmry_file()
base_ext_smry = ESmry(test_path("data/SPE1CASE1.ESMRY"))
time0 = base_ext_smry["TIME"]
self.assertEqual(time0[0], 1.0)
rst_smry1 = ESmry(test_path("data/SPE1CASE1_RST60.SMSPEC"))
rst_smry1.make_esmry_file()
rst_ext_smry1 = ESmry(test_path("data/SPE1CASE1_RST60.ESMRY"))
time1 = rst_ext_smry1["TIME"]
gor1 = rst_ext_smry1["WGOR:PROD"]
self.assertEqual(base_ext_smry.start_date, datetime.datetime(2015,1,1) )
time0 = base_ext_smry["TIME"]
self.assertEqual(time0[0], 1.0)
rst_ext_smry1 = ESmry(test_path("data/SPE1CASE1_RST60.ESMRY"))
time1 = rst_ext_smry1["TIME"]
gor1 = rst_ext_smry1["WGOR:PROD"]
self.assertEqual(rst_smry1.start_date, datetime.datetime(2015,1,1) )
self.assertEqual(len(rst_smry1), 60)
self.assertEqual(time1[0], 1856.0)
self.assertEqual(len(time1), 60)
self.assertEqual(len(gor1), 60)
rst_ext_smry2 = ESmry(test_path("data/SPE1CASE1_RST60.ESMRY"), load_base_run = True)
time2 = rst_ext_smry2["TIME"]
gor2 = rst_ext_smry2["WGOR:PROD"]
self.assertEqual(rst_ext_smry2.start_date, datetime.datetime(2015,1,1) )
self.assertEqual(len(rst_ext_smry2), 123)
self.assertEqual(time2[0], 1.0)
self.assertEqual(len(rst_ext_smry2), 123)
self.assertEqual(len(time2), 123)
self.assertEqual(len(gor2), 123)
def test_keylist_ext(self):
ref_key_list = ["BPR:1,1,1", "BPR:10,10,3", "FGOR", "FOPR", "TIME", "WBHP:INJ", "WBHP:PROD",
"WGIR:INJ", "WGIR:PROD", "WGIT:INJ", "WGIT:PROD", "WGOR:PROD", "WGPR:INJ",
"WGPR:PROD", "WGPT:INJ", "WGPT:PROD", "WOIR:INJ", "WOIR:PROD", "WOIT:INJ",
"WOIT:PROD", "WOPR:INJ", "WOPR:PROD", "WOPT:INJ", "WOPT:PROD", "WWIR:INJ",
"WWIR:PROD", "WWIT:INJ", "WWIT:PROD", "WWPR:INJ", "WWPR:PROD", "WWPT:INJ",
"WWPT:PROD"]
ref_keys_pattern = ["WGPR:INJ", "WGPR:PROD", "WOPR:INJ", "WOPR:PROD", "WWPR:INJ", "WWPR:PROD"]
smry1 = ESmry(test_path("data/SPE1CASE1.SMSPEC"))
smry1.make_esmry_file()
ext_smry1 = ESmry(test_path("data/SPE1CASE1.ESMRY"))
list_of_keys = ext_smry1.keys()
self.assertEqual(len(list_of_keys), len(ref_key_list))
for key, ref_key in zip(list_of_keys, ref_key_list):
self.assertEqual(key, ref_key)
for key in list_of_keys:
data = smry1[key]
self.assertEqual(len(smry1), len(data))
list_of_keys2 = ext_smry1.keys("W?PR:*")
self.assertEqual(len(list_of_keys2), len(ref_keys_pattern))
for key, ref in zip(list_of_keys2, ref_keys_pattern):
self.assertEqual(key, ref)
if __name__ == "__main__":
unittest.main()