diff --git a/CMakeLists.txt b/CMakeLists.txt index af029aab2..85a0d606a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,7 +197,11 @@ if(ENABLE_ECL_INPUT) test_util/summary.cpp ) - foreach(target compareECL convertECL summary) + add_executable(rewriteEclFile + test_util/rewriteEclFile.cpp + ) + + foreach(target compareECL convertECL summary rewriteEclFile) target_link_libraries(${target} opmcommon) install(TARGETS ${target} DESTINATION bin) endforeach() diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 9821b0730..d8a3b08b9 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -472,6 +472,10 @@ if(ENABLE_ECL_INPUT) list (APPEND TEST_DATA_FILES tests/ECLFILE.INIT tests/ECLFILE.FINIT + tests/ECLFILE.FINIT + tests/MODEL1_IX.INIT + tests/MODEL1_IX.SMSPEC + tests/MODEL1_IX.UNSMRY tests/SPE1CASE1.EGRID tests/SPE1CASE1.RFT tests/SPE1_TESTCASE.UNRST diff --git a/opm/io/eclipse/EclFile.hpp b/opm/io/eclipse/EclFile.hpp index 0f5d6f628..0d5136410 100644 --- a/opm/io/eclipse/EclFile.hpp +++ b/opm/io/eclipse/EclFile.hpp @@ -36,7 +36,7 @@ class EclFile { public: explicit EclFile(const std::string& filename, bool preload = false); - bool formattedInput() { return formatted; } + bool formattedInput() const { return formatted; } void loadData(); // load all data void loadData(const std::string& arrName); // load all arrays with array name equal to arrName @@ -55,6 +55,8 @@ public: using EclEntry = std::tuple; std::vector getList() const; + const std::vector& getElementSizeList() const { return array_element_size; } + template const std::vector& get(int arrIndex); @@ -66,6 +68,7 @@ public: const std::vector& arrayNames() const { return array_name; } std::size_t size() const; + bool is_ix() const; protected: bool formatted; @@ -80,6 +83,7 @@ protected: std::vector array_name; std::vector array_type; std::vector array_size; + std::vector array_element_size; std::vector ifStreamPos; @@ -110,7 +114,10 @@ private: void loadBinaryArray(std::fstream& fileH, std::size_t arrIndex); void loadFormattedArray(const std::string& fileStr, std::size_t arrIndex, int64_t fromPos); - + + std::vector get_bin_logi_raw_values(int arrIndex) const; + std::vector get_fmt_real_raw_str_values(int arrIndex) const; + }; }} // namespace Opm::EclIO diff --git a/opm/io/eclipse/EclIOdata.hpp b/opm/io/eclipse/EclIOdata.hpp index 7fdcbc034..eb349f5ee 100644 --- a/opm/io/eclipse/EclIOdata.hpp +++ b/opm/io/eclipse/EclIOdata.hpp @@ -24,26 +24,28 @@ namespace Opm { namespace EclIO { - // type MESS have no assisiated data + // type MESS have no assisiated data enum eclArrType { - INTE, REAL, DOUB, CHAR, LOGI, MESS + INTE, REAL, DOUB, CHAR, LOGI, MESS, C0NN }; // named constants related to binary file format - const unsigned int true_value = 0xffffffff; + const unsigned int true_value_ecl = 0xffffffff; + const unsigned int true_value_ix = 0x1000000; const unsigned int false_value = 0x00000000; + const int sizeOfInte = 4; // number of bytes pr integer (inte) element const int sizeOfReal = 4; // number of bytes pr float (real) element const int sizeOfDoub = 8; // number of bytes pr double (doub) element const int sizeOfLogi = 4; // number of bytes pr bool (logi) element const int sizeOfChar = 8; // number of bytes pr string (char) element - const int MaxBlockSizeInte = 4000; // Maximum block size for INTE arrays in binary files - const int MaxBlockSizeReal = 4000; // Maximum block size for REAL arrays in binary files - const int MaxBlockSizeDoub = 8000; // Maximum block size for DOUB arrays in binary files - const int MaxBlockSizeLogi = 4000; // Maximum block size for LOGI arrays in binary files - const int MaxBlockSizeChar = 840; // Maximum block size for CHAR arrays in binary files + const int MaxBlockSizeInte = 4000; // Maximum block size for INTE arrays in binary files + const int MaxBlockSizeReal = 4000; // Maximum block size for REAL arrays in binary files + const int MaxBlockSizeDoub = 8000; // Maximum block size for DOUB arrays in binary files + const int MaxBlockSizeLogi = 4000; // Maximum block size for LOGI arrays in binary files + const int MaxBlockSizeChar = 840; // Maximum block size for CHAR arrays in binary files // named constants related to formatted file file format const int MaxNumBlockInte = 1000; // maximum number of Inte values in block => hard line shift @@ -52,17 +54,17 @@ namespace Opm { namespace EclIO { const int MaxNumBlockLogi = 1000; // maximum number of Logi values in block => hard line shift const int MaxNumBlockChar = 105; // maximum number of Char values in block => hard line shift - const int numColumnsInte = 6; // number of columns for Inte values - const int numColumnsReal = 4; // number of columns for Real values - const int numColumnsDoub = 3; // number of columns for Doub values - const int numColumnsLogi = 25; // number of columns for Logi values - const int numColumnsChar = 7; // number of columns for Char values + const int numColumnsInte = 6; // number of columns for Inte values + const int numColumnsReal = 4; // number of columns for Real values + const int numColumnsDoub = 3; // number of columns for Doub values + const int numColumnsLogi = 25; // number of columns for Logi values + const int numColumnsChar = 7; // number of columns for Char values - const int columnWidthInte = 12; // number of characters fore each Inte Element - const int columnWidthReal = 17; // number of characters fore each Inte Element - const int columnWidthDoub = 23; // number of characters fore each Inte Element - const int columnWidthLogi = 3; // number of characters fore each Inte Element - const int columnWidthChar = 11; // number of characters fore each Inte Element + const int columnWidthInte = 12; // number of characters fore each Inte Element + const int columnWidthReal = 17; // number of characters fore each Inte Element + const int columnWidthDoub = 23; // number of characters fore each Inte Element + const int columnWidthLogi = 3; // number of characters fore each Inte Element + const int columnWidthChar = 11; // number of characters fore each Inte Element }} // namespace Opm::EclIO diff --git a/opm/io/eclipse/EclOutput.hpp b/opm/io/eclipse/EclOutput.hpp index edfa383a4..a20c4d0dd 100644 --- a/opm/io/eclipse/EclOutput.hpp +++ b/opm/io/eclipse/EclOutput.hpp @@ -47,59 +47,71 @@ public: const std::vector& data) { eclArrType arrType = MESS; + int element_size = 4; + if (typeid(T) == typeid(int)) arrType = INTE; else if (typeid(T) == typeid(float)) arrType = REAL; - else if (typeid(T) == typeid(double)) + else if (typeid(T) == typeid(double)){ arrType = DOUB; - else if (typeid(T) == typeid(bool)) + element_size = 8; + } else if (typeid(T) == typeid(bool)) arrType = LOGI; else if (typeid(T) == typeid(char)) arrType = MESS; if (isFormatted) { - writeFormattedHeader(name, data.size(), arrType); + writeFormattedHeader(name, data.size(), arrType, element_size); if (arrType != MESS) writeFormattedArray(data); } else { - writeBinaryHeader(name, data.size(), arrType); + writeBinaryHeader(name, data.size(), arrType, element_size); if (arrType != MESS) writeBinaryArray(data); } } + // when this function is used array type will be assumed C0NN (not CHAR). + // Also in cases where element size is 8 or less, element size will be 8. + + void write(const std::string& name, const std::vector& data, int element_size); + void message(const std::string& msg); void flushStream(); + void set_ix() { ix_standard = true; } + friend class OutputStream::Restart; friend class OutputStream::SummarySpecification; private: - void writeBinaryHeader(const std::string& arrName, int64_t size, eclArrType arrType); + void writeBinaryHeader(const std::string& arrName, int64_t size, eclArrType arrType, int element_size); template void writeBinaryArray(const std::vector& data); - void writeBinaryCharArray(const std::vector& data); + void writeBinaryCharArray(const std::vector& data, int element_size); void writeBinaryCharArray(const std::vector>& data); - void writeFormattedHeader(const std::string& arrName, int size, eclArrType arrType); + void writeFormattedHeader(const std::string& arrName, int size, eclArrType arrType, int element_size); template void writeFormattedArray(const std::vector& data); - void writeFormattedCharArray(const std::vector& data); + void writeFormattedCharArray(const std::vector& data, int element_size); void writeFormattedCharArray(const std::vector>& data); void writeArrayType(const eclArrType arrType); - std::string make_real_string(float value) const; - std::string make_doub_string(double value) const; + std::string make_real_string_ecl(float value) const; + std::string make_real_string_ix(float value) const; + std::string make_doub_string_ecl(double value) const; + std::string make_doub_string_ix(double value) const; - bool isFormatted; + bool isFormatted, ix_standard; std::ofstream ofileH; }; diff --git a/opm/io/eclipse/EclUtil.hpp b/opm/io/eclipse/EclUtil.hpp index 7e0501f96..68cca1625 100644 --- a/opm/io/eclipse/EclUtil.hpp +++ b/opm/io/eclipse/EclUtil.hpp @@ -41,35 +41,42 @@ namespace Opm { namespace EclIO { std::string trimr(const std::string &str1); - uint64_t sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrType); - uint64_t sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrType arrType); + uint64_t sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrType, int elementSize); + uint64_t sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrType arrType, int elementSize); void readBinaryHeader(std::fstream& fileH, std::string& tmpStrName, int& tmpSize, std::string& tmpStrType); void readBinaryHeader(std::fstream& fileH, std::string& arrName, - int64_t& size, Opm::EclIO::eclArrType &arrType); + int64_t& size, Opm::EclIO::eclArrType &arrType, int& elementSize); void readFormattedHeader(std::fstream& fileH, std::string& arrName, - int64_t &num, Opm::EclIO::eclArrType &arrType); + int64_t &num, Opm::EclIO::eclArrType &arrType, int& elementSize); template std::vector readBinaryArray(std::fstream& fileH, const int64_t size, Opm::EclIO::eclArrType type, - std::function& flip); + std::function& flip, int elementSize); std::vector readBinaryInteArray(std::fstream &fileH, const int64_t size); std::vector readBinaryRealArray(std::fstream& fileH, const int64_t size); std::vector readBinaryDoubArray(std::fstream& fileH, const int64_t size); std::vector readBinaryLogiArray(std::fstream &fileH, const int64_t size); + std::vector readBinaryRawLogiArray(std::fstream &fileH, const int64_t size); std::vector readBinaryCharArray(std::fstream& fileH, const int64_t size); + std::vector readBinaryC0nnArray(std::fstream& fileH, const int64_t size, int elementSize); template std::vector readFormattedArray(const std::string& file_str, const int size, int64_t fromPos, std::function& process); std::vector readFormattedInteArray(const std::string& file_str, const int64_t size, int64_t fromPos); - std::vector readFormattedCharArray(const std::string& file_str, const int64_t size, int64_t fromPos); + + std::vector readFormattedCharArray(const std::string& file_str, const int64_t size, + int64_t fromPos, int elementSize); + std::vector readFormattedRealArray(const std::string& file_str, const int64_t size, int64_t fromPos); + std::vector readFormattedRealRawStrings(const std::string& file_str, const int64_t size, int64_t fromPos); + std::vector readFormattedLogiArray(const std::string& file_str, const int64_t size, int64_t fromPos); std::vector readFormattedDoubArray(const std::string& file_str, const int64_t size, int64_t fromPos); diff --git a/python/cxx/converters.cpp b/python/cxx/converters.cpp index f2a617aae..b4f195a76 100644 --- a/python/cxx/converters.cpp +++ b/python/cxx/converters.cpp @@ -3,13 +3,13 @@ namespace convert { py::array numpy_string_array(const std::vector& input) { - const std::size_t target_length = 8; + const std::size_t target_length = 99; using numpy_string_t = char[target_length]; auto output = py::array_t(input.size()); auto output_ptr = reinterpret_cast(output.request().ptr); for (std::size_t index = 0; index < input.size(); index++) { if (input[index].size() > target_length) - throw std::invalid_argument("Current implementation only works with 8 character strings"); + throw std::invalid_argument("Current implementation only works with 99 character strings"); std::size_t length = input[index].size(); std::strncpy(output_ptr[index], input[index].c_str(), length); diff --git a/python/cxx/eclipse_io.cpp b/python/cxx/eclipse_io.cpp index d8e33d1ac..58f09476b 100644 --- a/python/cxx/eclipse_io.cpp +++ b/python/cxx/eclipse_io.cpp @@ -43,6 +43,11 @@ public: m_output->flushStream(); } + void writeC0nnArray(const std::string& name, const std::vector& data, int element_size){ + m_output->write(name, data, element_size); + m_output->flushStream(); + } + void writeMessage(const std::string& name) { m_output->message(name); @@ -70,7 +75,7 @@ npArray get_vector_index(Opm::EclIO::EclFile * file_ptr, std::size_t array_index if (array_type == Opm::EclIO::LOGI) return std::make_tuple (convert::numpy_array( file_ptr->get(array_index)), array_type); - if (array_type == Opm::EclIO::CHAR) + if ((array_type == Opm::EclIO::CHAR) || (array_type == Opm::EclIO::C0NN)) return std::make_tuple (convert::numpy_string_array( file_ptr->get(array_index)), array_type); throw std::logic_error("Data type not supported"); @@ -305,6 +310,7 @@ void python::common::export_IO(py::module& m) { .value("REAL", Opm::EclIO::REAL) .value("DOUB", Opm::EclIO::DOUB) .value("CHAR", Opm::EclIO::CHAR) + .value("C0nn", Opm::EclIO::C0NN) .value("LOGI", Opm::EclIO::LOGI) .value("MESS", Opm::EclIO::MESS) .export_values(); @@ -384,6 +390,9 @@ void python::common::export_IO(py::module& m) { .def("write_message", &EclOutputBind::writeMessage) .def("__write_char_array", (void (EclOutputBind::*)(const std::string&, const std::vector&)) &EclOutputBind::writeArray) + + .def("__write_c0nn_array", &EclOutputBind::writeC0nnArray) + .def("__write_logi_array", (void (EclOutputBind::*)(const std::string&, const std::vector&)) &EclOutputBind::writeArray) .def("__write_inte_array", (void (EclOutputBind::*)(const std::string&, diff --git a/python/opm/io/ecl/__init__.py b/python/opm/io/ecl/__init__.py index 85d2b0801..a11710cac 100644 --- a/python/opm/io/ecl/__init__.py +++ b/python/opm/io/ecl/__init__.py @@ -33,7 +33,7 @@ def getitem_eclfile(self, arg): else: data, array_type = self.__get_data(arg) - if array_type == eclArrType.CHAR: + if array_type == eclArrType.CHAR or array_type == eclArrType.C0nn: return [ x.decode("utf-8") for x in data ] return data @@ -63,7 +63,7 @@ def getitem_erst(self, arg): else: raise ValueError("expecting tuple argument with 2 or 3 argumens: (index, rstep), (name, rstep) or (name, rstep, occurrence) ") - if array_type == eclArrType.CHAR: + if array_type == eclArrType.CHAR or array_type == eclArrType.C0nn: return [ x.decode("utf-8") for x in data ] return data @@ -169,7 +169,7 @@ def getitem_erft(self, arg): (CHAR, LOGI, INTE) ''' -def ecloutput_write(self, name, array): +def ecloutput_write(self, name, array, C0nn=False): if isinstance(array, list): if all(isinstance(element, str) for element in array): @@ -197,8 +197,11 @@ def ecloutput_write(self, name, array): self.__write_doub_array(name, array) elif array.dtype == "bool": self.__write_logi_array(name, array) - elif array.dtype.kind in {'U', 'S'}: + elif array.dtype.kind in {'U', 'S'} and not C0nn: self.__write_char_array(name, array) + elif array.dtype.kind in {'U', 'S'} and C0nn: + maxStrLength = max([len(x) for x in array]) + self.__write_c0nn_array(name, array, max([maxStrLength, 8])) else: raise ValueError("unknown array type for array {}".format(name)) diff --git a/python/tests/test_ecloutput.py b/python/tests/test_ecloutput.py index f3019f71a..50b66fa8b 100755 --- a/python/tests/test_ecloutput.py +++ b/python/tests/test_ecloutput.py @@ -271,6 +271,137 @@ class TestEclOutput(unittest.TestCase): os.remove(testFile) + def test_write_strings_binary(self): + + testFile = test_path("data/TMP1.INIT") + + shortWelNames = ["PROD-1", "PROD-2", "PROD-3", "PROD-4", "PROD-5"] + longWelNames = ["PRODUCER-1", "PRODUCER-2", "PRODUCER-13", "PRODUCER-4"] + + out1 = EclOutput(testFile) + + out1.write("WGNAME", shortWelNames) + + file1 = EclFile(testFile) + array = file1["WGNAME"] + + self.assertEqual(len(array), len(shortWelNames)) + + for v1,v2 in zip (array, shortWelNames): + self.assertEqual(v1, v2) + + arrayList = file1.arrays + name, arr_type, num = arrayList[0] + + self.assertEqual(name, "WGNAME") + self.assertEqual(arr_type, eclArrType.CHAR) + self.assertEqual(num, len(shortWelNames)) + + out2 = EclOutput(testFile) + out2.write("NAMES", longWelNames) + + file2 = EclFile(testFile) + array = file2["NAMES"] + + self.assertEqual(len(array), len(longWelNames)) + + for v1,v2 in zip (array, longWelNames): + self.assertEqual(v1, v2) + + arrayList = file2.arrays + name, arr_type, num = arrayList[0] + + self.assertEqual(name, "NAMES") + self.assertEqual(arr_type, eclArrType.C0nn) + self.assertEqual(num, len(longWelNames)) + + out3 = EclOutput(testFile, formatted=False) + out3.write("NAMES", shortWelNames, C0nn=True) + + file3 = EclFile(testFile) + array = file3["NAMES"] + + self.assertEqual(len(array), len(shortWelNames)) + + for v1,v2 in zip (array, shortWelNames): + self.assertEqual(v1, v2) + + arrayList = file3.arrays + name, arr_type, num = arrayList[0] + + self.assertEqual(name, "NAMES") + self.assertEqual(arr_type, eclArrType.C0nn) + self.assertEqual(num, len(shortWelNames)) + + if os.path.isfile(testFile): + os.remove(testFile) + + + def test_write_strings_formattede(self): + + testFile = test_path("data/TMP1.FINIT") + + shortWelNames = ["PROD-1", "PROD-2", "PROD-3", "PROD-4", "PROD-5"] + longWelNames = ["PRODUCER-1", "PRODUCER-2", "PRODUCER-13", "PRODUCER-4"] + + out1 = EclOutput(testFile, formatted=True) + + out1.write("WGNAME", shortWelNames) + + file1 = EclFile(testFile) + array = file1["WGNAME"] + + self.assertEqual(len(array), len(shortWelNames)) + + for v1,v2 in zip (array, shortWelNames): + self.assertEqual(v1, v2) + + arrayList = file1.arrays + name, arr_type, num = arrayList[0] + + self.assertEqual(name, "WGNAME") + self.assertEqual(arr_type, eclArrType.CHAR) + self.assertEqual(num, len(shortWelNames)) + + out2 = EclOutput(testFile, formatted=True) + out2.write("NAMES", longWelNames) + + file2 = EclFile(testFile) + array = file2["NAMES"] + + self.assertEqual(len(array), len(longWelNames)) + + for v1,v2 in zip (array, longWelNames): + self.assertEqual(v1, v2) + + arrayList = file2.arrays + name, arr_type, num = arrayList[0] + + self.assertEqual(name, "NAMES") + self.assertEqual(arr_type, eclArrType.C0nn) + self.assertEqual(num, len(longWelNames)) + + out3 = EclOutput(testFile, formatted=True) + out3.write("NAMES", shortWelNames, C0nn=True) + + file3 = EclFile(testFile) + array = file3["NAMES"] + + self.assertEqual(len(array), len(shortWelNames)) + + for v1,v2 in zip (array, shortWelNames): + self.assertEqual(v1, v2) + + arrayList = file3.arrays + name, arr_type, num = arrayList[0] + + self.assertEqual(name, "NAMES") + self.assertEqual(arr_type, eclArrType.C0nn) + self.assertEqual(num, len(shortWelNames)) + + if os.path.isfile(testFile): + os.remove(testFile) + if __name__ == "__main__": diff --git a/src/opm/io/eclipse/ESmry.cpp b/src/opm/io/eclipse/ESmry.cpp index 9b775c475..e96ab56db 100644 --- a/src/opm/io/eclipse/ESmry.cpp +++ b/src/opm/io/eclipse/ESmry.cpp @@ -158,7 +158,13 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) : const std::vector restartArray = smspecList.back().get("RESTART"); const std::vector keywords = smspecList.back().get("KEYWORDS"); - const std::vector wgnames = smspecList.back().get("WGNAMES"); + std::vector wgnames; + + if (smspecList.back().hasKey("WGNAMES")) + wgnames = smspecList.back().get("WGNAMES"); + else + wgnames = smspecList.back().get("NAMES"); + const std::vector nums = smspecList.back().get("NUMS"); const std::vector units = smspecList.back().get("UNITS"); @@ -223,7 +229,13 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) : const std::vector dimens = smspecList.back().get("DIMENS"); const std::vector restartArray = smspecList.back().get("RESTART"); const std::vector keywords = smspecList.back().get("KEYWORDS"); - const std::vector wgnames = smspecList.back().get("WGNAMES"); + std::vector wgnames; + + if (smspecList.back().hasKey("WGNAMES")) + wgnames = smspecList.back().get("WGNAMES"); + else + wgnames = smspecList.back().get("NAMES"); + const std::vector nums = smspecList.back().get("NUMS"); const std::vector units = smspecList.back().get("UNITS"); @@ -285,7 +297,13 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) : nParamsSpecFile[specInd] = dimens[0]; const std::vector keywords = smspecList[specInd].get("KEYWORDS"); - const std::vector wgnames = smspecList[specInd].get("WGNAMES"); + std::vector wgnames; + + if (smspecList.back().hasKey("WGNAMES")) + wgnames = smspecList.back().get("WGNAMES"); + else + wgnames = smspecList.back().get("NAMES"); + const std::vector nums = smspecList[specInd].get("NUMS"); for (size_t i=0; i < keywords.size(); i++) { @@ -457,15 +475,16 @@ void ESmry::inspect_lodsmry() std::string arrName; int64_t arr_size; Opm::EclIO::eclArrType arrType; + int sizeOfElement; std::fstream fileH; if (formattedFiles[0]) { fileH.open(lodFileName, std::ios::in); - Opm::EclIO::readFormattedHeader(fileH, arrName, arr_size, arrType); + Opm::EclIO::readFormattedHeader(fileH, arrName, arr_size, arrType, sizeOfElement); } else { fileH.open(lodFileName, std::ios::in | std::ios::binary); - Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType); + Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType, sizeOfElement); } if ((arrName != "KEYCHECK") or (arrType != Opm::EclIO::CHAR)) @@ -474,10 +493,10 @@ void ESmry::inspect_lodsmry() std::vector keycheck; if (formattedFiles[0]) { - uint64_t size = Opm::EclIO::sizeOnDiskFormatted(arr_size, Opm::EclIO::CHAR) + 1; + uint64_t size = Opm::EclIO::sizeOnDiskFormatted(arr_size, Opm::EclIO::CHAR, sizeOfChar) + 1; std::string fileStr = read_string_from_disk(fileH, size); - keycheck = Opm::EclIO::readFormattedCharArray(fileStr, arr_size, 0); + keycheck = Opm::EclIO::readFormattedCharArray(fileStr, arr_size, 0, sizeOfChar); } else { keycheck = Opm::EclIO::readBinaryCharArray(fileH, arr_size); } @@ -501,9 +520,9 @@ void ESmry::inspect_lodsmry() } if (formattedFiles[0]) - Opm::EclIO::readFormattedHeader(fileH, arrName, arr_size, arrType); + Opm::EclIO::readFormattedHeader(fileH, arrName, arr_size, arrType, sizeOfElement); else - Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType); + Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType, sizeOfElement); if ((arrName != "RSTEP ") or (arrType != Opm::EclIO::LOGI)) OPM_THROW(std::invalid_argument, "reading rstep, invalid lod file"); @@ -511,7 +530,7 @@ void ESmry::inspect_lodsmry() std::vector rstep; if (formattedFiles[0]) { - uint64_t size = Opm::EclIO::sizeOnDiskFormatted(arr_size, Opm::EclIO::LOGI) + 1; + uint64_t size = Opm::EclIO::sizeOnDiskFormatted(arr_size, Opm::EclIO::LOGI, sizeOfLogi) + 1; std::string fileStr = read_string_from_disk(fileH, size); rstep = Opm::EclIO::readFormattedLogiArray(fileStr, arr_size, 0); @@ -527,9 +546,9 @@ void ESmry::inspect_lodsmry() nTstep = rstep.size(); if (formattedFiles[0]) - lod_arr_size = sizeOnDiskFormatted(nTstep, Opm::EclIO::REAL); + lod_arr_size = sizeOnDiskFormatted(nTstep, Opm::EclIO::REAL, sizeOfReal); else - lod_arr_size = sizeOnDiskBinary(nTstep, Opm::EclIO::REAL); + lod_arr_size = sizeOnDiskBinary(nTstep, Opm::EclIO::REAL, sizeOfReal); fileH.close(); } @@ -558,6 +577,7 @@ void ESmry::Load_from_lodsmry(const std::vector& keywIndVect) const std::string arrName; int64_t size; Opm::EclIO::eclArrType arrType; + int sizeOfElement; uint64_t pos = lod_offset + lod_arr_size*static_cast(ind); @@ -569,9 +589,9 @@ void ESmry::Load_from_lodsmry(const std::vector& keywIndVect) const fileH.seekg (pos, fileH.beg); if (formattedFiles[0]) - readFormattedHeader(fileH, arrName, size, arrType); + readFormattedHeader(fileH, arrName, size, arrType, sizeOfElement); else - readBinaryHeader(fileH, arrName, size, arrType); + readBinaryHeader(fileH, arrName, size, arrType, sizeOfElement); arrName = Opm::EclIO::trimr(arrName); @@ -777,7 +797,7 @@ void ESmry::LoadData() const if (formattedFiles[specInd]) { char* buffer; - size_t size = sizeOnDiskFormatted(nParamsSpecFile[specInd], Opm::EclIO::REAL)+1; + size_t size = sizeOnDiskFormatted(nParamsSpecFile[specInd], Opm::EclIO::REAL, sizeOfReal) + 1; buffer = new char [size]; fileH.read (buffer, size); @@ -932,10 +952,10 @@ ESmry::getListOfArrays(std::string filename, bool formatted) if (num > 0) { if (formatted) { - uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType); + uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType, 4); fseek(ptr, static_cast(sizeOfNextArray), SEEK_CUR); } else { - uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType); + uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType, 4); fseek(ptr, static_cast(sizeOfNextArray), SEEK_CUR); } } diff --git a/src/opm/io/eclipse/EclFile.cpp b/src/opm/io/eclipse/EclFile.cpp index e906e0a71..44b951703 100644 --- a/src/opm/io/eclipse/EclFile.cpp +++ b/src/opm/io/eclipse/EclFile.cpp @@ -64,17 +64,19 @@ EclFile::EclFile(const std::string& filename, bool preload) : inputFilename(file std::string arrName(8,' '); eclArrType arrType; int64_t num; + int sizeOfElement; if (formatted) { - readFormattedHeader(fileH,arrName,num,arrType); + readFormattedHeader(fileH,arrName,num,arrType, sizeOfElement); } else { - readBinaryHeader(fileH,arrName,num,arrType); + readBinaryHeader(fileH,arrName,num, arrType, sizeOfElement); } array_size.push_back(num); array_type.push_back(arrType); - array_name.push_back(trimr(arrName)); + array_element_size.push_back(sizeOfElement); + array_index[array_name[n]] = n; uint64_t pos = fileH.tellg(); @@ -84,15 +86,14 @@ EclFile::EclFile(const std::string& filename, bool preload) : inputFilename(file if (num > 0){ if (formatted) { - uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType); + uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType, sizeOfElement); fileH.seekg(static_cast(sizeOfNextArray), std::ios_base::cur); } else { - uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType); + uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType, sizeOfElement); fileH.seekg(static_cast(sizeOfNextArray), std::ios_base::cur); } } - n++; }; @@ -125,6 +126,9 @@ void EclFile::loadBinaryArray(std::fstream& fileH, std::size_t arrIndex) case CHAR: char_array[arrIndex] = readBinaryCharArray(fileH, array_size[arrIndex]); break; + case C0NN: + char_array[arrIndex] = readBinaryC0nnArray(fileH, array_size[arrIndex], array_element_size[arrIndex]); + break; case MESS: break; default: @@ -152,7 +156,10 @@ void EclFile::loadFormattedArray(const std::string& fileStr, std::size_t arrInde logi_array[arrIndex] = readFormattedLogiArray(fileStr, array_size[arrIndex], fromPos); break; case CHAR: - char_array[arrIndex] = readFormattedCharArray(fileStr, array_size[arrIndex], fromPos); + char_array[arrIndex] = readFormattedCharArray(fileStr, array_size[arrIndex], fromPos, sizeOfChar); + break; + case C0NN: + char_array[arrIndex] = readFormattedCharArray(fileStr, array_size[arrIndex], fromPos, array_element_size[arrIndex]); break; case MESS: break; @@ -208,7 +215,7 @@ void EclFile::loadData(const std::string& name) inFile.seekg(ifStreamPos[arrIndex]); char* buffer; - size_t size = sizeOnDiskFormatted(array_size[arrIndex], array_type[arrIndex])+1; + size_t size = sizeOnDiskFormatted(array_size[arrIndex], array_type[arrIndex], array_element_size[arrIndex])+1; buffer = new char [size]; inFile.read (buffer, size); @@ -253,7 +260,7 @@ void EclFile::loadData(const std::vector& arrIndex) inFile.seekg(ifStreamPos[ind]); char* buffer; - size_t size = sizeOnDiskFormatted(array_size[ind], array_type[ind])+1; + size_t size = sizeOnDiskFormatted(array_size[ind], array_type[ind], array_element_size[ind])+1; buffer = new char [size]; inFile.read (buffer, size); @@ -284,7 +291,6 @@ void EclFile::loadData(const std::vector& arrIndex) void EclFile::loadData(int arrIndex) { - if (formatted) { std::ifstream inFile(inputFilename); @@ -292,7 +298,7 @@ void EclFile::loadData(int arrIndex) inFile.seekg(ifStreamPos[arrIndex]); char* buffer; - size_t size = sizeOnDiskFormatted(array_size[arrIndex], array_type[arrIndex])+1; + size_t size = sizeOnDiskFormatted(array_size[arrIndex], array_type[arrIndex], array_element_size[arrIndex])+1; buffer = new char [size]; inFile.read (buffer, size); @@ -318,6 +324,109 @@ void EclFile::loadData(int arrIndex) } } +bool EclFile::is_ix() const +{ + // assuming that array data type C0nn only are used in IX. This may change in future. + + // Formatted files, + // >> use real arrays. Example Ecl = '0.70000000E-01', IX = '7.0000000E-02' + // Binary files, + // >> if logi array exists in file, look for IX spes binary representation of true value + + if (formatted) { + for (size_t n=0; n < array_type.size(); n++) { + if (array_type[n] == Opm::EclIO::C0NN) { + return true; + } else if (array_type[n] == Opm::EclIO::REAL) { + auto realStr = get_fmt_real_raw_str_values(n); + int p, first; + + for (auto val : realStr) { + double dtmpv = abs(std::stod(val)); + + if (dtmpv > 0.0) { + p = val.find_first_of("."); + first = abs(std::stoi(val.substr(0, p))); + + if (first > 0) + return true; + else + return false; + } + } + } + } + } else { + for (size_t n=0; n < array_type.size(); n++) { + if (array_type[n] == Opm::EclIO::C0NN) { + return true; + } else if (array_type[n] == Opm::EclIO::LOGI) { + auto raw_logi_values = get_bin_logi_raw_values(n); + for (unsigned int val : raw_logi_values) { + if (val == Opm::EclIO::true_value_ix) + return true; + } + } + } + + return false; + } + + return false; +} + +std::vector EclFile::get_bin_logi_raw_values(int arrIndex) const +{ + if (array_type[arrIndex] != Opm::EclIO::LOGI) + OPM_THROW(std::runtime_error, "Error, selected array is not of type LOGI"); + + std::fstream fileH; + fileH.open(inputFilename, std::ios::in | std::ios::binary); + + if (!fileH) { + std::string message="Could not open file: '" + inputFilename +"'"; + OPM_THROW(std::runtime_error, message); + } + + fileH.seekg (ifStreamPos[arrIndex], fileH.beg); + + std::vector raw_logi = readBinaryRawLogiArray(fileH, array_size[arrIndex]); + + return raw_logi; +} + +std::vector EclFile::get_fmt_real_raw_str_values(int arrIndex) const +{ + std::vector real_vect; + + if (array_type[arrIndex] != Opm::EclIO::REAL) + OPM_THROW(std::runtime_error, "Error, selected array is not of type REAL"); + + std::ifstream inFile(inputFilename); + + if (!inFile) { + std::string message="Could not open file: '" + inputFilename +"'"; + OPM_THROW(std::runtime_error, message); + } + + inFile.seekg(ifStreamPos[arrIndex]); + + char* buffer; + size_t size = sizeOnDiskFormatted(array_size[arrIndex], array_type[arrIndex], array_element_size[arrIndex])+1; + + buffer = new char [size]; + inFile.read (buffer, size); + + std::string fileStr = std::string(buffer, size); + + std::vector real_vect_str; + real_vect_str = readFormattedRealRawStrings(fileStr, array_size[arrIndex], 0); + delete buffer; + + return real_vect_str; +} + + std::vector EclFile::getList() const { std::vector list; @@ -362,7 +471,12 @@ const std::vector& EclFile::get(int arrIndex) template<> const std::vector& EclFile::get(int arrIndex) { - return getImpl(arrIndex, CHAR, char_array, "string"); + if ((array_type[arrIndex] != Opm::EclIO::C0NN) && (array_type[arrIndex] != Opm::EclIO::CHAR)){ + std::string message = "Array with index " + std::to_string(arrIndex) + " is not of type " + "std::string"; + OPM_THROW(std::runtime_error, message); + } + + return getImpl(arrIndex, array_type[arrIndex], char_array, "string"); } @@ -498,7 +612,12 @@ const std::vector& EclFile::get(const std::string &nam OPM_THROW(std::invalid_argument, message); } - return getImpl(search->second, CHAR, char_array, "string"); + if ((array_type[search->second] != Opm::EclIO::C0NN) && (array_type[search->second] != Opm::EclIO::CHAR)){ + std::string message = "Array with index " + std::to_string(search->second) + " is not of type " + "std::string"; + OPM_THROW(std::runtime_error, message); + } + + return getImpl(search->second, array_type[search->second], char_array, "string"); } diff --git a/src/opm/io/eclipse/EclOutput.cpp b/src/opm/io/eclipse/EclOutput.cpp index f112cf9ea..3431824f6 100644 --- a/src/opm/io/eclipse/EclOutput.cpp +++ b/src/opm/io/eclipse/EclOutput.cpp @@ -41,6 +41,7 @@ EclOutput::EclOutput(const std::string& filename, : isFormatted{formatted} { const auto binmode = mode | std::ios_base::binary; + ix_standard = false; this->ofileH.open(filename, this->isFormatted ? mode : binmode); } @@ -50,15 +51,79 @@ template<> void EclOutput::write(const std::string& name, const std::vector& data) { + // array type will be assumed CHAR if maximum string length is 8 or less + // If maximum string length is > 8, C0nn will be used with element size equal to + // maximum string length + + int maximum_length = 8; + + if (data.size() > 0) { + auto it = std::max_element(data.begin(), data.end(), [] + (const std::string& str1, const std::string& str2) + { + return str2.size() > str1.size(); + }); + + maximum_length = it->size(); + } + + if (isFormatted) { - writeFormattedHeader(name, data.size(), CHAR); - writeFormattedCharArray(data); + if (maximum_length > sizeOfChar){ + writeFormattedHeader(name, data.size(), C0NN, maximum_length); + writeFormattedCharArray(data, maximum_length); + } else { + writeFormattedHeader(name, data.size(), CHAR, sizeOfChar); + writeFormattedCharArray(data, sizeOfChar); + } } else { - writeBinaryHeader(name, data.size(), CHAR); - writeBinaryCharArray(data); + if (maximum_length > sizeOfChar){ + writeBinaryHeader(name, data.size(), C0NN, maximum_length); + writeBinaryCharArray(data, maximum_length); + } else { + writeBinaryHeader(name, data.size(), CHAR, sizeOfChar); + writeBinaryCharArray(data, sizeOfChar); + } + } +} + +void EclOutput::write(const std::string& name, const std::vector& data, int element_size) +{ + // array type will be assumed C0NN (not CHAR). Also in cases where element size is 8 or less + + if (data.size() > 0) { + auto it = std::max_element(data.begin(), data.end(), [] + (const std::string& str1, const std::string& str2) + { + return str2.size() > str1.size(); + }); + + if (it->size() > static_cast(element_size)) + OPM_THROW(std::runtime_error, "specified element size for type C0NN less than maximum string length in ouput data"); + } + + if (isFormatted) + { + if (element_size > sizeOfChar){ + writeFormattedHeader(name, data.size(), C0NN, element_size); + writeFormattedCharArray(data, element_size); + } else { + writeFormattedHeader(name, data.size(), C0NN, sizeOfChar); + writeFormattedCharArray(data, sizeOfChar); + } + } + else + { + if (element_size > sizeOfChar){ + writeBinaryHeader(name, data.size(), C0NN, element_size); + writeBinaryCharArray(data, element_size); + } else { + writeBinaryHeader(name, data.size(), C0NN, sizeOfChar); + writeBinaryCharArray(data, sizeOfChar); + } } } @@ -68,11 +133,11 @@ void EclOutput::write> const std::vector>& data) { if (this->isFormatted) { - writeFormattedHeader(name, data.size(), CHAR); + writeFormattedHeader(name, data.size(), CHAR, sizeOfChar); writeFormattedCharArray(data); } else { - writeBinaryHeader(name, data.size(), CHAR); + writeBinaryHeader(name, data.size(), CHAR, sizeOfChar); writeBinaryCharArray(data); } } @@ -91,7 +156,7 @@ void EclOutput::flushStream() this->ofileH.flush(); } -void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclArrType arrType) +void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclArrType arrType, int element_size) { int bhead = flipEndianInt(16); std::string name = arrName + std::string(8 - arrName.size(),' '); @@ -102,13 +167,13 @@ void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclAr int64_t x231 = size / val231; int flippedx231 = flipEndianInt(static_cast( (-1)*x231 )); - + ofileH.write(reinterpret_cast(&bhead), sizeof(bhead)); ofileH.write(name.c_str(), 8); ofileH.write(reinterpret_cast(&flippedx231), sizeof(flippedx231)); ofileH.write("X231", 4); ofileH.write(reinterpret_cast(&bhead), sizeof(bhead)); - + size = size - (x231 * val231); } @@ -119,6 +184,14 @@ void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclAr ofileH.write(name.c_str(), 8); ofileH.write(reinterpret_cast(&flippedSize), sizeof(flippedSize)); + std::string c0nn_str; + + if (arrType == C0NN){ + std::ostringstream ss; + ss << "C" << std::setw(3) << std::setfill('0') << element_size; + c0nn_str = ss.str(); + } + switch(arrType) { case INTE: ofileH.write("INTE", 4); @@ -135,6 +208,9 @@ void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclAr case CHAR: ofileH.write("CHAR", 4); break; + case C0NN: + ofileH.write(c0nn_str.c_str(), 4); + break; case MESS: ofileH.write("MESS", 4); break; @@ -178,6 +254,8 @@ void EclOutput::writeBinaryArray(const std::vector& data) OPM_THROW(std::runtime_error, "fstream fileH not open for writing"); } + int logi_true_val = ix_standard ? true_value_ix : true_value_ecl; + rest = size * static_cast(sizeOfElement); while (rest > 0) { if (rest > maxBlockSize) { @@ -203,7 +281,7 @@ void EclOutput::writeBinaryArray(const std::vector& data) value_d = flipEndianDouble(data[n]); ofileH.write(reinterpret_cast(&value_d), sizeof(value_d)); } else if (arrType == LOGI) { - intVal = data[n] ? true_value : false_value; + intVal = data[n] ? logi_true_val : false_value; ofileH.write(reinterpret_cast(&intVal), sizeOfElement); } else { std::cerr << "type not supported in write binaryarray\n"; @@ -225,7 +303,7 @@ template void EclOutput::writeBinaryArray(const std::vector& data); template void EclOutput::writeBinaryArray(const std::vector& data); -void EclOutput::writeBinaryCharArray(const std::vector& data) +void EclOutput::writeBinaryCharArray(const std::vector& data, int element_size) { int num,dhead; @@ -234,6 +312,11 @@ void EclOutput::writeBinaryCharArray(const std::vector& data) auto sizeData = block_size_data_binary(CHAR); + if (element_size > sizeOfChar){ + std::get<1>(sizeData)= std::get<1>(sizeData) / std::get<0>(sizeData) * element_size; + std::get<0>(sizeData) = element_size; + } + int sizeOfElement = std::get<0>(sizeData); int maxBlockSize = std::get<1>(sizeData); int maxNumberOfElements = maxBlockSize / sizeOfElement; @@ -258,7 +341,7 @@ void EclOutput::writeBinaryCharArray(const std::vector& data) ofileH.write(reinterpret_cast(&dhead), sizeof(dhead)); for (int i = 0; i < num; i++) { - std::string tmpStr = data[n] + std::string(8 - data[n].size(),' '); + std::string tmpStr = data[n] + std::string(sizeOfElement - data[n].size(),' '); ofileH.write(tmpStr.c_str(), sizeOfElement); n++; } @@ -303,12 +386,21 @@ void EclOutput::writeBinaryCharArray(const std::vector>& d } } -void EclOutput::writeFormattedHeader(const std::string& arrName, int size, eclArrType arrType) +void EclOutput::writeFormattedHeader(const std::string& arrName, int size, eclArrType arrType, int element_size) { std::string name = arrName + std::string(8 - arrName.size(),' '); ofileH << " '" << name << "' " << std::setw(11) << size; + std::string c0nn_str; + + if (arrType == C0NN){ + std::ostringstream ss; + ss << "C" << std::setw(3) << std::setfill('0') << element_size; + c0nn_str = ss.str(); + } + + switch (arrType) { case INTE: ofileH << " 'INTE'" << std::endl; @@ -325,6 +417,9 @@ void EclOutput::writeFormattedHeader(const std::string& arrName, int size, eclAr case CHAR: ofileH << " 'CHAR'" << std::endl; break; + case C0NN: + ofileH << " '" << c0nn_str << "'" << std::endl; + break; case MESS: ofileH << " 'MESS'" << std::endl; break; @@ -332,7 +427,7 @@ void EclOutput::writeFormattedHeader(const std::string& arrName, int size, eclAr } -std::string EclOutput::make_real_string(float value) const +std::string EclOutput::make_real_string_ecl(float value) const { char buffer [15]; std::sprintf (buffer, "%10.7E", value); @@ -367,8 +462,32 @@ std::string EclOutput::make_real_string(float value) const } } +std::string EclOutput::make_real_string_ix(float value) const +{ + char buffer [15]; + std::sprintf (buffer, "%10.7E", value); -std::string EclOutput::make_doub_string(double value) const + if (value == 0.0) { + return " 0.0000000E+00"; + } else { + if (std::isnan(value)) + return "NAN"; + + if (std::isinf(value)) { + if (value > 0) + return "INF"; + else + return "-INF"; + } + + std::string tmpstr(buffer); + + return tmpstr; + } +} + + +std::string EclOutput::make_doub_string_ecl(double value) const { char buffer [21]; std::sprintf (buffer, "%19.13E", value); @@ -409,6 +528,30 @@ std::string EclOutput::make_doub_string(double value) const } } +std::string EclOutput::make_doub_string_ix(double value) const +{ + char buffer [21]; + std::sprintf (buffer, "%19.13E", value); + + if (value == 0.0) { + return " 0.0000000000000E+00"; + } else { + if (std::isnan(value)) + return "NAN"; + + if (std::isinf(value)) { + if (value > 0) + return "INF"; + else + return "-INF"; + } + + std::string tmpstr(buffer); + + return tmpstr; + } +} + template void EclOutput::writeFormattedArray(const std::vector& data) @@ -427,6 +570,7 @@ void EclOutput::writeFormattedArray(const std::vector& data) arrType = LOGI; } + auto sizeData = block_size_data_formatted(arrType); int maxBlockSize = std::get<0>(sizeData); @@ -441,10 +585,16 @@ void EclOutput::writeFormattedArray(const std::vector& data) ofileH << std::setw(columnWidth) << data[i]; break; case REAL: - ofileH << std::setw(columnWidth) << make_real_string(data[i]); + if (ix_standard) + ofileH << std::setw(columnWidth) << make_real_string_ix(data[i]); + else + ofileH << std::setw(columnWidth) << make_real_string_ecl(data[i]); break; case DOUB: - ofileH << std::setw(columnWidth) << make_doub_string(data[i]); + if (ix_standard) + ofileH << std::setw(columnWidth) << make_doub_string_ix(data[i]); + else + ofileH << std::setw(columnWidth) << make_doub_string_ecl(data[i]); break; case LOGI: if (data[i]) { @@ -479,30 +629,50 @@ template void EclOutput::writeFormattedArray(const std::vector& data template void EclOutput::writeFormattedArray(const std::vector& data); -void EclOutput::writeFormattedCharArray(const std::vector& data) +void EclOutput::writeFormattedCharArray(const std::vector& data, int element_size) { auto sizeData = block_size_data_formatted(CHAR); + int maxBlockSize = std::get<0>(sizeData); - int nColumns = std::get<1>(sizeData); + int nColumns; - int size = data.size(); + if (element_size < 9) + { + element_size = 8; + nColumns = std::get<1>(sizeData); + } else + nColumns = 80 / (element_size + 3); - for (int i = 0; i < size; i++) { - std::string str1(8,' '); - str1 = data[i] + std::string(8 - data[i].size(),' '); + int rest = data.size(); + int n = 0; - ofileH << " '" << str1 << "'"; + while (rest > 0) { + int size = rest; - if ((i+1) % nColumns == 0) { + if (size > maxBlockSize) + size = maxBlockSize; + + for (int i = 0; i < size; i++) { + std::string str1(element_size,' '); + str1 = data[n] + std::string(element_size - data[n].size(),' '); + + n++; + ofileH << " '" << str1 << "'"; + + if ((i+1) % nColumns == 0) { + ofileH << std::endl; + } + } + + if ((size % nColumns) != 0) { ofileH << std::endl; } - } - if ((size % nColumns) != 0) { - ofileH << std::endl; + rest = (rest > maxBlockSize) ? rest - maxBlockSize : 0; } } + void EclOutput::writeFormattedCharArray(const std::vector>& data) { const auto sizeData = block_size_data_formatted(CHAR); diff --git a/src/opm/io/eclipse/EclUtil.cpp b/src/opm/io/eclipse/EclUtil.cpp index dfa548dfc..f349f3996 100644 --- a/src/opm/io/eclipse/EclUtil.cpp +++ b/src/opm/io/eclipse/EclUtil.cpp @@ -27,6 +27,8 @@ #include #include +//temporary +#include int Opm::EclIO::flipEndianInt(int num) { @@ -111,6 +113,9 @@ std::tuple Opm::EclIO::block_size_data_binary(eclArrType arrType) case CHAR: return BlockSizeTuple{sizeOfChar, MaxBlockSizeChar}; break; + case C0NN: + return BlockSizeTuple{sizeOfChar, MaxBlockSizeChar}; + break; case MESS: OPM_THROW(std::invalid_argument, "Type 'MESS' have no associated data"); break; @@ -141,6 +146,9 @@ std::tuple Opm::EclIO::block_size_data_formatted(eclArrType arrTy case CHAR: return BlockSizeTuple{MaxNumBlockChar,numColumnsChar, columnWidthChar}; break; + case C0NN: + return BlockSizeTuple{MaxNumBlockChar,numColumnsChar, columnWidthChar}; + break; case MESS: OPM_THROW(std::invalid_argument, "Type 'MESS' have no associated data") ; break; @@ -162,7 +170,7 @@ std::string Opm::EclIO::trimr(const std::string &str1) } } -uint64_t Opm::EclIO::sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrType) +uint64_t Opm::EclIO::sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrType, int elementSize) { uint64_t size = 0; @@ -175,6 +183,11 @@ uint64_t Opm::EclIO::sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrTyp if (num > 0) { auto sizeData = Opm::EclIO::block_size_data_binary(arrType); + if (arrType == Opm::EclIO::C0NN){ + std::get<1>(sizeData)= std::get<1>(sizeData) / std::get<0>(sizeData) * elementSize; + std::get<0>(sizeData) = elementSize; + } + int sizeOfElement = std::get<0>(sizeData); int maxBlockSize = std::get<1>(sizeData); int maxNumberOfElements = maxBlockSize / sizeOfElement; @@ -197,7 +210,7 @@ uint64_t Opm::EclIO::sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrTyp return size; } -uint64_t Opm::EclIO::sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrType arrType) +uint64_t Opm::EclIO::sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrType arrType, int elementSize) { uint64_t size = 0; @@ -208,6 +221,11 @@ uint64_t Opm::EclIO::sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrTy } else { auto sizeData = block_size_data_formatted(arrType); + if (arrType == Opm::EclIO::C0NN){ + std::get<2>(sizeData) = elementSize + 3; + std::get<1>(sizeData) = 80 / std::get<2>(sizeData); + } + int maxBlockSize = std::get<0>(sizeData); int nColumns = std::get<1>(sizeData); int columnWidth = std::get<2>(sizeData); @@ -272,7 +290,7 @@ void Opm::EclIO::readBinaryHeader(std::fstream& fileH, std::string& tmpStrName, } void Opm::EclIO::readBinaryHeader(std::fstream& fileH, std::string& arrName, - int64_t& size, Opm::EclIO::eclArrType &arrType) + int64_t& size, Opm::EclIO::eclArrType &arrType, int& elementSize) { std::string tmpStrName(8,' '); std::string tmpStrType(4,' '); @@ -297,15 +315,25 @@ void Opm::EclIO::readBinaryHeader(std::fstream& fileH, std::string& arrName, size = static_cast(tmpSize); } + elementSize = 4; + arrName = tmpStrName; if (tmpStrType == "INTE") arrType = Opm::EclIO::INTE; else if (tmpStrType == "REAL") arrType = Opm::EclIO::REAL; - else if (tmpStrType == "DOUB") + else if (tmpStrType == "DOUB"){ arrType = Opm::EclIO::DOUB; - else if (tmpStrType == "CHAR") + elementSize = 8; + } + else if (tmpStrType == "CHAR"){ arrType = Opm::EclIO::CHAR; + elementSize = 8; + } + else if (tmpStrType.substr(0,1)=="C"){ + arrType = Opm::EclIO::C0NN; + elementSize = std::stoi(tmpStrType.substr(1,3)); + } else if (tmpStrType =="LOGI") arrType = Opm::EclIO::LOGI; else if (tmpStrType == "MESS") @@ -316,7 +344,7 @@ void Opm::EclIO::readBinaryHeader(std::fstream& fileH, std::string& arrName, void Opm::EclIO::readFormattedHeader(std::fstream& fileH, std::string& arrName, - int64_t &num, Opm::EclIO::eclArrType &arrType) + int64_t &num, Opm::EclIO::eclArrType &arrType, int& elementSize) { std::string line; std::getline(fileH,line); @@ -336,14 +364,24 @@ void Opm::EclIO::readFormattedHeader(std::fstream& fileH, std::string& arrName, num = std::stol(antStr); + elementSize = 4; + if (arrTypeStr == "INTE") arrType = Opm::EclIO::INTE; else if (arrTypeStr == "REAL") arrType = Opm::EclIO::REAL; - else if (arrTypeStr == "DOUB") + else if (arrTypeStr == "DOUB"){ arrType = Opm::EclIO::DOUB; - else if (arrTypeStr == "CHAR") + elementSize = 8; + } + else if (arrTypeStr == "CHAR"){ arrType = Opm::EclIO::CHAR; + elementSize = 8; + } + else if (arrTypeStr.substr(0,1)=="C"){ + arrType = Opm::EclIO::C0NN; + elementSize = std::stoi(arrTypeStr.substr(1,3)); + } else if (arrTypeStr == "LOGI") arrType = Opm::EclIO::LOGI; else if (arrTypeStr == "MESS") @@ -358,11 +396,17 @@ void Opm::EclIO::readFormattedHeader(std::fstream& fileH, std::string& arrName, template std::vector Opm::EclIO::readBinaryArray(std::fstream& fileH, const int64_t size, Opm::EclIO::eclArrType type, - std::function& flip) + std::function& flip, int elementSize) { std::vector arr; auto sizeData = block_size_data_binary(type); + + if (type == Opm::EclIO::C0NN){ + std::get<1>(sizeData)= std::get<1>(sizeData) / std::get<0>(sizeData) * elementSize; + std::get<0>(sizeData) = elementSize; + } + int sizeOfElement = std::get<0>(sizeData); int maxBlockSize = std::get<1>(sizeData); int maxNumberOfElements = maxBlockSize / sizeOfElement; @@ -370,11 +414,11 @@ std::vector Opm::EclIO::readBinaryArray(std::fstream& fileH, const int64_t si arr.reserve(size); int64_t rest = size; + while (rest > 0) { int dhead; fileH.read(reinterpret_cast(&dhead), sizeof(dhead)); dhead = Opm::EclIO::flipEndianInt(dhead); - int num = dhead / sizeOfElement; if ((num > maxNumberOfElements) || (num < 0)) { @@ -383,7 +427,13 @@ std::vector Opm::EclIO::readBinaryArray(std::fstream& fileH, const int64_t si for (int i = 0; i < num; i++) { T2 value; - fileH.read(reinterpret_cast(&value), sizeOfElement); + + if constexpr (std::is_same_v) { + value.resize(sizeOfElement) ; + fileH.read(&value[0], sizeOfElement); + } else + fileH.read(reinterpret_cast(&value), sizeOfElement); + arr.push_back(flip(value)); } @@ -411,21 +461,21 @@ std::vector Opm::EclIO::readBinaryArray(std::fstream& fileH, const int64_t si std::vector Opm::EclIO::readBinaryInteArray(std::fstream &fileH, const int64_t size) { std::function f = Opm::EclIO::flipEndianInt; - return readBinaryArray(fileH, size, Opm::EclIO::INTE, f); + return readBinaryArray(fileH, size, Opm::EclIO::INTE, f, sizeOfInte); } std::vector Opm::EclIO::readBinaryRealArray(std::fstream& fileH, const int64_t size) { std::function f = Opm::EclIO::flipEndianFloat; - return readBinaryArray(fileH, size, Opm::EclIO::REAL, f); + return readBinaryArray(fileH, size, Opm::EclIO::REAL, f, sizeOfReal); } std::vector Opm::EclIO::readBinaryDoubArray(std::fstream& fileH, const int64_t size) { std::function f = Opm::EclIO::flipEndianDouble; - return readBinaryArray(fileH, size, Opm::EclIO::DOUB, f); + return readBinaryArray(fileH, size, Opm::EclIO::DOUB, f, sizeOfDoub); } std::vector Opm::EclIO::readBinaryLogiArray(std::fstream &fileH, const int64_t size) @@ -433,17 +483,28 @@ std::vector Opm::EclIO::readBinaryLogiArray(std::fstream &fileH, const int std::function f = [](unsigned int intVal) { bool value; - if (intVal == Opm::EclIO::true_value) { + if (intVal == Opm::EclIO::true_value_ecl) { value = true; } else if (intVal == Opm::EclIO::false_value) { value = false; + } else if (intVal == Opm::EclIO::true_value_ix) { + value = true; } else { OPM_THROW(std::runtime_error, "Error reading logi value"); } return value; }; - return readBinaryArray(fileH, size, Opm::EclIO::LOGI, f); + return readBinaryArray(fileH, size, Opm::EclIO::LOGI, f, sizeOfLogi); +} + +std::vector Opm::EclIO::readBinaryRawLogiArray(std::fstream &fileH, const int64_t size) +{ + std::function f = [](unsigned int intVal) + { + return intVal; + }; + return readBinaryArray(fileH, size, Opm::EclIO::LOGI, f, sizeOfLogi); } @@ -455,7 +516,18 @@ std::vector Opm::EclIO::readBinaryCharArray(std::fstream& fileH, co std::string res(val.begin(), val.end()); return Opm::EclIO::trimr(res); }; - return readBinaryArray(fileH, size, Opm::EclIO::CHAR, f); + return readBinaryArray(fileH, size, Opm::EclIO::CHAR, f, sizeOfChar); +} + + +std::vector Opm::EclIO::readBinaryC0nnArray(std::fstream& fileH, const int64_t size, int elementSize) +{ + std::function f = [](const std::string& val) + { + return Opm::EclIO::trimr(val); + }; + + return readBinaryArray(fileH, size, Opm::EclIO::C0NN, f, elementSize); } @@ -479,7 +551,6 @@ std::vector Opm::EclIO::readFormattedArray(const std::string& file_str, const } return arr; - } @@ -495,7 +566,8 @@ std::vector Opm::EclIO::readFormattedInteArray(const std::string& file_str, } -std::vector Opm::EclIO::readFormattedCharArray(const std::string& file_str, const int64_t size, int64_t fromPos) +std::vector Opm::EclIO::readFormattedCharArray(const std::string& file_str, const int64_t size, + int64_t fromPos, int elementSize) { std::vector arr; arr.reserve(size); @@ -504,7 +576,7 @@ std::vector Opm::EclIO::readFormattedCharArray(const std::string& f for (int i=0; i< size; i++) { p1 = file_str.find_first_of('\'',p1); - std::string value = file_str.substr(p1 + 1, 8); + std::string value = file_str.substr(p1 + 1, elementSize); if (value == " ") { arr.push_back(""); @@ -512,7 +584,7 @@ std::vector Opm::EclIO::readFormattedCharArray(const std::string& f arr.push_back(Opm::EclIO::trimr(value)); } - p1 = p1+10; + p1 = p1 + elementSize + 2; } return arr; @@ -533,6 +605,18 @@ std::vector Opm::EclIO::readFormattedRealArray(const std::string& file_st return readFormattedArray(file_str, size, fromPos, f); } +std::vector Opm::EclIO::readFormattedRealRawStrings(const std::string& file_str, const int64_t size, int64_t fromPos) +{ + + + std::function f = [](const std::string& val) + { + return val; + }; + + return readFormattedArray(file_str, size, fromPos, f); +} + std::vector Opm::EclIO::readFormattedLogiArray(const std::string& file_str, const int64_t size, int64_t fromPos) { @@ -559,15 +643,18 @@ std::vector Opm::EclIO::readFormattedDoubArray(const std::string& file_s { auto p1 = val.find_first_of("D"); - if (p1 == std::string::npos) { - auto p2 = val.find_first_of("-+", 1); - if (p2 != std::string::npos) { - val = val.insert(p2,"E"); - } - } else { + if (p1 != std::string::npos) { val.replace(p1,1,"E"); } + p1 = val.find_first_of("E"); + + if (p1 == std::string::npos) { + auto p2 = val.find_first_of("-+", 1); + + if (p2 != std::string::npos) + val = val.insert(p2,"E"); + } return std::stod(val); }; diff --git a/test_util/convertECL.cpp b/test_util/convertECL.cpp index 2e944ae3d..979028913 100644 --- a/test_util/convertECL.cpp +++ b/test_util/convertECL.cpp @@ -50,6 +50,8 @@ void writeArray(std::string name, eclArrType arrType, T& file1, int index, EclOu write(outFile, file1, name, index); } else if (arrType == CHAR) { write(outFile, file1, name, index); + } else if (arrType == C0NN) { + write(outFile, file1, name, index); } else if (arrType == MESS) { outFile.message(name); } else { @@ -58,6 +60,7 @@ void writeArray(std::string name, eclArrType arrType, T& file1, int index, EclOu } } + template void writeArray(std::string name, eclArrType arrType, T& file1, int index, int reportStepNumber, EclOutput& outFile) { @@ -79,12 +82,24 @@ void writeArray(std::string name, eclArrType arrType, T& file1, int index, int r } } -void writeArrayList(std::vector& arrayList, EclFile file1, EclOutput& outFile) { + +void writeC0nnArray(std::string name, int elementSize, EclFile& file1, int index, EclOutput& outFile) +{ + auto vect = file1.get(index); + outFile.write(name, vect, elementSize); +} + + +void writeArrayList(std::vector& arrayList, std::vector& elementSizeList, EclFile file1, EclOutput& outFile) { for (size_t index = 0; index < arrayList.size(); index++) { std::string name = std::get<0>(arrayList[index]); eclArrType arrType = std::get<1>(arrayList[index]); - writeArray(name, arrType, file1, index, outFile); + + if (arrType == Opm::EclIO::C0NN){ + writeC0nnArray(name, elementSizeList[index], file1, index, outFile); + } else + writeArray(name, arrType, file1, index, outFile); } } @@ -102,8 +117,9 @@ static void printHelp() { std::cout << "\nconvertECL needs one argument which is the input file to be converted. If this is a binary file the output file will be formatted. If the input file is formatted the output will be binary. \n" << "\nIn addition, the program takes these options (which must be given before the arguments):\n\n" << "-h Print help and exit.\n" - << "-l list report step numbers in the selected restart file.\n" - << "-r extract and convert a spesific report time step number from a unified restart file. \n\n"; + << "-l List report step numbers in the selected restart file.\n" + << "-i Enforce IX standard on output file.\n" + << "-r Extract and convert a spesific report time step number from a unified restart file. \n\n"; } int main(int argc, char **argv) { @@ -112,8 +128,9 @@ int main(int argc, char **argv) { int reportStepNumber = -1; bool specificReportStepNumber = false; bool listProperties = false; + bool enforce_ix_output = false; - while ((c = getopt(argc, argv, "hr:l")) != -1) { + while ((c = getopt(argc, argv, "hr:li")) != -1) { switch (c) { case 'h': printHelp(); @@ -121,6 +138,9 @@ int main(int argc, char **argv) { case 'l': listProperties=true; break; + case 'i': + enforce_ix_output=true; + break; case 'r': specificReportStepNumber=true; reportStepNumber = atoi(optarg); @@ -215,6 +235,11 @@ int main(int argc, char **argv) { EclOutput outFile(resFile, formattedOutput); + if ((file1.is_ix()) || (enforce_ix_output)) { + std::cout << "setting IX flag on output file \n"; + outFile.set_ix(); + } + if (specificReportStepNumber) { if (extension!=".UNRST") { @@ -239,8 +264,8 @@ int main(int argc, char **argv) { file1.loadData(); auto arrayList = file1.getList(); - - writeArrayList(arrayList, file1, outFile); + std::vector elementSizeList = file1.getElementSizeList(); + writeArrayList(arrayList, elementSizeList, file1, outFile); } auto end = std::chrono::system_clock::now(); diff --git a/test_util/rewriteEclFile.cpp b/test_util/rewriteEclFile.cpp new file mode 100644 index 000000000..2dbd58fd9 --- /dev/null +++ b/test_util/rewriteEclFile.cpp @@ -0,0 +1,102 @@ +/* + 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 . +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +static void printHelp() { + + std::cout << "\rewriteEclFile needs a minimum of one arguments which is the input file name. \n" + << "\nIn addition, the program takes these options (which must be given before the arguments):\n\n" + << "-h Print help and exit.\n\n"; +} + +int main(int argc, char **argv) { + + int c = 0; + + while ((c = getopt(argc, argv, "h")) != -1) { + switch (c) { + case 'h': + printHelp(); + return 0; + default: + return EXIT_FAILURE; + } + } + + int argOffset = optind; + + Opm::EclIO::EclFile reffile(argv[argOffset]); + auto arrayList = reffile.getList(); + + std::string outputFile=std::string(argv[argOffset]); + + int p1 = outputFile.find_last_of("."); + std::string ext = outputFile.substr(p1+1); + + outputFile = outputFile.substr(0,p1) + "_REWRITE." + ext; + Opm::EclIO::EclOutput outFile(outputFile, reffile.formattedInput()); + + if (reffile.is_ix()) + outFile.set_ix(); + + reffile.loadData(); + + std::vector elementSizeList = reffile.getElementSizeList(); + + for (size_t n = 0; n < arrayList.size(); n++){ + + std::string name = std::get<0>(arrayList[n]); + auto arrType = std::get<1>(arrayList[n]); + + if (arrType == Opm::EclIO::INTE) { + auto data = reffile.get(n); + outFile.write(name, data); + } else if (arrType == Opm::EclIO::CHAR) { + auto data = reffile.get(n); + outFile.write(name, data); + } else if (arrType == Opm::EclIO::C0NN) { + auto data = reffile.get(n); + outFile.write(name, data, elementSizeList[n]); + } else if (arrType == Opm::EclIO::REAL) { + auto data = reffile.get(n); + outFile.write(name, data); + } else if (arrType == Opm::EclIO::DOUB) { + auto data = reffile.get(n); + outFile.write(name, data); + } else if (arrType == Opm::EclIO::LOGI) { + auto data = reffile.get(n); + outFile.write(name, data); + } else if (arrType == Opm::EclIO::MESS) { + outFile.message(name); + } + } + + return 0; +} diff --git a/test_util/summary.cpp b/test_util/summary.cpp index 57fea83f0..c4f19264e 100644 --- a/test_util/summary.cpp +++ b/test_util/summary.cpp @@ -26,7 +26,6 @@ #include - static void printHelp() { std::cout << "\nsummary needs a minimum of two arguments. First is smspec filename and then list of vectors \n" @@ -36,26 +35,32 @@ static void printHelp() { << "-r extract data only for report steps. \n\n"; } -void printHeader(const std::vector& keyList){ +void printHeader(const std::vector& keyList, const std::vector& width){ - std::cout << "--" << std::setw(14) << keyList[0]; + std::cout << std::endl; - for (size_t n= 1; n < keyList.size(); n++){ - std::cout << std::setw(16) << keyList[n]; + for (size_t n= 0; n < keyList.size(); n++){ + if (width[n] < 14) + std::cout << std::setw(16) << keyList[n]; + else + std::cout << std::setw(width[n] + 2) << keyList[n]; } std::cout << std::endl; } -std::string formatString(float data){ +std::string formatString(float data, int width){ std::stringstream stream; - if (std::fabs(data) < 1e6){ - stream << std::fixed << std::setw(16) << std::setprecision(6) << data; - } else { + if (std::fabs(data) < 1e6) + if (width < 14) + stream << std::fixed << std::setw(16) << std::setprecision(6) << data; + else + stream << std::fixed << std::setw(width + 2) << std::setprecision(6) << data; + + else stream << std::scientific << std::setw(16) << std::setprecision(6) << data; - } return stream.str(); } @@ -128,20 +133,27 @@ int main(int argc, char **argv) { } std::vector> smryData; + std::vector width; + + for (auto name : smryList) + width.push_back(name.size()); + for (auto key : smryList) { std::vector vect = reportStepsOnly ? smryFile.get_at_rstep(key) : smryFile.get(key); smryData.push_back(vect); } - printHeader(smryList); + printHeader(smryList, width); for (size_t s=0; s report_timesteps = {31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0, 364.0}; + + std::vector qoil_p2 = { 1160.149902, 1199.301147, 1199.304932, 1199.147583, 1199.120239, 1199.040405, 1198.917725, + 1198.765381, 1198.627930, 1198.406616, 1198.143555, 1197.853760 }; + + + std::vector timeVect = smry1.get_at_rstep("TIME"); + std::vector wopr_prod2 = smry1.get_at_rstep("WOPR:PROD-2"); + + for (size_t n = 0; n < timeVect.size() ; n ++) + BOOST_CHECK_CLOSE(timeVect[n], report_timesteps[n], 1e-6); + + for (size_t n = 0; n < wopr_prod2.size() ; n ++) + BOOST_CHECK_CLOSE(wopr_prod2[n], qoil_p2[n], 1e-6); +} + + + namespace fs = Opm::filesystem; BOOST_AUTO_TEST_CASE(TestCreateRSM) { ESmry smry1("SPE1CASE1.SMSPEC"); diff --git a/tests/test_EclIO.cpp b/tests/test_EclIO.cpp index 3067bc13f..493382fa7 100644 --- a/tests/test_EclIO.cpp +++ b/tests/test_EclIO.cpp @@ -87,41 +87,40 @@ void write_header(std::ofstream& ofileH, std::string& arrName, int size, std::st ofileH.write(reinterpret_cast(&bhead), sizeof(bhead)); } - BOOST_AUTO_TEST_CASE(TestEclFile_X231) { std::string filename = "TEST.DAT"; std::string arrName = "TESTX231"; std::vector ivect(10); - std::iota(ivect.begin(), ivect.end(), -4); + std::iota(ivect.begin(), ivect.end(), -4); { std::ofstream ofileH; - ofileH.open(filename, std::ios_base::binary); + ofileH.open(filename, std::ios_base::binary); - int size = static_cast((-1) * std::pow(2,31) + 10); + int size = static_cast((-1) * std::pow(2,31) + 10); write_header(ofileH, arrName, -1, std::string("X231")); write_header(ofileH, arrName, size, std::string("INTE")); int sizeData = ivect.size()*sizeof(int); sizeData = flipEndianInt(sizeData); - + ofileH.write(reinterpret_cast(&sizeData), sizeof(sizeData)); for (auto v : ivect){ - int fval = flipEndianInt(v); + int fval = flipEndianInt(v); ofileH.write(reinterpret_cast(&fval), sizeof(fval)); } - + ofileH.write(reinterpret_cast(&sizeData), sizeof(sizeData)); ofileH.close(); } - + EclFile test1(filename); auto array = test1.get(arrName); - + for (size_t n = 0; n < 10; n++){ BOOST_CHECK_EQUAL(array[n], ivect[n]); } @@ -193,6 +192,7 @@ BOOST_AUTO_TEST_CASE(TestEclFile_BINARY) { BOOST_CHECK_EQUAL(vect5b.size(), 312U); } + BOOST_AUTO_TEST_CASE(TestEclFile_FORMATTED) { std::string testFile1="ECLFILE.INIT"; @@ -238,6 +238,31 @@ BOOST_AUTO_TEST_CASE(TestEclFile_FORMATTED) { } + +BOOST_AUTO_TEST_CASE(TestEclFile_IX) { + + // file MODEL1_IX.INIT is output from comercial simulator ix with + // BASE_MODEL_1.DATA in opm-tests + + // binary representation of true value for data type LOGI is different + // compared with output from Eclipse and OPM-Flow + + std::string testInitFile="MODEL1_IX.INIT"; + + EclFile file1(testInitFile); + file1.loadData(); + + std::vector refLogihead = {true, true, false, false, true, false, false, false, false, false, false, + false, false, false, false, false, true, false, true, false }; + + auto logih = file1.get("LOGIHEAD"); + + for (size_t n = 0 ; n < refLogihead.size(); n++) + BOOST_CHECK_EQUAL(refLogihead[n], logih[n]); +} + + + BOOST_AUTO_TEST_CASE(TestEcl_Write_binary) { std::string inputFile="ECLFILE.INIT"; @@ -391,26 +416,128 @@ BOOST_AUTO_TEST_CASE(TestEcl_getList) { BOOST_AUTO_TEST_CASE(TestEcl_Write_CHAR) { - std::string testFile="TEST.FDAT"; - std::vector refStrList = {"This", "is", "a test.", "", "charact", "er >'<", "can be", "part of", "a string"}; + std::string testFile1="TEST.FDAT"; + std::string testFile2="TEST2.DAT"; + + std::vector refStrList1 = {"This", "is", "a test.", "", "charact", "er >'<", "can be", "part of", "a string"}; + std::vector refStrList2 = {"strings with length", "beyone 8 character","is also possible", "will use type C0nn"}; { - EclOutput eclTest(testFile, true); - eclTest.write("TEST",refStrList); + EclOutput eclTest(testFile1, true); + eclTest.write("TEST1",refStrList1); } { - EclFile file1(testFile); - std::vector strList=file1.get("TEST"); + EclFile file1(testFile1); + std::vector strList=file1.get("TEST1"); - for (size_t n = 0; n < refStrList.size(); n++) { - BOOST_CHECK(refStrList[n] == strList[n]); + for (size_t n = 0; n < refStrList1.size(); n++) { + BOOST_CHECK(refStrList1[n] == strList[n]); } + + auto arrayList =file1.getList(); + BOOST_CHECK(std::get<1>(arrayList[0]) == Opm::EclIO::CHAR); } - if (remove(testFile.c_str())==-1) { + // the next should automatically use C019 + { + EclOutput eclTest(testFile1, true); + eclTest.write("TEST2",refStrList2); + } + + { + EclFile file1(testFile1); + std::vector strList=file1.get("TEST2"); + + for (size_t n = 0; n < refStrList2.size(); n++) { + BOOST_CHECK(refStrList2[n] == strList[n]); + } + + auto arrayList =file1.getList(); + BOOST_CHECK(std::get<1>(arrayList[0]) == Opm::EclIO::C0NN); + } + + // the next should automatically use C008 (and not CHAR) + // will use C0nn since element size is specified in function call + { + EclOutput eclTest(testFile1, true); + eclTest.write("TEST3",refStrList1, 8); + } + + { + EclFile file1(testFile1); + std::vector strList=file1.get("TEST3"); + + for (size_t n = 0; n < refStrList1.size(); n++) { + BOOST_CHECK(refStrList1[n] == strList[n]); + } + + auto arrayList =file1.getList(); + BOOST_CHECK(std::get<1>(arrayList[0]) == Opm::EclIO::C0NN); + } + + // testing binary CHAR/C0nn format + + { + EclOutput eclTest(testFile2, false); + eclTest.write("TEST4",refStrList1); + } + + { + EclFile file1(testFile2); + std::vector strList=file1.get("TEST4"); + + for (size_t n = 0; n < refStrList1.size(); n++) { + BOOST_CHECK(refStrList1[n] == strList[n]); + } + + auto arrayList =file1.getList(); + BOOST_CHECK(std::get<1>(arrayList[0]) == Opm::EclIO::CHAR); + } + + // the next should automatically use C019 + { + EclOutput eclTest(testFile2, false); + eclTest.write("TEST5",refStrList2); + } + + { + EclFile file1(testFile2); + std::vector strList=file1.get("TEST5"); + + for (size_t n = 0; n < refStrList2.size(); n++) { + BOOST_CHECK(refStrList2[n] == strList[n]); + } + + auto arrayList =file1.getList(); + BOOST_CHECK(std::get<1>(arrayList[0]) == Opm::EclIO::C0NN); + } + + // the next should automatically use C008 (and not CHAR) + // will use C0nn since element size is specified in function call + { + EclOutput eclTest(testFile2, false); + eclTest.write("TEST6",refStrList1, 8); + } + + { + EclFile file1(testFile2); + std::vector strList=file1.get("TEST6"); + + for (size_t n = 0; n < refStrList1.size(); n++) { + BOOST_CHECK(refStrList1[n] == strList[n]); + } + + auto arrayList =file1.getList(); + BOOST_CHECK(std::get<1>(arrayList[0]) == Opm::EclIO::C0NN); + } + + if (remove(testFile1.c_str())==-1) { std::cout << " > Warning! temporary file was not deleted" << std::endl; }; + if (remove(testFile2.c_str())==-1) { + std::cout << " > Warning! temporary file was not deleted" << std::endl; + }; }