Adding python bindings for C++ class EclOutput
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <src/opm/io/eclipse/ESmry.cpp>
|
||||
#include <src/opm/io/eclipse/EGrid.cpp>
|
||||
#include <src/opm/io/eclipse/ERft.cpp>
|
||||
#include <src/opm/io/eclipse/EclOutput.cpp>
|
||||
|
||||
#include <opm/common/utility/numeric/calculateCellVol.hpp>
|
||||
|
||||
@@ -22,6 +23,35 @@ namespace {
|
||||
using npArray = std::tuple<py::array, Opm::EclIO::eclArrType>;
|
||||
using EclEntry = std::tuple<std::string, Opm::EclIO::eclArrType, long int>;
|
||||
|
||||
class EclOutputBind {
|
||||
|
||||
public:
|
||||
|
||||
EclOutputBind(const std::string& filename,const bool formatted, const bool append)
|
||||
{
|
||||
if (append == true)
|
||||
m_output = std::make_unique<Opm::EclIO::EclOutput>(filename, formatted, std::ios::app);
|
||||
else
|
||||
m_output = std::make_unique<Opm::EclIO::EclOutput>(filename, formatted, std::ios::out);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void writeArray(const std::string& name, const std::vector<T>& data){
|
||||
m_output->write<T>(name, data);
|
||||
m_output->flushStream();
|
||||
}
|
||||
|
||||
void writeMessage(const std::string& name)
|
||||
{
|
||||
m_output->message(name);
|
||||
m_output->flushStream();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Opm::EclIO::EclOutput> m_output;
|
||||
};
|
||||
|
||||
|
||||
npArray get_vector_index(Opm::EclIO::EclFile * file_ptr, std::size_t array_index)
|
||||
{
|
||||
auto array_type = std::get<1>(file_ptr->getList()[array_index]);
|
||||
@@ -323,4 +353,19 @@ void python::common::export_IO(py::module& m) {
|
||||
std::tuple<int,int,int>&) const) &Opm::EclIO::ERft::hasArray)
|
||||
|
||||
.def("__len__", &Opm::EclIO::ERft::numberOfReports);
|
||||
|
||||
py::class_<EclOutputBind>(m, "EclOutput")
|
||||
.def(py::init<const std::string &, const bool, const bool>(), py::arg("filename"),
|
||||
py::arg("formatted") = false, py::arg("append") = false)
|
||||
.def("write_message", &EclOutputBind::writeMessage)
|
||||
.def("__write_char_array", (void (EclOutputBind::*)(const std::string&,
|
||||
const std::vector<std::string>&)) &EclOutputBind::writeArray)
|
||||
.def("__write_logi_array", (void (EclOutputBind::*)(const std::string&,
|
||||
const std::vector<bool>&)) &EclOutputBind::writeArray)
|
||||
.def("__write_inte_array", (void (EclOutputBind::*)(const std::string&,
|
||||
const std::vector<int>&)) &EclOutputBind::writeArray)
|
||||
.def("__write_real_array", (void (EclOutputBind::*)(const std::string&,
|
||||
const std::vector<float>&)) &EclOutputBind::writeArray)
|
||||
.def("__write_doub_array", (void (EclOutputBind::*)(const std::string&,
|
||||
const std::vector<double>&)) &EclOutputBind::writeArray);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ from .libopmcommon_python import ERst
|
||||
from .libopmcommon_python import ESmry
|
||||
from .libopmcommon_python import EGrid
|
||||
from .libopmcommon_python import ERft
|
||||
from .libopmcommon_python import EclOutput
|
||||
from .libopmcommon_python import SummaryState
|
||||
|
||||
#from .schedule import Well, Connection, Schedule
|
||||
|
||||
@@ -4,6 +4,7 @@ from opm._common import ERst
|
||||
from opm._common import ESmry
|
||||
from opm._common import EGrid
|
||||
from opm._common import ERft
|
||||
from opm._common import EclOutput
|
||||
|
||||
import sys
|
||||
import datetime
|
||||
@@ -177,6 +178,47 @@ def getitem_erft(self, arg):
|
||||
return data
|
||||
|
||||
|
||||
'''
|
||||
EclOutput supports writing of numpy arrays. Data types
|
||||
(CHAR, LOGI, REAL, DOUB and INTE) is derived from the numpy dtype property
|
||||
EclOutput partly supports writing of python lists
|
||||
(CHAR, LOGI, INTE)
|
||||
'''
|
||||
|
||||
def ecloutput_write(self, name, array):
|
||||
|
||||
if isinstance(array, list):
|
||||
if all(isinstance(element, str) for element in array):
|
||||
array = np.array(array)
|
||||
elif all(isinstance(element, bool) for element in array):
|
||||
array = np.array(array)
|
||||
elif all(isinstance(element, int) for element in array):
|
||||
array = np.array(array, dtype = "int32")
|
||||
elif sys.version_info.major == 2 and all(isinstance(element, unicode) for element in array):
|
||||
array = np.array(array)
|
||||
else:
|
||||
raise ValueError("!!array {} is python list, type {}, not supported".format(name, type(array[0])))
|
||||
|
||||
if not isinstance(array, np.ndarray):
|
||||
raise ValueError("EclOutput - write function works only for numpy arrays")
|
||||
|
||||
if array.dtype == "float32":
|
||||
self.__write_real_array(name, array)
|
||||
elif array.dtype == "int32":
|
||||
self.__write_inte_array(name, array)
|
||||
elif array.dtype == "int64":
|
||||
print ("!Warning, writing numpy dtype=int64 to 32 bit integer format")
|
||||
self.__write_inte_array(name, array)
|
||||
elif array.dtype == "float64":
|
||||
self.__write_doub_array(name, array)
|
||||
elif array.dtype == "bool":
|
||||
self.__write_logi_array(name, array)
|
||||
elif array.dtype.kind in {'U', 'S'}:
|
||||
self.__write_char_array(name, array)
|
||||
else:
|
||||
raise ValueError("unknown array type for array {}".format(name))
|
||||
|
||||
|
||||
setattr(EclFile, "__getitem__", getitem_eclfile)
|
||||
setattr(EclFile, "arrays", eclfile_get_list_of_arrays)
|
||||
|
||||
@@ -192,3 +234,5 @@ setattr(ERft, "__contains__", contains_erft)
|
||||
setattr(ERft, "list_of_rfts", erft_list_of_rfts)
|
||||
setattr(ERft, "arrays", erft_list_of_arrays)
|
||||
setattr(ERft, "__getitem__",getitem_erft)
|
||||
|
||||
setattr(EclOutput, "write", ecloutput_write)
|
||||
|
||||
278
python/tests/test_ecloutput.py
Executable file
278
python/tests/test_ecloutput.py
Executable file
@@ -0,0 +1,278 @@
|
||||
import unittest
|
||||
import sys
|
||||
import numpy as np
|
||||
import io
|
||||
import os
|
||||
|
||||
from opm.io.ecl import EclOutput, EclFile, ERst, eclArrType
|
||||
try:
|
||||
from tests.utils import test_path
|
||||
except ImportError:
|
||||
from utils import test_path
|
||||
|
||||
|
||||
class TestEclOutput(unittest.TestCase):
|
||||
|
||||
def test_write_formatted_float32(self):
|
||||
|
||||
npArr1=np.array([1.1, 2.2e+28, 3.3, 4.4], dtype='float32')
|
||||
|
||||
testFile = test_path("data/RESULT.FINIT")
|
||||
|
||||
# default is binary format (unformatted), new file
|
||||
out1 = EclOutput(testFile, formatted=True, append=False)
|
||||
out1.write("ARR1", npArr1)
|
||||
|
||||
file1 = EclFile(testFile)
|
||||
testArray = file1[0]
|
||||
|
||||
self.assertEqual(len(testArray), len(npArr1))
|
||||
|
||||
for v1,v2 in zip (testArray, npArr1):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
if os.path.isfile(testFile):
|
||||
os.remove(testFile)
|
||||
|
||||
|
||||
def test_write_binary_float32(self):
|
||||
|
||||
npArr1=np.array([1.1, 2.2e+28, 3.3, 4.4], dtype='float32')
|
||||
|
||||
testFile = test_path("data/RESULT.INIT")
|
||||
|
||||
# default is binary format (unformatted) and append = false
|
||||
out1 = EclOutput(testFile)
|
||||
out1.write("ARR1", npArr1)
|
||||
|
||||
file1 = EclFile(testFile)
|
||||
testArray = file1[0]
|
||||
|
||||
self.assertEqual(len(testArray), len(npArr1))
|
||||
|
||||
for v1,v2 in zip (testArray, npArr1):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
if os.path.isfile(testFile):
|
||||
os.remove(testFile)
|
||||
|
||||
|
||||
def test_write_binary_append(self):
|
||||
|
||||
npArr1 = np.array([1.1, 2.2e+28, 3.3, 4.4], dtype='float32')
|
||||
npArr2 = np.array([11.11, 12.12, 13.13, 14.14], dtype='float64')
|
||||
npArr3 = np.array([1,2,3,4], dtype='int32')
|
||||
npArr4 = np.array(["PROD1","","INJ1"], dtype='str')
|
||||
npArr5 = np.array([True, True, False, True, False, False], dtype='bool')
|
||||
#npArr6=np.array([11,12,13,14], dtype='int64')
|
||||
|
||||
testFile = test_path("data/RESULT.INIT")
|
||||
|
||||
# default is binary format (unformatted) and append = false
|
||||
# will create a new file1
|
||||
|
||||
out1 = EclOutput(testFile)
|
||||
out1.write("ARR0", npArr1)
|
||||
|
||||
# append = False (default value), will create a new file,
|
||||
# hence, array ARR0 from out1 will be errased
|
||||
|
||||
out2 = EclOutput(testFile)
|
||||
out2.write("ARR1", npArr1)
|
||||
|
||||
# append =True, will add ARR2 to existing file
|
||||
out3 = EclOutput(testFile, append=True)
|
||||
out3.write("ARR2", npArr2)
|
||||
out3.write("ARR3", npArr3)
|
||||
out3.write("ARR4", npArr4)
|
||||
out3.write("ARR5", npArr5)
|
||||
|
||||
file1 = EclFile(testFile)
|
||||
|
||||
self.assertEqual(len(file1), 5)
|
||||
|
||||
# check array ARR1
|
||||
testArray = file1[0]
|
||||
self.assertEqual(len(testArray), len(npArr1))
|
||||
for v1,v2 in zip (testArray, npArr1):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
# check array ARR2
|
||||
testArray = file1[1]
|
||||
self.assertEqual(len(testArray), len(npArr2))
|
||||
for v1,v2 in zip (testArray, npArr2):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
# check array ARR3
|
||||
testArray = file1[2]
|
||||
self.assertEqual(len(testArray), len(npArr3))
|
||||
for v1,v2 in zip (testArray, npArr3):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
# check array ARR4
|
||||
testArray = file1[3]
|
||||
self.assertEqual(len(testArray), len(npArr4))
|
||||
for v1,v2 in zip (testArray, npArr4):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
# check array ARR5
|
||||
testArray = file1[4]
|
||||
self.assertEqual(len(testArray), len(npArr5))
|
||||
for v1,v2 in zip (testArray, npArr5):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
if os.path.isfile(testFile):
|
||||
os.remove(testFile)
|
||||
|
||||
|
||||
def test_write_formatted_append(self):
|
||||
|
||||
npArr1 = np.array([1.1, 2.2e+28, 3.3, 4.4], dtype='float32')
|
||||
npArr2 = np.array([11.11, 12.12, 13.13, 14.14], dtype='float64')
|
||||
npArr3 = np.array([1,2,3,4], dtype='int32')
|
||||
npArr4 = np.array(["PROD1","","INJ1"], dtype='str')
|
||||
npArr5 = np.array([True, True, False, True, False, False], dtype='bool')
|
||||
#npArr6=np.array([11,12,13,14], dtype='int64')
|
||||
|
||||
testFile = test_path("data/RESULT.FINIT")
|
||||
|
||||
# default is binary format (unformatted) and append = false
|
||||
# will create a new file1
|
||||
|
||||
out1 = EclOutput(testFile, formatted = True)
|
||||
out1.write("ARR0", npArr1)
|
||||
|
||||
# append = False (default value), will create a new file,
|
||||
# hence, array ARR0 from out1 will be errased
|
||||
out2 = EclOutput(testFile, formatted = True)
|
||||
out2.write("ARR1", npArr1)
|
||||
|
||||
# append =True, will add ARR2 to existing file
|
||||
out3 = EclOutput(testFile, append=True, formatted = True)
|
||||
out3.write("ARR2", npArr2)
|
||||
out3.write("ARR3", npArr3)
|
||||
out3.write("ARR4", npArr4)
|
||||
out3.write("ARR5", npArr5)
|
||||
|
||||
file1 = EclFile(testFile)
|
||||
|
||||
self.assertEqual(len(file1), 5)
|
||||
|
||||
# check array ARR1
|
||||
testArray = file1[0]
|
||||
self.assertEqual(len(testArray), len(npArr1))
|
||||
for v1,v2 in zip (testArray, npArr1):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
# check array ARR2
|
||||
testArray = file1[1]
|
||||
self.assertEqual(len(testArray), len(npArr2))
|
||||
for v1,v2 in zip (testArray, npArr2):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
# check array ARR3
|
||||
testArray = file1[2]
|
||||
self.assertEqual(len(testArray), len(npArr3))
|
||||
for v1,v2 in zip (testArray, npArr3):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
# check array ARR4
|
||||
testArray = file1[3]
|
||||
self.assertEqual(len(testArray), len(npArr4))
|
||||
for v1,v2 in zip (testArray, npArr4):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
# check array ARR5
|
||||
testArray = file1[4]
|
||||
self.assertEqual(len(testArray), len(npArr5))
|
||||
for v1,v2 in zip (testArray, npArr5):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
if os.path.isfile(testFile):
|
||||
os.remove(testFile)
|
||||
|
||||
|
||||
def test_rewrite_rstfile_(self):
|
||||
|
||||
rstep = 74
|
||||
rst1 = ERst(test_path("data/SPE9.UNRST"))
|
||||
arrayList74=rst1.arrays(rstep)
|
||||
|
||||
outFile = test_path("data/TMP.UNRST")
|
||||
|
||||
out1 = EclOutput(outFile)
|
||||
|
||||
for n, (name, arrType, arrSize) in enumerate(arrayList74):
|
||||
if arrType == eclArrType.MESS:
|
||||
out1.write_message(name)
|
||||
else:
|
||||
array = rst1[name, rstep]
|
||||
out1.write(name, array)
|
||||
|
||||
rst2 = ERst(outFile)
|
||||
tmpArrayList74=rst2.arrays(rstep)
|
||||
|
||||
self.assertEqual(len(tmpArrayList74), len(arrayList74))
|
||||
|
||||
for n in range(0, len(tmpArrayList74)):
|
||||
name1, arrType1, arrSize1 = tmpArrayList74[n]
|
||||
name2, arrType2, arrSize2 = arrayList74[n]
|
||||
|
||||
self.assertEqual(name1, name2)
|
||||
self.assertEqual(arrType1, arrType2)
|
||||
|
||||
if arrType1 != eclArrType.MESS:
|
||||
arr1 = rst1[name1, rstep]
|
||||
arr2 = rst2[name2, rstep]
|
||||
|
||||
self.assertEqual(len(arr1), len(arr2))
|
||||
|
||||
for v1,v2 in zip(arr1, arr2):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
if os.path.isfile(outFile):
|
||||
os.remove(outFile)
|
||||
|
||||
|
||||
def test_write_lists(self):
|
||||
|
||||
intList = [1,2,3,4,5,6]
|
||||
boolList = [True, True, False, True]
|
||||
strList = ["A-1H", "A-2H", "A-3H"]
|
||||
|
||||
testFile = "data/TMP.DAT"
|
||||
outFile = test_path(testFile)
|
||||
out1 = EclOutput(outFile)
|
||||
|
||||
out1.write("ARR1", intList)
|
||||
out1.write("ARR2", boolList)
|
||||
out1.write("ARR3", strList)
|
||||
|
||||
file1 = EclFile(outFile)
|
||||
|
||||
arr1 = file1["ARR1"]
|
||||
arr2 = file1["ARR2"]
|
||||
arr3 = file1["ARR3"]
|
||||
|
||||
self.assertEqual(len(arr1), len(intList))
|
||||
self.assertEqual(len(arr2), len(boolList))
|
||||
self.assertEqual(len(arr3), len(strList))
|
||||
|
||||
for v1, v2 in zip(arr1, intList):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
for v1, v2 in zip(arr2, boolList):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
for v1, v2 in zip(arr3, strList):
|
||||
self.assertEqual(v1, v2)
|
||||
|
||||
if os.path.isfile(testFile):
|
||||
os.remove(testFile)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user