#7912 Summary Data Import : Update selected opm-common files

This commit is contained in:
magnesj 2021-09-10 12:27:25 +00:00 committed by Magne Sjaastad
parent c7917915cd
commit 2dbe0a0c9c
17 changed files with 2432 additions and 1797 deletions

View File

@ -21,10 +21,12 @@
#include "RiaLogging.h"
#include "opm/io/eclipse/ESmry.hpp"
#include "opm/io/eclipse/ExtESmry.hpp"
#ifdef USE_OPENMP
#include <omp.h>
#endif
#include "QFileInfo"
size_t RifOpmCommonEclipseSummary::sm_createdLodFileCount = 0;
@ -83,26 +85,34 @@ bool RifOpmCommonEclipseSummary::open( const QString& headerFileName,
bool includeRestartFiles,
RiaThreadSafeLogger* threadSafeLogger )
{
if ( !openESmryFile( headerFileName, includeRestartFiles, threadSafeLogger ) ) return false;
if ( m_createLodsmryFiles && !includeRestartFiles )
if ( m_createLodsmryFiles )
{
// Create the lodsmry file, no-op if already present.
bool hasFileBeenCreated = m_eSmry->make_lodsmry_file();
if ( hasFileBeenCreated )
auto candidateFileName = extendedSummaryFilename( headerFileName );
if ( !QFileInfo::exists( candidateFileName ) )
{
RifOpmCommonEclipseSummary::increaseLodFileCount();
try
{
auto temporarySummaryFile =
std::make_unique<Opm::EclIO::ESmry>(headerFileName.toStdString(), includeRestartFiles );
// If a LODSMRY file has been created, all data for all vectors has now been loaded into the summary file
// object. Close the file object to make sure allocated data is released, and create a new file object
// that will import only the meta data and no curve data. This is a relatively fast operation.
temporarySummaryFile->make_esmry_file();
if ( !openESmryFile( headerFileName, includeRestartFiles, threadSafeLogger ) ) return false;
RifOpmCommonEclipseSummary::increaseLodFileCount();
}
catch ( std::exception& e )
{
QString txt = QString( "Failed to create optimized summary file. Error text : %1" ).arg( e.what() );
if ( threadSafeLogger ) threadSafeLogger->error( txt );
return false;
}
}
}
if ( !m_eSmry ) return false;
if ( !openESmryFile( headerFileName, includeRestartFiles, threadSafeLogger ) ) return false;
if ( !m_eSmry && !m_exteSmry ) return false;
buildMetaData();
@ -122,6 +132,20 @@ const std::vector<time_t>& RifOpmCommonEclipseSummary::timeSteps( const RifEclip
//--------------------------------------------------------------------------------------------------
bool RifOpmCommonEclipseSummary::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{
if ( m_exteSmry )
{
auto it = m_adrToSummaryNodeIndex.find( resultAddress );
if ( it != m_adrToSummaryNodeIndex.end() )
{
// auto index = it->second;
// auto node = m_exteSmry->summaryNodeList()[index];
// auto fileValues = m_exteSmry->get( node );
// values->insert( values->begin(), fileValues.begin(), fileValues.end() );
}
return true;
}
if ( m_eSmry )
{
auto it = m_adrToSummaryNodeIndex.find( resultAddress );
@ -195,10 +219,24 @@ bool RifOpmCommonEclipseSummary::openESmryFile( const QString& headerFileN
bool includeRestartFiles,
RiaThreadSafeLogger* threadSafeLogger )
{
if ( m_useLodsmryFiles )
{
try
{
auto candidateFileName = extendedSummaryFilename( headerFileName );
m_exteSmry = std::make_unique<Opm::EclIO::ExtESmry>( candidateFileName.toStdString(), includeRestartFiles );
return true;
}
catch ( ... )
{
// Do not do anything here, try to open the file using standard esmy reader
}
}
try
{
m_eSmry =
std::make_unique<Opm::EclIO::ESmry>( headerFileName.toStdString(), includeRestartFiles, m_useLodsmryFiles );
m_eSmry = std::make_unique<Opm::EclIO::ESmry>( headerFileName.toStdString(), includeRestartFiles );
}
catch ( std::exception& e )
{
@ -222,6 +260,15 @@ void RifOpmCommonEclipseSummary::increaseLodFileCount()
sm_createdLodFileCount++;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifOpmCommonEclipseSummary::extendedSummaryFilename( const QString& headerFileName)
{
QString s(headerFileName);
return s.replace( ".SMSPEC", ".ESMRY" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -37,6 +37,7 @@ namespace Opm
namespace EclIO
{
class ESmry;
class ExtESmry;
struct SummaryNode;
} // namespace EclIO
} // namespace Opm
@ -81,9 +82,12 @@ private:
bool openESmryFile( const QString& headerFileName, bool includeRestartFiles, RiaThreadSafeLogger* threadSafeLogger );
static void increaseLodFileCount();
static QString extendedSummaryFilename(const QString& headerFileName);
private:
std::unique_ptr<Opm::EclIO::ESmry> m_eSmry;
std::unique_ptr<Opm::EclIO::ExtESmry> m_exteSmry;
std::vector<std::string> m_eSmryKeywords;
std::map<RifEclipseSummaryAddress, size_t> m_adrToSummaryNodeIndex;
std::vector<time_t> m_timeSteps;

View File

@ -180,7 +180,7 @@ bool RifOpmHdf5Summary::openESmryFile( const QString& headerFileName,
{
try
{
m_eSmry = std::make_unique<Opm::EclIO::ESmry>( headerFileName.toStdString(), includeRestartFiles, false );
m_eSmry = std::make_unique<Opm::EclIO::ESmry>( headerFileName.toStdString(), includeRestartFiles );
}
catch ( std::exception& e )
{

View File

@ -16,7 +16,7 @@ endif()
if(MSVC)
add_definitions( "/wd4996 /wd4244 /wd4267" )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /permissive-")
endif(MSVC)
project (custom-opm-common)
@ -82,6 +82,7 @@ add_library(${PROJECT_NAME}
opm-common/src/opm/io/eclipse/EclUtil.cpp
opm-common/src/opm/io/eclipse/EGrid.cpp
opm-common/src/opm/io/eclipse/ESmry.cpp
opm-common/src/opm/io/eclipse/ExtESmry.cpp
opm-common/src/opm/io/eclipse/EInit.cpp
# Required for use of static function RstConnection::inverse_peaceman

View File

@ -19,7 +19,8 @@
#ifndef OPM_FILESYSTEM_HPP
#define OPM_FILESYSTEM_HPP
#if !defined(_WIN32) && (__cplusplus < 201703L || (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)))
#if !defined(_WIN32) && (__cplusplus < 201703L || \
(defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)))
#include <experimental/filesystem>
#else
#include <filesystem>
@ -30,10 +31,14 @@
namespace Opm
{
#if !defined(_WIN32) && (__cplusplus < 201703L || (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)))
#if !defined(_WIN32) && (__cplusplus < 201703L || \
(defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)))
namespace filesystem = std::experimental::filesystem;
filesystem::path proximate(const filesystem::path& p,
const filesystem::path& base = filesystem::current_path());
#else
namespace filesystem = std::filesystem;
using filesystem::proximate;
#endif
// A poor man's filesystem::unique_path

View File

@ -49,7 +49,7 @@ public:
void getCellCorners(const std::array<int, 3>& ijk, std::array<double,8>& X, std::array<double,8>& Y, std::array<double,8>& Z);
std::vector<std::array<float, 3>> getXYZ_layer(int layer, bool bottom=false);
std::vector<std::array<float, 3>> getXYZ_layer(int layer, std::array<int, 4>& box, bool bottom=false);
std::vector<std::array<float, 3>> getXYZ_layer(int layer, const std::array<int, 4>& box, bool bottom=false);
int activeCells() const { return nactive; }
int totalNumberOfCells() const { return nijk[0] * nijk[1] * nijk[2]; }
@ -67,8 +67,8 @@ public:
const std::vector<std::string>& list_of_lgrs() const { return lgr_names; }
std::vector<float> get_mapaxes() const { return m_mapaxes; }
std::string get_mapunits() const { return m_mapunits; }
const std::vector<float>& get_mapaxes() const { return m_mapaxes; }
const std::string& get_mapunits() const { return m_mapunits; }
private:
Opm::filesystem::path inputFileName, initFileName;

View File

@ -35,15 +35,16 @@ namespace Opm { namespace EclIO {
using ArrSourceEntry = std::tuple<std::string, std::string, int, uint64_t>;
using TimeStepEntry = std::tuple<int, int, uint64_t>;
using RstEntry = std::tuple<std::string, int>;
class ESmry
{
public:
// input is smspec (or fsmspec file)
explicit ESmry(const std::string& filename, bool loadBaseRunData=false, bool uselodsmry=false);
explicit ESmry(const std::string& filename, bool loadBaseRunData=false);
int numberOfVectors() const { return nVect; }
int numberOfVectors() const { return static_cast<int>(nVect); }
bool hasKey(const std::string& key) const;
@ -58,10 +59,7 @@ public:
void LoadData(const std::vector<std::string>& vectList) const;
void LoadData() const;
bool make_lodsmry_file();
// Added based on requirements from ResInsight
void use_lodsmry_file(bool enable);
bool make_esmry_file();
time_point startdate() const { return startdat; }
@ -77,16 +75,19 @@ public:
const std::string& get_unit(const SummaryNode& node) const;
void write_rsm(std::ostream&) const;
void write_rsm_file(std::optional<Opm::filesystem::path> = std::nullopt) const;
void write_rsm_file(std::optional<filesystem::path> = std::nullopt) const;
bool all_steps_available();
void ijk_from_global_index(int glob, int &i, int &j, int &k) const;
private:
bool useLodsmryFile; // Added by ResInsight use
Opm::filesystem::path inputFileName, lodFileName;
private:
filesystem::path inputFileName;
RstEntry restart_info;
int nI, nJ, nK, nSpecFiles;
bool fromSingleRun, lodEnabeled;
uint64_t lod_offset, lod_arr_size;
bool fromSingleRun;
size_t nVect, nTstep;
std::vector<bool> formattedFiles;
@ -94,6 +95,7 @@ private:
mutable std::vector<std::vector<float>> vectorData;
mutable std::vector<bool> vectorLoaded;
std::vector<TimeStepEntry> timeStepList;
std::vector<TimeStepEntry> miniStepList;
std::vector<std::map<int, int>> arrayPos;
std::vector<std::string> keyword;
std::map<std::string, int> keyword_index;
@ -102,6 +104,7 @@ private:
std::vector<std::vector<std::string>> keywordListSpecFile;
std::vector<int> seqIndex;
std::vector<int> mini_steps;
std::vector<SummaryNode> summaryNodes;
@ -109,15 +112,15 @@ private:
time_point startdat;
std::vector<std::string> checkForMultipleResultFiles(const Opm::filesystem::path& rootN, bool formatted) const;
std::vector<std::string> checkForMultipleResultFiles(const filesystem::path& rootN, bool formatted) const;
void getRstString(const std::vector<std::string>& restartArray,
Opm::filesystem::path& pathRst,
Opm::filesystem::path& rootN) const;
filesystem::path& pathRst,
filesystem::path& rootN) const;
void updatePathAndRootName(Opm::filesystem::path& dir, Opm::filesystem::path& rootN) const;
void updatePathAndRootName(filesystem::path& dir, filesystem::path& rootN) const;
std::string makeKeyString(const std::string& keyword, const std::string& wgname, int num, const std::string& lgr, int lgri, int lgrj, int lgrk) const;
std::string makeKeyString(const std::string& keyword, const std::string& wgname, int num) const;
std::string unpackNumber(const SummaryNode&) const;
std::string lookupKey(const SummaryNode&) const;
@ -140,8 +143,9 @@ private:
std::vector<std::tuple <std::string, uint64_t>> getListOfArrays(std::string filename, bool formatted);
std::vector<int> makeKeywPosVector(int speInd) const;
std::string read_string_from_disk(std::fstream& fileH, uint64_t size) const;
void inspect_lodsmry();
void Load_from_lodsmry(const std::vector<int>& keywIndVect) const;
void read_ministeps_from_disk();
int read_ministep_formatted(std::fstream& fileH);
};
}} // namespace Opm::EclIO

View File

@ -20,7 +20,6 @@
#define OPM_IO_ECLUTIL_HPP
#include <opm/io/eclipse/EclIOdata.hpp>
#include <opm/common/utility/FileSystem.hpp>
#include <string>
#include <tuple>
@ -38,9 +37,6 @@ namespace Opm { namespace EclIO {
bool isFormatted(const std::string& filename);
bool is_number(const std::string& numstr);
bool isEqualCaseInsensitive(const std::string& string1, const std::string& string2);
Opm::filesystem::path findFileCaseInsensitive(const Opm::filesystem::path& folder, const std::string& filename);
std::tuple<int, int> block_size_data_binary(eclArrType arrType);
std::tuple<int, int, int> block_size_data_formatted(eclArrType arrType);

View File

@ -0,0 +1,106 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_IO_ExtESmry_HPP
#define OPM_IO_ExtESmry_HPP
#include <chrono>
#include <ostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <map>
#include <stdint.h>
#include <opm/common/utility/FileSystem.hpp>
#include <opm/common/utility/TimeService.hpp>
namespace Opm { namespace EclIO {
using ArrSourceEntry = std::tuple<std::string, std::string, int, uint64_t>;
using TimeStepEntry = std::tuple<int, int, uint64_t>;
using RstEntry = std::tuple<std::string, int>;
// start, rstart + rstnum, keycheck, units, rstep, tstep
using LodsmryHeadType = std::tuple<time_point, RstEntry, std::vector<std::string>, std::vector<std::string>,
std::vector<int>, std::vector<int>>;
class ExtESmry
{
public:
// input is esmry, only binary supported.
explicit ExtESmry(const std::string& filename, bool loadBaseRunData=false);
const std::vector<float>& get(const std::string& name);
std::vector<float> get_at_rstep(const std::string& name);
std::string& get_unit(const std::string& name);
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; }
size_t numberOfVectors() const { return m_nVect; }
const std::vector<std::string>& keywordList() const { return m_keyword;}
std::vector<std::string> keywordList(const std::string& pattern) const;
std::vector<time_point> dates();
bool all_steps_available();
private:
filesystem::path m_inputFileName;
std::vector<filesystem::path> m_lodsmry_files;
bool m_loadBaseRun;
std::vector<std::map<std::string, int>> m_keyword_index;
std::vector<std::tuple<int,int>> m_tstep_range;
std::vector<std::string> m_keyword;
std::vector<int> m_rstep;
std::vector<int> m_tstep;
std::vector<std::vector<int>> m_rstep_v;
std::vector<std::vector<int>> m_tstep_v;
std::vector<std::vector<float>> m_vectorData;
std::vector<bool> m_vectorLoaded;
std::unordered_map<std::string, std::string> kwunits;
size_t m_nVect;
std::vector<size_t> m_nTstep_v;
size_t m_nTstep;
std::vector<int> m_seqIndex;
std::vector<uint64_t> m_lod_offset;
std::vector<uint64_t> m_lod_arr_size;
time_point m_startdat;
uint64_t open_esmry(Opm::filesystem::path& inputFileName, LodsmryHeadType& lodsmry_head);
void updatePathAndRootName(Opm::filesystem::path& dir, Opm::filesystem::path& rootN);
};
}} // namespace Opm::EclIO
#endif // OPM_IO_ExtESmry_HPP

View File

@ -0,0 +1,70 @@
/*
Copyright 2021 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_RESTART_FILE_VIEW_HPP
#define OPM_RESTART_FILE_VIEW_HPP
#include <cstddef>
#include <memory>
#include <vector>
namespace Opm { namespace EclIO {
class ERst;
}} // Opm::EclIO
namespace Opm { namespace EclIO {
class RestartFileView
{
public:
explicit RestartFileView(std::shared_ptr<ERst> restart_file,
const int report_step);
~RestartFileView();
RestartFileView(const RestartFileView& rhs) = delete;
RestartFileView(RestartFileView&& rhs);
RestartFileView& operator=(const RestartFileView& rhs) = delete;
RestartFileView& operator=(RestartFileView&& rhs);
std::size_t simStep() const;
int reportStep() const;
int occurrenceCount(const std::string& vector) const;
template <typename ElmType>
bool hasKeyword(const std::string& vector) const;
template <typename ElmType>
const std::vector<ElmType>&
getKeyword(const std::string& vector, const int occurrence = 0) const;
const std::vector<int>& intehead() const;
const std::vector<bool>& logihead() const;
const std::vector<double>& doubhead() const;
private:
class Implementation;
std::unique_ptr<Implementation> pImpl_;
};
}} // Opm::RestartIO
#endif // OPM_RESTART_FILE_VIEW_HPP

View File

@ -47,4 +47,134 @@ std::string unique_path(const std::string& input)
return ret;
}
#if !defined(_WIN32) && (__cplusplus < 201703L || \
(defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)))
// The following code has been extracted from libstdc++,
// and slightly modified for use here.
// License is replicated here for attribution.
// Copyright (C) 2014-2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library 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, or (at your option)
// any later version.
// This library 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.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
namespace {
bool is_dot(Opm::filesystem::path::value_type c) { return c == '.'; }
bool is_dot(const Opm::filesystem::path& path)
{
const auto& filename = path.native();
return filename.size() == 1 && is_dot(filename[0]);
}
bool is_dotdot(const Opm::filesystem::path& path)
{
const auto& filename = path.native();
return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
}
Opm::filesystem::path lexically_relative(const Opm::filesystem::path& p,
const Opm::filesystem::path& base)
{
Opm::filesystem::path ret;
if (p.root_name() != base.root_name())
return ret;
if (p.is_absolute() != base.is_absolute())
return ret;
if (!p.has_root_directory() && base.has_root_directory())
return ret;
auto [a, b] = std::mismatch(p.begin(), p.end(), base.begin(), base.end());
if (a == p.end() && b == base.end())
ret = ".";
else
{
int n = 0;
for (; b != base.end(); ++b)
{
const Opm::filesystem::path& p2 = *b;
if (is_dotdot(p2))
--n;
else if (!p2.empty() && !is_dot(p2))
++n;
}
if (n == 0 && (a == p.end() || a->empty()))
ret = ".";
else if (n >= 0)
{
const Opm::filesystem::path dotdot("..");
while (n--)
ret /= dotdot;
for (; a != p.end(); ++a)
ret /= *a;
}
}
return ret;
}
Opm::filesystem::path
lexically_proximate(const Opm::filesystem::path& p, const Opm::filesystem::path& base)
{
Opm::filesystem::path rel = lexically_relative(p, base);
return rel.empty() ? p : rel;
}
Opm::filesystem::path
weakly_canonical(const Opm::filesystem::path& p)
{
Opm::filesystem::path result;
if (exists(status(p)))
return canonical(p);
Opm::filesystem::path tmp;
auto iter = p.begin(), end = p.end();
// find leading elements of p that exist:
while (iter != end)
{
tmp = result / *iter;
if (exists(status(tmp)))
swap(result, tmp);
else
break;
++iter;
}
// canonicalize:
if (!result.empty())
result = canonical(result);
// append the non-existing elements:
while (iter != end)
result /= *iter++;
return result;
}
}
filesystem::path proximate(const filesystem::path& p, const filesystem::path& base)
{
return lexically_proximate(weakly_canonical(p), weakly_canonical(base));
}
#endif
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -102,7 +102,7 @@ void EclOutput::write(const std::string& name, const std::vector<std::string>& d
});
if (it->size() > static_cast<size_t>(element_size))
OPM_THROW(std::runtime_error, "specified element size for type C0NN less than maximum string length in ouput data");
OPM_THROW(std::runtime_error, "specified element size for type C0NN less than maximum string length in output data");
}
if (isFormatted)
@ -222,14 +222,9 @@ void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclAr
template <typename T>
void EclOutput::writeBinaryArray(const std::vector<T>& data)
{
int num, rval;
int64_t rest;
int num;
int64_t rest, offset;
int dhead;
float value_f;
double value_d;
int intVal;
int64_t n = 0;
int64_t size = data.size();
eclArrType arrType = MESS;
@ -257,6 +252,9 @@ void EclOutput::writeBinaryArray(const std::vector<T>& data)
int logi_true_val = ix_standard ? true_value_ix : true_value_ecl;
rest = size * static_cast<int64_t>(sizeOfElement);
offset = 0;
while (rest > 0) {
if (rest > maxBlockSize) {
rest -= maxBlockSize;
@ -270,27 +268,56 @@ void EclOutput::writeBinaryArray(const std::vector<T>& data)
ofileH.write(reinterpret_cast<char*>(&dhead), sizeof(dhead));
for (int i = 0; i < num; i++) {
if (arrType == INTE) {
rval = flipEndianInt(data[n]);
ofileH.write(reinterpret_cast<char*>(&rval), sizeof(rval));
} else if (arrType == REAL) {
value_f = flipEndianFloat(data[n]);
ofileH.write(reinterpret_cast<char*>(&value_f), sizeof(value_f));
} else if (arrType == DOUB) {
value_d = flipEndianDouble(data[n]);
ofileH.write(reinterpret_cast<char*>(&value_d), sizeof(value_d));
} else if (arrType == LOGI) {
intVal = data[n] ? logi_true_val : false_value;
ofileH.write(reinterpret_cast<char*>(&intVal), sizeOfElement);
} else {
std::cerr << "type not supported in write binaryarray\n";
std::exit(EXIT_FAILURE);
}
if (arrType == INTE) {
n++;
std::vector<int> flipped_data;
flipped_data.resize(num, 0);
for (int m = 0; m < num; m++)
flipped_data[m] = flipEndianInt(data[m + offset]);
ofileH.write((char*)(flipped_data.data()), flipped_data.size() * sizeof(int)) ;
} else if (arrType == REAL) {
std::vector<float> flipped_data;
flipped_data.resize(num, 0);
for (int m = 0; m < num; m++)
flipped_data[m] = flipEndianFloat(data[m + offset]);
ofileH.write((char*)(flipped_data.data()), flipped_data.size() * sizeof(float)) ;
} else if (arrType == DOUB) {
std::vector<double> flipped_data;
flipped_data.resize(num, 0);
for (int m = 0; m < num; m++)
flipped_data[m] = flipEndianDouble(data[m + offset]);
ofileH.write((char*)(flipped_data.data()), flipped_data.size() * sizeof(double)) ;
} else if (arrType == LOGI) {
std::vector<int> logi_data;
logi_data.resize(num, 0);
for (int m = 0; m < num; m++)
if (data[m + offset])
logi_data[m] = logi_true_val;
else
logi_data[m] = false_value;
ofileH.write((char*)(logi_data.data()), logi_data.size() * sizeof(int)) ;
} else {
std::cerr << "type not supported in write binaryarray\n";
std::exit(EXIT_FAILURE);
}
offset += num;
ofileH.write(reinterpret_cast<char*>(&dhead), sizeof(dhead));
}
}

View File

@ -25,7 +25,6 @@
#include <algorithm>
#include <array>
#include <stdexcept>
#include <cctype>
#include <cmath>
#include <fstream>
#include <cstring>
@ -83,28 +82,6 @@ bool Opm::EclIO::is_number(const std::string& numstr)
}
bool Opm::EclIO::isEqualCaseInsensitive(const std::string& string1, const std::string& string2)
{
std::string string1LowerCase(string1);
std::string string2LowerCase(string2);
std::transform(string1.begin(), string1.end(), string1LowerCase.begin(), ::tolower);
std::transform(string2.begin(), string2.end(), string2LowerCase.begin(), ::tolower);
return string1LowerCase == string2LowerCase;
}
Opm::filesystem::path Opm::EclIO::findFileCaseInsensitive(const Opm::filesystem::path& folder, const std::string& filename)
{
for (auto& p : Opm::filesystem::directory_iterator(folder)) {
std::string candidate = p.path().filename().string();
if (isEqualCaseInsensitive(filename, candidate)) return p.path();
}
return { };
}
bool Opm::EclIO::isFormatted(const std::string& filename)
{
const auto p = filename.find_last_of(".");
@ -443,9 +420,9 @@ std::vector<T> Opm::EclIO::readBinaryArray(std::fstream& fileH, const int64_t si
std::get<0>(sizeData) = elementSize;
}
int sizeOfElement = std::get<0>(sizeData);
int maxBlockSize = std::get<1>(sizeData);
int maxNumberOfElements = maxBlockSize / sizeOfElement;
const int sizeOfElement = std::get<0>(sizeData);
const int maxBlockSize = std::get<1>(sizeData);
const int maxNumberOfElements = maxBlockSize / sizeOfElement;
arr.reserve(size);
@ -455,22 +432,25 @@ std::vector<T> Opm::EclIO::readBinaryArray(std::fstream& fileH, const int64_t si
int dhead;
fileH.read(reinterpret_cast<char*>(&dhead), sizeof(dhead));
dhead = Opm::EclIO::flipEndianInt(dhead);
int num = dhead / sizeOfElement;
const int num = dhead / sizeOfElement;
if ((num > maxNumberOfElements) || (num < 0)) {
OPM_THROW(std::runtime_error, "Error reading binary data, inconsistent header data or incorrect number of elements");
}
for (int i = 0; i < num; i++) {
T2 value;
if constexpr (std::is_same_v<T2, std::string>) {
if constexpr (std::is_same_v<T2, std::string>) {
for (int i = 0; i < num; i++) {
T2 value;
value.resize(sizeOfElement) ;
fileH.read(&value[0], sizeOfElement);
} else
fileH.read(reinterpret_cast<char*>(&value), sizeOfElement);
arr.push_back(flip(value));
}
} else {
std::vector<T2> buf(num);
fileH.read(reinterpret_cast<char*>(buf.data()), buf.size()*sizeof(T2));
arr.push_back(flip(value));
for (const auto& value : buf)
arr.push_back(flip(value));
}
rest -= num;

View File

@ -0,0 +1,478 @@
/*
Copyright 2019 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/io/eclipse/ExtESmry.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/common/utility/FileSystem.hpp>
#include <opm/common/utility/TimeService.hpp>
#include <opm/io/eclipse/EclFile.hpp>
#include <opm/io/eclipse/EclUtil.hpp>
#include <algorithm>
#include <numeric>
#include <chrono>
#include <exception>
#include <iterator>
#include <limits>
#include <set>
#include <stdexcept>
#include <string>
#ifdef _WIN32
#include "cross-platform/windows/Substitutes.hpp"
#else
#include <fnmatch.h>
#endif
#include <fstream>
#include <cmath>
#include <cstring>
#include <iostream>
#include <iostream>
namespace {
Opm::time_point make_date(const std::vector<int>& datetime) {
auto day = datetime[0];
auto month = datetime[1];
auto year = datetime[2];
auto hour = 0;
auto minute = 0;
auto second = 0;
if (datetime.size() == 6) {
hour = datetime[3];
minute = datetime[4];
auto total_usec = datetime[5];
second = total_usec / 1000000;
}
const auto ts = Opm::TimeStampUTC{ Opm::TimeStampUTC::YMD{ year, month, day}}.hour(hour).minutes(minute).seconds(second);
return Opm::TimeService::from_time_t( Opm::asTimeT(ts) );
}
}
/*
KEYWORDS WGNAMES NUMS | PARAM index Corresponding ERT key
------------------------------------------------+--------------------------------------------------
WGOR OP_1 0 | 0 WGOR:OP_1
FOPT +-+-+-+- 0 | 1 FOPT
WWCT OP_1 0 | 2 WWCT:OP_1
WIR OP_1 0 | 3 WIR:OP_1
WGOR WI_1 0 | 4 WWCT:OP_1
WWCT W1_1 0 | 5 WWCT:WI_1
BPR +-+-+- 12675 | 6 BPR:12675, BPR:i,j,k
RPR +-+-+- 1 | 7 RPR:1
FOPT +-+-+- 0 | 8 FOPT
GGPR NORTH 0 | 9 GGPR:NORTH
COPR OP_1 5628 | 10 COPR:OP_1:56286, COPR:OP_1:i,j,k
RXF +-+-+- 32768*R1(R2 + 10) | 11 RXF:2-3
SOFX OP_1 12675 | 12 SOFX:OP_1:12675, SOFX:OP_1:i,j,jk
*/
namespace Opm { namespace EclIO {
ExtESmry::ExtESmry(const std::string &filename, bool loadBaseRunData) :
m_inputFileName { filename },
m_loadBaseRun(loadBaseRunData)
{
if (m_inputFileName.extension()=="")
m_inputFileName+=".ESMRY";
if (m_inputFileName.extension()!=".ESMRY")
throw std::invalid_argument("Input file should have extension .ESMRY");
m_lodsmry_files.push_back(m_inputFileName);
Opm::filesystem::path rootName = m_inputFileName.parent_path() / m_inputFileName.stem();
Opm::filesystem::path path = Opm::filesystem::current_path();
Opm::filesystem::path rstRootN;
updatePathAndRootName(path, rootName);
LodsmryHeadType lodsmry_head;
auto lod_offset = open_esmry(m_inputFileName, lodsmry_head);
m_startdat = std::get<0>(lodsmry_head);
m_lod_offset.push_back(lod_offset);
std::map<std::string, int> key_index;
auto keyword = std::get<2>(lodsmry_head);
auto units = std::get<3>(lodsmry_head);
for (size_t n = 0; n < keyword.size(); n++){
key_index[keyword[n]] = n;
m_keyword.push_back(keyword[n]);
}
m_keyword_index.push_back(key_index);
for (size_t n = 0; n < m_keyword.size(); n++)
kwunits[m_keyword[n]] = units[n];
RstEntry rst_entry = std::get<1>(lodsmry_head);
m_rstep_v.push_back(std::get<4>(lodsmry_head));
m_tstep_v.push_back(std::get<5>(lodsmry_head));
m_nTstep_v.push_back(m_tstep_v.back().size());
auto lod_arr_size = sizeOnDiskBinary(m_nTstep_v.back(), Opm::EclIO::REAL, sizeOfReal);
m_lod_arr_size.push_back(lod_arr_size);
m_tstep_range.push_back(std::make_tuple(0, m_tstep_v.back().size() - 1));
if ((loadBaseRunData) && (!std::get<0>(rst_entry).empty())) {
auto restart = std::get<0>(rst_entry);
auto rstNum = std::get<1>(rst_entry);
int sim_ind = 0;
while (!restart.empty()){
sim_ind++;
rstRootN = Opm::filesystem::path(restart);
updatePathAndRootName(path, rstRootN);
Opm::filesystem::path rstLodSmryFile = path / rstRootN;
rstLodSmryFile += ".ESMRY";
m_lodsmry_files.push_back(rstLodSmryFile);
lod_offset = open_esmry(rstLodSmryFile, lodsmry_head);
m_lod_offset.push_back(lod_offset);
m_rstep_v.push_back(std::get<4>(lodsmry_head));
m_tstep_v.push_back(std::get<5>(lodsmry_head));
m_nTstep_v.push_back(m_tstep_v.back().size());
lod_arr_size = sizeOnDiskBinary(m_nTstep_v.back(), Opm::EclIO::REAL, sizeOfReal);
m_lod_arr_size.push_back(lod_arr_size);
int cidx = 0;
auto it = std::find_if(m_rstep_v[sim_ind].begin(), m_rstep_v[sim_ind].end(),
[&cidx, &rstNum](const int & val)
{
if (val == 1)
++cidx;
return cidx == rstNum;
});
size_t ind = std::distance(m_rstep_v[sim_ind].begin(), it);
m_tstep_range.push_back(std::make_tuple(0, ind));
key_index.clear();
keyword = std::get<2>(lodsmry_head);
for (size_t n = 0; n < keyword.size(); n++)
key_index[keyword[n]] = n;
m_keyword_index.push_back(key_index);
rst_entry = std::get<1>(lodsmry_head);
restart = std::get<0>(rst_entry);
rstNum = std::get<1>(rst_entry);
}
}
m_nVect = m_keyword.size();
m_vectorData.resize(m_nVect, {});
m_vectorLoaded.resize(m_nVect, false);
int ind = static_cast<int>(m_tstep_range.size()) - 1 ;
while (ind > -1) {
int to_ind = std::get<1>(m_tstep_range[ind]);
m_rstep.insert(m_rstep.end(), m_rstep_v[ind].begin(), m_rstep_v[ind].begin() + to_ind + 1);
m_tstep.insert(m_tstep.end(), m_tstep_v[ind].begin(), m_tstep_v[ind].begin() + to_ind + 1);
ind--;
}
m_nTstep = m_rstep.size();
for (size_t m = 0; m < m_rstep.size(); m++)
if (m_rstep[m] == 1)
m_seqIndex.push_back(m);
}
std::vector<float> ExtESmry::get_at_rstep(const std::string& name)
{
auto full_vect = this->get(name);
std::vector<float> rs_vect;
rs_vect.reserve(m_seqIndex.size());
for (auto r : m_seqIndex)
rs_vect.push_back(full_vect[r]);
return rs_vect;
}
std::string& ExtESmry::get_unit(const std::string& name)
{
if ( m_keyword_index[0].find(name) == m_keyword_index[0].end() )
throw std::invalid_argument("summary key '" + name + "' not found");
return kwunits.at(name);
}
bool ExtESmry::all_steps_available()
{
for (size_t n = 1; n < m_tstep.size(); n++)
if ((m_tstep[n] - m_tstep[n-1]) > 1)
return false;
return true;
}
uint64_t ExtESmry::open_esmry(Opm::filesystem::path& inputFileName, LodsmryHeadType& lodsmry_head)
{
std::fstream fileH;
fileH.open(inputFileName, std::ios::in | std::ios::binary);
if (!fileH)
throw std::runtime_error("Can not open file ");
std::string arrName;
int64_t arr_size;
Opm::EclIO::eclArrType arrType;
int sizeOfElement;
Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType, sizeOfElement);
if ((arrName != "START ") or (arrType != Opm::EclIO::INTE))
OPM_THROW(std::invalid_argument, "reading start, invalid lod file");
auto start_vect = Opm::EclIO::readBinaryInteArray(fileH, arr_size);
auto startdat = make_date(start_vect);
Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType, sizeOfElement);
Opm::EclIO::RstEntry rst_entry = std::make_tuple("", 0);
if (arrName == "RESTART "){
if (m_loadBaseRun) {
std::vector<std::string> rstfile = Opm::EclIO::readBinaryC0nnArray(fileH, arr_size, sizeOfElement);
Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType, sizeOfElement);
std::vector<int> rst_num = Opm::EclIO::readBinaryInteArray(fileH, arr_size);
rst_entry = std::make_tuple(rstfile[0], rst_num[0]);
} else {
uint64_t numIgnore = sizeOnDiskBinary(arr_size, arrType, sizeOfElement);
numIgnore = numIgnore + 24 + sizeOnDiskBinary(1, Opm::EclIO::INTE, Opm::EclIO::sizeOfInte);
fileH.seekg(static_cast<std::streamoff>(numIgnore), std::ios_base::cur);
}
Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType, sizeOfElement);
}
if (arrName != "KEYCHECK")
OPM_THROW(std::invalid_argument, "!!reading keycheck, invalid lod file");
std::vector<std::string> keywords;
keywords = Opm::EclIO::readBinaryC0nnArray(fileH, arr_size, sizeOfElement);
Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType, sizeOfElement);
if (arrName != "UNITS ")
OPM_THROW(std::invalid_argument, "reading UNITS, invalid lod file");
auto units = Opm::EclIO::readBinaryC0nnArray(fileH, arr_size, sizeOfElement);
if (keywords.size() != units.size())
throw std::runtime_error("invalied LODSMRY file, size of units not equal size of keywords");
Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType, sizeOfElement);
if ((arrName != "RSTEP ") or (arrType != Opm::EclIO::INTE))
OPM_THROW(std::invalid_argument, "reading RSTEP, invalid lod file");
auto rstep = Opm::EclIO::readBinaryInteArray(fileH, arr_size);
Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType, sizeOfElement);
if ((arrName != "TSTEP ") or (arrType != Opm::EclIO::INTE))
OPM_THROW(std::invalid_argument, "reading TSTEP, invalid lod file");
auto tstep = Opm::EclIO::readBinaryInteArray(fileH, arr_size);
lodsmry_head = std::make_tuple(startdat, rst_entry, keywords, units, rstep, tstep);
uint64_t lodsmry_offset = static_cast<uint64_t>(fileH.tellg());
fileH.close();
return lodsmry_offset;
}
void ExtESmry::updatePathAndRootName(Opm::filesystem::path& dir, Opm::filesystem::path& rootN) {
if (rootN.parent_path().is_absolute()){
dir = rootN.parent_path();
} else {
dir = dir / rootN.parent_path();
}
rootN = rootN.stem();
}
void ExtESmry::loadData(const std::vector<std::string>& stringVect)
{
std::vector<int> keyIndexVect;
for (const auto& key: stringVect)
keyIndexVect.push_back(m_keyword_index[0].at(key));
std::fstream fileH;
int ind = static_cast<int>(m_tstep_range.size()) - 1 ;
while (ind > -1) {
int to_ind = std::get<1>(m_tstep_range[ind]);
fileH.open(m_lodsmry_files[ind], std::ios::in | std::ios::binary);
if (!fileH)
throw std::runtime_error("Can not open file lodFile");
for (size_t n = 0 ; n < stringVect.size(); n++) {
std::string key = stringVect[n];
std::string arrName;
Opm::EclIO::eclArrType arrType;
if ( m_keyword_index[ind].find(key) == m_keyword_index[ind].end() ) {
for (int m = 0; m < to_ind + 1; m++)
m_vectorData[keyIndexVect[n]].push_back(0.0);
} else {
int key_ind = m_keyword_index[ind].at(key);
uint64_t pos = m_lod_offset[ind] + m_lod_arr_size[ind]*static_cast<uint64_t>(key_ind);
pos = pos + static_cast<uint64_t>(key_ind * 24); // adding size of binary headers
fileH.seekg (pos, fileH.beg);
int64_t size;
int sizeOfElement;
readBinaryHeader(fileH, arrName, size, arrType, sizeOfElement);
arrName = Opm::EclIO::trimr(arrName);
std::string checkName = "V" + std::to_string(key_ind);
if (arrName != checkName)
OPM_THROW(std::invalid_argument, "lodsmry, wrong header expecting " + checkName + " found " + arrName);
auto smry_data = readBinaryRealArray(fileH, size);
m_vectorData[keyIndexVect[n]].insert(m_vectorData[keyIndexVect[n]].end(), smry_data.begin(), smry_data.begin() + to_ind + 1);
}
}
fileH.close();
ind--;
}
for (auto kind : keyIndexVect)
m_vectorLoaded[kind] = true;
}
void ExtESmry::loadData()
{
this->loadData(m_keyword);
}
const std::vector<float>& ExtESmry::get(const std::string& name)
{
if ( m_keyword_index[0].find(name) == m_keyword_index[0].end() )
throw std::invalid_argument("summary key '" + name + "' not found");
int index = m_keyword_index[0].at(name);
if (!m_vectorLoaded[index]){
loadData({name});
}
return m_vectorData[index];
}
std::vector<Opm::time_point> ExtESmry::dates() {
double time_unit = 24 * 3600;
std::vector<Opm::time_point> d;
for (const auto& t : this->get("TIME"))
d.push_back( this->m_startdat + std::chrono::duration_cast<std::chrono::seconds>( std::chrono::duration<double, std::chrono::seconds::period>( t * time_unit)));
return d;
}
std::vector<std::string> ExtESmry::keywordList(const std::string& pattern) const
{
std::vector<std::string> list;
for (const auto& key : m_keyword)
if (fnmatch( pattern.c_str(), key.c_str(), 0 ) == 0 )
list.push_back(key);
return list;
}
bool ExtESmry::hasKey(const std::string &key) const
{
return std::find(m_keyword.begin(), m_keyword.end(), key) != m_keyword.end();
}
}} // namespace Opm::ecl