diff --git a/ApplicationLibCode/Application/RiaPreferences.cpp b/ApplicationLibCode/Application/RiaPreferences.cpp index 926c0b4d21..0cdbadbaf0 100644 --- a/ApplicationLibCode/Application/RiaPreferences.cpp +++ b/ApplicationLibCode/Application/RiaPreferences.cpp @@ -81,6 +81,15 @@ void RiaPreferences::PageOrientationEnum::setUp() addItem( QPageLayout::Landscape, "LANDSCAPE", "Landscape" ); setDefault( QPageLayout::Portrait ); } + +template <> +void RiaPreferences::SummaryReaderModeType::setUp() +{ + addItem( RiaPreferences::SummaryReaderMode::LIBECL, "LIBECL", "Default Reader (ecl)" ); + addItem( RiaPreferences::SummaryReaderMode::HDF5_OPM_COMMON, "HDF5_OPM_COMMON", "[BETA] H5 Reader (HDF5 Eclipse)" ); + addItem( RiaPreferences::SummaryReaderMode::OPM_COMMON, "OPM_COMMON", "[BETA] Performance Reader (omp-common)" ); + setDefault( RiaPreferences::SummaryReaderMode::LIBECL ); +} } // namespace caf CAF_PDM_SOURCE_INIT( RiaPreferences, "RiaPreferences" ); @@ -88,7 +97,7 @@ CAF_PDM_SOURCE_INIT( RiaPreferences, "RiaPreferences" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiaPreferences::RiaPreferences( void ) +RiaPreferences::RiaPreferences() { CAF_PDM_InitField( &m_navigationPolicy, "navigationPolicy", @@ -404,15 +413,6 @@ RiaPreferences::RiaPreferences( void ) CAF_PDM_InitFieldNoDefault( &m_guiTheme, "guiTheme", "GUI theme", "", "", "" ); - CAF_PDM_InitField( &m_useOptimizedSummaryDataFileReader, - "useOptimizedSummaryDataFileReader", - false, - "Use Optimized Summary Data Reader [BETA]", - "", - "", - "" ); - m_useOptimizedSummaryDataFileReader.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); - CAF_PDM_InitField( &m_createOptimizedSummaryDataFile, "createOptimizedSummaryDataFile", true, @@ -430,12 +430,14 @@ RiaPreferences::RiaPreferences( void ) "If not present, read optimized file with extension '*.LODSMRY'", "" ); m_useOptimizedSummaryDataFile.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); + + CAF_PDM_InitFieldNoDefault( &m_summaryReader, "summaryReaderType", "Summary Data File Reader", "", "", "" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiaPreferences::~RiaPreferences( void ) +RiaPreferences::~RiaPreferences() { delete m_readerSettings; } @@ -471,14 +473,14 @@ void RiaPreferences::defineEditorAttribute( const caf::PdmFieldHandle* field, if ( field == &octaveShowHeaderInfoWhenExecutingScripts || field == &autocomputeDepthRelatedProperties || field == &loadAndShowSoil || field == &m_useShaders || field == &m_showHud || - field == &m_appendClassNameToUiText || field == &m_appendFieldKeywordToToolTipText || field == &m_showTestToolbar || - field == &m_includeFractureDebugInfoFile || field == &showLasCurveWithoutTvdWarning || - field == &holoLensDisableCertificateVerification || field == &m_showProjectChangedDialog || - field == &m_searchPlotTemplateFoldersRecursively || field == &m_showLegendBackground || - field == &m_showSummaryTimeAsLongString || field == &m_showViewIdInProjectTree || - field == &m_useMultipleThreadsWhenLoadingSummaryData || field == &m_enableFaultsByDefault || - field == &m_showProgressBar || field == &m_openExportedPdfInViewer || field == &m_showInfoBox || - field == &m_showGridBox || field == &m_useUndoRedo || field == &m_useOptimizedSummaryDataFileReader || + field == &m_appendClassNameToUiText || field == &m_appendFieldKeywordToToolTipText || + field == &m_showTestToolbar || field == &m_includeFractureDebugInfoFile || + field == &showLasCurveWithoutTvdWarning || field == &holoLensDisableCertificateVerification || + field == &m_showProjectChangedDialog || field == &m_searchPlotTemplateFoldersRecursively || + field == &m_showLegendBackground || field == &m_showSummaryTimeAsLongString || + field == &m_showViewIdInProjectTree || field == &m_useMultipleThreadsWhenLoadingSummaryData || + field == &m_enableFaultsByDefault || field == &m_showProgressBar || field == &m_openExportedPdfInViewer || + field == &m_showInfoBox || field == &m_showGridBox || field == &m_useUndoRedo || field == &m_createOptimizedSummaryDataFile || field == &m_useOptimizedSummaryDataFile ) { caf::PdmUiCheckBoxEditorAttribute* myAttr = dynamic_cast( attribute ); @@ -608,13 +610,13 @@ void RiaPreferences::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& { caf::PdmUiGroup* group = uiOrdering.addNewGroup( "[BETA] Optimized Summary Reader" ); group->setCollapsedByDefault( true ); - group->add( &m_useOptimizedSummaryDataFileReader ); + group->add( &m_summaryReader ); - group->add( &m_createOptimizedSummaryDataFile ); - group->add( &m_useOptimizedSummaryDataFile ); - - m_createOptimizedSummaryDataFile.uiCapability()->setUiReadOnly( !m_useOptimizedSummaryDataFileReader ); - m_useOptimizedSummaryDataFile.uiCapability()->setUiReadOnly( !m_useOptimizedSummaryDataFileReader ); + if ( m_summaryReader == SummaryReaderMode::OPM_COMMON ) + { + group->add( &m_createOptimizedSummaryDataFile ); + group->add( &m_useOptimizedSummaryDataFile ); + } } } @@ -727,7 +729,21 @@ QList RiaPreferences::calculateValueOptions( const caf:: options.push_back( caf::PdmOptionItemInfo( uiText, QVariant::fromValue( timeFormat ) ) ); } } + else if ( fieldNeedingOptions == &m_summaryReader ) + { + std::vector availableModes; + availableModes.push_back( SummaryReaderMode::LIBECL ); +#ifdef USE_HDF5 + availableModes.push_back( SummaryReaderMode::HDF5_OPM_COMMON ); +#endif // USE_HDF5 + availableModes.push_back( SummaryReaderMode::OPM_COMMON ); + + for ( auto enumValue : availableModes ) + { + options.push_back( caf::PdmOptionItemInfo( SummaryReaderModeType::uiText( enumValue ), enumValue ) ); + } + } return options; } @@ -1214,9 +1230,9 @@ QString RiaPreferences::octaveExecutable() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RiaPreferences::useOptimizedSummaryDataReader() const +RiaPreferences::SummaryReaderMode RiaPreferences::summaryDataReader() const { - return m_useOptimizedSummaryDataFileReader(); + return m_summaryReader(); } //-------------------------------------------------------------------------------------------------- @@ -1224,7 +1240,7 @@ bool RiaPreferences::useOptimizedSummaryDataReader() const //-------------------------------------------------------------------------------------------------- bool RiaPreferences::useOptimizedSummaryDataFiles() const { - return m_useOptimizedSummaryDataFileReader(); + return m_useOptimizedSummaryDataFile(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Application/RiaPreferences.h b/ApplicationLibCode/Application/RiaPreferences.h index fa8db4618d..d6ef38bc62 100644 --- a/ApplicationLibCode/Application/RiaPreferences.h +++ b/ApplicationLibCode/Application/RiaPreferences.h @@ -70,6 +70,14 @@ public: }; typedef caf::AppEnum SummaryHistoryCurveStyleModeType; + enum class SummaryReaderMode + { + LIBECL, + OPM_COMMON, + HDF5_OPM_COMMON + }; + typedef caf::AppEnum SummaryReaderModeType; + typedef caf::AppEnum PageSizeEnum; typedef caf::AppEnum PageOrientationEnum; @@ -139,9 +147,9 @@ public: QString octaveExecutable() const; // Summary readers - bool useOptimizedSummaryDataReader() const; - bool useOptimizedSummaryDataFiles() const; - bool createOptimizedSummaryDataFiles() const; + SummaryReaderMode summaryDataReader() const; + bool useOptimizedSummaryDataFiles() const; + bool createOptimizedSummaryDataFiles() const; public: // Pdm Fields caf::PdmField enableGrpcServer; @@ -249,10 +257,11 @@ private: caf::PdmField m_multiLateralWellPattern; // Summary data - caf::PdmField m_useOptimizedSummaryDataFileReader; caf::PdmField m_createOptimizedSummaryDataFile; caf::PdmField m_useOptimizedSummaryDataFile; + caf::PdmField m_summaryReader; + // 3d view caf::PdmField> m_defaultMeshModeType; caf::PdmField> m_navigationPolicy; diff --git a/ApplicationLibCode/CMakeLists.txt b/ApplicationLibCode/CMakeLists.txt index cc0bce690c..b40cadf649 100644 --- a/ApplicationLibCode/CMakeLists.txt +++ b/ApplicationLibCode/CMakeLists.txt @@ -231,8 +231,15 @@ list(APPEND RI_LIBRARIES RigGeoMechDataModel) # HDF5 # if(RESINSIGHT_FOUND_HDF5) - list(APPEND CPP_SOURCES FileInterface/RifHdf5Reader.h - FileInterface/RifHdf5Reader.cpp) + list( + APPEND + CPP_SOURCES + FileInterface/RifHdf5Reader.h + FileInterface/RifHdf5Reader.cpp + FileInterface/RifHdf5SummaryReader.h + FileInterface/RifHdf5SummaryReader.cpp + FileInterface/RifOpmHdf5Summary.h + FileInterface/RifOpmHdf5Summary.cpp) add_definitions(-DUSE_HDF5) @@ -247,8 +254,15 @@ if(RESINSIGHT_FOUND_HDF5) include_directories(${HDF5_INCLUDE_DIRS}) endif() # MSVC - source_group("FileInterface" FILES FileInterface/RifHdf5Reader.h - FileInterface/RifHdf5Reader.cpp) + source_group( + "FileInterface" + FILES FileInterface/RifHdf5Reader.h + FileInterface/RifHdf5Reader.cpp + FileInterface/RifHdf5SummaryReader.h + FileInterface/RifHdf5SummaryReader.cpp + FileInterface/RifOpmHdf5Summary.h + FileInterface/RifOpmHdf5Summary.cpp) + endif() # ############################################################################## diff --git a/ApplicationLibCode/FileInterface/RifHdf5Reader.cpp b/ApplicationLibCode/FileInterface/RifHdf5Reader.cpp index 7091a7c61e..74c76dfec9 100644 --- a/ApplicationLibCode/FileInterface/RifHdf5Reader.cpp +++ b/ApplicationLibCode/FileInterface/RifHdf5Reader.cpp @@ -356,24 +356,7 @@ std::string RifHdf5Reader::getStringAttribute( H5::H5File file, std::string grou //-------------------------------------------------------------------------------------------------- std::vector RifHdf5Reader::getSubGroupNames( H5::H5File file, std::string baseGroupName ) const { - H5::Group baseGroup = file.openGroup( baseGroupName.c_str() ); - - std::vector 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 RifHdf5ReaderTools::getSubGroupNames( H5::H5File* file, const std::string& baseGroupName ) +{ + if ( file ) + { + H5::Group baseGroup = file->openGroup( baseGroupName.c_str() ); + + std::vector 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 {}; +} diff --git a/ApplicationLibCode/FileInterface/RifHdf5Reader.h b/ApplicationLibCode/FileInterface/RifHdf5Reader.h index a3536dab7a..1bf40de35c 100644 --- a/ApplicationLibCode/FileInterface/RifHdf5Reader.h +++ b/ApplicationLibCode/FileInterface/RifHdf5Reader.h @@ -24,6 +24,12 @@ #include "H5Cpp.h" +class RifHdf5ReaderTools +{ +public: + static std::vector getSubGroupNames( H5::H5File* file, const std::string& baseGroupName ); +}; + //================================================================================================== // // diff --git a/ApplicationLibCode/FileInterface/RifHdf5SummaryReader.cpp b/ApplicationLibCode/FileInterface/RifHdf5SummaryReader.cpp new file mode 100644 index 0000000000..027d1c893f --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifHdf5SummaryReader.cpp @@ -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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RifHdf5SummaryReader.h" + +#include "RiaLogging.h" +#include "RiaQDateTimeTools.h" +#include "RiaTimeTTools.h" +#include "RifHdf5Reader.h" + +#include "H5Cpp.h" + +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +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 RifHdf5SummaryReader::vectorNames() +{ + if ( m_hdfFile ) + { + std::vector 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 RifHdf5SummaryReader::timeSteps() const +{ + std::vector 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; + using DoubSec = duration; + + auto timeDeltasInDays = values( "TIME" ); + + std::vector 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( 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 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 values; + values.resize( dims[0] ); + dataset.read( values.data(), H5::PredType::NATIVE_DOUBLE ); + + return values; + } + } + catch ( ... ) + { + } + } + + return {}; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector 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 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 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 {}; +} diff --git a/ApplicationLibCode/FileInterface/RifHdf5SummaryReader.h b/ApplicationLibCode/FileInterface/RifHdf5SummaryReader.h new file mode 100644 index 0000000000..c4b4ca109f --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifHdf5SummaryReader.h @@ -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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "H5Cpp.h" + +#include +#include + +class QString; + +//================================================================================================== +// +// +//================================================================================================== +class RifHdf5SummaryReader +{ +public: + explicit RifHdf5SummaryReader( const QString& fileName ); + ~RifHdf5SummaryReader(); + + bool isValid() const; + + std::vector vectorNames(); + std::vector timeSteps() const; + + std::vector values( const std::string& vectorName, int smspecKeywordIndex ) const; + std::vector values( const std::string& vectorName ) const; + +private: + time_t startDate() const; + +private: + H5::H5File* m_hdfFile; +}; diff --git a/ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp b/ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp index cf9f330f64..f2a97a0e60 100644 --- a/ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp +++ b/ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp @@ -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::map> + RifOpmCommonSummaryTools::buildMetaData( const Opm::EclIO::ESmry* summaryFile ) +{ + std::set addresses; + std::map 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 }; +} diff --git a/ApplicationLibCode/FileInterface/RifOpmCommonSummary.h b/ApplicationLibCode/FileInterface/RifOpmCommonSummary.h index 3817b74509..02b31b6fe2 100644 --- a/ApplicationLibCode/FileInterface/RifOpmCommonSummary.h +++ b/ApplicationLibCode/FileInterface/RifOpmCommonSummary.h @@ -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::map> + 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& timeSteps( const RifEclipseSummaryAddress& resultAddress ) const override; bool values( const RifEclipseSummaryAddress& resultAddress, std::vector* 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 m_eSmry; std::vector m_eSmryKeywords; diff --git a/ApplicationLibCode/FileInterface/RifOpmHdf5Summary.cpp b/ApplicationLibCode/FileInterface/RifOpmHdf5Summary.cpp new file mode 100644 index 0000000000..8c76e6981d --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifOpmHdf5Summary.cpp @@ -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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RifOpmHdf5Summary.h" + +#include "RiaLogging.h" + +#include "RifHdf5SummaryReader.h" +#include "RifOpmCommonSummary.h" + +#include "opm/io/eclipse/ESmry.hpp" + +#include + +#ifdef USE_OPENMP +#include +#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( hdfFileName ); + + if ( !m_eSmry || !m_hdf5Reader ) return false; + + buildMetaData(); + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RifOpmHdf5Summary::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const +{ + return m_timeSteps; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifOpmHdf5Summary::values( const RifEclipseSummaryAddress& resultAddress, std::vector* 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( 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 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( 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; +} diff --git a/ApplicationLibCode/FileInterface/RifOpmHdf5Summary.h b/ApplicationLibCode/FileInterface/RifOpmHdf5Summary.h new file mode 100644 index 0000000000..366eb78e8a --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifOpmHdf5Summary.h @@ -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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaDefines.h" + +#include "RifEclipseSummaryAddress.h" +#include "RifSummaryReaderInterface.h" + +#include +#include + +#include +#include +#include +#include +#include + +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& timeSteps( const RifEclipseSummaryAddress& resultAddress ) const override; + bool values( const RifEclipseSummaryAddress& resultAddress, std::vector* 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 m_eSmry; + std::vector m_eSmryKeywords; + std::map m_adrToSummaryNodeIndex; + std::vector m_timeSteps; + + std::unique_ptr m_hdf5Reader; +}; diff --git a/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.cpp b/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.cpp index dcd2241e68..419ddf3ed5 100644 --- a/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.cpp +++ b/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.cpp @@ -28,6 +28,10 @@ #include "RifOpmCommonSummary.h" #include "RifReaderEclipseOutput.h" +#ifdef USE_HDF5 +#include "RifOpmHdf5Summary.h" +#endif + #include #include @@ -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(); + + 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* values ) const { + CVF_ASSERT( values ); + values->clear(); values->reserve( timeStepCount() ); - // assert( m_ecl_sum != nullptr ); - const std::vector& 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( ecl_sum_get_data_length( m_ecl_sum ) ); + return m_timeSteps.size(); } //-------------------------------------------------------------------------------------------------- @@ -553,8 +577,6 @@ size_t RifReaderEclipseSummary::timeStepCount() const //-------------------------------------------------------------------------------------------------- const std::vector& 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(); diff --git a/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.h b/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.h index ad35cf884b..448538f996 100644 --- a/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.h +++ b/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.h @@ -32,6 +32,8 @@ #include 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 getRestartFiles( const QString& headerFileName, bool* hasWarnings ); RifRestartFileInfo getFileInfo( const QString& headerFileName ); @@ -107,6 +109,7 @@ private: std::set m_differenceAddresses; std::unique_ptr m_opmCommonReader; + std::unique_ptr m_hdf5OpmReader; //================================================================================================== // diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.cpp index 04c83dd0a5..e3ec131d1c 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.cpp @@ -85,13 +85,24 @@ void RimFileSummaryCase::updateFilePathsFromProjectPath( const QString& newProje // RimTools::relocateFile( m_summaryHeaderFilename().path(), newProjectPath, oldProjectPath, nullptr, nullptr ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimFileSummaryCase::createSummaryReaderInterfaceThreadSafe( RiaThreadSafeLogger* threadSafeLogger ) +{ + m_summaryFileReader = RimFileSummaryCase::findRelatedFilesAndCreateReader( this->summaryHeaderFilename(), + m_includeRestartFiles, + threadSafeLogger ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFileSummaryCase::createSummaryReaderInterface() { - m_summaryFileReader = - RimFileSummaryCase::findRelatedFilesAndCreateReader( this->summaryHeaderFilename(), m_includeRestartFiles ); + m_summaryFileReader = RimFileSummaryCase::findRelatedFilesAndCreateReader( this->summaryHeaderFilename(), + m_includeRestartFiles, + nullptr ); } //-------------------------------------------------------------------------------------------------- @@ -109,17 +120,16 @@ void RimFileSummaryCase::createRftReaderInterface() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RifReaderEclipseSummary* RimFileSummaryCase::findRelatedFilesAndCreateReader( const QString& headerFileName, - bool includeRestartFiles ) +RifReaderEclipseSummary* RimFileSummaryCase::findRelatedFilesAndCreateReader( const QString& headerFileName, + bool includeRestartFiles, + RiaThreadSafeLogger* threadSafeLogger ) { RifReaderEclipseSummary* summaryFileReader = new RifReaderEclipseSummary; - if ( !summaryFileReader->open( headerFileName, includeRestartFiles ) ) + if ( !summaryFileReader->open( headerFileName, includeRestartFiles, threadSafeLogger ) ) { - RiaLogging::warning( QString( "Failed to open summary file %1" ).arg( headerFileName ) ); - delete summaryFileReader; - summaryFileReader = nullptr; + return nullptr; } return summaryFileReader; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.h b/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.h index 902bb5dfe0..2728511495 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.h @@ -25,6 +25,7 @@ class RifReaderRftInterface; class RifReaderEclipseRft; class RifReaderEclipseSummary; +class RiaThreadSafeLogger; //================================================================================================== // @@ -43,6 +44,7 @@ public: QString caseName() const override; void updateFilePathsFromProjectPath( const QString& newProjectPath, const QString& oldProjectPath ) override; + void createSummaryReaderInterfaceThreadSafe( RiaThreadSafeLogger* threadSafeLogger ); void createSummaryReaderInterface() override; void createRftReaderInterface() override; RifSummaryReaderInterface* summaryReader() override; @@ -50,9 +52,11 @@ public: void setIncludeRestartFiles( bool includeRestartFiles ); - static RifReaderEclipseSummary* findRelatedFilesAndCreateReader( const QString& headerFileName, - bool includeRestartFiles ); - static RifReaderEclipseRft* findRftDataAndCreateReader( const QString& headerFileName ); + static RifReaderEclipseSummary* findRelatedFilesAndCreateReader( const QString& headerFileName, + bool includeRestartFiles, + RiaThreadSafeLogger* threadSafeLogger ); + + static RifReaderEclipseRft* findRftDataAndCreateReader( const QString& headerFileName ); private: cvf::ref m_summaryFileReader; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimGridSummaryCase.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimGridSummaryCase.cpp index 5937160dc2..0abfb23846 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimGridSummaryCase.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimGridSummaryCase.cpp @@ -182,8 +182,9 @@ void RimGridSummaryCase::updateFilePathsFromProjectPath( const QString& newProje //-------------------------------------------------------------------------------------------------- void RimGridSummaryCase::createSummaryReaderInterface() { - m_summaryFileReader = - RimFileSummaryCase::findRelatedFilesAndCreateReader( this->summaryHeaderFilename(), m_includeRestartFiles ); + m_summaryFileReader = RimFileSummaryCase::findRelatedFilesAndCreateReader( this->summaryHeaderFilename(), + m_includeRestartFiles, + nullptr ); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp index 4e4e0615e1..37e300f307 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp @@ -441,18 +441,29 @@ void RimSummaryCaseMainCollection::loadFileSummaryCaseData( std::vectorsummaryDataReader() != RiaPreferences::SummaryReaderMode::HDF5_OPM_COMMON ); + +#pragma omp parallel for schedule( dynamic ) if ( canUseMultipleTreads ) for ( int cIdx = 0; cIdx < static_cast( fileSummaryCases.size() ); ++cIdx ) { RimFileSummaryCase* fileSummaryCase = fileSummaryCases[cIdx]; if ( fileSummaryCase ) { - fileSummaryCase->createSummaryReaderInterface(); + fileSummaryCase->createSummaryReaderInterfaceThreadSafe( &threadSafeLogger ); } progInfo.setProgress( cIdx ); } + for ( const auto& txt : threadSafeLogger.messages() ) + { + RiaLogging::info( txt ); + } + auto numberOfLodFilesCreated = RifOpmCommonEclipseSummary::numberOfLodFilesCreated(); if ( numberOfLodFilesCreated > 0 ) { diff --git a/ApplicationLibCode/UnitTests/HDF5FileReader-Test.cpp b/ApplicationLibCode/UnitTests/HDF5FileReader-Test.cpp index d2fe078084..e66e74ebd1 100644 --- a/ApplicationLibCode/UnitTests/HDF5FileReader-Test.cpp +++ b/ApplicationLibCode/UnitTests/HDF5FileReader-Test.cpp @@ -2,10 +2,130 @@ #include "gtest/gtest.h" +#include "RiaTestDataDirectory.h" +#include "RifHdf5SummaryReader.h" +#include "RifOpmHdf5Summary.h" + #include "H5Cpp.h" + #include -#include +#include "opm/io/eclipse/ESmry.hpp" + +static const QString H5_TEST_DATA_DIRECTORY = QString( "%1/h5-file/" ).arg( TEST_DATA_DIR ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( HDFTests, InspectSummaryData ) +{ + std::string file_path = H5_TEST_DATA_DIRECTORY.toStdString() + "NORNE_ATW2013_RFTPLT_V2.h5"; + + try + { + H5::Exception::dontPrint(); // Turn off auto-printing of failures to handle the errors appropriately + + H5::H5File file( file_path.c_str(), H5F_ACC_RDONLY ); + + { + H5::Group GridFunction_00002 = file.openGroup( "summary_vectors/BPR/66" ); + H5::DataSet dataset = H5::DataSet( GridFunction_00002.openDataSet( "values" ) ); + + hsize_t dims[2]; + H5::DataSpace dataspace = dataset.getSpace(); + dataspace.getSimpleExtentDims( dims, nullptr ); + + std::vector values; + values.resize( dims[0] ); + dataset.read( values.data(), H5::PredType::NATIVE_DOUBLE ); + EXPECT_EQ( size_t( 894 ), values.size() ); + } + } + + catch ( H5::FileIException& error ) // catch failure caused by the H5File operations + { + std::cout << error.getCDetailMsg(); + } + + catch ( H5::DataSetIException& error ) // catch failure caused by the DataSet operations + { + std::cout << error.getCDetailMsg(); + } + + catch ( H5::DataSpaceIException& error ) // catch failure caused by the DataSpace operations + { + std::cout << error.getCDetailMsg(); + } + + catch ( H5::DataTypeIException& error ) // catch failure caused by the DataSpace operations + { + std::cout << error.getCDetailMsg(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( HDFTests, ReadSummaryData ) +{ + QString filePath = H5_TEST_DATA_DIRECTORY + "NORNE_ATW2013_RFTPLT_V2.h5"; + + RifHdf5SummaryReader hdf5SummaryReader( filePath ); + + auto vectorNames = hdf5SummaryReader.vectorNames(); + EXPECT_EQ( size_t( 211 ), vectorNames.size() ); + + auto timeSteps = hdf5SummaryReader.timeSteps(); + EXPECT_EQ( size_t( 894 ), timeSteps.size() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( HDFTests, ReadOpmSummaryData ) +{ + QString filePath = H5_TEST_DATA_DIRECTORY + "NORNE_ATW2013_RFTPLT_V2.SMSPEC"; + + RifOpmHdf5Summary hdf5SummaryReader; + hdf5SummaryReader.open( filePath, false, nullptr ); + + auto addresses = hdf5SummaryReader.allResultAddresses(); + EXPECT_EQ( size_t( 2770 ), addresses.size() ); + + int itemCount = 0; + size_t totalValueCount = 0; + for ( const auto& adr : addresses ) + { + if ( itemCount++ < 10 ) + { + std::vector values; + hdf5SummaryReader.values( adr, &values ); + + totalValueCount += values.size(); + } + } + + EXPECT_EQ( size_t( 8940 ), totalValueCount ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( DISABLED_HDFTests, ReadOpmSummaryDataListContent ) +{ + QString filePath = H5_TEST_DATA_DIRECTORY + "NORNE_ATW2013_RFTPLT_V2.SMSPEC"; + + Opm::EclIO::ESmry eSmry( filePath.toStdString() ); + + auto nodes = eSmry.summaryNodeList(); + + for ( size_t i = 0; i < nodes.size(); i++ ) + { + Opm::EclIO::SummaryNode n = nodes[i]; + std::cout << n.keyword << " number: " << n.number << " msjNumber: " << n.smspecKeywordIndex << " " + << n.unique_key() << "\n"; + } +} //-------------------------------------------------------------------------------------------------- /// diff --git a/ApplicationLibCode/UnitTests/RifSummaryDataReader-Test.cpp b/ApplicationLibCode/UnitTests/RifSummaryDataReader-Test.cpp index e5afa2edb4..6f09d3a051 100644 --- a/ApplicationLibCode/UnitTests/RifSummaryDataReader-Test.cpp +++ b/ApplicationLibCode/UnitTests/RifSummaryDataReader-Test.cpp @@ -23,7 +23,7 @@ TEST( DISABLED_RifSummaryDataTest, OpmCommonAllData ) { auto start = std::chrono::high_resolution_clock::now(); - reader.open( filename, true ); + reader.open( filename, true, nullptr ); auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration diff = end - start; @@ -74,7 +74,7 @@ TEST( DISABLED_RifSummaryDataTest, LibEclAllData ) { auto start = std::chrono::high_resolution_clock::now(); - reader.open( filename, true ); + reader.open( filename, true, nullptr ); auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration diff = end - start; diff --git a/ApplicationLibCode/UnitTests/TestData/h5-file/NORNE_ATW2013_RFTPLT_V2.SMSPEC b/ApplicationLibCode/UnitTests/TestData/h5-file/NORNE_ATW2013_RFTPLT_V2.SMSPEC new file mode 100644 index 0000000000..e724531aa0 Binary files /dev/null and b/ApplicationLibCode/UnitTests/TestData/h5-file/NORNE_ATW2013_RFTPLT_V2.SMSPEC differ diff --git a/ApplicationLibCode/UnitTests/TestData/h5-file/NORNE_ATW2013_RFTPLT_V2.UNSMRY b/ApplicationLibCode/UnitTests/TestData/h5-file/NORNE_ATW2013_RFTPLT_V2.UNSMRY new file mode 100644 index 0000000000..f48e42db67 Binary files /dev/null and b/ApplicationLibCode/UnitTests/TestData/h5-file/NORNE_ATW2013_RFTPLT_V2.UNSMRY differ diff --git a/ApplicationLibCode/UnitTests/TestData/h5-file/NORNE_ATW2013_RFTPLT_V2.h5 b/ApplicationLibCode/UnitTests/TestData/h5-file/NORNE_ATW2013_RFTPLT_V2.h5 new file mode 100644 index 0000000000..60302372e5 Binary files /dev/null and b/ApplicationLibCode/UnitTests/TestData/h5-file/NORNE_ATW2013_RFTPLT_V2.h5 differ