mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-14 09:22:13 -05:00
#7527 HDF Summary Reader : Add first working prototype
HDF5 must be compiled with special options to support multithreading. Disable file object multithreading for HDF5. Some vector types are not supported, as the support in opm-common reader is not complete (region, region_to_region, ...).
This commit is contained in:
1 parent
d082ce7eb1
commit
dd97e7741a
22 files changed
+990
-147
No files matched your search
@@ -356,24 +356,7 @@ std::string RifHdf5Reader::getStringAttribute( H5::H5File file, std::string grou
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::string> RifHdf5Reader::getSubGroupNames( H5::H5File file, std::string baseGroupName ) const
|
||||
{
|
||||
H5::Group baseGroup = file.openGroup( baseGroupName.c_str() );
|
||||
|
||||
std::vector<std::string> subGroupNames;
|
||||
|
||||
hsize_t groupSize = baseGroup.getNumObjs();
|
||||
|
||||
for ( hsize_t i = 0; i < groupSize; i++ )
|
||||
{
|
||||
std::string nodeName( 1024, '\0' );
|
||||
|
||||
ssize_t slen = baseGroup.getObjnameByIdx( i, &nodeName[0], 1023 );
|
||||
|
||||
nodeName.resize( slen + 1 );
|
||||
|
||||
subGroupNames.push_back( nodeName );
|
||||
}
|
||||
|
||||
return subGroupNames;
|
||||
return RifHdf5ReaderTools::getSubGroupNames( &file, baseGroupName );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -412,3 +395,33 @@ void RifHdf5Reader::getElementResultValues( H5::H5File file, std::string groupNa
|
||||
( *resultValues ).resize( dims[0] );
|
||||
dataset.read( resultValues->data(), H5::PredType::NATIVE_DOUBLE );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::string> RifHdf5ReaderTools::getSubGroupNames( H5::H5File* file, const std::string& baseGroupName )
|
||||
{
|
||||
if ( file )
|
||||
{
|
||||
H5::Group baseGroup = file->openGroup( baseGroupName.c_str() );
|
||||
|
||||
std::vector<std::string> subGroupNames;
|
||||
|
||||
hsize_t groupSize = baseGroup.getNumObjs();
|
||||
|
||||
for ( hsize_t i = 0; i < groupSize; i++ )
|
||||
{
|
||||
std::string nodeName( 1024, '\0' );
|
||||
|
||||
ssize_t slen = baseGroup.getObjnameByIdx( i, &nodeName[0], 1023 );
|
||||
|
||||
nodeName.resize( slen + 1 );
|
||||
|
||||
subGroupNames.push_back( nodeName );
|
||||
}
|
||||
|
||||
return subGroupNames;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -24,6 +24,12 @@
|
||||
|
||||
#include "H5Cpp.h"
|
||||
|
||||
class RifHdf5ReaderTools
|
||||
{
|
||||
public:
|
||||
static std::vector<std::string> getSubGroupNames( H5::H5File* file, const std::string& baseGroupName );
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017 Statoil ASA
|
||||
//
|
||||
// ResInsight 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.
|
||||
//
|
||||
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RifHdf5SummaryReader.h"
|
||||
|
||||
#include "RiaLogging.h"
|
||||
#include "RiaQDateTimeTools.h"
|
||||
#include "RiaTimeTTools.h"
|
||||
#include "RifHdf5Reader.h"
|
||||
|
||||
#include "H5Cpp.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RifHdf5SummaryReader::RifHdf5SummaryReader( const QString& fileName )
|
||||
{
|
||||
try
|
||||
{
|
||||
m_hdfFile = new H5::H5File( fileName.toStdString().c_str(), H5F_ACC_RDONLY );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
RiaLogging::error( "Failed to open HDF file " + fileName );
|
||||
|
||||
delete m_hdfFile;
|
||||
m_hdfFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RifHdf5SummaryReader::~RifHdf5SummaryReader()
|
||||
{
|
||||
if ( m_hdfFile )
|
||||
{
|
||||
m_hdfFile->close();
|
||||
|
||||
delete m_hdfFile;
|
||||
m_hdfFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RifHdf5SummaryReader::isValid() const
|
||||
{
|
||||
return ( m_hdfFile != nullptr );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::string> RifHdf5SummaryReader::vectorNames()
|
||||
{
|
||||
if ( m_hdfFile )
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
|
||||
auto groupNames = RifHdf5ReaderTools::getSubGroupNames( m_hdfFile, "summary_vectors" );
|
||||
names.reserve( groupNames.size() );
|
||||
for ( const auto& name : groupNames )
|
||||
{
|
||||
names.push_back( name );
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<time_t> RifHdf5SummaryReader::timeSteps() const
|
||||
{
|
||||
std::vector<time_t> times;
|
||||
|
||||
// TODO: This function uses code taken from ESmry::dates(). There is conversion from time_t to
|
||||
// chrono::system_clock::time_points, and then back to time_t again. Consider using one representation
|
||||
|
||||
double time_unit = 24 * 3600;
|
||||
|
||||
using namespace std::chrono;
|
||||
using TP = time_point<system_clock>;
|
||||
using DoubSec = duration<double, seconds::period>;
|
||||
|
||||
auto timeDeltasInDays = values( "TIME" );
|
||||
|
||||
std::vector<std::chrono::system_clock::time_point> timePoints;
|
||||
|
||||
TP startDat = std::chrono::system_clock::from_time_t( startDate() );
|
||||
|
||||
timePoints.reserve( timeDeltasInDays.size() );
|
||||
for ( const auto& t : timeDeltasInDays )
|
||||
{
|
||||
timePoints.push_back( startDat + duration_cast<TP::duration>( DoubSec( t * time_unit ) ) );
|
||||
}
|
||||
|
||||
for ( const auto& d : timePoints )
|
||||
{
|
||||
auto timeAsTimeT = std::chrono::system_clock::to_time_t( d );
|
||||
times.push_back( timeAsTimeT );
|
||||
}
|
||||
|
||||
return times;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<double> RifHdf5SummaryReader::values( const std::string& vectorName, int smspecKeywordIndex ) const
|
||||
{
|
||||
if ( m_hdfFile )
|
||||
{
|
||||
try
|
||||
{
|
||||
H5::Exception::dontPrint(); // Turn off auto-printing of failures to handle the errors appropriately
|
||||
|
||||
std::string idText = std::to_string( smspecKeywordIndex );
|
||||
|
||||
std::string groupPath = "summary_vectors/" + vectorName + "/" + idText;
|
||||
|
||||
{
|
||||
H5::Group generalGroup = m_hdfFile->openGroup( groupPath.c_str() );
|
||||
H5::DataSet dataset = H5::DataSet( generalGroup.openDataSet( "values" ) );
|
||||
|
||||
hsize_t dims[2];
|
||||
H5::DataSpace dataspace = dataset.getSpace();
|
||||
dataspace.getSimpleExtentDims( dims, nullptr );
|
||||
|
||||
std::vector<double> values;
|
||||
values.resize( dims[0] );
|
||||
dataset.read( values.data(), H5::PredType::NATIVE_DOUBLE );
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<double> RifHdf5SummaryReader::values( const std::string& vectorName ) const
|
||||
{
|
||||
if ( m_hdfFile )
|
||||
{
|
||||
try
|
||||
{
|
||||
H5::Exception::dontPrint(); // Turn off auto-printing of failures to handle the errors appropriately
|
||||
|
||||
std::string groupPath = "summary_vectors/" + vectorName;
|
||||
|
||||
auto groupNames = RifHdf5ReaderTools::getSubGroupNames( m_hdfFile, groupPath );
|
||||
if ( !groupNames.empty() )
|
||||
{
|
||||
groupPath = groupPath + "/" + groupNames[0];
|
||||
|
||||
H5::Group generalGroup = m_hdfFile->openGroup( groupPath.c_str() );
|
||||
H5::DataSet dataset = H5::DataSet( generalGroup.openDataSet( "values" ) );
|
||||
|
||||
hsize_t dims[2];
|
||||
H5::DataSpace dataspace = dataset.getSpace();
|
||||
dataspace.getSimpleExtentDims( dims, nullptr );
|
||||
|
||||
std::vector<double> values;
|
||||
values.resize( dims[0] );
|
||||
dataset.read( values.data(), H5::PredType::NATIVE_DOUBLE );
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
time_t RifHdf5SummaryReader::startDate() const
|
||||
{
|
||||
if ( m_hdfFile )
|
||||
{
|
||||
try
|
||||
{
|
||||
H5::Exception::dontPrint(); // Turn off auto-printing of failures to handle the errors appropriately
|
||||
|
||||
QString groupPath = QString( "general" );
|
||||
|
||||
H5::Group GridFunction_00002 = m_hdfFile->openGroup( groupPath.toStdString().c_str() );
|
||||
H5::DataSet dataset = H5::DataSet( GridFunction_00002.openDataSet( "start_date" ) );
|
||||
|
||||
hsize_t dims[2];
|
||||
H5::DataSpace dataspace = dataset.getSpace();
|
||||
dataspace.getSimpleExtentDims( dims, nullptr );
|
||||
|
||||
std::vector<int> values;
|
||||
values.resize( dims[0] );
|
||||
dataset.read( values.data(), H5::PredType::NATIVE_INT );
|
||||
|
||||
int day = values[0];
|
||||
int month = values[1];
|
||||
int year = values[2];
|
||||
|
||||
QDateTime reportDateTime = RiaQDateTimeTools::createUtcDateTime( QDate( year, month, day ) );
|
||||
|
||||
time_t myTime = RiaTimeTTools::fromQDateTime( reportDateTime );
|
||||
return myTime;
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
}
|
||||
|
||||
RiaLogging::error( "Not able to read start_date from HDF5 " );
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017 Statoil ASA
|
||||
//
|
||||
// ResInsight 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.
|
||||
//
|
||||
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "H5Cpp.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class QString;
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RifHdf5SummaryReader
|
||||
{
|
||||
public:
|
||||
explicit RifHdf5SummaryReader( const QString& fileName );
|
||||
~RifHdf5SummaryReader();
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
std::vector<std::string> vectorNames();
|
||||
std::vector<time_t> timeSteps() const;
|
||||
|
||||
std::vector<double> values( const std::string& vectorName, int smspecKeywordIndex ) const;
|
||||
std::vector<double> values( const std::string& vectorName ) const;
|
||||
|
||||
private:
|
||||
time_t startDate() const;
|
||||
|
||||
private:
|
||||
H5::H5File* m_hdfFile;
|
||||
};
|
||||
@@ -79,9 +79,11 @@ size_t RifOpmCommonEclipseSummary::numberOfLodFilesCreated()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RifOpmCommonEclipseSummary::open( const QString& headerFileName, bool includeRestartFiles )
|
||||
bool RifOpmCommonEclipseSummary::open( const QString& headerFileName,
|
||||
bool includeRestartFiles,
|
||||
RiaThreadSafeLogger* threadSafeLogger )
|
||||
{
|
||||
if ( !openESmryFile( headerFileName, includeRestartFiles ) ) return false;
|
||||
if ( !openESmryFile( headerFileName, includeRestartFiles, threadSafeLogger ) ) return false;
|
||||
|
||||
if ( m_createLodsmryFiles && !includeRestartFiles )
|
||||
{
|
||||
@@ -96,7 +98,7 @@ bool RifOpmCommonEclipseSummary::open( const QString& headerFileName, bool inclu
|
||||
// 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.
|
||||
|
||||
if ( !openESmryFile( headerFileName, includeRestartFiles ) ) return false;
|
||||
if ( !openESmryFile( headerFileName, includeRestartFiles, threadSafeLogger ) ) return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,25 +181,19 @@ void RifOpmCommonEclipseSummary::buildMetaData()
|
||||
m_timeSteps.push_back( timeAsTimeT );
|
||||
}
|
||||
|
||||
auto nodes = m_eSmry->summaryNodeList();
|
||||
for ( size_t i = 0; i < nodes.size(); i++ )
|
||||
{
|
||||
auto summaryNode = nodes[i];
|
||||
auto eclAdr = createAddressFromSummaryNode( summaryNode, m_eSmry.get() );
|
||||
auto [addresses, addressMap] = RifOpmCommonSummaryTools::buildMetaData( m_eSmry.get() );
|
||||
|
||||
if ( eclAdr.isValid() )
|
||||
{
|
||||
m_allResultAddresses.insert( eclAdr );
|
||||
m_adrToSummaryNodeIndex[eclAdr] = i;
|
||||
}
|
||||
}
|
||||
m_allResultAddresses = addresses;
|
||||
m_adrToSummaryNodeIndex = addressMap;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RifOpmCommonEclipseSummary::openESmryFile( const QString& headerFileName, bool includeRestartFiles )
|
||||
bool RifOpmCommonEclipseSummary::openESmryFile( const QString& headerFileName,
|
||||
bool includeRestartFiles,
|
||||
RiaThreadSafeLogger* threadSafeLogger )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -207,7 +203,8 @@ bool RifOpmCommonEclipseSummary::openESmryFile( const QString& headerFileName, b
|
||||
catch ( std::exception& e )
|
||||
{
|
||||
QString txt = QString( "Optimized Summary Reader error : %1" ).arg( e.what() );
|
||||
RiaLogging::error( txt );
|
||||
|
||||
if ( threadSafeLogger ) threadSafeLogger->error( txt );
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -228,43 +225,43 @@ void RifOpmCommonEclipseSummary::increaseLodFileCount()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RifEclipseSummaryAddress RifOpmCommonEclipseSummary::createAddressFromSummaryNode( const Opm::EclIO::SummaryNode& node,
|
||||
Opm::EclIO::ESmry* summaryFile )
|
||||
RifEclipseSummaryAddress RifOpmCommonSummaryTools::createAddressFromSummaryNode( const Opm::EclIO::SummaryNode& summaryNode,
|
||||
const Opm::EclIO::ESmry* summaryFile )
|
||||
{
|
||||
int i = -1;
|
||||
int j = -1;
|
||||
int k = -1;
|
||||
|
||||
switch ( node.category )
|
||||
switch ( summaryNode.category )
|
||||
{
|
||||
case Opm::EclIO::SummaryNode::Category::Aquifer:
|
||||
return RifEclipseSummaryAddress::aquiferAddress( node.keyword, node.number );
|
||||
return RifEclipseSummaryAddress::aquiferAddress( summaryNode.keyword, summaryNode.number );
|
||||
break;
|
||||
case Opm::EclIO::SummaryNode::Category::Well:
|
||||
return RifEclipseSummaryAddress::wellAddress( node.keyword, node.wgname );
|
||||
return RifEclipseSummaryAddress::wellAddress( summaryNode.keyword, summaryNode.wgname );
|
||||
break;
|
||||
case Opm::EclIO::SummaryNode::Category::Group:
|
||||
return RifEclipseSummaryAddress::wellGroupAddress( node.keyword, node.wgname );
|
||||
return RifEclipseSummaryAddress::wellGroupAddress( summaryNode.keyword, summaryNode.wgname );
|
||||
break;
|
||||
case Opm::EclIO::SummaryNode::Category::Field:
|
||||
return RifEclipseSummaryAddress::fieldAddress( node.keyword );
|
||||
return RifEclipseSummaryAddress::fieldAddress( summaryNode.keyword );
|
||||
break;
|
||||
case Opm::EclIO::SummaryNode::Category::Region:
|
||||
return RifEclipseSummaryAddress::regionAddress( node.keyword, node.number );
|
||||
return RifEclipseSummaryAddress::regionAddress( summaryNode.keyword, summaryNode.number );
|
||||
break;
|
||||
case Opm::EclIO::SummaryNode::Category::Block:
|
||||
summaryFile->ijk_from_global_index( node.number, i, j, k );
|
||||
return RifEclipseSummaryAddress::blockAddress( node.keyword, i, j, k );
|
||||
summaryFile->ijk_from_global_index( summaryNode.number, i, j, k );
|
||||
return RifEclipseSummaryAddress::blockAddress( summaryNode.keyword, i, j, k );
|
||||
break;
|
||||
case Opm::EclIO::SummaryNode::Category::Connection:
|
||||
summaryFile->ijk_from_global_index( node.number, i, j, k );
|
||||
return RifEclipseSummaryAddress::wellCompletionAddress( node.keyword, node.wgname, i, j, k );
|
||||
summaryFile->ijk_from_global_index( summaryNode.number, i, j, k );
|
||||
return RifEclipseSummaryAddress::wellCompletionAddress( summaryNode.keyword, summaryNode.wgname, i, j, k );
|
||||
break;
|
||||
case Opm::EclIO::SummaryNode::Category::Segment:
|
||||
return RifEclipseSummaryAddress::wellSegmentAddress( node.keyword, node.wgname, node.number );
|
||||
return RifEclipseSummaryAddress::wellSegmentAddress( summaryNode.keyword, summaryNode.wgname, summaryNode.number );
|
||||
break;
|
||||
case Opm::EclIO::SummaryNode::Category::Miscellaneous:
|
||||
return RifEclipseSummaryAddress::miscAddress( node.keyword );
|
||||
return RifEclipseSummaryAddress::miscAddress( summaryNode.keyword );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -272,3 +269,31 @@ RifEclipseSummaryAddress RifOpmCommonEclipseSummary::createAddressFromSummaryNod
|
||||
|
||||
return RifEclipseSummaryAddress();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::pair<std::set<RifEclipseSummaryAddress>, std::map<RifEclipseSummaryAddress, size_t>>
|
||||
RifOpmCommonSummaryTools::buildMetaData( const Opm::EclIO::ESmry* summaryFile )
|
||||
{
|
||||
std::set<RifEclipseSummaryAddress> addresses;
|
||||
std::map<RifEclipseSummaryAddress, size_t> addressToNodeIndexMap;
|
||||
|
||||
if ( summaryFile )
|
||||
{
|
||||
auto nodes = summaryFile->summaryNodeList();
|
||||
for ( size_t i = 0; i < nodes.size(); i++ )
|
||||
{
|
||||
auto summaryNode = nodes[i];
|
||||
auto eclAdr = createAddressFromSummaryNode( summaryNode, summaryFile );
|
||||
|
||||
if ( eclAdr.isValid() )
|
||||
{
|
||||
addresses.insert( eclAdr );
|
||||
addressToNodeIndexMap[eclAdr] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { addresses, addressToNodeIndexMap };
|
||||
}
|
||||
@@ -41,6 +41,18 @@ namespace EclIO
|
||||
} // namespace EclIO
|
||||
} // namespace Opm
|
||||
|
||||
class RiaThreadSafeLogger;
|
||||
|
||||
class RifOpmCommonSummaryTools
|
||||
{
|
||||
public:
|
||||
static RifEclipseSummaryAddress createAddressFromSummaryNode( const Opm::EclIO::SummaryNode& summaryNode,
|
||||
const Opm::EclIO::ESmry* summaryFile );
|
||||
|
||||
static std::pair<std::set<RifEclipseSummaryAddress>, std::map<RifEclipseSummaryAddress, size_t>>
|
||||
buildMetaData( const Opm::EclIO::ESmry* summaryFile );
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
@@ -57,7 +69,7 @@ public:
|
||||
static void resetLodCount();
|
||||
static size_t numberOfLodFilesCreated();
|
||||
|
||||
bool open( const QString& headerFileName, bool includeRestartFiles );
|
||||
bool open( const QString& headerFileName, bool includeRestartFiles, RiaThreadSafeLogger* threadSafeLogger );
|
||||
|
||||
const std::vector<time_t>& timeSteps( const RifEclipseSummaryAddress& resultAddress ) const override;
|
||||
bool values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const override;
|
||||
@@ -66,13 +78,10 @@ public:
|
||||
|
||||
private:
|
||||
void buildMetaData();
|
||||
bool openESmryFile( const QString& headerFileName, bool includeRestartFiles );
|
||||
bool openESmryFile( const QString& headerFileName, bool includeRestartFiles, RiaThreadSafeLogger* threadSafeLogger );
|
||||
|
||||
static void increaseLodFileCount();
|
||||
|
||||
static RifEclipseSummaryAddress createAddressFromSummaryNode( const Opm::EclIO::SummaryNode& summaryNode,
|
||||
Opm::EclIO::ESmry* summaryFile );
|
||||
|
||||
private:
|
||||
std::unique_ptr<Opm::EclIO::ESmry> m_eSmry;
|
||||
std::vector<std::string> m_eSmryKeywords;
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2021- Equinor ASA
|
||||
//
|
||||
// ResInsight 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.
|
||||
//
|
||||
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RifOpmHdf5Summary.h"
|
||||
|
||||
#include "RiaLogging.h"
|
||||
|
||||
#include "RifHdf5SummaryReader.h"
|
||||
#include "RifOpmCommonSummary.h"
|
||||
|
||||
#include "opm/io/eclipse/ESmry.hpp"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#ifdef USE_OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RifOpmHdf5Summary::RifOpmHdf5Summary()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RifOpmHdf5Summary::~RifOpmHdf5Summary()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RifOpmHdf5Summary::open( const QString& headerFileName, bool includeRestartFiles, RiaThreadSafeLogger* threadSafeLogger )
|
||||
{
|
||||
if ( !openESmryFile( headerFileName, includeRestartFiles, threadSafeLogger ) )
|
||||
{
|
||||
QString errorTxt = "Failed to open " + headerFileName;
|
||||
|
||||
if ( threadSafeLogger ) threadSafeLogger->error( errorTxt );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo fi( headerFileName );
|
||||
QString hdfFileName = fi.absolutePath() + "/" + fi.baseName() + ".h5";
|
||||
|
||||
if ( !QFile::exists( hdfFileName ) )
|
||||
{
|
||||
QString errorTxt = "Failed to open H5 file " + hdfFileName;
|
||||
if ( threadSafeLogger ) threadSafeLogger->error( errorTxt );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_hdf5Reader = std::make_unique<RifHdf5SummaryReader>( hdfFileName );
|
||||
|
||||
if ( !m_eSmry || !m_hdf5Reader ) return false;
|
||||
|
||||
buildMetaData();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<time_t>& RifOpmHdf5Summary::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
|
||||
{
|
||||
return m_timeSteps;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RifOpmHdf5Summary::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
|
||||
{
|
||||
if ( m_eSmry && m_hdf5Reader )
|
||||
{
|
||||
auto it = m_adrToSummaryNodeIndex.find( resultAddress );
|
||||
if ( it != m_adrToSummaryNodeIndex.end() )
|
||||
{
|
||||
size_t index = it->second;
|
||||
auto node = m_eSmry->summaryNodeList()[index];
|
||||
|
||||
int smspecIndex = static_cast<int>( node.smspecKeywordIndex );
|
||||
const auto& vectorName = resultAddress.quantityName();
|
||||
|
||||
*values = m_hdf5Reader->values( vectorName, smspecIndex );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string RifOpmHdf5Summary::unitName( const RifEclipseSummaryAddress& resultAddress ) const
|
||||
{
|
||||
if ( m_eSmry )
|
||||
{
|
||||
auto it = m_adrToSummaryNodeIndex.find( resultAddress );
|
||||
if ( it != m_adrToSummaryNodeIndex.end() )
|
||||
{
|
||||
auto index = it->second;
|
||||
auto node = m_eSmry->summaryNodeList()[index];
|
||||
return m_eSmry->get_unit( node );
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaDefines::EclipseUnitSystem RifOpmHdf5Summary::unitSystem() const
|
||||
{
|
||||
// TODO: Not implemented
|
||||
return RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RifOpmHdf5Summary::buildMetaData()
|
||||
{
|
||||
if ( m_eSmry )
|
||||
{
|
||||
// Get time step data from HDF
|
||||
if ( m_hdf5Reader )
|
||||
{
|
||||
m_timeSteps = m_hdf5Reader->timeSteps();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback to using opm-reader for time step data
|
||||
std::vector<std::chrono::system_clock::time_point> timePoints;
|
||||
timePoints = m_eSmry->dates();
|
||||
|
||||
for ( const auto& d : timePoints )
|
||||
{
|
||||
auto timeAsTimeT = std::chrono::system_clock::to_time_t( d );
|
||||
m_timeSteps.push_back( timeAsTimeT );
|
||||
}
|
||||
}
|
||||
|
||||
auto [addresses, addressMap] = RifOpmCommonSummaryTools::buildMetaData( m_eSmry.get() );
|
||||
|
||||
m_allResultAddresses = addresses;
|
||||
m_adrToSummaryNodeIndex = addressMap;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RifOpmHdf5Summary::openESmryFile( const QString& headerFileName,
|
||||
bool includeRestartFiles,
|
||||
RiaThreadSafeLogger* threadSafeLogger )
|
||||
{
|
||||
try
|
||||
{
|
||||
m_eSmry = std::make_unique<Opm::EclIO::ESmry>( headerFileName.toStdString(), includeRestartFiles, false );
|
||||
}
|
||||
catch ( std::exception& e )
|
||||
{
|
||||
QString txt = QString( "Optimized Summary Reader error : %1" ).arg( e.what() );
|
||||
|
||||
if ( threadSafeLogger ) threadSafeLogger->error( txt );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2021- Equinor ASA
|
||||
//
|
||||
// ResInsight 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.
|
||||
//
|
||||
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RiaDefines.h"
|
||||
|
||||
#include "RifEclipseSummaryAddress.h"
|
||||
#include "RifSummaryReaderInterface.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class RifHdf5SummaryReader;
|
||||
class RiaThreadSafeLogger;
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
namespace EclIO
|
||||
{
|
||||
class ESmry;
|
||||
struct SummaryNode;
|
||||
} // namespace EclIO
|
||||
} // namespace Opm
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RifOpmHdf5Summary : public RifSummaryReaderInterface
|
||||
{
|
||||
public:
|
||||
RifOpmHdf5Summary();
|
||||
~RifOpmHdf5Summary();
|
||||
|
||||
bool open( const QString& headerFileName, bool includeRestartFiles, RiaThreadSafeLogger* threadSafeLogger );
|
||||
|
||||
const std::vector<time_t>& timeSteps( const RifEclipseSummaryAddress& resultAddress ) const override;
|
||||
bool values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const override;
|
||||
std::string unitName( const RifEclipseSummaryAddress& resultAddress ) const override;
|
||||
RiaDefines::EclipseUnitSystem unitSystem() const override;
|
||||
|
||||
private:
|
||||
void buildMetaData();
|
||||
bool openESmryFile( const QString& headerFileName, bool includeRestartFiles, RiaThreadSafeLogger* threadSafeLogger );
|
||||
|
||||
private:
|
||||
std::unique_ptr<Opm::EclIO::ESmry> m_eSmry;
|
||||
std::vector<std::string> m_eSmryKeywords;
|
||||
std::map<RifEclipseSummaryAddress, size_t> m_adrToSummaryNodeIndex;
|
||||
std::vector<time_t> m_timeSteps;
|
||||
|
||||
std::unique_ptr<RifHdf5SummaryReader> m_hdf5Reader;
|
||||
};
|
||||
@@ -28,6 +28,10 @@
|
||||
#include "RifOpmCommonSummary.h"
|
||||
#include "RifReaderEclipseOutput.h"
|
||||
|
||||
#ifdef USE_HDF5
|
||||
#include "RifOpmHdf5Summary.h"
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
@@ -147,17 +151,33 @@ RifReaderEclipseSummary::~RifReaderEclipseSummary()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RifReaderEclipseSummary::open( const QString& headerFileName, bool includeRestartFiles )
|
||||
bool RifReaderEclipseSummary::open( const QString& headerFileName,
|
||||
bool includeRestartFiles,
|
||||
RiaThreadSafeLogger* threadSafeLogger )
|
||||
{
|
||||
bool useOpmCommonReader = RiaPreferences::current()->useOptimizedSummaryDataReader();
|
||||
bool isValid = false;
|
||||
|
||||
if ( useOpmCommonReader )
|
||||
// Try to create readers. If HDF5 or Opm readers fails to create, use ecllib reader
|
||||
|
||||
if ( RiaPreferences::current()->summaryDataReader() == RiaPreferences::SummaryReaderMode::HDF5_OPM_COMMON )
|
||||
{
|
||||
#ifdef USE_HDF5
|
||||
auto hdfReader = std::make_unique<RifOpmHdf5Summary>();
|
||||
|
||||
isValid = hdfReader->open( headerFileName, false, threadSafeLogger );
|
||||
if ( isValid )
|
||||
{
|
||||
m_hdf5OpmReader = std::move( hdfReader );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if ( RiaPreferences::current()->summaryDataReader() == RiaPreferences::SummaryReaderMode::OPM_COMMON )
|
||||
{
|
||||
bool useLodsmryFiles = RiaPreferences::current()->useOptimizedSummaryDataFiles();
|
||||
if ( useLodsmryFiles && includeRestartFiles )
|
||||
{
|
||||
RiaLogging::error(
|
||||
"LODSMRY file loading for summary restart files is not supported. Disable one of the options" );
|
||||
QString txt = "LODSMRY file loading for summary restart files is not supported. Disable one of the options";
|
||||
if ( threadSafeLogger ) threadSafeLogger->error( txt );
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -166,29 +186,33 @@ bool RifReaderEclipseSummary::open( const QString& headerFileName, bool includeR
|
||||
|
||||
m_opmCommonReader->useLodsmaryFiles( RiaPreferences::current()->useOptimizedSummaryDataFiles() );
|
||||
m_opmCommonReader->createLodsmaryFiles( RiaPreferences::current()->createOptimizedSummaryDataFiles() );
|
||||
m_opmCommonReader->open( headerFileName, includeRestartFiles );
|
||||
|
||||
buildMetaData();
|
||||
|
||||
return true;
|
||||
isValid = m_opmCommonReader->open( headerFileName, includeRestartFiles, threadSafeLogger );
|
||||
if ( !isValid ) m_opmCommonReader.reset();
|
||||
}
|
||||
|
||||
assert( m_ecl_sum == nullptr );
|
||||
|
||||
m_ecl_sum = openEclSum( headerFileName, includeRestartFiles );
|
||||
|
||||
if ( m_ecl_sum )
|
||||
if ( !isValid || RiaPreferences::current()->summaryDataReader() == RiaPreferences::SummaryReaderMode::LIBECL )
|
||||
{
|
||||
m_timeSteps.clear();
|
||||
m_ecl_SmSpec = ecl_sum_get_smspec( m_ecl_sum );
|
||||
m_timeSteps = getTimeSteps( m_ecl_sum );
|
||||
m_unitSystem = readUnitSystem( m_ecl_sum );
|
||||
buildMetaData();
|
||||
assert( m_ecl_sum == nullptr );
|
||||
|
||||
return true;
|
||||
m_ecl_sum = openEclSum( headerFileName, includeRestartFiles );
|
||||
|
||||
if ( m_ecl_sum )
|
||||
{
|
||||
m_timeSteps.clear();
|
||||
m_ecl_SmSpec = ecl_sum_get_smspec( m_ecl_sum );
|
||||
m_timeSteps = getTimeSteps( m_ecl_sum );
|
||||
m_unitSystem = readUnitSystem( m_ecl_sum );
|
||||
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if ( isValid )
|
||||
{
|
||||
buildMetaData();
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -455,11 +479,11 @@ RifEclipseSummaryAddress addressFromErtSmSpecNode( const ecl::smspec_node& ertSu
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RifReaderEclipseSummary::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
|
||||
{
|
||||
CVF_ASSERT( values );
|
||||
|
||||
values->clear();
|
||||
values->reserve( timeStepCount() );
|
||||
|
||||
// assert( m_ecl_sum != nullptr );
|
||||
|
||||
const std::vector<double>& cachedValues = m_valuesCache->getValues( resultAddress );
|
||||
if ( !cachedValues.empty() )
|
||||
{
|
||||
@@ -468,12 +492,21 @@ bool RifReaderEclipseSummary::values( const RifEclipseSummaryAddress& resultAddr
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( m_hdf5OpmReader )
|
||||
{
|
||||
auto status = m_hdf5OpmReader->values( resultAddress, values );
|
||||
|
||||
if ( status ) m_valuesCache->insertValues( resultAddress, *values );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if ( m_opmCommonReader )
|
||||
{
|
||||
m_opmCommonReader->values( resultAddress, values );
|
||||
m_valuesCache->insertValues( resultAddress, *values );
|
||||
auto status = m_opmCommonReader->values( resultAddress, values );
|
||||
if ( status ) m_valuesCache->insertValues( resultAddress, *values );
|
||||
|
||||
return true;
|
||||
return status;
|
||||
}
|
||||
|
||||
if ( m_ecl_SmSpec )
|
||||
@@ -536,16 +569,7 @@ bool RifReaderEclipseSummary::values( const RifEclipseSummaryAddress& resultAddr
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RifReaderEclipseSummary::timeStepCount() const
|
||||
{
|
||||
if ( m_opmCommonReader )
|
||||
{
|
||||
return m_timeSteps.size();
|
||||
}
|
||||
|
||||
assert( m_ecl_sum != nullptr );
|
||||
|
||||
if ( m_ecl_SmSpec == nullptr ) return 0;
|
||||
|
||||
return static_cast<size_t>( ecl_sum_get_data_length( m_ecl_sum ) );
|
||||
return m_timeSteps.size();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -553,8 +577,6 @@ size_t RifReaderEclipseSummary::timeStepCount() const
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<time_t>& RifReaderEclipseSummary::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
|
||||
{
|
||||
// assert( m_ecl_sum != nullptr );
|
||||
|
||||
return m_timeSteps;
|
||||
}
|
||||
|
||||
@@ -580,6 +602,15 @@ void RifReaderEclipseSummary::buildMetaData()
|
||||
m_allResultAddresses.clear();
|
||||
m_resultAddressToErtNodeIdx.clear();
|
||||
|
||||
if ( m_hdf5OpmReader )
|
||||
{
|
||||
m_allResultAddresses = m_hdf5OpmReader->allResultAddresses();
|
||||
m_allErrorAddresses = m_hdf5OpmReader->allErrorAddresses();
|
||||
|
||||
m_timeSteps = m_hdf5OpmReader->timeSteps( RifEclipseSummaryAddress() );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_opmCommonReader )
|
||||
{
|
||||
m_allResultAddresses = m_opmCommonReader->allResultAddresses();
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <vector>
|
||||
|
||||
class RifOpmCommonEclipseSummary;
|
||||
class RifOpmHdf5Summary;
|
||||
class RiaThreadSafeLogger;
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
@@ -68,7 +70,7 @@ public:
|
||||
RifReaderEclipseSummary();
|
||||
~RifReaderEclipseSummary() override;
|
||||
|
||||
bool open( const QString& headerFileName, bool includeRestartFiles );
|
||||
bool open( const QString& headerFileName, bool includeRestartFiles, RiaThreadSafeLogger* threadSafeLogger );
|
||||
|
||||
std::vector<RifRestartFileInfo> getRestartFiles( const QString& headerFileName, bool* hasWarnings );
|
||||
RifRestartFileInfo getFileInfo( const QString& headerFileName );
|
||||
@@ -107,6 +109,7 @@ private:
|
||||
std::set<RifEclipseSummaryAddress> m_differenceAddresses;
|
||||
|
||||
std::unique_ptr<RifOpmCommonEclipseSummary> m_opmCommonReader;
|
||||
std::unique_ptr<RifSummaryReaderInterface> m_hdf5OpmReader;
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
|
||||
Reference in new issue
Block a user