From f5547dd551709f56ef1a52473c7e218025fc9f63 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 25 Mar 2021 12:56:09 +0100 Subject: [PATCH] #7512 Support optimized summary reader --- .../Application/RiaPreferences.cpp | 80 +- .../Application/RiaPreferences.h | 10 + .../FileInterface/CMakeLists_files.cmake | 3 + .../FileInterface/RifOpmCommonSummary.cpp | 245 +++++ .../FileInterface/RifOpmCommonSummary.h | 85 ++ .../FileInterface/RifReaderEclipseSummary.cpp | 76 +- .../FileInterface/RifReaderEclipseSummary.h | 6 +- .../Summary/RimSummaryCaseMainCollection.cpp | 15 +- .../UnitTests/CMakeLists_files.cmake | 1 + .../UnitTests/RifSummaryDataReader-Test.cpp | 113 +++ ThirdParty/custom-opm-common/CMakeLists.txt | 4 + .../cross-platform/windows/Substitutes.cpp | 1 + .../cross-platform/windows/Substitutes.hpp | 4 - .../opm-common/opm/io/eclipse/EGrid.hpp | 43 +- .../opm-common/opm/io/eclipse/EInit.hpp | 102 ++ .../opm-common/opm/io/eclipse/ERst.hpp | 47 +- .../opm-common/opm/io/eclipse/ESmry.hpp | 23 +- .../opm-common/opm/io/eclipse/EclFile.hpp | 11 +- .../opm-common/opm/io/eclipse/EclIOdata.hpp | 38 +- .../opm-common/opm/io/eclipse/EclOutput.hpp | 34 +- .../opm-common/opm/io/eclipse/EclUtil.hpp | 38 +- .../opm-common/opm/io/eclipse/SummaryNode.hpp | 12 +- .../opm-common/opm/io/eclipse/rst/group.hpp | 9 + .../opm-common/opm/io/eclipse/rst/header.hpp | 11 +- .../opm-common/opm/io/eclipse/rst/state.hpp | 5 + .../opm-common/opm/io/eclipse/rst/well.hpp | 6 +- .../opm-common/src/opm/io/eclipse/EGrid.cpp | 289 ++++-- .../opm-common/src/opm/io/eclipse/EInit.cpp | 161 +++ .../opm-common/src/opm/io/eclipse/ERsm.cpp | 30 +- .../opm-common/src/opm/io/eclipse/ERst.cpp | 197 +++- .../opm-common/src/opm/io/eclipse/ESmry.cpp | 951 ++++++++++++------ .../opm-common/src/opm/io/eclipse/EclFile.cpp | 403 +++----- .../src/opm/io/eclipse/EclOutput.cpp | 239 ++++- .../opm-common/src/opm/io/eclipse/EclUtil.cpp | 339 ++++++- .../src/opm/io/eclipse/SummaryNode.cpp | 30 +- .../src/opm/io/eclipse/rst/group.cpp | 44 +- .../src/opm/io/eclipse/rst/header.cpp | 14 +- .../src/opm/io/eclipse/rst/segment.cpp | 2 + .../src/opm/io/eclipse/rst/state.cpp | 85 +- .../src/opm/io/eclipse/rst/well.cpp | 23 +- .../EclipseState/Schedule/Well/Well.cpp | 2 +- 41 files changed, 2996 insertions(+), 835 deletions(-) create mode 100644 ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp create mode 100644 ApplicationLibCode/FileInterface/RifOpmCommonSummary.h create mode 100644 ApplicationLibCode/UnitTests/RifSummaryDataReader-Test.cpp create mode 100644 ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EInit.hpp create mode 100644 ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EInit.cpp diff --git a/ApplicationLibCode/Application/RiaPreferences.cpp b/ApplicationLibCode/Application/RiaPreferences.cpp index afa207bf62..926c0b4d21 100644 --- a/ApplicationLibCode/Application/RiaPreferences.cpp +++ b/ApplicationLibCode/Application/RiaPreferences.cpp @@ -403,6 +403,33 @@ RiaPreferences::RiaPreferences( void ) m_multiLateralWellPattern.uiCapability()->setUiEditorTypeName( caf::PdmUiLineEditor::uiEditorTypeName() ); 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, + "Create Optimized Summary Data Files [BETA]", + "", + "If not present, create optimized file with extension '*.LODSMRY'", + "" ); + m_createOptimizedSummaryDataFile.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); + + CAF_PDM_InitField( &m_useOptimizedSummaryDataFile, + "useOptimizedSummaryDataFile", + true, + "Use Optimized Summary Data Files [BETA]", + "", + "If not present, read optimized file with extension '*.LODSMRY'", + "" ); + m_useOptimizedSummaryDataFile.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); } //-------------------------------------------------------------------------------------------------- @@ -444,14 +471,15 @@ 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_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_createOptimizedSummaryDataFile || field == &m_useOptimizedSummaryDataFile ) { caf::PdmUiCheckBoxEditorAttribute* myAttr = dynamic_cast( attribute ); if ( myAttr ) @@ -576,6 +604,18 @@ void RiaPreferences::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& m_pageRightMargin.uiCapability()->setUiName( "Right Margin" + unitLabel ); m_pageTopMargin.uiCapability()->setUiName( "Top Margin" + unitLabel ); m_pageBottomMargin.uiCapability()->setUiName( "Bottom Margin" + unitLabel ); + + { + caf::PdmUiGroup* group = uiOrdering.addNewGroup( "[BETA] Optimized Summary Reader" ); + group->setCollapsedByDefault( true ); + group->add( &m_useOptimizedSummaryDataFileReader ); + + group->add( &m_createOptimizedSummaryDataFile ); + group->add( &m_useOptimizedSummaryDataFile ); + + m_createOptimizedSummaryDataFile.uiCapability()->setUiReadOnly( !m_useOptimizedSummaryDataFileReader ); + m_useOptimizedSummaryDataFile.uiCapability()->setUiReadOnly( !m_useOptimizedSummaryDataFileReader ); + } } else if ( uiConfigName == RiaPreferences::tabNameScripting() ) @@ -1171,6 +1211,30 @@ QString RiaPreferences::octaveExecutable() const return m_octaveExecutable().trimmed(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaPreferences::useOptimizedSummaryDataReader() const +{ + return m_useOptimizedSummaryDataFileReader(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaPreferences::useOptimizedSummaryDataFiles() const +{ + return m_useOptimizedSummaryDataFileReader(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaPreferences::createOptimizedSummaryDataFiles() const +{ + return m_createOptimizedSummaryDataFile(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Application/RiaPreferences.h b/ApplicationLibCode/Application/RiaPreferences.h index 48b26307d7..fa8db4618d 100644 --- a/ApplicationLibCode/Application/RiaPreferences.h +++ b/ApplicationLibCode/Application/RiaPreferences.h @@ -138,6 +138,11 @@ public: QString pythonExecutable() const; QString octaveExecutable() const; + // Summary readers + bool useOptimizedSummaryDataReader() const; + bool useOptimizedSummaryDataFiles() const; + bool createOptimizedSummaryDataFiles() const; + public: // Pdm Fields caf::PdmField enableGrpcServer; caf::PdmField defaultGrpcPortNumber; @@ -243,6 +248,11 @@ private: // Well Path Import caf::PdmField m_multiLateralWellPattern; + // Summary data + caf::PdmField m_useOptimizedSummaryDataFileReader; + caf::PdmField m_createOptimizedSummaryDataFile; + caf::PdmField m_useOptimizedSummaryDataFile; + // 3d view caf::PdmField> m_defaultMeshModeType; caf::PdmField> m_navigationPolicy; diff --git a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake index 01460b55ef..bea7013066 100644 --- a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake +++ b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake @@ -60,6 +60,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelDeviationFrkExporter.h ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelPerfsFrkExporter.h ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelAsymmetricFrkExporter.h ${CMAKE_CURRENT_LIST_DIR}/RifSurfaceExporter.h +${CMAKE_CURRENT_LIST_DIR}/RifOpmCommonSummary.h + # HDF5 file reader is directly included in ResInsight main CmakeList.txt @@ -125,6 +127,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelDeviationFrkExporter.cpp ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelPerfsFrkExporter.cpp ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelAsymmetricFrkExporter.cpp ${CMAKE_CURRENT_LIST_DIR}/RifSurfaceExporter.cpp +${CMAKE_CURRENT_LIST_DIR}/RifOpmCommonSummary.cpp # HDF5 file reader is directly included in ResInsight main CmakeList.txt #${CMAKE_CURRENT_LIST_DIR}/RifHdf5Reader.cpp diff --git a/ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp b/ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp new file mode 100644 index 0000000000..be8a211c21 --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp @@ -0,0 +1,245 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RifOpmCommonSummary.h" + +#include "opm/io/eclipse/ESmry.hpp" + +#ifdef USE_OPENMP +#include +#endif + +size_t RifOpmCommonEclipseSummary::sm_createdLodFileCount = 0; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RifOpmCommonEclipseSummary::RifOpmCommonEclipseSummary() + : m_useLodsmryFiles( false ) + , m_createLodsmryFiles( false ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RifOpmCommonEclipseSummary::~RifOpmCommonEclipseSummary() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifOpmCommonEclipseSummary::useLodsmaryFiles( bool enable ) +{ + m_useLodsmryFiles = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifOpmCommonEclipseSummary::createLodsmaryFiles( bool enable ) +{ + m_createLodsmryFiles = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifOpmCommonEclipseSummary::resetLodCount() +{ + sm_createdLodFileCount = 0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RifOpmCommonEclipseSummary::numberOfLodFilesCreated() +{ + return sm_createdLodFileCount; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifOpmCommonEclipseSummary::open( const QString& headerFileName, bool includeRestartFiles ) +{ + m_eSmry = std::make_unique( headerFileName.toStdString(), includeRestartFiles, m_useLodsmryFiles ); + + if ( m_createLodsmryFiles && !includeRestartFiles ) + { + // Create the lodsmry file, no-op if already present. + bool hasFileBeenCreated = m_eSmry->make_lodsmry_file(); + + if ( hasFileBeenCreated ) + { + RifOpmCommonEclipseSummary::increaseLodFileCount(); + } + } + + if ( !m_eSmry ) return false; + + buildMetaData(); + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RifOpmCommonEclipseSummary::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const +{ + return m_timeSteps; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifOpmCommonEclipseSummary::values( const RifEclipseSummaryAddress& resultAddress, std::vector* values ) 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]; + auto fileValues = m_eSmry->get( node ); + values->insert( values->begin(), fileValues.begin(), fileValues.end() ); + } + + return true; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::string RifOpmCommonEclipseSummary::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 RifOpmCommonEclipseSummary::unitSystem() const +{ + // TODO: Not implemented + return RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifOpmCommonEclipseSummary::buildMetaData() +{ + if ( m_eSmry ) + { + auto dates = m_eSmry->dates(); + for ( const auto& d : dates ) + { + auto timeAsTimeT = std::chrono::system_clock::to_time_t( d ); + 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() ); + + if ( eclAdr.isValid() ) + { + m_allResultAddresses.insert( eclAdr ); + m_adrToSummaryNodeIndex[eclAdr] = i; + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifOpmCommonEclipseSummary::increaseLodFileCount() +{ + // This function can be called from a parallel loop, make it thread safe +#pragma omp critical + sm_createdLodFileCount++; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RifEclipseSummaryAddress RifOpmCommonEclipseSummary::createAddressFromSummaryNode( const Opm::EclIO::SummaryNode& node, + Opm::EclIO::ESmry* summaryFile ) +{ + int i = -1; + int j = -1; + int k = -1; + + switch ( node.category ) + { + case Opm::EclIO::SummaryNode::Category::Aquifer: + return RifEclipseSummaryAddress::aquiferAddress( node.keyword, node.number ); + break; + case Opm::EclIO::SummaryNode::Category::Well: + return RifEclipseSummaryAddress::wellAddress( node.keyword, node.wgname ); + break; + case Opm::EclIO::SummaryNode::Category::Group: + return RifEclipseSummaryAddress::wellGroupAddress( node.keyword, node.wgname ); + break; + case Opm::EclIO::SummaryNode::Category::Field: + return RifEclipseSummaryAddress::fieldAddress( node.keyword ); + break; + case Opm::EclIO::SummaryNode::Category::Region: + return RifEclipseSummaryAddress::regionAddress( node.keyword, node.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 ); + 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 ); + break; + case Opm::EclIO::SummaryNode::Category::Segment: + return RifEclipseSummaryAddress::wellSegmentAddress( node.keyword, node.wgname, node.number ); + break; + case Opm::EclIO::SummaryNode::Category::Miscellaneous: + return RifEclipseSummaryAddress::miscAddress( node.keyword ); + break; + default: + break; + } + + return RifEclipseSummaryAddress(); +} diff --git a/ApplicationLibCode/FileInterface/RifOpmCommonSummary.h b/ApplicationLibCode/FileInterface/RifOpmCommonSummary.h new file mode 100644 index 0000000000..9168daa22b --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifOpmCommonSummary.h @@ -0,0 +1,85 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 + +namespace Opm +{ +namespace EclIO +{ + class ESmry; + struct SummaryNode; +} // namespace EclIO +} // namespace Opm + +//================================================================================================== +// +// +//================================================================================================== +class RifOpmCommonEclipseSummary : public RifSummaryReaderInterface +{ +public: + RifOpmCommonEclipseSummary(); + ~RifOpmCommonEclipseSummary(); + + void useLodsmaryFiles( bool enable ); + void createLodsmaryFiles( bool enable ); + + static void resetLodCount(); + static size_t numberOfLodFilesCreated(); + + bool open( const QString& headerFileName, bool includeRestartFiles ); + + 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(); + + 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; + std::map m_adrToSummaryNodeIndex; + std::vector m_timeSteps; + + static size_t sm_createdLodFileCount; + + bool m_useLodsmryFiles; + bool m_createLodsmryFiles; +}; diff --git a/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.cpp b/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.cpp index 6b623d0cf8..4a0b797af8 100644 --- a/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.cpp +++ b/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.cpp @@ -19,10 +19,13 @@ #include "RifReaderEclipseSummary.h" #include "RiaFilePathTools.h" +#include "RiaLogging.h" +#include "RiaPreferences.h" #include "RiaStdStringTools.h" #include "RiaStringEncodingTools.h" #include "RifEclipseSummaryTools.h" +#include "RifOpmCommonSummary.h" #include "RifReaderEclipseOutput.h" #include @@ -86,7 +89,7 @@ ecl_sum_type* openEclSum( const QString& inHeaderFileName, bool includeRestartFi QString nativeHeaderFileName = QDir::toNativeSeparators( inHeaderFileName ); RifEclipseSummaryTools::findSummaryFiles( nativeHeaderFileName, &headerFileName, &dataFileNames ); - if ( headerFileName.isEmpty() || dataFileNames.size() == 0 ) return nullptr; + if ( headerFileName.isEmpty() || dataFileNames.isEmpty() ) return nullptr; assert( !headerFileName.isEmpty() ); assert( dataFileNames.size() > 0 ); @@ -126,7 +129,7 @@ RifReaderEclipseSummary::RifReaderEclipseSummary() , m_ecl_SmSpec( nullptr ) , m_unitSystem( RiaDefines::EclipseUnitSystem::UNITS_METRIC ) { - m_valuesCache.reset( new ValuesCache() ); + m_valuesCache = std::make_unique(); } //-------------------------------------------------------------------------------------------------- @@ -146,6 +149,30 @@ RifReaderEclipseSummary::~RifReaderEclipseSummary() //-------------------------------------------------------------------------------------------------- bool RifReaderEclipseSummary::open( const QString& headerFileName, bool includeRestartFiles ) { + bool useOpmCommonReader = RiaPreferences::current()->useOptimizedSummaryDataReader(); + + if ( useOpmCommonReader ) + { + 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" ); + + return false; + } + + m_opmCommonReader = std::make_unique(); + + m_opmCommonReader->useLodsmaryFiles( RiaPreferences::current()->useOptimizedSummaryDataFiles() ); + m_opmCommonReader->createLodsmaryFiles( RiaPreferences::current()->createOptimizedSummaryDataFiles() ); + m_opmCommonReader->open( headerFileName, includeRestartFiles ); + + buildMetaData(); + + return true; + } + assert( m_ecl_sum == nullptr ); m_ecl_sum = openEclSum( headerFileName, includeRestartFiles ); @@ -241,7 +268,7 @@ RifRestartFileInfo RifReaderEclipseSummary::getFileInfo( const QString& headerFi RifRestartFileInfo fileInfo; ecl_sum_type* ecl_sum = openEclSum( headerFileName, false ); std::vector timeSteps = getTimeSteps( ecl_sum ); - if ( timeSteps.size() > 0 ) + if ( !timeSteps.empty() ) { fileInfo.fileName = headerFileName; fileInfo.startDate = timeSteps.front(); @@ -426,22 +453,33 @@ RifEclipseSummaryAddress addressFromErtSmSpecNode( const ecl::smspec_node& ertSu //-------------------------------------------------------------------------------------------------- bool RifReaderEclipseSummary::values( const RifEclipseSummaryAddress& resultAddress, std::vector* values ) const { - assert( m_ecl_sum != nullptr ); - values->clear(); values->reserve( timeStepCount() ); + // assert( m_ecl_sum != nullptr ); + const std::vector& cachedValues = m_valuesCache->getValues( resultAddress ); if ( !cachedValues.empty() ) { values->insert( values->begin(), cachedValues.begin(), cachedValues.end() ); + + return true; } - else if ( m_ecl_SmSpec ) + + if ( m_opmCommonReader ) + { + m_opmCommonReader->values( resultAddress, values ); + m_valuesCache->insertValues( resultAddress, *values ); + + return true; + } + + if ( m_ecl_SmSpec ) { if ( m_differenceAddresses.count( resultAddress ) ) { - std::string quantityName = resultAddress.quantityName(); - auto historyQuantity = quantityName.substr( 0, quantityName.size() - differenceIdentifier().size() ) + + const std::string& quantityName = resultAddress.quantityName(); + auto historyQuantity = quantityName.substr( 0, quantityName.size() - differenceIdentifier().size() ) + historyIdentifier(); RifEclipseSummaryAddress nativeAdrNoHistory = resultAddress; @@ -494,13 +532,18 @@ bool RifReaderEclipseSummary::values( const RifEclipseSummaryAddress& resultAddr //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -int RifReaderEclipseSummary::timeStepCount() const +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 ecl_sum_get_data_length( m_ecl_sum ); + return static_cast( ecl_sum_get_data_length( m_ecl_sum ) ); } //-------------------------------------------------------------------------------------------------- @@ -508,7 +551,7 @@ int RifReaderEclipseSummary::timeStepCount() const //-------------------------------------------------------------------------------------------------- const std::vector& RifReaderEclipseSummary::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const { - assert( m_ecl_sum != nullptr ); + // assert( m_ecl_sum != nullptr ); return m_timeSteps; } @@ -535,6 +578,15 @@ void RifReaderEclipseSummary::buildMetaData() m_allResultAddresses.clear(); m_resultAddressToErtNodeIdx.clear(); + if ( m_opmCommonReader ) + { + m_allResultAddresses = m_opmCommonReader->allResultAddresses(); + m_allErrorAddresses = m_opmCommonReader->allErrorAddresses(); + + m_timeSteps = m_opmCommonReader->timeSteps( RifEclipseSummaryAddress() ); + return; + } + if ( m_ecl_SmSpec ) { int varCount = ecl_smspec_num_nodes( m_ecl_SmSpec ); @@ -556,7 +608,7 @@ void RifReaderEclipseSummary::buildMetaData() RifEclipseSummaryAddress adrWithoutHistory; { - std::string s = adr.quantityName(); + const std::string& s = adr.quantityName(); if ( !RiaStdStringTools::endsWith( s, historyIdentifier() ) ) { RifEclipseSummaryAddress candidate = adr; diff --git a/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.h b/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.h index 1e93420151..ad35cf884b 100644 --- a/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.h +++ b/ApplicationLibCode/FileInterface/RifReaderEclipseSummary.h @@ -31,6 +31,8 @@ #include #include +class RifOpmCommonEclipseSummary; + //================================================================================================== // // @@ -82,7 +84,7 @@ public: static const std::string historyIdentifier() { return "H"; } private: - int timeStepCount() const; + size_t timeStepCount() const; int indexFromAddress( const RifEclipseSummaryAddress& resultAddress ) const; void buildMetaData(); RifRestartFileInfo getRestartFile( const QString& headerFileName ); @@ -104,6 +106,8 @@ private: std::set m_differenceAddresses; + std::unique_ptr m_opmCommonReader; + //================================================================================================== // //================================================================================================== diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp index afb16da05f..4e4e0615e1 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp @@ -15,13 +15,15 @@ // for more details. // ///////////////////////////////////////////////////////////////////////////////// + #include "RimSummaryCaseMainCollection.h" +#include "RiaLogging.h" #include "RiaSummaryTools.h" -#include "RimSummaryPlotCollection.h" #include "RifCaseRealizationParametersReader.h" #include "RifEclipseSummaryTools.h" +#include "RifOpmCommonSummary.h" #include "RifSummaryCaseRestartSelector.h" #include "RimCaseDisplayNameTools.h" @@ -35,8 +37,10 @@ #include "RimSummaryCaseCollection.h" #include "RimSummaryCurve.h" #include "RimSummaryPlot.h" +#include "RimSummaryPlotCollection.h" #include "cafProgressInfo.h" + #include CAF_PDM_SOURCE_INIT( RimSummaryCaseMainCollection, "SummaryCaseCollection" ); @@ -435,6 +439,8 @@ void RimSummaryCaseMainCollection::loadFileSummaryCaseData( std::vector( fileSummaryCases.size() ); ++cIdx ) { @@ -447,6 +453,13 @@ void RimSummaryCaseMainCollection::loadFileSummaryCaseData( std::vector 0 ) + { + RiaLogging::info( QString( "Optimized Summary Reader : Converted and created %1 '*.LODSMRY' files on disk." ) + .arg( numberOfLodFilesCreated ) ); + } + for ( int cIdx = 0; cIdx < static_cast( fileSummaryCases.size() ); ++cIdx ) { RimFileSummaryCase* fileSummaryCase = fileSummaryCases[cIdx]; diff --git a/ApplicationLibCode/UnitTests/CMakeLists_files.cmake b/ApplicationLibCode/UnitTests/CMakeLists_files.cmake index e440ec4f34..c1a9decdc6 100644 --- a/ApplicationLibCode/UnitTests/CMakeLists_files.cmake +++ b/ApplicationLibCode/UnitTests/CMakeLists_files.cmake @@ -74,6 +74,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaStatisticsTools-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanXmlReader-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RigWellPathGeometryExporter-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelDeviationFrkExporter-Test.cpp +${CMAKE_CURRENT_LIST_DIR}/RifSummaryDataReader-Test.cpp ) if (RESINSIGHT_ENABLE_GRPC) diff --git a/ApplicationLibCode/UnitTests/RifSummaryDataReader-Test.cpp b/ApplicationLibCode/UnitTests/RifSummaryDataReader-Test.cpp new file mode 100644 index 0000000000..e5afa2edb4 --- /dev/null +++ b/ApplicationLibCode/UnitTests/RifSummaryDataReader-Test.cpp @@ -0,0 +1,113 @@ +#include "gtest/gtest.h" + +//#include "RiaTestDataDirectory.h" + +#include "RifOpmCommonSummary.h" +#include "RifReaderEclipseSummary.h" +#include + +size_t iterationCount = 5; +size_t maxCount = 500; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( DISABLED_RifSummaryDataTest, OpmCommonAllData ) +{ + QString filename = "e:/models/reek_history_match_large/realization-1/iter-0/eclipse/model/R001_REEK-1.SMSPEC"; + + for ( size_t iteration = 0; iteration < iterationCount; iteration++ ) + { + RifOpmCommonEclipseSummary reader; + + { + auto start = std::chrono::high_resolution_clock::now(); + + reader.open( filename, true ); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration diff = end - start; + std::cout << "OPM : Open " << std::setw( 9 ) << diff.count() << " s\n"; + } + + // for ( auto adr : reader.allResultAddresses() ) + // { + // std::cout << adr.uiText(); + // std::cout << std::endl; + // } + + { + auto start = std::chrono::high_resolution_clock::now(); + + size_t totalValuesRead = 0; + + // do some work + size_t i = 0; + for ( auto adr : reader.allResultAddresses() ) + { + std::vector values; + + reader.values( adr, &values ); + totalValuesRead += values.size(); + i++; + if ( i > maxCount ) break; + } + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration diff = end - start; + std::cout << "OPM Read data " << std::setw( 9 ) << totalValuesRead << "totalValueCount" << diff.count() + << " s\n"; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( DISABLED_RifSummaryDataTest, LibEclAllData ) +{ + QString filename = "e:/models/reek_history_match_large/realization-1/iter-0/eclipse/model/R001_REEK-1.SMSPEC"; + + for ( size_t iteration = 0; iteration < iterationCount; iteration++ ) + { + RifReaderEclipseSummary reader; + { + auto start = std::chrono::high_resolution_clock::now(); + + reader.open( filename, true ); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration diff = end - start; + std::cout << "LibEcl : Open " << std::setw( 9 ) << diff.count() << " s\n"; + } + + // for ( auto adr : reader.allResultAddresses() ) + // { + // std::cout << adr.uiText(); + // std::cout << std::endl; + // } + + { + auto start = std::chrono::high_resolution_clock::now(); + + size_t totalValuesRead = 0; + + size_t i = 0; + for ( auto adr : reader.allResultAddresses() ) + { + std::vector values; + + reader.values( adr, &values ); + totalValuesRead += values.size(); + + i++; + if ( i > maxCount ) break; + } + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration diff = end - start; + std::cout << "LibEcl read data" << std::setw( 9 ) << totalValuesRead << "totalValueCount" << diff.count() + << " s\n"; + } + } +} diff --git a/ThirdParty/custom-opm-common/CMakeLists.txt b/ThirdParty/custom-opm-common/CMakeLists.txt index 9a3d0fe3ad..c97e496d2e 100644 --- a/ThirdParty/custom-opm-common/CMakeLists.txt +++ b/ThirdParty/custom-opm-common/CMakeLists.txt @@ -78,6 +78,8 @@ add_library(${PROJECT_NAME} opm-common/src/opm/io/eclipse/EclOutput.cpp opm-common/src/opm/io/eclipse/EclUtil.cpp opm-common/src/opm/io/eclipse/EGrid.cpp + opm-common/src/opm/io/eclipse/ESmry.cpp + opm-common/src/opm/io/eclipse/EInit.cpp # Required for use of static function RstConnection::inverse_peaceman opm-common/src/opm/io/eclipse/rst/connection.cpp @@ -95,6 +97,8 @@ if(RESINSIGHT_ENABLE_UNITY_BUILD) opm-common/src/opm/parser/eclipse/EclipseState/Schedule/Well/WListManager.cpp opm-common/src/opm/parser/eclipse/EclipseState/Schedule/MSW/SpiralICD.cpp opm-common/src/opm/io/eclipse/EclOutput.cpp + opm-common/src/opm/io/eclipse/ESmry.cpp + opm-common/src/opm/io/eclipse/EGrid.cpp ) foreach(fileToExclude ${UNITY_EXCLUDE_FILES}) diff --git a/ThirdParty/custom-opm-common/opm-common/cross-platform/windows/Substitutes.cpp b/ThirdParty/custom-opm-common/opm-common/cross-platform/windows/Substitutes.cpp index 4d11cf142a..328e10d8ee 100644 --- a/ThirdParty/custom-opm-common/opm-common/cross-platform/windows/Substitutes.cpp +++ b/ThirdParty/custom-opm-common/opm-common/cross-platform/windows/Substitutes.cpp @@ -1,6 +1,7 @@ #ifdef _WIN32 #include "Substitutes.hpp" +#include int fnmatch(const char* pattern, const char* string, int flags) diff --git a/ThirdParty/custom-opm-common/opm-common/cross-platform/windows/Substitutes.hpp b/ThirdParty/custom-opm-common/opm-common/cross-platform/windows/Substitutes.hpp index 62c46cd2b7..d9ebdd47c9 100644 --- a/ThirdParty/custom-opm-common/opm-common/cross-platform/windows/Substitutes.hpp +++ b/ThirdParty/custom-opm-common/opm-common/cross-platform/windows/Substitutes.hpp @@ -2,10 +2,6 @@ #ifdef _WIN32 -#include -#define NOMINMAX -#include -#undef NOMINMAX // IGNORE is used in InputErrorAction.hpp, as an enum value, // but is defined as a #def in WinBase.h which is included by Shlwapi.h. // It is not required here, so we can undefine it. diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EGrid.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EGrid.hpp index 9e1455b80d..c1d26f7800 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EGrid.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EGrid.hpp @@ -20,6 +20,7 @@ #define OPM_IO_EGRID_HPP #include +#include #include #include @@ -34,7 +35,7 @@ namespace Opm { namespace EclIO { class EGrid : public EclFile { public: - explicit EGrid(const std::string& filename); + explicit EGrid(const std::string& filename, std::string grid_name = "global"); int global_index(int i, int j, int k) const; int active_index(int i, int j, int k) const; @@ -44,20 +45,54 @@ public: std::array ijk_from_active_index(int actInd) const; std::array ijk_from_global_index(int globInd) const; - void getCellCorners(int globindex, std::array& X, std::array& Y, std::array& Z) const; - void getCellCorners(const std::array& ijk, std::array& X, std::array& Y, std::array& Z) const; + void getCellCorners(int globindex, std::array& X, std::array& Y, std::array& Z); + void getCellCorners(const std::array& ijk, std::array& X, std::array& Y, std::array& Z); int activeCells() const { return nactive; } int totalNumberOfCells() const { return nijk[0] * nijk[1] * nijk[2]; } + void load_grid_data(); + void load_nnc_data(); + bool is_radial() const { return m_radial; } + + const std::vector& hostCellsGlobalIndex() const { return host_cells; } + std::vector> hostCellsIJK(); + + // zero based: i1, j1,k1, i2,j2,k2, transmisibility + using NNCentry = std::tuple; + std::vector get_nnc_ijk(); + + const std::vector& list_of_lgrs() const { return lgr_names; } + private: + Opm::filesystem::path inputFileName, initFileName; + std::string m_grid_name; + bool m_radial; + std::array nijk; - int nactive; + std::array host_nijk; + + int nactive, m_nncs; + mutable bool m_nncs_loaded; std::vector act_index; std::vector glob_index; + std::vector coord_array; std::vector zcorn_array; + + std::vector nnc1_array; + std::vector nnc2_array; + std::vector transnnc_array; + std::vector host_cells; + + std::vector lgr_names; + + int zcorn_array_index; + int coord_array_index; + int actnum_array_index; + int nnc1_array_index; + int nnc2_array_index; }; }} // namespace Opm::EclIO diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EInit.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EInit.hpp new file mode 100644 index 0000000000..82b4afddcc --- /dev/null +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EInit.hpp @@ -0,0 +1,102 @@ +/* + Copyright 2020 Equinor ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . + */ + +#ifndef OPM_IO_EINIT_HPP +#define OPM_IO_EINIT_HPP + +#include + +#include +#include +#include + +namespace Opm { namespace EclIO { + +class EInit : public EclFile +{ +public: + explicit EInit(const std::string& filename); + + const std::vector& list_of_lgrs() const { return lgr_names; } + + std::vector list_arrays() const; + std::vector list_arrays(const std::string& grid_name) const; + + const std::array& grid_dimension(const std::string& grid_name = "global") const; + int activeCells(const std::string& grid_name = "global") const; + + bool hasLGR(const std::string& name) const; + + template + const std::vector& getInitData(const std::string& name, const std::string& grid_name = "global") + { + return this->ImplgetInitData(name, grid_name); + } + +protected: + + template + const std::vector& ImplgetInitData(const std::string& name, const std::string& grid_name = "global") + { + int arr_ind = get_array_index(name, grid_name); + + if constexpr (std::is_same_v) + return getImpl(arr_ind, INTE, inte_array, "integer"); + + if constexpr (std::is_same_v) + return getImpl(arr_ind, REAL, real_array, "float"); + + if constexpr (std::is_same_v) + return getImpl(arr_ind, DOUB, doub_array, "double"); + + if constexpr (std::is_same_v) + return getImpl(arr_ind, LOGI, logi_array, "bool"); + + if constexpr (std::is_same_v) + { + if (array_type[arr_ind] == Opm::EclIO::CHAR) + return getImpl(arr_ind, array_type[arr_ind], char_array, "char"); + + if (array_type[arr_ind] == Opm::EclIO::C0NN) + return getImpl(arr_ind, array_type[arr_ind], char_array, "c0nn"); + + OPM_THROW(std::runtime_error, "Array not of type CHAR or C0nn"); + } + + OPM_THROW(std::runtime_error, "type not supported"); + } + +private: + std::array global_nijk; + std::vector> lgr_nijk; + + int global_nactive; + std::vector lgr_nactive; + + std::vector lgr_names; + + std::map global_array_index; + std::vector> lgr_array_index; + + int get_array_index(const std::string& name, const std::string& grid_name) const; + int get_lgr_index(const std::string& grid_name) const; +}; + +}} // namespace Opm::EclIO + +#endif // OPM_IO_EINIT_HPP diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/ERst.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/ERst.hpp index a0fa0f7414..cd29598843 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/ERst.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/ERst.hpp @@ -27,6 +27,7 @@ #include #include + namespace Opm { namespace EclIO { namespace OutputStream { class Restart; }}} @@ -37,43 +38,73 @@ class ERst : public EclFile { public: explicit ERst(const std::string& filename); + bool hasReportStepNumber(int number) const; + bool hasLGR(const std::string& gridname, int reportStepNumber) const; void loadReportStepNumber(int number); template - const std::vector& getRst(const std::string& name, int reportStepNumber, int occurrence); + const std::vector& getRestartData(const std::string& name, int reportStepNumber) + { + return getRestartData(name,reportStepNumber, 0); + } template - const std::vector& getRst(int index, int reportStepNumber){ + const std::vector& getRestartData(const std::string& name, int reportStepNumber, int occurrence); + + template + const std::vector& getRestartData(const std::string& name, int reportStepNumber, const std::string& lgr_name); + + template + const std::vector& getRestartData(int index, int reportStepNumber) + { auto indRange = this->getIndexRange(reportStepNumber); return this->get(index + std::get<0>(indRange)); } - int count(const std::string& name, int reportStepNumber) const; + template + const std::vector& getRestartData(int index, int reportStepNumber, const std::string& lgr_name) + { + auto indRange = this->getIndexRange(reportStepNumber); + + if ((std::get<0>(indRange) + index) > std::get<1>(indRange)) + OPM_THROW(std::invalid_argument, "getRestartData, index out of range"); + + int start_ind = get_start_index_lgrname(reportStepNumber, lgr_name); + return this->get(index + start_ind); + } + + int occurrence_count(const std::string& name, int reportStepNumber) const; size_t numberOfReportSteps() const { return seqnum.size(); }; const std::vector& listOfReportStepNumbers() const { return seqnum; } - + std::vector listOfRstArrays(int reportStepNumber); + std::vector listOfRstArrays(int reportStepNumber, const std::string& lgr_name); friend class OutputStream::Restart; private: int nReports; std::vector seqnum; // report step numbers, from SEQNUM array in restart file - std::unordered_map reportLoaded; + mutable std::unordered_map reportLoaded; std::map> arrIndexRange; // mapping report step number to array indeces (start and end) + std::vector> lgr_names; // report step numbers, from SEQNUM array in restart file void initUnified(); void initSeparate(const int number); - int getArrayIndex(const std::string& name, int seqnum, int occurrence) const; - std::tuple getIndexRange(int reportStepNumber) const; + int get_start_index_lgrname(int number, const std::string& lgr_name); + + int getArrayIndex(const std::string& name, int seqnum, int occurrence); + int getArrayIndex(const std::string& name, int number, const std::string& lgr_name); + + std::tuple getIndexRange(int reportStepNumber) const; std::streampos restartStepWritePosition(const int seqnumValue) const; - + }; }} // namespace Opm::EclIO diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/ESmry.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/ESmry.hpp index 81b6adf8fc..ddf9ac2463 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/ESmry.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/ESmry.hpp @@ -40,7 +40,7 @@ class ESmry public: // input is smspec (or fsmspec file) - explicit ESmry(const std::string& filename, bool loadBaseRunData=false); + explicit ESmry(const std::string& filename, bool loadBaseRunData=false, bool uselodsmry=false); int numberOfVectors() const { return nVect; } @@ -57,6 +57,11 @@ public: void LoadData(const std::vector& vectList) const; void LoadData() const; + bool make_lodsmry_file(); + + // Added based on requirements from ResInsight + void use_lodsmry_file(bool enable); + std::chrono::system_clock::time_point startdate() const { return startdat; } const std::vector& keywordList() const; @@ -65,7 +70,7 @@ public: int timestepIdxAtReportstepStart(const int reportStep) const; - size_t numberOfTimeSteps() const { return timeStepList.size(); } + size_t numberOfTimeSteps() const { return nTstep; } const std::string& get_unit(const std::string& name) const; const std::string& get_unit(const SummaryNode& node) const; @@ -73,10 +78,16 @@ public: void write_rsm(std::ostream&) const; void write_rsm_file(std::optional = std::nullopt) const; + void ijk_from_global_index(int glob, int &i, int &j, int &k) const; private: - Opm::filesystem::path inputFileName; + + bool useLodsmryFile; // Added by ResInsight use + + Opm::filesystem::path inputFileName, lodFileName; int nI, nJ, nK, nSpecFiles; - size_t nVect; + bool fromSingleRun, lodEnabeled; + uint64_t lod_offset, lod_arr_size; + size_t nVect, nTstep; std::vector formattedFiles; std::vector dataFileList; @@ -92,7 +103,6 @@ private: std::vector seqIndex; - void ijk_from_global_index(int glob, int &i, int &j, int &k) const; std::vector summaryNodes; std::unordered_map kwunits; @@ -129,6 +139,9 @@ private: std::vector> getListOfArrays(std::string filename, bool formatted); std::vector makeKeywPosVector(int speInd) const; + std::string read_string_from_disk(std::fstream& fileH, uint64_t size) const; + void inspect_lodsmry(); + void Load_from_lodsmry(const std::vector& keywIndVect) const; }; }} // namespace Opm::EclIO diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclFile.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclFile.hpp index 0f5d6f628d..0d5136410c 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclFile.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclFile.hpp @@ -36,7 +36,7 @@ class EclFile { public: explicit EclFile(const std::string& filename, bool preload = false); - bool formattedInput() { return formatted; } + bool formattedInput() const { return formatted; } void loadData(); // load all data void loadData(const std::string& arrName); // load all arrays with array name equal to arrName @@ -55,6 +55,8 @@ public: using EclEntry = std::tuple; std::vector getList() const; + const std::vector& getElementSizeList() const { return array_element_size; } + template const std::vector& get(int arrIndex); @@ -66,6 +68,7 @@ public: const std::vector& arrayNames() const { return array_name; } std::size_t size() const; + bool is_ix() const; protected: bool formatted; @@ -80,6 +83,7 @@ protected: std::vector array_name; std::vector array_type; std::vector array_size; + std::vector array_element_size; std::vector ifStreamPos; @@ -110,7 +114,10 @@ private: void loadBinaryArray(std::fstream& fileH, std::size_t arrIndex); void loadFormattedArray(const std::string& fileStr, std::size_t arrIndex, int64_t fromPos); - + + std::vector get_bin_logi_raw_values(int arrIndex) const; + std::vector get_fmt_real_raw_str_values(int arrIndex) const; + }; }} // namespace Opm::EclIO diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclIOdata.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclIOdata.hpp index 7fdcbc0344..eb349f5ee6 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclIOdata.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclIOdata.hpp @@ -24,26 +24,28 @@ namespace Opm { namespace EclIO { - // type MESS have no assisiated data + // type MESS have no assisiated data enum eclArrType { - INTE, REAL, DOUB, CHAR, LOGI, MESS + INTE, REAL, DOUB, CHAR, LOGI, MESS, C0NN }; // named constants related to binary file format - const unsigned int true_value = 0xffffffff; + const unsigned int true_value_ecl = 0xffffffff; + const unsigned int true_value_ix = 0x1000000; const unsigned int false_value = 0x00000000; + const int sizeOfInte = 4; // number of bytes pr integer (inte) element const int sizeOfReal = 4; // number of bytes pr float (real) element const int sizeOfDoub = 8; // number of bytes pr double (doub) element const int sizeOfLogi = 4; // number of bytes pr bool (logi) element const int sizeOfChar = 8; // number of bytes pr string (char) element - const int MaxBlockSizeInte = 4000; // Maximum block size for INTE arrays in binary files - const int MaxBlockSizeReal = 4000; // Maximum block size for REAL arrays in binary files - const int MaxBlockSizeDoub = 8000; // Maximum block size for DOUB arrays in binary files - const int MaxBlockSizeLogi = 4000; // Maximum block size for LOGI arrays in binary files - const int MaxBlockSizeChar = 840; // Maximum block size for CHAR arrays in binary files + const int MaxBlockSizeInte = 4000; // Maximum block size for INTE arrays in binary files + const int MaxBlockSizeReal = 4000; // Maximum block size for REAL arrays in binary files + const int MaxBlockSizeDoub = 8000; // Maximum block size for DOUB arrays in binary files + const int MaxBlockSizeLogi = 4000; // Maximum block size for LOGI arrays in binary files + const int MaxBlockSizeChar = 840; // Maximum block size for CHAR arrays in binary files // named constants related to formatted file file format const int MaxNumBlockInte = 1000; // maximum number of Inte values in block => hard line shift @@ -52,17 +54,17 @@ namespace Opm { namespace EclIO { const int MaxNumBlockLogi = 1000; // maximum number of Logi values in block => hard line shift const int MaxNumBlockChar = 105; // maximum number of Char values in block => hard line shift - const int numColumnsInte = 6; // number of columns for Inte values - const int numColumnsReal = 4; // number of columns for Real values - const int numColumnsDoub = 3; // number of columns for Doub values - const int numColumnsLogi = 25; // number of columns for Logi values - const int numColumnsChar = 7; // number of columns for Char values + const int numColumnsInte = 6; // number of columns for Inte values + const int numColumnsReal = 4; // number of columns for Real values + const int numColumnsDoub = 3; // number of columns for Doub values + const int numColumnsLogi = 25; // number of columns for Logi values + const int numColumnsChar = 7; // number of columns for Char values - const int columnWidthInte = 12; // number of characters fore each Inte Element - const int columnWidthReal = 17; // number of characters fore each Inte Element - const int columnWidthDoub = 23; // number of characters fore each Inte Element - const int columnWidthLogi = 3; // number of characters fore each Inte Element - const int columnWidthChar = 11; // number of characters fore each Inte Element + const int columnWidthInte = 12; // number of characters fore each Inte Element + const int columnWidthReal = 17; // number of characters fore each Inte Element + const int columnWidthDoub = 23; // number of characters fore each Inte Element + const int columnWidthLogi = 3; // number of characters fore each Inte Element + const int columnWidthChar = 11; // number of characters fore each Inte Element }} // namespace Opm::EclIO diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclOutput.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclOutput.hpp index edfa383a42..a20c4d0dd2 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclOutput.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclOutput.hpp @@ -47,59 +47,71 @@ public: const std::vector& data) { eclArrType arrType = MESS; + int element_size = 4; + if (typeid(T) == typeid(int)) arrType = INTE; else if (typeid(T) == typeid(float)) arrType = REAL; - else if (typeid(T) == typeid(double)) + else if (typeid(T) == typeid(double)){ arrType = DOUB; - else if (typeid(T) == typeid(bool)) + element_size = 8; + } else if (typeid(T) == typeid(bool)) arrType = LOGI; else if (typeid(T) == typeid(char)) arrType = MESS; if (isFormatted) { - writeFormattedHeader(name, data.size(), arrType); + writeFormattedHeader(name, data.size(), arrType, element_size); if (arrType != MESS) writeFormattedArray(data); } else { - writeBinaryHeader(name, data.size(), arrType); + writeBinaryHeader(name, data.size(), arrType, element_size); if (arrType != MESS) writeBinaryArray(data); } } + // when this function is used array type will be assumed C0NN (not CHAR). + // Also in cases where element size is 8 or less, element size will be 8. + + void write(const std::string& name, const std::vector& data, int element_size); + void message(const std::string& msg); void flushStream(); + void set_ix() { ix_standard = true; } + friend class OutputStream::Restart; friend class OutputStream::SummarySpecification; private: - void writeBinaryHeader(const std::string& arrName, int64_t size, eclArrType arrType); + void writeBinaryHeader(const std::string& arrName, int64_t size, eclArrType arrType, int element_size); template void writeBinaryArray(const std::vector& data); - void writeBinaryCharArray(const std::vector& data); + void writeBinaryCharArray(const std::vector& data, int element_size); void writeBinaryCharArray(const std::vector>& data); - void writeFormattedHeader(const std::string& arrName, int size, eclArrType arrType); + void writeFormattedHeader(const std::string& arrName, int size, eclArrType arrType, int element_size); template void writeFormattedArray(const std::vector& data); - void writeFormattedCharArray(const std::vector& data); + void writeFormattedCharArray(const std::vector& data, int element_size); void writeFormattedCharArray(const std::vector>& data); void writeArrayType(const eclArrType arrType); - std::string make_real_string(float value) const; - std::string make_doub_string(double value) const; + std::string make_real_string_ecl(float value) const; + std::string make_real_string_ix(float value) const; + std::string make_doub_string_ecl(double value) const; + std::string make_doub_string_ix(double value) const; - bool isFormatted; + bool isFormatted, ix_standard; std::ofstream ofileH; }; diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclUtil.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclUtil.hpp index c80873fe34..68cca16256 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclUtil.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/EclUtil.hpp @@ -23,6 +23,8 @@ #include #include +#include +#include namespace Opm { namespace EclIO { @@ -31,24 +33,52 @@ namespace Opm { namespace EclIO { float flipEndianFloat(float num); double flipEndianDouble(double num); bool isEOF(std::fstream* fileH); + bool fileExists(const std::string& filename); + bool isFormatted(const std::string& filename); std::tuple block_size_data_binary(eclArrType arrType); std::tuple block_size_data_formatted(eclArrType arrType); std::string trimr(const std::string &str1); - uint64_t sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrType); - uint64_t sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrType arrType); + uint64_t sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrType, int elementSize); + uint64_t sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrType arrType, int elementSize); void readBinaryHeader(std::fstream& fileH, std::string& tmpStrName, int& tmpSize, std::string& tmpStrType); void readBinaryHeader(std::fstream& fileH, std::string& arrName, - int64_t& size, Opm::EclIO::eclArrType &arrType); + int64_t& size, Opm::EclIO::eclArrType &arrType, int& elementSize); void readFormattedHeader(std::fstream& fileH, std::string& arrName, - int64_t &num, Opm::EclIO::eclArrType &arrType); + int64_t &num, Opm::EclIO::eclArrType &arrType, int& elementSize); + template + std::vector readBinaryArray(std::fstream& fileH, const int64_t size, Opm::EclIO::eclArrType type, + std::function& flip, int elementSize); + + std::vector readBinaryInteArray(std::fstream &fileH, const int64_t size); + std::vector readBinaryRealArray(std::fstream& fileH, const int64_t size); + std::vector readBinaryDoubArray(std::fstream& fileH, const int64_t size); + std::vector readBinaryLogiArray(std::fstream &fileH, const int64_t size); + std::vector readBinaryRawLogiArray(std::fstream &fileH, const int64_t size); + std::vector readBinaryCharArray(std::fstream& fileH, const int64_t size); + std::vector readBinaryC0nnArray(std::fstream& fileH, const int64_t size, int elementSize); + + template + std::vector readFormattedArray(const std::string& file_str, const int size, int64_t fromPos, + std::function& process); + + std::vector readFormattedInteArray(const std::string& file_str, const int64_t size, int64_t fromPos); + + std::vector readFormattedCharArray(const std::string& file_str, const int64_t size, + int64_t fromPos, int elementSize); + + std::vector readFormattedRealArray(const std::string& file_str, const int64_t size, int64_t fromPos); + std::vector readFormattedRealRawStrings(const std::string& file_str, const int64_t size, int64_t fromPos); + + std::vector readFormattedLogiArray(const std::string& file_str, const int64_t size, int64_t fromPos); + std::vector readFormattedDoubArray(const std::string& file_str, const int64_t size, int64_t fromPos); }} // namespace Opm::EclIO diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/SummaryNode.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/SummaryNode.hpp index f29543c031..4690dadea7 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/SummaryNode.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/SummaryNode.hpp @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with OPM. If not, see . - */ +*/ #ifndef OPM_IO_SUMMARYNODE_HPP #define OPM_IO_SUMMARYNODE_HPP @@ -25,11 +25,10 @@ #include #include -namespace Opm::EclIO { +namespace Opm { namespace EclIO { struct SummaryNode { enum class Category { - Aquifer, Well, Group, Field, @@ -37,6 +36,8 @@ struct SummaryNode { Block, Connection, Segment, + Aquifer, + Node, Miscellaneous, }; @@ -47,6 +48,7 @@ struct SummaryNode { Pressure, Count, Mode, + ProdIndex, Undefined, }; @@ -56,6 +58,8 @@ struct SummaryNode { std::string wgname; int number; + std::optional fip_region; + constexpr static int default_number { std::numeric_limits::min() }; std::string unique_key() const; @@ -72,6 +76,6 @@ struct SummaryNode { std::optional display_number(number_renderer) const; }; -} // namespace Opm::EclIO +}} // namespace Opm::EclIO #endif // OPM_IO_SUMMARYNODE_HPP diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/group.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/group.hpp index 131cc62571..0ac506a47e 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/group.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/group.hpp @@ -32,12 +32,21 @@ struct RstHeader; struct RstGroup { RstGroup(const UnitSystem& unit_system, + const RstHeader& header, const std::string* zwel, const int * igrp, const float * sgrp, const double * xgrp); std::string name; + + int parent_group; + int prod_active_cmode; + int gconprod_cmode; + int winj_cmode; + int ginj_cmode; + int guide_rate_def; + float oil_rate_limit; float water_rate_limit; float gas_rate_limit; diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/header.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/header.hpp index 2c57e85891..c177b795e2 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/header.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/header.hpp @@ -24,10 +24,12 @@ #include namespace Opm { +class UnitSystem; + namespace RestartIO { struct RstHeader { - RstHeader(const std::vector& intehead, const std::vector& logihead, const std::vector& doubhead); + RstHeader(const UnitSystem& unit_system, const std::vector& intehead, const std::vector& logihead, const std::vector& doubhead); int nx; int ny; @@ -82,10 +84,8 @@ struct RstHeader { int nilbrz; int ntfip ; int nmfipr; - int nrfreg; - int ntfreg; - int nplmix; int ngroup; + int nwgmax; bool e300_radial; bool e100_radial; @@ -100,6 +100,7 @@ struct RstHeader { bool dir_eps; bool reversible_eps; bool alt_eps; + bool group_control_active; double next_timestep1; double next_timestep2; @@ -110,6 +111,8 @@ struct RstHeader { double guide_rate_d; double guide_rate_e; double guide_rate_f; + double guide_rate_delay; + double guide_rate_damping; double udq_range; double udq_undefined; double udq_eps; diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/state.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/state.hpp index 5520aa4ca6..c3d8689d67 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/state.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/state.hpp @@ -35,6 +35,11 @@ namespace Opm { namespace RestartIO { struct RstState { + RstState(const ::Opm::UnitSystem& unit_system, + const std::vector& intehead, + const std::vector& logihead, + const std::vector& doubhead); + RstState(const ::Opm::UnitSystem& unit_system, const std::vector& intehead, const std::vector& logihead, diff --git a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/well.hpp b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/well.hpp index 2db54ad332..e6ba452a22 100644 --- a/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/well.hpp +++ b/ThirdParty/custom-opm-common/opm-common/opm/io/eclipse/rst/well.hpp @@ -66,14 +66,16 @@ struct RstWell { std::array ij; std::pair k1k2; WellType wtype; + int well_status; int active_control; int vfp_table; - int pred_requested_control; bool allow_xflow; + int preferred_phase; int hist_requested_control; int msw_index; int completion_ordering; int pvt_table; + int msw_pressure_drop_model; float orat_target; float wrat_target; @@ -88,12 +90,14 @@ struct RstWell { float datum_depth; float drainage_radius; float efficiency_factor; + float alq_value; double oil_rate; double water_rate; double gas_rate; double liquid_rate; double void_rate; + double thp; double flow_bhp; double wct; double gor; diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EGrid.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EGrid.cpp index f92c078b95..7427c2a97f 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EGrid.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EGrid.cpp @@ -16,7 +16,12 @@ along with OPM. If not, see . */ +#define _USE_MATH_DEFINES +#include // For definition of M_PI + #include +#include +#include #include @@ -30,41 +35,200 @@ namespace Opm { namespace EclIO { -EGrid::EGrid(const std::string &filename) : EclFile(filename) +using NNCentry = std::tuple; + +EGrid::EGrid(const std::string &filename, std::string grid_name) : + EclFile(filename), inputFileName { filename }, m_grid_name {grid_name} { - EclFile file(filename); + initFileName = inputFileName.parent_path() / inputFileName.stem(); - auto gridhead = get("GRIDHEAD"); + if (this->formattedInput()) + initFileName += ".FINIT"; + else + initFileName += ".INIT"; - nijk[0] = gridhead[1]; - nijk[1] = gridhead[2]; - nijk[2] = gridhead[3]; + std::string lgrname = "global"; - if (file.hasKey("ACTNUM")) { - auto actnum = get("ACTNUM"); + m_nncs_loaded = false; + actnum_array_index = -1; + nnc1_array_index = -1; + nnc2_array_index = -1; + m_radial = false; - nactive = 0; - for (unsigned int i = 0; i < actnum.size(); i++) { - if (actnum[i] > 0) { - act_index.push_back(nactive); - glob_index.push_back(i); - nactive++; - } else { - act_index.push_back(-1); - } + int hostnum_index = -1; + + for (size_t n = 0; n < array_name.size(); n++) { + + if (array_name[n] == "ENDLGR") + lgrname = "global"; + + if (array_name[n] == "LGR") { + auto lgr = this->get(n); + lgrname = lgr[0]; + lgr_names.push_back(lgr[0]); } - } else { - int nCells = nijk[0] * nijk[1] * nijk[2]; - act_index.resize(nCells); - glob_index.resize(nCells); - std::iota(act_index.begin(), act_index.end(), 0); - std::iota(glob_index.begin(), glob_index.end(), 0); - } - coord_array = get("COORD"); - zcorn_array = get("ZCORN"); + if (array_name[n] == "NNCHEAD"){ + auto nnchead = this->get(n); + + if (nnchead[1] == 0) + lgrname = "global"; + else + lgrname = lgr_names[nnchead[1] - 1]; + } + + if (lgrname == grid_name) { + if (array_name[n] == "GRIDHEAD") { + auto gridhead = get(n); + nijk[0] = gridhead[1]; + nijk[1] = gridhead[2]; + nijk[2] = gridhead[3]; + + if (gridhead.size() > 26) + m_radial = gridhead[26] > 0 ? true: false; + } + + if (array_name[n] == "COORD") + coord_array_index= n; + else if (array_name[n] == "ZCORN") + zcorn_array_index= n; + else if (array_name[n] == "ACTNUM") + actnum_array_index= n; + else if (array_name[n] == "NNC1") + nnc1_array_index= n; + else if (array_name[n] == "NNC2") + nnc2_array_index= n; + else if (array_name[n] == "HOSTNUM") + hostnum_index= n; + } + + if ((lgrname == "global") && (array_name[n] == "GRIDHEAD")) { + auto gridhead = get(n); + host_nijk[0] = gridhead[1]; + host_nijk[1] = gridhead[2]; + host_nijk[2] = gridhead[3]; + } + + } + + if (actnum_array_index != -1) { + auto actnum = this->get(actnum_array_index); + nactive = 0; + for (size_t i = 0; i < actnum.size(); i++) { + if (actnum[i] > 0) { + act_index.push_back(nactive); + glob_index.push_back(i); + nactive++; + } else { + act_index.push_back(-1); + } + } + } else { + int nCells = nijk[0] * nijk[1] * nijk[2]; + act_index.resize(nCells); + glob_index.resize(nCells); + std::iota(act_index.begin(), act_index.end(), 0); + std::iota(glob_index.begin(), glob_index.end(), 0); + } + + if (hostnum_index > -1){ + auto hostnum = getImpl(hostnum_index, INTE, inte_array, "integer"); + host_cells.reserve(hostnum.size()); + + for (auto val : hostnum) + host_cells.push_back(val -1); + } } +std::vector> EGrid::hostCellsIJK() +{ + std::vector> res_vect; + res_vect.reserve(host_cells.size()); + + for (auto val : host_cells){ + std::array tmp; + tmp[2] = val / (host_nijk[0] * host_nijk[1]); + int rest = val % (host_nijk[0] * host_nijk[1]); + + tmp[1] = rest / host_nijk[0]; + tmp[0] = rest % host_nijk[0]; + + res_vect.push_back(tmp); + } + + return res_vect; +} + +std::vector EGrid::get_nnc_ijk() +{ + if (!m_nncs_loaded) + load_nnc_data(); + + std::vector res_vect; + res_vect.reserve(nnc1_array.size()); + + for (size_t n=0; n< nnc1_array.size(); n++){ + auto ijk1 = ijk_from_global_index(nnc1_array[n] - 1); + auto ijk2 = ijk_from_global_index(nnc2_array[n] - 1); + + if (transnnc_array.size() > 0) + res_vect.push_back({ijk1[0], ijk1[1], ijk1[2], ijk2[0], ijk2[1], ijk2[2], transnnc_array[n]}); + else + res_vect.push_back({ijk1[0], ijk1[1], ijk1[2], ijk2[0], ijk2[1], ijk2[2], -1.0 }); + } + + return res_vect; +} + + +void EGrid::load_grid_data() +{ + coord_array = getImpl(coord_array_index, REAL, real_array, "float"); + zcorn_array = getImpl(zcorn_array_index, REAL, real_array, "float"); +} + +void EGrid::load_nnc_data() +{ + if ((nnc1_array_index > -1) && (nnc2_array_index > -1)) { + + nnc1_array = getImpl(nnc1_array_index, Opm::EclIO::INTE, inte_array, "inte"); + nnc2_array = getImpl(nnc2_array_index, Opm::EclIO::INTE, inte_array, "inte"); + + if ((Opm::filesystem::exists(initFileName)) && (nnc1_array.size() > 0)){ + Opm::EclIO::EInit init(initFileName.string()); + + auto init_dims = init.grid_dimension(m_grid_name); + int init_nactive = init.activeCells(m_grid_name); + + if (init_dims != nijk){ + std::string message = "Dimensions of Egrid differ from dimensions found in init file. "; + std::string grid_str = std::to_string(nijk[0]) + "x" + std::to_string(nijk[1]) + "x" + std::to_string(nijk[2]); + std::string init_str = std::to_string(init_dims[0]) + "x" + std::to_string(init_dims[1]) + "x" + std::to_string(init_dims[2]); + message = message + "Egrid: " + grid_str + ". INIT file: " + init_str; + OPM_THROW(std::invalid_argument, message); + } + + if (init_nactive != nactive){ + std::string message = "Number of active cells are different in Egrid and Init file."; + message = message + " Egrid: " + std::to_string(nactive) + ". INIT file: " + std::to_string(init_nactive); + OPM_THROW(std::invalid_argument, message); + } + + auto trans_data = init.getInitData("TRANNNC", m_grid_name); + + if (trans_data.size() != nnc1_array.size()){ + std::string message = "inconsistent size of array TRANNNC in init file. "; + message = message + " Size of NNC1 and NNC2: " + std::to_string(nnc1_array.size()); + message = message + " Size of TRANNNC: " + std::to_string(trans_data.size()); + OPM_THROW(std::invalid_argument, message); + } + + transnnc_array = trans_data; + } + + m_nncs_loaded = true; + } +} int EGrid::global_index(int i, int j, int k) const { @@ -129,52 +293,65 @@ std::array EGrid::ijk_from_global_index(int globInd) const void EGrid::getCellCorners(const std::array& ijk, std::array& X, std::array& Y, - std::array& Z) const + std::array& Z) { + if (coord_array.empty()) + load_grid_data(); + std::vector zind; std::vector pind; - // calculate indices for grid pillars in COORD arrray - pind.push_back(ijk[1]*(nijk[0]+1)*6 + ijk[0]*6); - pind.push_back(pind[0] + 6); - pind.push_back(pind[0] + (nijk[0]+1)*6); - pind.push_back(pind[2] + 6); + pind.push_back(ijk[1]*(nijk[0]+1)*6 + ijk[0]*6); + pind.push_back(pind[0] + 6); + pind.push_back(pind[0] + (nijk[0]+1)*6); + pind.push_back(pind[2] + 6); - // get depths from zcorn array in ZCORN array - zind.push_back(ijk[2]*nijk[0]*nijk[1]*8 + ijk[1]*nijk[0]*4 + ijk[0]*2); - zind.push_back(zind[0] + 1); - zind.push_back(zind[0] + nijk[0]*2); - zind.push_back(zind[2] + 1); + // get depths from zcorn array in ZCORN array + zind.push_back(ijk[2]*nijk[0]*nijk[1]*8 + ijk[1]*nijk[0]*4 + ijk[0]*2); + zind.push_back(zind[0] + 1); + zind.push_back(zind[0] + nijk[0]*2); + zind.push_back(zind[2] + 1); - for (int n = 0; n < 4; n++) { - zind.push_back(zind[n] + nijk[0]*nijk[1]*4); - } + for (int n = 0; n < 4; n++) + zind.push_back(zind[n] + nijk[0]*nijk[1]*4); - for (int n = 0; n< 8; n++){ - Z[n] = zcorn_array[zind[n]]; - } + for (int n = 0; n< 8; n++) + Z[n] = zcorn_array[zind[n]]; - for (int n = 0; n < 4; n++) { - double xt = coord_array[pind[n]]; - double yt = coord_array[pind[n] + 1]; - double zt = coord_array[pind[n] + 2]; + for (int n = 0; n < 4; n++) { + double xt; + double yt; + double xb; + double yb; - double xb = coord_array[pind[n] + 3]; - double yb = coord_array[pind[n] + 4]; - double zb = coord_array[pind[n]+5]; + double zt = coord_array[pind[n] + 2]; + double zb = coord_array[pind[n] + 5]; - X[n] = xt + (xb-xt) / (zt-zb) * (zt - Z[n]); - X[n+4] = xt + (xb-xt) / (zt-zb) * (zt-Z[n+4]); + if (m_radial) { + xt = coord_array[pind[n]] * cos(coord_array[pind[n] + 1] / 180.0 * M_PI); + yt = coord_array[pind[n]] * sin(coord_array[pind[n] + 1] / 180.0 * M_PI); + xb = coord_array[pind[n]+3] * cos(coord_array[pind[n] + 4] / 180.0 * M_PI); + yb = coord_array[pind[n]+3] * sin(coord_array[pind[n] + 4] / 180.0 * M_PI); + } else { + xt = coord_array[pind[n]]; + yt = coord_array[pind[n] + 1]; + xb = coord_array[pind[n] + 3]; + yb = coord_array[pind[n] + 4]; + } - Y[n] = yt+(yb-yt)/(zt-zb)*(zt-Z[n]); - Y[n+4] = yt+(yb-yt)/(zt-zb)*(zt-Z[n+4]); - } + X[n] = xt + (xb-xt) / (zt-zb) * (zt - Z[n]); + X[n+4] = xt + (xb-xt) / (zt-zb) * (zt-Z[n+4]); + + Y[n] = yt+(yb-yt)/(zt-zb)*(zt-Z[n]); + Y[n+4] = yt+(yb-yt)/(zt-zb)*(zt-Z[n+4]); + } } + void EGrid::getCellCorners(int globindex, std::array& X, - std::array& Y, std::array& Z) const + std::array& Y, std::array& Z) { return getCellCorners(ijk_from_global_index(globindex),X,Y,Z); } diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EInit.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EInit.cpp new file mode 100644 index 0000000000..5754109454 --- /dev/null +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EInit.cpp @@ -0,0 +1,161 @@ +/* + Copyright 2020 Equinor ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . + */ + +#include +#include + +#include + +namespace Opm { namespace EclIO { + + +EInit::EInit(const std::string &filename) : EclFile(filename) +{ + std::string lgrname; + std::string nncname; + + lgrname = "global"; + + for (size_t n = 0; n < array_name.size(); n++) { + if (array_name[n] == "LGR"){ + auto lgr = this->get(n); + lgrname = lgr[0]; + + if (std::find(lgr_names.begin(), lgr_names.end(), lgrname) == lgr_names.end()){ + lgr_names.push_back(lgrname); + lgr_array_index.push_back({}); + lgr_nijk.push_back({}); + lgr_nactive.push_back(0); + } + } + + if (array_name[n] == "LGRSGONE") + lgrname = "global"; + + if ((lgrname == "global") && (array_name[n] != "LGRSGONE")) + global_array_index[array_name[n]] = n; + + if ((lgrname != "global") && (array_name[n] != "LGRSGONE") && (array_name[n] != "LGR")) + { + auto it = std::find(lgr_names.begin(), lgr_names.end(), lgrname); + size_t ind = std::distance(lgr_names.begin(), it); + lgr_array_index[ind][array_name[n]] = n; + } + + if (array_name[n] == "INTEHEAD") + { + auto inteh = getImpl(n, INTE, inte_array, "integer"); + + if (lgrname == "global") { + global_nijk = {inteh[8], inteh[9], inteh[10]}; + global_nactive = inteh[11]; + } else { + auto it = std::find(lgr_names.begin(), lgr_names.end(), lgrname); + size_t lgr_ind = std::distance(lgr_names.begin(), it); + lgr_nijk[lgr_ind] = {inteh[8], inteh[9], inteh[10]}; + lgr_nactive[lgr_ind] = inteh[11]; + } + } + } +} + + +int EInit::get_array_index(const std::string& name, const std::string& grid_name) const +{ + if (grid_name == "global"){ + if (global_array_index.count(name) == 0) + OPM_THROW(std::runtime_error, "Map key '" + name + "' not found in global_array_index"); + + return global_array_index.at(name); + + } else { + + int lgr_index = get_lgr_index(grid_name); + + if (lgr_array_index[lgr_index].count(name) == 0) + OPM_THROW(std::invalid_argument, "Map key '" + name + "' not found in lgr_array_index"); + + return lgr_array_index[lgr_index].at(name); + } +}; + +int EInit::activeCells(const std::string& grid_name) const +{ + if (grid_name == "global") + return global_nactive; + else + return lgr_nactive[get_lgr_index(grid_name)]; +} + +const std::array& EInit::grid_dimension(const std::string& grid_name) const +{ + if (grid_name == "global") + return global_nijk; + else + return lgr_nijk[get_lgr_index(grid_name)]; +} + +bool EInit::hasLGR(const std::string& name) const{ + if (std::find(lgr_names.begin(), lgr_names.end(), name) == lgr_names.end()) + return false; + else + return true; +} + +int EInit::get_lgr_index(const std::string& grid_name) const +{ + auto it = std::find(lgr_names.begin(), lgr_names.end(), grid_name); + + if (it == lgr_names.end()) { + std::string message = "LGR '" + grid_name + "' not found in init file."; + OPM_THROW(std::invalid_argument, message); + } + + return std::distance(lgr_names.begin(), it); +} + +std::vector EInit::list_arrays(const std::string& grid_name) const +{ + std::vector array_list; + + int lgr_index = this->get_lgr_index(grid_name); + + for (auto const& x : lgr_array_index[lgr_index]) + { + int ind = x.second; + array_list.push_back(std::make_tuple(array_name[ind], array_type[ind], array_size[ind])); + } + + return array_list; +} + +std::vector EInit::list_arrays() const +{ + std::vector array_list; + + for (auto const& x : global_array_index) + { + int ind = x.second; + array_list.push_back(std::make_tuple(array_name[ind], array_type[ind], array_size[ind])); + } + + return array_list; +} + + +}} // namespace Opm::EclIO diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ERsm.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ERsm.cpp index 1715e41d2f..9fbf72154b 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ERsm.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ERsm.cpp @@ -22,6 +22,8 @@ #include #include +#include + #include #include #include @@ -174,7 +176,8 @@ void ERsm::load_block(std::deque& lines, std::size_t& vector_length SummaryNode::category_from_keyword(kw_list[kw_index]), SummaryNode::Type::Undefined, wgnames[kw_index], - make_num(nums_list[kw_index])}; + make_num(nums_list[kw_index]), + ""}; block_data.emplace_back( node, vector_length ); } @@ -254,21 +257,29 @@ bool cmp(const ESmry& smry, const ERsm& rsm) { const auto& summary_dates = smry.dates(); if (rsm.has_dates()) { const auto& rsm_dates = rsm.dates(); - if (rsm_dates.size() != summary_dates.size()) + if (rsm_dates.size() != summary_dates.size()) { + fmt::print(stderr, "len(summary) = {} len(rsm) = {}", summary_dates.size(), rsm_dates.size()); return false; + } for (std::size_t time_index = 0; time_index < rsm_dates.size(); time_index++) { const auto smry_ts = TimeStampUTC( std::chrono::system_clock::to_time_t(summary_dates[time_index]) ); const auto rsm_ts = rsm_dates[time_index]; - if (smry_ts.year() != rsm_ts.year()) + if (smry_ts.year() != rsm_ts.year()) { + fmt::print(stderr, "time_index: {} summary.year: {} rsm.year: {}", time_index, smry_ts.year(), rsm_ts.year()); return false; + } - if (smry_ts.month() != rsm_ts.month()) + if (smry_ts.month() != rsm_ts.month()) { + fmt::print(stderr, "time_index: {} summary.month: {} rsm.month: {}", time_index, smry_ts.month(), rsm_ts.month()); return false; + } - if (smry_ts.day() != rsm_ts.day()) + if (smry_ts.day() != rsm_ts.day()) { + fmt::print(stderr, "time_index: {} summary.day: {} rsm.day: {}", time_index, smry_ts.day(), rsm_ts.day()); return false; + } } } else { const auto& rsm_days = rsm.days(); @@ -280,8 +291,10 @@ bool cmp(const ESmry& smry, const ERsm& rsm) { using TP = time_point; auto smry_days = duration_cast(summary_dates[time_index] - summary_dates[0]).count() / 86400.0 ; - if (!cmp::scalar_equal(smry_days, rsm_days[time_index])) + if (!cmp::scalar_equal(smry_days, rsm_days[time_index])) { + fmt::print(stderr, "time_index: {} summary.days: {} rsm.days: {}", time_index, smry_days, rsm_days[time_index]); return false; + } } } @@ -309,11 +322,14 @@ bool cmp(const ESmry& smry, const ERsm& rsm) { const auto& smry_vector = smry.get(node); const auto& rsm_vector = rsm.get(key); for (std::size_t index = 0; index < smry_vector.size(); index++) { + const double eps = 5e-5; const double diff = static_cast(smry_vector[index]) - rsm_vector[index]; const double sum = std::fabs(static_cast(smry_vector[index])) + std::fabs(rsm_vector[index]); - if (diff > 1e-5 * sum) + if (diff > eps * sum) { + fmt::print(stderr, "time_index: {} key: {} summary: {} rsm: {}", index, key, smry_vector[index], rsm_vector[index]); return false; + } } } diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ERst.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ERst.cpp index db400460e6..b4964bb920 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ERst.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ERst.cpp @@ -28,8 +28,6 @@ #include #include -#include - namespace { int seqnumFromSeparateFilename(const std::string& filename) @@ -80,9 +78,9 @@ void ERst::loadReportStepNumber(int number) } std::vector arrayIndexList; - arrayIndexList.reserve(arrIndexRange[number].second - arrIndexRange[number].first + 1); + arrayIndexList.reserve(arrIndexRange.at(number).second - arrIndexRange.at(number).first + 1); - for (int i = arrIndexRange[number].first; i < arrIndexRange[number].second; i++) { + for (int i = arrIndexRange.at(number).first; i < arrIndexRange.at(number).second; i++) { arrayIndexList.push_back(i); } @@ -93,6 +91,12 @@ void ERst::loadReportStepNumber(int number) std::vector ERst::listOfRstArrays(int reportStepNumber) +{ + return this->listOfRstArrays(reportStepNumber, "global"); +} + + +std::vector ERst::listOfRstArrays(int reportStepNumber, const std::string& lgr_name) { std::vector list; @@ -101,36 +105,66 @@ std::vector ERst::listOfRstArrays(int reportStepNumber) OPM_THROW(std::invalid_argument, message); } - const auto& rng = this->arrIndexRange[reportStepNumber]; - list.reserve(rng.second - rng.first); - - for (int i = rng.first; i < rng.second; i++) { - list.emplace_back(array_name[i], array_type[i], array_size[i]); + if ((lgr_name != "global") && (!this->hasLGR(lgr_name, reportStepNumber))) { + std::string message = "Trying to get list of arrays from non existing LGR " + lgr_name; + OPM_THROW(std::invalid_argument, message); } + std::string lgr_name_upper = lgr_name; + std::transform(lgr_name_upper.begin(), lgr_name_upper.end(),lgr_name_upper.begin(), ::toupper); + + int start_ind_lgr; + std::string last_array_name; + + if ((lgr_name == "") or (lgr_name_upper == "GLOBAL")){ + auto rng = this->arrIndexRange.at(reportStepNumber); + start_ind_lgr = std::get<0>(rng); + + // if keyword LGR not found, loop will be stopped with keyword SEQNUM (next report step) + // or last array (end of file) + // Opm flow can have extra keywords after ENDSOL, which maks ENDSOL + // not usable for a global arrays end signal. + + last_array_name = "LGR"; + } else { + start_ind_lgr = get_start_index_lgrname(reportStepNumber, lgr_name); + last_array_name = "ENDLGR"; + } + + int n = start_ind_lgr; + list.emplace_back(array_name[n], array_type[n], array_size[n]); + + do { + n++; + + if ((array_name[n] != "SEQNUM") && (array_name[n] != "LGR")) + list.emplace_back(array_name[n], array_type[n], array_size[n]); + + } while ((array_name[n] != "SEQNUM") && (array_name[n] != last_array_name) && (n < static_cast(array_name.size()) -1 )); + return list; } -int ERst::count(const std::string& name, int reportStepNumber) const -{ +int ERst::occurrence_count(const std::string& name, int reportStepNumber) const +{ if (!hasReportStepNumber(reportStepNumber)) { std::string message = "Trying to count vectors of name " + name + " from non existing sequence " + std::to_string(reportStepNumber); OPM_THROW(std::invalid_argument, message); } - + int count = 0; - + auto range_it = arrIndexRange.find(reportStepNumber); std::pair indexRange = range_it->second; - + for (int i=std::get<0>(indexRange); i(indexRange);i++){ if (array_name[i] == name){ count++; } } - + return count; } @@ -145,10 +179,15 @@ void ERst::initUnified() auto seqn = get(i); seqnum.push_back(seqn[0]); firstIndex.push_back(i); + lgr_names.push_back({}); + } + + if (array_name[i] == "LGRNAMES") { + auto names = getImpl(i, CHAR, char_array, "string"); + lgr_names[seqnum.size() -1 ] = names; } } - for (size_t i = 0; i < seqnum.size(); i++) { std::pair range; range.first = firstIndex[i]; @@ -169,6 +208,21 @@ void ERst::initUnified() } } +bool ERst::hasLGR(const std::string& gridname, int reportStepNumber) const +{ + if (!hasReportStepNumber(reportStepNumber)) { + std::string message = "Checking for LGR name in non existing sequence " + std::to_string(reportStepNumber); + OPM_THROW(std::invalid_argument, message); + } + + auto it_seqnum = std::find(seqnum.begin(), seqnum.end(), reportStepNumber); + int report_index = std::distance(seqnum.begin(), it_seqnum); + auto it_lgrname = std::find(lgr_names[report_index].begin(), lgr_names[report_index].end(), gridname); + + return (it_lgrname != lgr_names[report_index].end()); +} + + void ERst::initSeparate(const int number) { auto& range = this->arrIndexRange[number]; @@ -178,6 +232,41 @@ void ERst::initSeparate(const int number) this->seqnum.assign(1, number); this->nReports = 1; this->reportLoaded[number] = false; + this->lgr_names.push_back({}); + + for (int i = range.first; i < range.second; i++) { + if (array_name[i] == "LGRNAMES") { + auto names = getImpl(i, CHAR, char_array, "string"); + lgr_names[0] = names; + } + } +} + +int ERst::get_start_index_lgrname(int number, const std::string& lgr_name) +{ + if (!hasReportStepNumber(number)) { + std::string message = "Trying to get a restart vector from non report step " + std::to_string(number); + OPM_THROW(std::invalid_argument, message); + } + + auto range_it = arrIndexRange.find(number); + std::pair indexRange = range_it->second; + int start_ind_lgr = -1; + + for (int n = indexRange.first; n < indexRange.second; n++) { + if (array_name[n] == "LGR") { + auto arr = getImpl(n, CHAR, char_array, "string"); + if (arr[0] == lgr_name) + start_ind_lgr = n; + } + } + + if (start_ind_lgr == -1){ + std::string message = "LGR '" + lgr_name + "'not found in restart file"; + OPM_THROW(std::runtime_error, message); + } + + return start_ind_lgr; } std::tuple ERst::getIndexRange(int reportStepNumber) const { @@ -186,19 +275,20 @@ std::tuple ERst::getIndexRange(int reportStepNumber) const { std::string message = "Trying to get index range for non existing sequence " + std::to_string(reportStepNumber); OPM_THROW(std::invalid_argument, message); } - + auto range_it = arrIndexRange.find(reportStepNumber); - + return range_it->second; } -int ERst::getArrayIndex(const std::string& name, int number, int occurrenc) const +int ERst::getArrayIndex(const std::string& name, int number, int occurrenc) { if (!hasReportStepNumber(number)) { std::string message = "Trying to get vector " + name + " from non existing sequence " + std::to_string(number); OPM_THROW(std::invalid_argument, message); } - + + auto range_it = arrIndexRange.find(number); std::pair indexRange = range_it->second; @@ -209,7 +299,7 @@ int ERst::getArrayIndex(const std::string& name, int number, int occurrenc) cons for (int t = 0; t < occurrenc; t++){ it = std::find(it + 1 , array_name.begin() + indexRange.second, name); } - + if (std::distance(array_name.begin(),it) == indexRange.second) { std::string message = "Array " + name + " not found in sequence " + std::to_string(number); OPM_THROW(std::runtime_error, message); @@ -218,6 +308,25 @@ int ERst::getArrayIndex(const std::string& name, int number, int occurrenc) cons return std::distance(array_name.begin(), it); } +int ERst::getArrayIndex(const std::string& name, int number, const std::string& lgr_name) +{ + auto range_it = arrIndexRange.find(number); + std::pair indexRange = range_it->second; + + int start_ind_lgr = get_start_index_lgrname(number, lgr_name); + + auto it = std::find(array_name.begin() + start_ind_lgr, + array_name.begin() + indexRange.second, name); + + if (std::distance(array_name.begin(),it) == indexRange.second) { + std::string message = "Array " + name + " not found for " + lgr_name; + OPM_THROW(std::runtime_error, message); + } + + return std::distance(array_name.begin(), it); +} + + std::streampos ERst::restartStepWritePosition(const int seqnumValue) const { @@ -229,38 +338,74 @@ ERst::restartStepWritePosition(const int seqnumValue) const } template<> -const std::vector& ERst::getRst(const std::string& name, int reportStepNumber, int occurrence) +const std::vector& ERst::getRestartData(const std::string& name, int reportStepNumber, int occurrence) { int ind = getArrayIndex(name, reportStepNumber, occurrence); return getImpl(ind, INTE, inte_array, "integer"); } template<> -const std::vector& ERst::getRst(const std::string& name, int reportStepNumber, int occurrence) +const std::vector& ERst::getRestartData(const std::string& name, int reportStepNumber, int occurrence) { int ind = getArrayIndex(name, reportStepNumber, occurrence); return getImpl(ind, REAL, real_array, "float"); } template<> -const std::vector& ERst::getRst(const std::string& name, int reportStepNumber, int occurrence) +const std::vector& ERst::getRestartData(const std::string& name, int reportStepNumber, int occurrence) { int ind = getArrayIndex(name, reportStepNumber, occurrence); return getImpl(ind, DOUB, doub_array, "double"); } template<> -const std::vector& ERst::getRst(const std::string& name, int reportStepNumber, int occurrence) +const std::vector& ERst::getRestartData(const std::string& name, int reportStepNumber, int occurrence) { int ind = getArrayIndex(name, reportStepNumber, occurrence); return getImpl(ind, LOGI, logi_array, "bool"); } template<> -const std::vector& ERst::getRst(const std::string& name, int reportStepNumber, int occurrence) +const std::vector& ERst::getRestartData(const std::string& name, int reportStepNumber, int occurrence) { int ind = getArrayIndex(name, reportStepNumber, occurrence); return getImpl(ind, CHAR, char_array, "string"); } +template<> +const std::vector& ERst::getRestartData(const std::string& name, int reportStepNumber,const std::string& lgr_name) +{ + int ind = getArrayIndex(name, reportStepNumber, lgr_name); + return getImpl(ind, REAL, real_array, "float"); +} + +template<> +const std::vector& ERst::getRestartData(const std::string& name, int reportStepNumber,const std::string& lgr_name) +{ + int ind = getArrayIndex(name, reportStepNumber, lgr_name); + return getImpl(ind, DOUB, doub_array, "double"); +} + +template<> +const std::vector& ERst::getRestartData(const std::string& name, int reportStepNumber,const std::string& lgr_name) +{ + int ind = getArrayIndex(name, reportStepNumber, lgr_name); + return getImpl(ind, INTE, inte_array, "int"); +} + +template<> +const std::vector& ERst::getRestartData(const std::string& name, int reportStepNumber,const std::string& lgr_name) +{ + int ind = getArrayIndex(name, reportStepNumber, lgr_name); + return getImpl(ind, LOGI, logi_array, "bool"); +} + +template<> +const std::vector& ERst::getRestartData(const std::string& name, int reportStepNumber,const std::string& lgr_name) +{ + int ind = getArrayIndex(name, reportStepNumber, lgr_name); + return getImpl(ind, CHAR, char_array, "char"); +} + + }} // namespace Opm::ecl diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ESmry.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ESmry.cpp index 7b704b3a30..6e41d687f9 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ESmry.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/ESmry.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -30,9 +31,18 @@ #include #include #include + +#ifdef _WIN32 +#include "cross-platform/windows/Substitutes.hpp" +#else #include +#endif + #include #include +#include + +#include /* @@ -83,14 +93,17 @@ std::chrono::system_clock::time_point make_date(const std::vector& datetime namespace Opm { namespace EclIO { -ESmry::ESmry(const std::string &filename, bool loadBaseRunData) : +ESmry::ESmry(const std::string &filename, bool loadBaseRunData , bool uselodsmry ) : inputFileName { filename }, - summaryNodes { } + summaryNodes { }, + useLodsmryFile(uselodsmry) { + fromSingleRun = !loadBaseRunData; Opm::filesystem::path rootName = inputFileName.parent_path() / inputFileName.stem(); - // if root name (without any extension) given as first argument in constructor, binary will then be assumed + // if only root name (without any extension) given as first argument in constructor + // binary will then be assumed if (inputFileName.extension()=="") inputFileName+=".SMSPEC"; @@ -101,6 +114,16 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) : const bool formatted = inputFileName.extension()==".SMSPEC" ? false : true; formattedFiles.push_back(formatted); + if (formatted) + lodFileName = rootName += ".FLODSMRY"; + else + lodFileName = rootName += ".LODSMRY"; + + if ((!loadBaseRunData) && (Opm::filesystem::exists(lodFileName))) + lodEnabeled = true; + else + lodEnabeled = false; + Opm::filesystem::path path = Opm::filesystem::current_path(); updatePathAndRootName(path, rootName); @@ -120,28 +143,44 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) : "SUMTHIN", } ; + std::vector smspecList; + std::vector vectList = {"DIMENS", "RESTART", "KEYWORDS", "NUMS", "UNITS"}; + // Read data from the summary into local data members. { - EclFile smspec(smspec_file.string()); + smspecList.emplace_back(EclFile(smspec_file.string())); - smspec.loadData(); // loading all data + auto arrays = smspecList.back().getList(); + std::vector vectIndices; - const std::vector dimens = smspec.get("DIMENS"); + for (size_t n = 0; n < arrays.size(); n++) + if(std::find(vectList.begin(), vectList.end(), std::get<0>(arrays[n])) != vectList.end()) + vectIndices.push_back(static_cast(n)); + + smspecList.back().loadData(vectIndices); + + const std::vector dimens = smspecList.back().get("DIMENS"); nI = dimens[1]; // This is correct -- dimens[0] is something else! nJ = dimens[2]; nK = dimens[3]; - const std::vector restartArray = smspec.get("RESTART"); - const std::vector keywords = smspec.get("KEYWORDS"); - const std::vector wgnames = smspec.get("WGNAMES"); - const std::vector nums = smspec.get("NUMS"); - const std::vector units = smspec.get("UNITS"); + const std::vector restartArray = smspecList.back().get("RESTART"); + const std::vector keywords = smspecList.back().get("KEYWORDS"); + std::vector wgnames; + + if (smspecList.back().hasKey("WGNAMES")) + wgnames = smspecList.back().get("WGNAMES"); + else + wgnames = smspecList.back().get("NAMES"); + + const std::vector nums = smspecList.back().get("NUMS"); + const std::vector units = smspecList.back().get("UNITS"); std::vector combindKeyList; combindKeyList.reserve(dimens[0]); - this->startdat = make_date(smspec.get("STARTDAT")); + this->startdat = make_date(smspecList.back().get("STARTDAT")); for (unsigned int i=0; i dimens = smspec_rst.get("DIMENS"); - const std::vector restartArray = smspec_rst.get("RESTART"); - const std::vector keywords = smspec_rst.get("KEYWORDS"); - const std::vector wgnames = smspec_rst.get("WGNAMES"); - const std::vector nums = smspec_rst.get("NUMS"); - const std::vector units = smspec_rst.get("UNITS"); + auto arrays = smspecList.back().getList(); + std::vector vectIndices; + + for (size_t n = 0; n < arrays.size(); n++) + if(std::find(vectList.begin(), vectList.end(), std::get<0>(arrays[n])) != vectList.end()) + vectIndices.push_back(static_cast(n)); + + smspecList.back().loadData(vectIndices); + + const std::vector dimens = smspecList.back().get("DIMENS"); + const std::vector restartArray = smspecList.back().get("RESTART"); + const std::vector keywords = smspecList.back().get("KEYWORDS"); + std::vector wgnames; + + if (smspecList.back().hasKey("WGNAMES")) + wgnames = smspecList.back().get("WGNAMES"); + else + wgnames = smspecList.back().get("NAMES"); + + const std::vector nums = smspecList.back().get("NUMS"); + const std::vector units = smspecList.back().get("UNITS"); std::vector combindKeyList; combindKeyList.reserve(dimens[0]); - this->startdat = make_date(smspec_rst.get("STARTDAT")); + this->startdat = make_date(smspecList.back().get("STARTDAT")); for (size_t i = 0; i < keywords.size(); i++) { const std::string keyString = makeKeyString(keywords[i], wgnames[i], nums[i]); @@ -209,7 +262,8 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) : SummaryNode::category_from_keyword(keywords[i], segmentExceptions), SummaryNode::Type::Undefined, wgnames[i], - nums[i] + nums[i], + "" }); keywList.insert(keyString); @@ -243,10 +297,7 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) : auto smry = smryArray[specInd]; - EclFile smspec(std::get<0>(smry)); - smspec.loadData(); - - const std::vector dimens = smspec.get("DIMENS"); + const std::vector dimens = smspecList[specInd].get("DIMENS"); nI = dimens[1]; nJ = dimens[2]; @@ -254,9 +305,15 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) : nParamsSpecFile[specInd] = dimens[0]; - const std::vector keywords = smspec.get("KEYWORDS"); - const std::vector wgnames = smspec.get("WGNAMES"); - const std::vector nums = smspec.get("NUMS"); + const std::vector keywords = smspecList[specInd].get("KEYWORDS"); + std::vector wgnames; + + if (smspecList.back().hasKey("WGNAMES")) + wgnames = smspecList.back().get("WGNAMES"); + else + wgnames = smspecList.back().get("NAMES"); + + const std::vector nums = smspecList[specInd].get("NUMS"); for (size_t i=0; i < keywords.size(); i++) { const std::string keyw = makeKeyString(keywords[i], wgnames[i], nums[i]); @@ -288,132 +345,286 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) : vectorLoaded.push_back(false); } - int dataFileIndex = -1; + if (useLodsmryFile && lodEnabeled) + { + // inspecting formatted or binary lod file. lodsmry possible only if + // loadBaseRunData=false - while (specInd >= 0){ + inspect_lodsmry(); - int reportStepNumber = fromReportStepNumber; + } else { - if (specInd > 0) { - auto rstFrom = smryArray[specInd-1]; - toReportStepNumber = std::get<1>(rstFrom); - } else { - toReportStepNumber = std::numeric_limits::max(); - } + // inspecting time step data, unified summary or multiple summary files both formatted or binary. + // this also include base run data if loadBaseRunData=true and restart runs exists. - Opm::filesystem::path smspecFile(std::get<0>(smryArray[specInd])); - rootName = smspecFile.parent_path() / smspecFile.stem(); + int dataFileIndex = -1; - // check if multiple or unified result files should be used - // to import data, no information in smspec file regarding this - // if both unified and non-unified files exists, will use most recent based on - // time stamp + while (specInd >= 0) { - Opm::filesystem::path unsmryFile = rootName; + int reportStepNumber = fromReportStepNumber; - unsmryFile += formattedFiles[specInd] ? ".FUNSMRY" : ".UNSMRY"; - const bool use_unified = Opm::filesystem::exists(unsmryFile.string()); - - const std::vector multFileList = checkForMultipleResultFiles(rootName, formattedFiles[specInd]); - - std::vector resultsFileList; - - if ((!use_unified) && (multFileList.size()==0)){ - throw std::runtime_error("neigther unified or non-unified result files found"); - } else if ((use_unified) && (multFileList.size()>0)){ - auto time_multiple = Opm::filesystem::last_write_time(multFileList.back()); - auto time_unified = Opm::filesystem::last_write_time(unsmryFile); - - if (time_multiple > time_unified){ - resultsFileList=multFileList; + if (specInd > 0) { + auto rstFrom = smryArray[specInd-1]; + toReportStepNumber = std::get<1>(rstFrom); } else { + toReportStepNumber = std::numeric_limits::max(); + } + + Opm::filesystem::path smspecFile(std::get<0>(smryArray[specInd])); + rootName = smspecFile.parent_path() / smspecFile.stem(); + + // check if multiple or unified result files should be used + // to import data, no information in smspec file regarding this + // if both unified and non-unified files exists, will use most recent based on + // time stamp + + Opm::filesystem::path unsmryFile = rootName; + + unsmryFile += formattedFiles[specInd] ? ".FUNSMRY" : ".UNSMRY"; + const bool use_unified = Opm::filesystem::exists(unsmryFile.string()); + + const std::vector multFileList = checkForMultipleResultFiles(rootName, formattedFiles[specInd]); + + std::vector resultsFileList; + + if ((!use_unified) && (multFileList.size()==0)) { + throw std::runtime_error("neigther unified or non-unified result files found"); + } else if ((use_unified) && (multFileList.size()>0)) { + auto time_multiple = Opm::filesystem::last_write_time(multFileList.back()); + auto time_unified = Opm::filesystem::last_write_time(unsmryFile); + + if (time_multiple > time_unified) { + resultsFileList=multFileList; + } else { + resultsFileList.push_back(unsmryFile.string()); + } + + } else if (use_unified) { resultsFileList.push_back(unsmryFile.string()); + } else { + resultsFileList=multFileList; } - } else if (use_unified){ - resultsFileList.push_back(unsmryFile.string()); - } else { - resultsFileList=multFileList; - } + std::vector arraySourceList; - // make array list with reference to source files (unifed or non unified) - - std::vector arraySourceList; - - for (std::string fileName : resultsFileList) - { - std::vector> arrayList; - arrayList = this->getListOfArrays(fileName, formattedFiles[specInd]); - - for (size_t n = 0; n < arrayList.size(); n++) { - ArrSourceEntry t1 = std::make_tuple(std::get<0>(arrayList[n]), fileName, n, std::get<1>(arrayList[n])); - arraySourceList.push_back(t1); - } - } - - // loop through arrays and for each ministep, store data file, location of params table - // - // 2 or 3 arrays pr time step. - // If timestep is a report step: MINISTEP, PARAMS and SEQHDR - // else : MINISTEP and PARAMS - - - size_t i = std::get<0>(arraySourceList[0]) == "SEQHDR" ? 1 : 0 ; - - while (i < arraySourceList.size()){ - - if (std::get<0>(arraySourceList[i]) != "MINISTEP"){ - std::string message="Reading summary file, expecting keyword MINISTEP, found '" + std::get<0>(arraySourceList[i]) + "'"; - throw std::invalid_argument(message); - } - - if (std::get<0>(arraySourceList[i+1]) != "PARAMS") { - std::string message="Reading summary file, expecting keyword PARAMS, found '" + std::get<0>(arraySourceList[i]) + "'"; - throw std::invalid_argument(message); - } - - i++; - - if (std::find(dataFileList.begin(), dataFileList.end(), std::get<1>(arraySourceList[i])) == dataFileList.end()) + for (std::string fileName : resultsFileList) { - dataFileList.push_back(std::get<1>(arraySourceList[i])); - dataFileIndex++; + std::vector> arrayList; + arrayList = this->getListOfArrays(fileName, formattedFiles[specInd]); + + for (size_t n = 0; n < arrayList.size(); n++) { + ArrSourceEntry t1 = std::make_tuple(std::get<0>(arrayList[n]), fileName, n, std::get<1>(arrayList[n])); + arraySourceList.push_back(t1); + } } - TimeStepEntry t1 = std::make_tuple(specInd, dataFileIndex, std::get<3>(arraySourceList[i])); - timeStepList.push_back(t1); + // loop through arrays and for each ministep, store data file, location of params table + // + // 2 or 3 arrays pr time step. + // If timestep is a report step: MINISTEP, PARAMS and SEQHDR + // else : MINISTEP and PARAMS - i++; - if (i < arraySourceList.size()){ - if (std::get<0>(arraySourceList[i]) == "SEQHDR") { - i++; + size_t i = std::get<0>(arraySourceList[0]) == "SEQHDR" ? 1 : 0 ; + + while (i < arraySourceList.size()) { + + if (std::get<0>(arraySourceList[i]) != "MINISTEP") { + std::string message="Reading summary file, expecting keyword MINISTEP, found '" + std::get<0>(arraySourceList[i]) + "'"; + throw std::invalid_argument(message); + } + + if (std::get<0>(arraySourceList[i+1]) != "PARAMS") { + std::string message="Reading summary file, expecting keyword PARAMS, found '" + std::get<0>(arraySourceList[i]) + "'"; + throw std::invalid_argument(message); + } + + i++; + + if (std::find(dataFileList.begin(), dataFileList.end(), std::get<1>(arraySourceList[i])) == dataFileList.end()) + { + dataFileList.push_back(std::get<1>(arraySourceList[i])); + dataFileIndex++; + } + + TimeStepEntry t1 = std::make_tuple(specInd, dataFileIndex, std::get<3>(arraySourceList[i])); + timeStepList.push_back(t1); + + i++; + + if (i < arraySourceList.size()) { + if (std::get<0>(arraySourceList[i]) == "SEQHDR") { + i++; + reportStepNumber++; + seqIndex.push_back(step); + } + } else { reportStepNumber++; seqIndex.push_back(step); } - } else { - reportStepNumber++; - seqIndex.push_back(step); + + if (reportStepNumber >= toReportStepNumber) { + i = arraySourceList.size(); + } + + step++; } - if (reportStepNumber >= toReportStepNumber) { - i = arraySourceList.size(); - } + fromReportStepNumber = toReportStepNumber; - step++; + specInd--; + + nTstep = timeStepList.size(); } - - fromReportStepNumber = toReportStepNumber; - - specInd--; } } +void ESmry::inspect_lodsmry() +{ + std::string arrName; + int64_t arr_size; + Opm::EclIO::eclArrType arrType; + int sizeOfElement; + + std::fstream fileH; + + if (formattedFiles[0]) { + fileH.open(lodFileName, std::ios::in); + Opm::EclIO::readFormattedHeader(fileH, arrName, arr_size, arrType, sizeOfElement); + } else { + fileH.open(lodFileName, std::ios::in | std::ios::binary); + Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType, sizeOfElement); + } + + if ((arrName != "KEYCHECK") or (arrType != Opm::EclIO::CHAR)) + OPM_THROW(std::invalid_argument, "reading keycheck, invalid lod file"); + + std::vector keycheck; + + if (formattedFiles[0]) { + uint64_t size = Opm::EclIO::sizeOnDiskFormatted(arr_size, Opm::EclIO::CHAR, sizeOfChar) + 1; + std::string fileStr = read_string_from_disk(fileH, size); + + keycheck = Opm::EclIO::readFormattedCharArray(fileStr, arr_size, 0, sizeOfChar); + } else { + keycheck = Opm::EclIO::readBinaryCharArray(fileH, arr_size); + } + + if ((arr_size / nVect != 3) or (arr_size % nVect != 0)) + OPM_THROW(std::invalid_argument, "reading keycheck, invalid lod file"); + + for (size_t n = 0; n < nVect; n++) { + size_t ind = n*3; + std::string test_str = keycheck[ind] + keycheck[ind+1] + keycheck[ind+2]; + + if (keyword[n].size() > 24) { + if (keyword[n].substr(0,24) != test_str) { + OPM_THROW(std::invalid_argument, "keycheck not maching keyword array"); + } + } else { + if (keyword[n] != test_str) { + OPM_THROW(std::invalid_argument, "keycheck not maching keyword array"); + } + } + } + + if (formattedFiles[0]) + Opm::EclIO::readFormattedHeader(fileH, arrName, arr_size, arrType, sizeOfElement); + else + Opm::EclIO::readBinaryHeader(fileH, arrName, arr_size, arrType, sizeOfElement); + + if ((arrName != "RSTEP ") or (arrType != Opm::EclIO::LOGI)) + OPM_THROW(std::invalid_argument, "reading rstep, invalid lod file"); + + std::vector rstep; + + if (formattedFiles[0]) { + uint64_t size = Opm::EclIO::sizeOnDiskFormatted(arr_size, Opm::EclIO::LOGI, sizeOfLogi) + 1; + std::string fileStr = read_string_from_disk(fileH, size); + + rstep = Opm::EclIO::readFormattedLogiArray(fileStr, arr_size, 0); + } else { + rstep = readBinaryLogiArray(fileH, arr_size); + } + + for (size_t m = 0; m < rstep.size(); m++) + if (rstep[m]) + seqIndex.push_back(m); + + lod_offset = static_cast(fileH.tellg()); + nTstep = rstep.size(); + + if (formattedFiles[0]) + lod_arr_size = sizeOnDiskFormatted(nTstep, Opm::EclIO::REAL, sizeOfReal); + else + lod_arr_size = sizeOnDiskBinary(nTstep, Opm::EclIO::REAL, sizeOfReal); + + fileH.close(); +} + +std::string ESmry::read_string_from_disk(std::fstream& fileH, uint64_t size) const +{ + char* buffer; + buffer = new char [size]; + fileH.read (buffer, size); + std::string fileStr = std::string(buffer, size); + delete[] buffer; + + return fileStr; +} + +void ESmry::Load_from_lodsmry(const std::vector& keywIndVect) const +{ + std::fstream fileH; + + if (formattedFiles[0]) + fileH.open(lodFileName, std::ios::in); + else + fileH.open(lodFileName, std::ios::in | std::ios::binary); + + for (auto ind : keywIndVect) { + std::string arrName; + int64_t size; + Opm::EclIO::eclArrType arrType; + int sizeOfElement; + + uint64_t pos = lod_offset + lod_arr_size*static_cast(ind); + + if (formattedFiles[0]) + pos = pos + static_cast(ind * 31); // adding size of formatted headers + else + pos = pos + static_cast(ind * 24); // adding size of binary headers + + fileH.seekg (pos, fileH.beg); + + if (formattedFiles[0]) + readFormattedHeader(fileH, arrName, size, arrType, sizeOfElement); + else + readBinaryHeader(fileH, arrName, size, arrType, sizeOfElement); + + arrName = Opm::EclIO::trimr(arrName); + + std::string checkName = "V" + std::to_string(ind); + + if (arrName != checkName) + OPM_THROW(std::invalid_argument, "lodsmry, wrong header expecting " + checkName + " found " + arrName); + + if (formattedFiles[0]) { + uint64_t size_buffer = lod_arr_size + 1; + std::string fileStr = read_string_from_disk(fileH, size_buffer); + vectorData[ind] = Opm::EclIO::readFormattedRealArray(fileStr, nTstep, 0); + } else { + vectorData[ind] = readBinaryRealArray(fileH, size); + } + } + + fileH.close(); +} + void ESmry::LoadData(const std::vector& vectList) const { size_t nvect = vectList.size(); - size_t ntstep = timeStepList.size(); std::vector keywIndVect; keywIndVect.reserve(nvect); @@ -427,89 +638,103 @@ void ESmry::LoadData(const std::vector& vectList) const } for (auto ind : keywIndVect) - vectorData[ind].reserve(ntstep); + vectorData[ind].reserve(nTstep); - std::fstream fileH; + if (useLodsmryFile && lodEnabeled) + { + Load_from_lodsmry(keywIndVect); - auto specInd = std::get<0>(timeStepList[0]); - auto dataFileIndex = std::get<1>(timeStepList[0]); - uint64_t stepFilePos = std::get<2>(timeStepList[0]); + } else { - if (formattedFiles[specInd]) - fileH.open(dataFileList[dataFileIndex], std::ios::in); - else - fileH.open(dataFileList[dataFileIndex], std::ios::in | std::ios::binary); + std::fstream fileH; - for (auto ministep : timeStepList) { - if (dataFileIndex != std::get<1>(ministep)) { - fileH.close(); - specInd = std::get<0>(ministep); - dataFileIndex = std::get<1>(ministep); + auto specInd = std::get<0>(timeStepList[0]); + auto dataFileIndex = std::get<1>(timeStepList[0]); + uint64_t stepFilePos = std::get<2>(timeStepList[0]); + uint64_t blockSize_f; - if (formattedFiles[specInd]) - fileH.open(dataFileList[dataFileIndex], std::ios::in ); - else - fileH.open(dataFileList[dataFileIndex], std::ios::in | std::ios::binary); + { + int nLinesBlock = MaxBlockSizeReal / numColumnsReal; + int rest = MaxBlockSizeReal % numColumnsReal; + + if (rest > 0) + nLinesBlock++; + + blockSize_f= static_cast(MaxNumBlockReal * numColumnsReal * columnWidthReal + nLinesBlock); } - stepFilePos = std::get<2>(ministep);; + if (formattedFiles[specInd]) + fileH.open(dataFileList[dataFileIndex], std::ios::in); + else + fileH.open(dataFileList[dataFileIndex], std::ios::in | std::ios::binary); - for (auto ind : keywIndVect) { - auto it = arrayPos[specInd].find(ind); + for (auto ministep : timeStepList) { - if (it == arrayPos[specInd].end()) { - // undefined vector in current summary file. Typically when loading - // base restart run and including base run data. Vectors can be added to restart runs - vectorData[ind].push_back(nanf("")); - } else { - int paramPos = it->second; + if (dataFileIndex != std::get<1>(ministep)) { + fileH.close(); + specInd = std::get<0>(ministep); + dataFileIndex = std::get<1>(ministep); - if (formattedFiles[specInd]) { - uint64_t elementPos = 0; - int nBlocks = paramPos /MaxBlockSizeReal; - int sizeOfLastBlock = paramPos % MaxBlockSizeReal; + if (formattedFiles[specInd]) + fileH.open(dataFileList[dataFileIndex], std::ios::in ); + else + fileH.open(dataFileList[dataFileIndex], std::ios::in | std::ios::binary); + } - if (nBlocks > 0) { - int nLinesBlock = MaxNumBlockReal / numColumnsReal; - int rest = MaxNumBlockReal % numColumnsReal; + stepFilePos = std::get<2>(ministep);; - if (rest > 0) - nLinesBlock++; + for (auto ind : keywIndVect) { - uint64_t blockSize = static_cast(MaxNumBlockReal * numColumnsReal + nLinesBlock); - elementPos = static_cast(nBlocks * blockSize); - } - - int nLines = sizeOfLastBlock / numColumnsReal; - elementPos = stepFilePos + elementPos + static_cast(sizeOfLastBlock * columnWidthReal + nLines); - - fileH.seekg (elementPos, fileH.beg); - - char* buffer; - size_t size = columnWidthReal; - buffer = new char [size]; - fileH.read (buffer, size); - double dtmpv = std::stod(std::string(buffer, size)); - vectorData[ind].push_back(static_cast(dtmpv)); - - delete[] buffer; + auto it = arrayPos[specInd].find(ind); + if (it == arrayPos[specInd].end()) { + // undefined vector in current summary file. Typically when loading + // base restart run and including base run data. Vectors can be added to restart runs + vectorData[ind].push_back(nanf("")); } else { + int paramPos = it->second; - uint64_t nFullBlocks = static_cast(paramPos/(MaxBlockSizeReal / sizeOfReal)); - uint64_t elementPos = ((2 * nFullBlocks) + 1)*static_cast(sizeOfInte); - elementPos += static_cast(paramPos)* static_cast(sizeOfReal) + stepFilePos; - fileH.seekg (elementPos, fileH.beg); + if (formattedFiles[specInd]) { + uint64_t elementPos = 0; + int nBlocks = paramPos / MaxBlockSizeReal; + int sizeOfLastBlock = paramPos % MaxBlockSizeReal; - float value; - fileH.read(reinterpret_cast(&value), sizeOfReal); - vectorData[ind].push_back(Opm::EclIO::flipEndianFloat(value)); + if (nBlocks > 0) + elementPos = static_cast(nBlocks * blockSize_f); + + int nLines = sizeOfLastBlock / numColumnsReal; + elementPos = stepFilePos + elementPos + static_cast(sizeOfLastBlock * columnWidthReal + nLines); + + fileH.seekg (elementPos, fileH.beg); + + char* buffer; + size_t size = columnWidthReal; + buffer = new char [size]; + fileH.read (buffer, size); + double dtmpv = std::stod(std::string(buffer, size)); + vectorData[ind].push_back(static_cast(dtmpv)); + + delete[] buffer; + + } else { + + uint64_t nFullBlocks = static_cast(paramPos/(MaxBlockSizeReal / sizeOfReal)); + uint64_t elementPos = ((2 * nFullBlocks) + 1)*static_cast(sizeOfInte); + elementPos += static_cast(paramPos)* static_cast(sizeOfReal) + stepFilePos; + + fileH.seekg (elementPos, fileH.beg); + + float value; + fileH.read(reinterpret_cast(&value), sizeOfReal); + + vectorData[ind].push_back(Opm::EclIO::flipEndianFloat(value)); + } } } } - } - fileH.close(); + fileH.close(); + } for (auto ind : keywIndVect) vectorLoaded[ind] = true; @@ -538,108 +763,116 @@ std::vector ESmry::makeKeywPosVector(int specInd) const { void ESmry::LoadData() const { - std::fstream fileH; + if (useLodsmryFile && lodEnabeled) { - auto specInd = std::get<0>(timeStepList[0]); - auto dataFileIndex = std::get<1>(timeStepList[0]); - uint64_t stepFilePos = std::get<2>(timeStepList[0]); + this ->LoadData(keyword); - std::vector keywpos = makeKeywPosVector(specInd); + } else { + std::fstream fileH; - if (formattedFiles[specInd]) - fileH.open(dataFileList[dataFileIndex], std::ios::in); - else - fileH.open(dataFileList[dataFileIndex], std::ios::in | std::ios::binary); + auto specInd = std::get<0>(timeStepList[0]); + auto dataFileIndex = std::get<1>(timeStepList[0]); + uint64_t stepFilePos = std::get<2>(timeStepList[0]); - for (auto ministep : timeStepList) { + std::vector keywpos = makeKeywPosVector(specInd); - if (dataFileIndex != std::get<1>(ministep)) { - fileH.close(); + if (formattedFiles[specInd]) + fileH.open(dataFileList[dataFileIndex], std::ios::in); + else + fileH.open(dataFileList[dataFileIndex], std::ios::in | std::ios::binary); - if (specInd != std::get<0>(ministep)){ - specInd = std::get<0>(ministep); - keywpos = makeKeywPosVector(specInd); - } + for (auto ministep : timeStepList) { - dataFileIndex = std::get<1>(ministep); + if (dataFileIndex != std::get<1>(ministep)) { + fileH.close(); - if (formattedFiles[specInd]) - fileH.open(dataFileList[dataFileIndex], std::ios::in ); - else - fileH.open(dataFileList[dataFileIndex], std::ios::in | std::ios::binary); - } - - stepFilePos = std::get<2>(ministep); - int maxNumberOfElements = MaxBlockSizeReal / sizeOfReal; - fileH.seekg (stepFilePos, fileH.beg); - - if (formattedFiles[specInd]) { - char* buffer; - size_t size = sizeOnDiskFormatted(nParamsSpecFile[specInd], Opm::EclIO::REAL)+1; - buffer = new char [size]; - fileH.read (buffer, size); - - std::string fileStr = std::string(buffer, size); - size_t p = 0; - int64_t p1= 0; - - for (int i=0; i< nParamsSpecFile[specInd]; i++) { - p1 = fileStr.find_first_not_of(' ',p1); - int64_t p2 = fileStr.find_first_of(' ', p1); - - if (keywpos[p] > -1) { - double dtmpv = std::stod(fileStr.substr(p1, p2-p1)); - vectorData[keywpos[p]].push_back(static_cast(dtmpv)); + if (specInd != std::get<0>(ministep)) { + specInd = std::get<0>(ministep); + keywpos = makeKeywPosVector(specInd); } - p1 = fileStr.find_first_not_of(' ',p2); - p++; + dataFileIndex = std::get<1>(ministep); + + if (formattedFiles[specInd]) + fileH.open(dataFileList[dataFileIndex], std::ios::in ); + else + fileH.open(dataFileList[dataFileIndex], std::ios::in | std::ios::binary); } - delete[] buffer; - } else { - int64_t rest = static_cast(nParamsSpecFile[specInd]); - size_t p = 0; + stepFilePos = std::get<2>(ministep); + int maxNumberOfElements = MaxBlockSizeReal / sizeOfReal; + fileH.seekg (stepFilePos, fileH.beg); - while (rest > 0) { - int dhead; - fileH.read(reinterpret_cast(&dhead), sizeof(dhead)); - dhead = Opm::EclIO::flipEndianInt(dhead); - int num = dhead / sizeOfInte; + if (formattedFiles[specInd]) { - if ((num > maxNumberOfElements) || (num < 0)) - OPM_THROW(std::runtime_error, "??Error reading binary data, inconsistent header data or incorrect number of elements"); + char* buffer; + size_t size = sizeOnDiskFormatted(nParamsSpecFile[specInd], Opm::EclIO::REAL, sizeOfReal) + 1; + buffer = new char [size]; + fileH.read (buffer, size); - for (int i = 0; i < num; i++) { - float value; - fileH.read(reinterpret_cast(&value), sizeOfReal); + std::string fileStr = std::string(buffer, size); + size_t p = 0; + int64_t p1= 0; - if (keywpos[p] > -1) - vectorData[keywpos[p]].push_back(Opm::EclIO::flipEndianFloat(value)); + for (int i=0; i< nParamsSpecFile[specInd]; i++) { + p1 = fileStr.find_first_not_of(' ',p1); + int64_t p2 = fileStr.find_first_of(' ', p1); + if ((keywpos[p] > -1) && (!vectorLoaded[keywpos[p]])) { + double dtmpv = std::stod(fileStr.substr(p1, p2-p1)); + vectorData[keywpos[p]].push_back(static_cast(dtmpv)); + } + + p1 = fileStr.find_first_not_of(' ',p2); p++; } - rest -= num; + delete[] buffer; - if (( num < maxNumberOfElements && rest != 0) || - (num == maxNumberOfElements && rest < 0)) { - std::string message = "Error reading binary data, incorrect number of elements"; - OPM_THROW(std::runtime_error, message); + } else { + int64_t rest = static_cast(nParamsSpecFile[specInd]); + size_t p = 0; + + while (rest > 0) { + int dhead; + fileH.read(reinterpret_cast(&dhead), sizeof(dhead)); + dhead = Opm::EclIO::flipEndianInt(dhead); + int num = dhead / sizeOfInte; + + if ((num > maxNumberOfElements) || (num < 0)) + OPM_THROW(std::runtime_error, "??Error reading binary data, inconsistent header data or incorrect number of elements"); + + for (int i = 0; i < num; i++) { + float value; + fileH.read(reinterpret_cast(&value), sizeOfReal); + + if ((keywpos[p] > -1) && (!vectorLoaded[keywpos[p]])) + vectorData[keywpos[p]].push_back(Opm::EclIO::flipEndianFloat(value)); + + p++; + } + + rest -= num; + + if (( num < maxNumberOfElements && rest != 0) || + (num == maxNumberOfElements && rest < 0)) { + std::string message = "Error reading binary data, incorrect number of elements"; + OPM_THROW(std::runtime_error, message); + } + + int dtail; + fileH.read(reinterpret_cast(&dtail), sizeof(dtail)); + dtail = Opm::EclIO::flipEndianInt(dtail); + + if (dhead != dtail) + OPM_THROW(std::runtime_error, "Error reading binary data, tail not matching header."); } - - int dtail; - fileH.read(reinterpret_cast(&dtail), sizeof(dtail)); - dtail = Opm::EclIO::flipEndianInt(dtail); - - if (dhead != dtail) - OPM_THROW(std::runtime_error, "Error reading binary data, tail not matching header."); } } - } - for (size_t n=0; n < nVect; n++) - vectorLoaded[n] = true; + for (size_t n=0; n < nVect; n++) + vectorLoaded[n] = true; + } } @@ -647,24 +880,80 @@ std::vector> ESmry::getListOfArrays(std::string filename, bool formatted) { std::vector> resultVect; - std::fstream fileH; + + FILE *ptr; + char arrName[9]; + char numstr[13]; + + int64_t num; if (formatted) - fileH.open(filename, std::ios::in); + ptr = fopen(filename.c_str(),"r"); // r for read, files opened as text files else - fileH.open(filename, std::ios::in | std::ios::binary); + ptr = fopen(filename.c_str(),"rb"); // r for read, b for binary - while (!Opm::EclIO::isEOF(&fileH)) { - std::string arrName(8,' '); + bool endOfFile = false; + + while (!endOfFile) + { Opm::EclIO::eclArrType arrType; - int64_t num; if (formatted) - Opm::EclIO::readFormattedHeader(fileH,arrName,num,arrType); - else - Opm::EclIO::readBinaryHeader(fileH,arrName,num,arrType); + { + fseek(ptr, 2, SEEK_CUR); - uint64_t filePos = fileH.tellg(); + if (fread(arrName, 8, 1, ptr) != 1 ) + throw std::runtime_error("fread error when loading summary data"); + + arrName[8]='\0'; + + fseek(ptr, 1, SEEK_CUR); + + if (fread(numstr, 12, 1, ptr) != 1) + throw std::runtime_error("fread error when loading summary data"); + + numstr[12]='\0'; + + int num_int = std::stoi(numstr); + num = static_cast(num_int); + + fseek(ptr, 8, SEEK_CUR); + + if ((strcmp(arrName, "SEQHDR ") == 0) || (strcmp(arrName, "MINISTEP") == 0)) + arrType = Opm::EclIO::INTE; + else if (strcmp(arrName, "PARAMS ") == 0) + arrType = Opm::EclIO::REAL; + else { + throw std::invalid_argument("unknown array in summary data file "); + } + + } else { + int num_int; + + fseek(ptr, 4, SEEK_CUR); + + if (fread(arrName, 8, 1, ptr) != 1) + throw std::runtime_error("fread error when loading summary data"); + + arrName[8]='\0'; + + if (fread(&num_int, 4, 1, ptr) != 1) + throw std::runtime_error("fread error when loading summary data"); + + num = static_cast(Opm::EclIO::flipEndianInt(num_int)); + + fseek(ptr, 8, SEEK_CUR); + + if ((strcmp(arrName, "SEQHDR ") == 0) || (strcmp(arrName, "MINISTEP") == 0)) + arrType = Opm::EclIO::INTE; + else if (strcmp(arrName, "PARAMS ") == 0) + arrType = Opm::EclIO::REAL; + else { + throw std::invalid_argument("unknown array in UNSMRY file "); + } + } + + uint64_t filePos = static_cast(ftell(ptr)); std::tuple t1; t1 = std::make_tuple(Opm::EclIO::trimr(arrName), filePos); @@ -672,21 +961,115 @@ ESmry::getListOfArrays(std::string filename, bool formatted) if (num > 0) { if (formatted) { - uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType); - fileH.seekg(static_cast(sizeOfNextArray), std::ios_base::cur); - + uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType, 4); + fseek(ptr, static_cast(sizeOfNextArray), SEEK_CUR); } else { - uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType); - fileH.seekg(static_cast(sizeOfNextArray), std::ios_base::cur); + uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType, 4); + fseek(ptr, static_cast(sizeOfNextArray), SEEK_CUR); } } + + if (fgetc(ptr) == EOF) + endOfFile = true; + else + fseek(ptr, -1, SEEK_CUR); } - fileH.close(); + fclose(ptr); return resultVect; } +bool ESmry::make_lodsmry_file() +{ + // check that loadBaseRunData is not set, this function only works for single smspec files + // function will not replace existing lodsmry files (since this is already loaded by this class) + // if lodsmry file exist, this function will return false and do nothing. + + if (!fromSingleRun) + OPM_THROW(std::invalid_argument, "creating lodsmry file only possible when loadBaseRunData=false"); + + Opm::filesystem::path path = inputFileName.parent_path(); + Opm::filesystem::path rootName = inputFileName.stem(); + Opm::filesystem::path smryDataFile; + + if (formattedFiles[0]) + smryDataFile = path / rootName += ".FLODSMRY"; + else + smryDataFile = path / rootName += ".LODSMRY"; + + if (Opm::EclIO::fileExists(smryDataFile.string())) + { + return false; + + } else { + + std::vector keycheck; + keycheck.reserve(keyword.size()); + + std::string str1; + std::string str2; + std::string str3; + + for (auto key : keyword){ + + str2=""; + str3=""; + + if (key.size() > 24) + str1 = key.substr(0,24); + else + str1 = key; + + if (str1.size() > 8){ + str2 = str1.substr(8); + str1 = str1.substr(0,8); + } + + if (str2.size() > 8){ + str3 = str2.substr(8); + str2 = str2.substr(0,8); + } + + keycheck.push_back(str1); + keycheck.push_back(str2); + keycheck.push_back(str3); + } + + std::vector is_rstep; + is_rstep.reserve(timeStepList.size()); + + for (size_t i = 0; i < timeStepList.size(); i++) + if(std::find(seqIndex.begin(), seqIndex.end(), i) != seqIndex.end()) + is_rstep.push_back(true); + else + is_rstep.push_back(false); + + this->LoadData(); + + { + Opm::EclIO::EclOutput outFile(smryDataFile.string(), formattedFiles[0], std::ios::out); + outFile.write("KEYCHECK", keycheck); + outFile.write("RSTEP", is_rstep); + + for (size_t n = 0; n < vectorData.size(); n++ ) { + std::string vect_name="V" + std::to_string(n); + outFile.write(vect_name, vectorData[n]); + } + } + + return true; + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void ESmry::use_lodsmry_file(bool enable) +{ + useLodsmryFile = enable; +} std::vector ESmry::checkForMultipleResultFiles(const Opm::filesystem::path& rootN, bool formatted) const { @@ -893,9 +1276,9 @@ std::vector ESmry::keywordList(const std::string& pattern) const { std::vector list; - for (auto key : keyword) - if (fnmatch( pattern.c_str(), key.c_str(), 0 ) == 0 ) - list.push_back(key); + for (auto key : keyword) + if (fnmatch( pattern.c_str(), key.c_str(), 0 ) == 0 ) + list.push_back(key); return list; } diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclFile.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclFile.cpp index e3f9c7212e..a8c3798a84 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclFile.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclFile.cpp @@ -20,6 +20,7 @@ #include #include +//#include #include #include #include @@ -34,256 +35,13 @@ #include -// anonymous namespace for EclFile - -namespace { - -bool fileExists(const std::string& filename){ - - std::ifstream fileH(filename.c_str()); - return fileH.good(); -} - -bool isFormatted(const std::string& filename) -{ - const auto p = filename.find_last_of("."); - if (p == std::string::npos) - OPM_THROW(std::invalid_argument, - "Purported ECLIPSE Filename'" + filename + "'does not contain extension"); - return std::strchr("ABCFGH", static_cast(filename[p+1])) != nullptr; -} - - -template -std::vector readBinaryArray(std::fstream& fileH, const int64_t size, Opm::EclIO::eclArrType type, - std::function& flip) -{ - std::vector arr; - - auto sizeData = block_size_data_binary(type); - int sizeOfElement = std::get<0>(sizeData); - int maxBlockSize = std::get<1>(sizeData); - int maxNumberOfElements = maxBlockSize / sizeOfElement; - - arr.reserve(size); - - int64_t rest = size; - while (rest > 0) { - int dhead; - fileH.read(reinterpret_cast(&dhead), sizeof(dhead)); - dhead = Opm::EclIO::flipEndianInt(dhead); - - int num = dhead / sizeOfElement; - - if ((num > maxNumberOfElements) || (num < 0)) { - OPM_THROW(std::runtime_error, "Error reading binary data, inconsistent header data or incorrect number of elements"); - } - - for (int i = 0; i < num; i++) { - T2 value; - fileH.read(reinterpret_cast(&value), sizeOfElement); - arr.push_back(flip(value)); - } - - rest -= num; - - if (( num < maxNumberOfElements && rest != 0) || - (num == maxNumberOfElements && rest < 0)) { - std::string message = "Error reading binary data, incorrect number of elements"; - OPM_THROW(std::runtime_error, message); - } - - int dtail; - fileH.read(reinterpret_cast(&dtail), sizeof(dtail)); - dtail = Opm::EclIO::flipEndianInt(dtail); - - if (dhead != dtail) { - OPM_THROW(std::runtime_error, "Error reading binary data, tail not matching header."); - } - } - - return arr; -} - - -std::vector readBinaryInteArray(std::fstream &fileH, const int64_t size) -{ - std::function f = Opm::EclIO::flipEndianInt; - return readBinaryArray(fileH, size, Opm::EclIO::INTE, f); -} - - -std::vector readBinaryRealArray(std::fstream& fileH, const int64_t size) -{ - std::function f = Opm::EclIO::flipEndianFloat; - return readBinaryArray(fileH, size, Opm::EclIO::REAL, f); -} - - -std::vector readBinaryDoubArray(std::fstream& fileH, const int64_t size) -{ - std::function f = Opm::EclIO::flipEndianDouble; - return readBinaryArray(fileH, size, Opm::EclIO::DOUB, f); -} - -std::vector readBinaryLogiArray(std::fstream &fileH, const int64_t size) -{ - std::function f = [](unsigned int intVal) - { - bool value; - if (intVal == Opm::EclIO::true_value) { - value = true; - } else if (intVal == Opm::EclIO::false_value) { - value = false; - } else { - OPM_THROW(std::runtime_error, "Error reading logi value"); - } - - return value; - }; - return readBinaryArray(fileH, size, Opm::EclIO::LOGI, f); -} - - -std::vector readBinaryCharArray(std::fstream& fileH, const int64_t size) -{ - using Char8 = std::array; - std::function f = [](const Char8& val) - { - std::string res(val.begin(), val.end()); - return Opm::EclIO::trimr(res); - }; - return readBinaryArray(fileH, size, Opm::EclIO::CHAR, f); -} - - -template -std::vector readFormattedArray(const std::string& file_str, const int size, int64_t fromPos, - std::function& process) -{ - std::vector arr; - - arr.reserve(size); - - int64_t p1=fromPos; - - for (int i=0; i< size; i++) { - p1 = file_str.find_first_not_of(' ',p1); - int64_t p2 = file_str.find_first_of(' ', p1); - - arr.push_back(process(file_str.substr(p1, p2-p1))); - - p1 = file_str.find_first_not_of(' ',p2); - } - - return arr; - -} - - -std::vector readFormattedInteArray(const std::string& file_str, const int64_t size, int64_t fromPos) -{ - - std::function f = [](const std::string& val) - { - return std::stoi(val); - }; - - return readFormattedArray(file_str, size, fromPos, f); -} - - -std::vector readFormattedCharArray(const std::string& file_str, const int64_t size, int64_t fromPos) -{ - std::vector arr; - arr.reserve(size); - - int64_t p1=fromPos; - - for (int i=0; i< size; i++) { - p1 = file_str.find_first_of('\'',p1); - std::string value = file_str.substr(p1 + 1, 8); - - if (value == " ") { - arr.push_back(""); - } else { - arr.push_back(Opm::EclIO::trimr(value)); - } - - p1 = p1+10; - } - - return arr; -} - - -std::vector readFormattedRealArray(const std::string& file_str, const int64_t size, int64_t fromPos) -{ - - std::function f = [](const std::string& val) - { - // tskille: temporary fix, need to be discussed. OPM flow writes numbers - // that are outside valid range for float, and function stof will fail - double dtmpv = std::stod(val); - return dtmpv; - }; - - return readFormattedArray(file_str, size, fromPos, f); -} - - -std::vector readFormattedLogiArray(const std::string& file_str, const int64_t size, int64_t fromPos) -{ - - std::function f = [](const std::string& val) - { - if (val[0] == 'T') { - return true; - } else if (val[0] == 'F') { - return false; - } else { - std::string message="Could not convert '" + val + "' to a bool value "; - OPM_THROW(std::invalid_argument, message); - } - }; - - return readFormattedArray(file_str, size, fromPos, f); -} - -std::vector readFormattedDoubArray(const std::string& file_str, const int64_t size, int64_t fromPos) -{ - - std::function f = [](std::string val) - { - auto p1 = val.find_first_of("D"); - - if (p1 == std::string::npos) { - auto p2 = val.find_first_of("-+", 1); - if (p2 != std::string::npos) { - val = val.insert(p2,"E"); - } - } else { - val.replace(p1,1,"E"); - } - - return std::stod(val); - }; - - return readFormattedArray(file_str, size, fromPos, f); -} - -} // anonymous namespace - -// ========================================================================== namespace Opm { namespace EclIO { EclFile::EclFile(const std::string& filename, bool preload) : inputFilename(filename) { - if (!fileExists(filename)){ - std::string message="Could not open EclFile: " + filename; - OPM_THROW(std::invalid_argument, message); - } + if (!fileExists(filename)) + throw std::runtime_error("Can not open EclFile: {}"); std::fstream fileH; @@ -295,27 +53,27 @@ EclFile::EclFile(const std::string& filename, bool preload) : inputFilename(file fileH.open(filename, std::ios::in | std::ios::binary); } - if (!fileH) { - std::string message="Could not open file: " + filename; - OPM_THROW(std::runtime_error, message); - } + if (!fileH) + throw std::runtime_error("Can not open EclFile: {}"); int n = 0; while (!isEOF(&fileH)) { std::string arrName(8,' '); eclArrType arrType; int64_t num; - + int sizeOfElement; + if (formatted) { - readFormattedHeader(fileH,arrName,num,arrType); + readFormattedHeader(fileH,arrName,num,arrType, sizeOfElement); } else { - readBinaryHeader(fileH,arrName,num,arrType); + readBinaryHeader(fileH,arrName,num, arrType, sizeOfElement); } array_size.push_back(num); array_type.push_back(arrType); - array_name.push_back(trimr(arrName)); + array_element_size.push_back(sizeOfElement); + array_index[array_name[n]] = n; uint64_t pos = fileH.tellg(); @@ -323,17 +81,16 @@ EclFile::EclFile(const std::string& filename, bool preload) : inputFilename(file arrayLoaded.push_back(false); - if (num > 0){ + if (num > 0){ if (formatted) { - uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType); + uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType, sizeOfElement); fileH.seekg(static_cast(sizeOfNextArray), std::ios_base::cur); } else { - uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType); + uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType, sizeOfElement); fileH.seekg(static_cast(sizeOfNextArray), std::ios_base::cur); } } - n++; }; @@ -366,6 +123,9 @@ void EclFile::loadBinaryArray(std::fstream& fileH, std::size_t arrIndex) case CHAR: char_array[arrIndex] = readBinaryCharArray(fileH, array_size[arrIndex]); break; + case C0NN: + char_array[arrIndex] = readBinaryC0nnArray(fileH, array_size[arrIndex], array_element_size[arrIndex]); + break; case MESS: break; default: @@ -393,7 +153,10 @@ void EclFile::loadFormattedArray(const std::string& fileStr, std::size_t arrInde logi_array[arrIndex] = readFormattedLogiArray(fileStr, array_size[arrIndex], fromPos); break; case CHAR: - char_array[arrIndex] = readFormattedCharArray(fileStr, array_size[arrIndex], fromPos); + char_array[arrIndex] = readFormattedCharArray(fileStr, array_size[arrIndex], fromPos, sizeOfChar); + break; + case C0NN: + char_array[arrIndex] = readFormattedCharArray(fileStr, array_size[arrIndex], fromPos, array_element_size[arrIndex]); break; case MESS: break; @@ -449,7 +212,7 @@ void EclFile::loadData(const std::string& name) inFile.seekg(ifStreamPos[arrIndex]); char* buffer; - size_t size = sizeOnDiskFormatted(array_size[arrIndex], array_type[arrIndex])+1; + size_t size = sizeOnDiskFormatted(array_size[arrIndex], array_type[arrIndex], array_element_size[arrIndex])+1; buffer = new char [size]; inFile.read (buffer, size); @@ -494,7 +257,7 @@ void EclFile::loadData(const std::vector& arrIndex) inFile.seekg(ifStreamPos[ind]); char* buffer; - size_t size = sizeOnDiskFormatted(array_size[ind], array_type[ind])+1; + size_t size = sizeOnDiskFormatted(array_size[ind], array_type[ind], array_element_size[ind])+1; buffer = new char [size]; inFile.read (buffer, size); @@ -525,7 +288,6 @@ void EclFile::loadData(const std::vector& arrIndex) void EclFile::loadData(int arrIndex) { - if (formatted) { std::ifstream inFile(inputFilename); @@ -533,7 +295,7 @@ void EclFile::loadData(int arrIndex) inFile.seekg(ifStreamPos[arrIndex]); char* buffer; - size_t size = sizeOnDiskFormatted(array_size[arrIndex], array_type[arrIndex])+1; + size_t size = sizeOnDiskFormatted(array_size[arrIndex], array_type[arrIndex], array_element_size[arrIndex])+1; buffer = new char [size]; inFile.read (buffer, size); @@ -559,6 +321,109 @@ void EclFile::loadData(int arrIndex) } } +bool EclFile::is_ix() const +{ + // assuming that array data type C0nn only are used in IX. This may change in future. + + // Formatted files, + // >> use real arrays. Example Ecl = '0.70000000E-01', IX = '7.0000000E-02' + // Binary files, + // >> if logi array exists in file, look for IX spes binary representation of true value + + if (formatted) { + for (size_t n=0; n < array_type.size(); n++) { + if (array_type[n] == Opm::EclIO::C0NN) { + return true; + } else if (array_type[n] == Opm::EclIO::REAL) { + auto realStr = get_fmt_real_raw_str_values(n); + int p, first; + + for (auto val : realStr) { + double dtmpv = fabs(std::stod(val)); + + if (dtmpv > 0.0) { + p = val.find_first_of("."); + first = abs(std::stoi(val.substr(0, p))); + + if (first > 0) + return true; + else + return false; + } + } + } + } + } else { + for (size_t n=0; n < array_type.size(); n++) { + if (array_type[n] == Opm::EclIO::C0NN) { + return true; + } else if (array_type[n] == Opm::EclIO::LOGI) { + auto raw_logi_values = get_bin_logi_raw_values(n); + for (unsigned int val : raw_logi_values) { + if (val == Opm::EclIO::true_value_ix) + return true; + } + } + } + + return false; + } + + return false; +} + +std::vector EclFile::get_bin_logi_raw_values(int arrIndex) const +{ + if (array_type[arrIndex] != Opm::EclIO::LOGI) + OPM_THROW(std::runtime_error, "Error, selected array is not of type LOGI"); + + std::fstream fileH; + fileH.open(inputFilename, std::ios::in | std::ios::binary); + + if (!fileH) { + std::string message="Could not open file: '" + inputFilename +"'"; + OPM_THROW(std::runtime_error, message); + } + + fileH.seekg (ifStreamPos[arrIndex], fileH.beg); + + std::vector raw_logi = readBinaryRawLogiArray(fileH, array_size[arrIndex]); + + return raw_logi; +} + +std::vector EclFile::get_fmt_real_raw_str_values(int arrIndex) const +{ + std::vector real_vect; + + if (array_type[arrIndex] != Opm::EclIO::REAL) + OPM_THROW(std::runtime_error, "Error, selected array is not of type REAL"); + + std::ifstream inFile(inputFilename); + + if (!inFile) { + std::string message="Could not open file: '" + inputFilename +"'"; + OPM_THROW(std::runtime_error, message); + } + + inFile.seekg(ifStreamPos[arrIndex]); + + char* buffer; + size_t size = sizeOnDiskFormatted(array_size[arrIndex], array_type[arrIndex], array_element_size[arrIndex])+1; + + buffer = new char [size]; + inFile.read (buffer, size); + + std::string fileStr = std::string(buffer, size); + + std::vector real_vect_str; + real_vect_str = readFormattedRealRawStrings(fileStr, array_size[arrIndex], 0); + delete buffer; + + return real_vect_str; +} + + std::vector EclFile::getList() const { std::vector list; @@ -603,7 +468,12 @@ const std::vector& EclFile::get(int arrIndex) template<> const std::vector& EclFile::get(int arrIndex) { - return getImpl(arrIndex, CHAR, char_array, "string"); + if ((array_type[arrIndex] != Opm::EclIO::C0NN) && (array_type[arrIndex] != Opm::EclIO::CHAR)){ + std::string message = "Array with index " + std::to_string(arrIndex) + " is not of type " + "std::string"; + OPM_THROW(std::runtime_error, message); + } + + return getImpl(arrIndex, array_type[arrIndex], char_array, "string"); } @@ -739,7 +609,12 @@ const std::vector& EclFile::get(const std::string &nam OPM_THROW(std::invalid_argument, message); } - return getImpl(search->second, CHAR, char_array, "string"); + if ((array_type[search->second] != Opm::EclIO::C0NN) && (array_type[search->second] != Opm::EclIO::CHAR)){ + std::string message = "Array with index " + std::to_string(search->second) + " is not of type " + "std::string"; + OPM_THROW(std::runtime_error, message); + } + + return getImpl(search->second, array_type[search->second], char_array, "string"); } diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclOutput.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclOutput.cpp index f112cf9eab..4be9ee6b0d 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclOutput.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclOutput.cpp @@ -41,6 +41,7 @@ EclOutput::EclOutput(const std::string& filename, : isFormatted{formatted} { const auto binmode = mode | std::ios_base::binary; + ix_standard = false; this->ofileH.open(filename, this->isFormatted ? mode : binmode); } @@ -50,15 +51,79 @@ template<> void EclOutput::write(const std::string& name, const std::vector& data) { + // array type will be assumed CHAR if maximum string length is 8 or less + // If maximum string length is > 8, C0nn will be used with element size equal to + // maximum string length + + int maximum_length = 8; + + if (data.size() > 0) { + auto it = std::max_element(data.begin(), data.end(), [] + (const std::string& str1, const std::string& str2) + { + return str2.size() > str1.size(); + }); + + maximum_length = it->size(); + } + + if (isFormatted) { - writeFormattedHeader(name, data.size(), CHAR); - writeFormattedCharArray(data); + if (maximum_length > sizeOfChar){ + writeFormattedHeader(name, data.size(), C0NN, maximum_length); + writeFormattedCharArray(data, maximum_length); + } else { + writeFormattedHeader(name, data.size(), CHAR, sizeOfChar); + writeFormattedCharArray(data, sizeOfChar); + } } else { - writeBinaryHeader(name, data.size(), CHAR); - writeBinaryCharArray(data); + if (maximum_length > sizeOfChar){ + writeBinaryHeader(name, data.size(), C0NN, maximum_length); + writeBinaryCharArray(data, maximum_length); + } else { + writeBinaryHeader(name, data.size(), CHAR, sizeOfChar); + writeBinaryCharArray(data, sizeOfChar); + } + } +} + +void EclOutput::write(const std::string& name, const std::vector& data, int element_size) +{ + // array type will be assumed C0NN (not CHAR). Also in cases where element size is 8 or less + + if (data.size() > 0) { + auto it = std::max_element(data.begin(), data.end(), [] + (const std::string& str1, const std::string& str2) + { + return str2.size() > str1.size(); + }); + + if (it->size() > static_cast(element_size)) + OPM_THROW(std::runtime_error, "specified element size for type C0NN less than maximum string length in ouput data"); + } + + if (isFormatted) + { + if (element_size > sizeOfChar){ + writeFormattedHeader(name, data.size(), C0NN, element_size); + writeFormattedCharArray(data, element_size); + } else { + writeFormattedHeader(name, data.size(), C0NN, sizeOfChar); + writeFormattedCharArray(data, sizeOfChar); + } + } + else + { + if (element_size > sizeOfChar){ + writeBinaryHeader(name, data.size(), C0NN, element_size); + writeBinaryCharArray(data, element_size); + } else { + writeBinaryHeader(name, data.size(), C0NN, sizeOfChar); + writeBinaryCharArray(data, sizeOfChar); + } } } @@ -68,11 +133,11 @@ void EclOutput::write> const std::vector>& data) { if (this->isFormatted) { - writeFormattedHeader(name, data.size(), CHAR); + writeFormattedHeader(name, data.size(), CHAR, sizeOfChar); writeFormattedCharArray(data); } else { - writeBinaryHeader(name, data.size(), CHAR); + writeBinaryHeader(name, data.size(), CHAR, sizeOfChar); writeBinaryCharArray(data); } } @@ -91,7 +156,7 @@ void EclOutput::flushStream() this->ofileH.flush(); } -void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclArrType arrType) +void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclArrType arrType, int element_size) { int bhead = flipEndianInt(16); std::string name = arrName + std::string(8 - arrName.size(),' '); @@ -102,13 +167,13 @@ void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclAr int64_t x231 = size / val231; int flippedx231 = flipEndianInt(static_cast( (-1)*x231 )); - + ofileH.write(reinterpret_cast(&bhead), sizeof(bhead)); ofileH.write(name.c_str(), 8); ofileH.write(reinterpret_cast(&flippedx231), sizeof(flippedx231)); ofileH.write("X231", 4); ofileH.write(reinterpret_cast(&bhead), sizeof(bhead)); - + size = size - (x231 * val231); } @@ -119,6 +184,14 @@ void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclAr ofileH.write(name.c_str(), 8); ofileH.write(reinterpret_cast(&flippedSize), sizeof(flippedSize)); + std::string c0nn_str; + + if (arrType == C0NN){ + std::ostringstream ss; + ss << "C" << std::setw(3) << std::setfill('0') << element_size; + c0nn_str = ss.str(); + } + switch(arrType) { case INTE: ofileH.write("INTE", 4); @@ -135,6 +208,9 @@ void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclAr case CHAR: ofileH.write("CHAR", 4); break; + case C0NN: + ofileH.write(c0nn_str.c_str(), 4); + break; case MESS: ofileH.write("MESS", 4); break; @@ -178,6 +254,8 @@ void EclOutput::writeBinaryArray(const std::vector& data) OPM_THROW(std::runtime_error, "fstream fileH not open for writing"); } + int logi_true_val = ix_standard ? true_value_ix : true_value_ecl; + rest = size * static_cast(sizeOfElement); while (rest > 0) { if (rest > maxBlockSize) { @@ -203,7 +281,7 @@ void EclOutput::writeBinaryArray(const std::vector& data) value_d = flipEndianDouble(data[n]); ofileH.write(reinterpret_cast(&value_d), sizeof(value_d)); } else if (arrType == LOGI) { - intVal = data[n] ? true_value : false_value; + intVal = data[n] ? logi_true_val : false_value; ofileH.write(reinterpret_cast(&intVal), sizeOfElement); } else { std::cerr << "type not supported in write binaryarray\n"; @@ -225,7 +303,7 @@ template void EclOutput::writeBinaryArray(const std::vector& data); template void EclOutput::writeBinaryArray(const std::vector& data); -void EclOutput::writeBinaryCharArray(const std::vector& data) +void EclOutput::writeBinaryCharArray(const std::vector& data, int element_size) { int num,dhead; @@ -234,6 +312,11 @@ void EclOutput::writeBinaryCharArray(const std::vector& data) auto sizeData = block_size_data_binary(CHAR); + if (element_size > sizeOfChar){ + std::get<1>(sizeData)= std::get<1>(sizeData) / std::get<0>(sizeData) * element_size; + std::get<0>(sizeData) = element_size; + } + int sizeOfElement = std::get<0>(sizeData); int maxBlockSize = std::get<1>(sizeData); int maxNumberOfElements = maxBlockSize / sizeOfElement; @@ -258,7 +341,7 @@ void EclOutput::writeBinaryCharArray(const std::vector& data) ofileH.write(reinterpret_cast(&dhead), sizeof(dhead)); for (int i = 0; i < num; i++) { - std::string tmpStr = data[n] + std::string(8 - data[n].size(),' '); + std::string tmpStr = data[n] + std::string(sizeOfElement - data[n].size(),' '); ofileH.write(tmpStr.c_str(), sizeOfElement); n++; } @@ -303,12 +386,21 @@ void EclOutput::writeBinaryCharArray(const std::vector>& d } } -void EclOutput::writeFormattedHeader(const std::string& arrName, int size, eclArrType arrType) +void EclOutput::writeFormattedHeader(const std::string& arrName, int size, eclArrType arrType, int element_size) { std::string name = arrName + std::string(8 - arrName.size(),' '); ofileH << " '" << name << "' " << std::setw(11) << size; + std::string c0nn_str; + + if (arrType == C0NN){ + std::ostringstream ss; + ss << "C" << std::setw(3) << std::setfill('0') << element_size; + c0nn_str = ss.str(); + } + + switch (arrType) { case INTE: ofileH << " 'INTE'" << std::endl; @@ -325,6 +417,9 @@ void EclOutput::writeFormattedHeader(const std::string& arrName, int size, eclAr case CHAR: ofileH << " 'CHAR'" << std::endl; break; + case C0NN: + ofileH << " '" << c0nn_str << "'" << std::endl; + break; case MESS: ofileH << " 'MESS'" << std::endl; break; @@ -332,7 +427,7 @@ void EclOutput::writeFormattedHeader(const std::string& arrName, int size, eclAr } -std::string EclOutput::make_real_string(float value) const +std::string EclOutput::make_real_string_ecl(float value) const { char buffer [15]; std::sprintf (buffer, "%10.7E", value); @@ -367,11 +462,35 @@ std::string EclOutput::make_real_string(float value) const } } - -std::string EclOutput::make_doub_string(double value) const +std::string EclOutput::make_real_string_ix(float value) const { - char buffer [21]; - std::sprintf (buffer, "%19.13E", value); + char buffer [15]; + std::sprintf (buffer, "%10.7E", value); + + if (value == 0.0) { + return " 0.0000000E+00"; + } else { + if (std::isnan(value)) + return "NAN"; + + if (std::isinf(value)) { + if (value > 0) + return "INF"; + else + return "-INF"; + } + + std::string tmpstr(buffer); + + return tmpstr; + } +} + + +std::string EclOutput::make_doub_string_ecl(double value) const +{ + char buffer [21 + 1]; + std::snprintf (buffer, sizeof buffer, "%19.13E", value); if (value == 0.0) { return "0.00000000000000D+00"; @@ -388,27 +507,52 @@ std::string EclOutput::make_doub_string(double value) const std::string tmpstr(buffer); int exp = value < 0.0 ? std::stoi(tmpstr.substr(17, 4)) : std::stoi(tmpstr.substr(16, 4)); + const bool use_exp_char = (exp >= -100) && (exp < 99); if (value < 0.0) { - if (std::abs(exp) < 100) { + if (use_exp_char) { tmpstr = "-0." + tmpstr.substr(1, 1) + tmpstr.substr(3, 13) + "D"; } else { tmpstr = "-0." + tmpstr.substr(1, 1) + tmpstr.substr(3, 13); } } else { - if (std::abs(exp) < 100) { + if (use_exp_char) { tmpstr = "0." + tmpstr.substr(0, 1) + tmpstr.substr(2, 13) + "D"; } else { tmpstr = "0." + tmpstr.substr(0, 1) + tmpstr.substr(2, 13); } } - std::sprintf(buffer, "%+03i", exp + 1); + std::snprintf(buffer, sizeof buffer, "%+03i", exp + 1); tmpstr = tmpstr + buffer; return tmpstr; } } +std::string EclOutput::make_doub_string_ix(double value) const +{ + char buffer [21]; + std::sprintf (buffer, "%19.13E", value); + + if (value == 0.0) { + return " 0.0000000000000E+00"; + } else { + if (std::isnan(value)) + return "NAN"; + + if (std::isinf(value)) { + if (value > 0) + return "INF"; + else + return "-INF"; + } + + std::string tmpstr(buffer); + + return tmpstr; + } +} + template void EclOutput::writeFormattedArray(const std::vector& data) @@ -427,6 +571,7 @@ void EclOutput::writeFormattedArray(const std::vector& data) arrType = LOGI; } + auto sizeData = block_size_data_formatted(arrType); int maxBlockSize = std::get<0>(sizeData); @@ -441,10 +586,16 @@ void EclOutput::writeFormattedArray(const std::vector& data) ofileH << std::setw(columnWidth) << data[i]; break; case REAL: - ofileH << std::setw(columnWidth) << make_real_string(data[i]); + if (ix_standard) + ofileH << std::setw(columnWidth) << make_real_string_ix(data[i]); + else + ofileH << std::setw(columnWidth) << make_real_string_ecl(data[i]); break; case DOUB: - ofileH << std::setw(columnWidth) << make_doub_string(data[i]); + if (ix_standard) + ofileH << std::setw(columnWidth) << make_doub_string_ix(data[i]); + else + ofileH << std::setw(columnWidth) << make_doub_string_ecl(data[i]); break; case LOGI: if (data[i]) { @@ -479,30 +630,50 @@ template void EclOutput::writeFormattedArray(const std::vector& data template void EclOutput::writeFormattedArray(const std::vector& data); -void EclOutput::writeFormattedCharArray(const std::vector& data) +void EclOutput::writeFormattedCharArray(const std::vector& data, int element_size) { auto sizeData = block_size_data_formatted(CHAR); + int maxBlockSize = std::get<0>(sizeData); - int nColumns = std::get<1>(sizeData); + int nColumns; - int size = data.size(); + if (element_size < 9) + { + element_size = 8; + nColumns = std::get<1>(sizeData); + } else + nColumns = 80 / (element_size + 3); - for (int i = 0; i < size; i++) { - std::string str1(8,' '); - str1 = data[i] + std::string(8 - data[i].size(),' '); + int rest = data.size(); + int n = 0; - ofileH << " '" << str1 << "'"; + while (rest > 0) { + int size = rest; - if ((i+1) % nColumns == 0) { + if (size > maxBlockSize) + size = maxBlockSize; + + for (int i = 0; i < size; i++) { + std::string str1(element_size,' '); + str1 = data[n] + std::string(element_size - data[n].size(),' '); + + n++; + ofileH << " '" << str1 << "'"; + + if ((i+1) % nColumns == 0) { + ofileH << std::endl; + } + } + + if ((size % nColumns) != 0) { ofileH << std::endl; } - } - if ((size % nColumns) != 0) { - ofileH << std::endl; + rest = (rest > maxBlockSize) ? rest - maxBlockSize : 0; } } + void EclOutput::writeFormattedCharArray(const std::vector>& data) { const auto sizeData = block_size_data_formatted(CHAR); diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclUtil.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclUtil.cpp index 1f28a5c650..cd482588a8 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclUtil.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/EclUtil.cpp @@ -23,10 +23,14 @@ #include #include +#include #include #include #include +#include +//temporary +#include int Opm::EclIO::flipEndianInt(int num) { @@ -61,6 +65,21 @@ double Opm::EclIO::flipEndianDouble(double num) return value; } +bool Opm::EclIO::fileExists(const std::string& filename){ + + std::ifstream fileH(filename.c_str()); + return fileH.good(); +} + +bool Opm::EclIO::isFormatted(const std::string& filename) +{ + const auto p = filename.find_last_of("."); + if (p == std::string::npos) + OPM_THROW(std::invalid_argument, + "Purported ECLIPSE Filename'" + filename + "'does not contain extension"); + return std::strchr("ABCFGH", static_cast(filename[p+1])) != nullptr; +} + bool Opm::EclIO::isEOF(std::fstream* fileH) { int num; @@ -96,6 +115,9 @@ std::tuple Opm::EclIO::block_size_data_binary(eclArrType arrType) case CHAR: return BlockSizeTuple{sizeOfChar, MaxBlockSizeChar}; break; + case C0NN: + return BlockSizeTuple{sizeOfChar, MaxBlockSizeChar}; + break; case MESS: OPM_THROW(std::invalid_argument, "Type 'MESS' have no associated data"); break; @@ -126,6 +148,9 @@ std::tuple Opm::EclIO::block_size_data_formatted(eclArrType arrTy case CHAR: return BlockSizeTuple{MaxNumBlockChar,numColumnsChar, columnWidthChar}; break; + case C0NN: + return BlockSizeTuple{MaxNumBlockChar,numColumnsChar, columnWidthChar}; + break; case MESS: OPM_THROW(std::invalid_argument, "Type 'MESS' have no associated data") ; break; @@ -147,7 +172,7 @@ std::string Opm::EclIO::trimr(const std::string &str1) } } -uint64_t Opm::EclIO::sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrType) +uint64_t Opm::EclIO::sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrType, int elementSize) { uint64_t size = 0; @@ -160,6 +185,11 @@ uint64_t Opm::EclIO::sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrTyp if (num > 0) { auto sizeData = Opm::EclIO::block_size_data_binary(arrType); + if (arrType == Opm::EclIO::C0NN){ + std::get<1>(sizeData)= std::get<1>(sizeData) / std::get<0>(sizeData) * elementSize; + std::get<0>(sizeData) = elementSize; + } + int sizeOfElement = std::get<0>(sizeData); int maxBlockSize = std::get<1>(sizeData); int maxNumberOfElements = maxBlockSize / sizeOfElement; @@ -182,7 +212,7 @@ uint64_t Opm::EclIO::sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrTyp return size; } -uint64_t Opm::EclIO::sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrType arrType) +uint64_t Opm::EclIO::sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrType arrType, int elementSize) { uint64_t size = 0; @@ -193,6 +223,11 @@ uint64_t Opm::EclIO::sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrTy } else { auto sizeData = block_size_data_formatted(arrType); + if (arrType == Opm::EclIO::C0NN){ + std::get<2>(sizeData) = elementSize + 3; + std::get<1>(sizeData) = 80 / std::get<2>(sizeData); + } + int maxBlockSize = std::get<0>(sizeData); int nColumns = std::get<1>(sizeData); int columnWidth = std::get<2>(sizeData); @@ -257,7 +292,7 @@ void Opm::EclIO::readBinaryHeader(std::fstream& fileH, std::string& tmpStrName, } void Opm::EclIO::readBinaryHeader(std::fstream& fileH, std::string& arrName, - int64_t& size, Opm::EclIO::eclArrType &arrType) + int64_t& size, Opm::EclIO::eclArrType &arrType, int& elementSize) { std::string tmpStrName(8,' '); std::string tmpStrType(4,' '); @@ -282,15 +317,25 @@ void Opm::EclIO::readBinaryHeader(std::fstream& fileH, std::string& arrName, size = static_cast(tmpSize); } + elementSize = 4; + arrName = tmpStrName; if (tmpStrType == "INTE") arrType = Opm::EclIO::INTE; else if (tmpStrType == "REAL") arrType = Opm::EclIO::REAL; - else if (tmpStrType == "DOUB") + else if (tmpStrType == "DOUB"){ arrType = Opm::EclIO::DOUB; - else if (tmpStrType == "CHAR") + elementSize = 8; + } + else if (tmpStrType == "CHAR"){ arrType = Opm::EclIO::CHAR; + elementSize = 8; + } + else if (tmpStrType.substr(0,1)=="C"){ + arrType = Opm::EclIO::C0NN; + elementSize = std::stoi(tmpStrType.substr(1,3)); + } else if (tmpStrType =="LOGI") arrType = Opm::EclIO::LOGI; else if (tmpStrType == "MESS") @@ -301,7 +346,7 @@ void Opm::EclIO::readBinaryHeader(std::fstream& fileH, std::string& arrName, void Opm::EclIO::readFormattedHeader(std::fstream& fileH, std::string& arrName, - int64_t &num, Opm::EclIO::eclArrType &arrType) + int64_t &num, Opm::EclIO::eclArrType &arrType, int& elementSize) { std::string line; std::getline(fileH,line); @@ -321,14 +366,24 @@ void Opm::EclIO::readFormattedHeader(std::fstream& fileH, std::string& arrName, num = std::stol(antStr); + elementSize = 4; + if (arrTypeStr == "INTE") arrType = Opm::EclIO::INTE; else if (arrTypeStr == "REAL") arrType = Opm::EclIO::REAL; - else if (arrTypeStr == "DOUB") + else if (arrTypeStr == "DOUB"){ arrType = Opm::EclIO::DOUB; - else if (arrTypeStr == "CHAR") + elementSize = 8; + } + else if (arrTypeStr == "CHAR"){ arrType = Opm::EclIO::CHAR; + elementSize = 8; + } + else if (arrTypeStr.substr(0,1)=="C"){ + arrType = Opm::EclIO::C0NN; + elementSize = std::stoi(arrTypeStr.substr(1,3)); + } else if (arrTypeStr == "LOGI") arrType = Opm::EclIO::LOGI; else if (arrTypeStr == "MESS") @@ -340,3 +395,271 @@ void Opm::EclIO::readFormattedHeader(std::fstream& fileH, std::string& arrName, OPM_THROW(std::runtime_error, "Header name should be 8 characters"); } } + +template +std::vector Opm::EclIO::readBinaryArray(std::fstream& fileH, const int64_t size, Opm::EclIO::eclArrType type, + std::function& flip, int elementSize) +{ + std::vector arr; + + auto sizeData = block_size_data_binary(type); + + if (type == Opm::EclIO::C0NN){ + std::get<1>(sizeData)= std::get<1>(sizeData) / std::get<0>(sizeData) * elementSize; + std::get<0>(sizeData) = elementSize; + } + + int sizeOfElement = std::get<0>(sizeData); + int maxBlockSize = std::get<1>(sizeData); + int maxNumberOfElements = maxBlockSize / sizeOfElement; + + arr.reserve(size); + + int64_t rest = size; + + while (rest > 0) { + int dhead; + fileH.read(reinterpret_cast(&dhead), sizeof(dhead)); + dhead = Opm::EclIO::flipEndianInt(dhead); + int num = dhead / sizeOfElement; + + if ((num > maxNumberOfElements) || (num < 0)) { + OPM_THROW(std::runtime_error, "Error reading binary data, inconsistent header data or incorrect number of elements"); + } + + for (int i = 0; i < num; i++) { + T2 value; + + if constexpr (std::is_same_v) { + value.resize(sizeOfElement) ; + fileH.read(&value[0], sizeOfElement); + } else + fileH.read(reinterpret_cast(&value), sizeOfElement); + + arr.push_back(flip(value)); + } + + rest -= num; + + if (( num < maxNumberOfElements && rest != 0) || + (num == maxNumberOfElements && rest < 0)) { + std::string message = "Error reading binary data, incorrect number of elements"; + OPM_THROW(std::runtime_error, message); + } + + int dtail; + fileH.read(reinterpret_cast(&dtail), sizeof(dtail)); + dtail = Opm::EclIO::flipEndianInt(dtail); + + if (dhead != dtail) { + OPM_THROW(std::runtime_error, "Error reading binary data, tail not matching header."); + } + } + + return arr; +} + + +std::vector Opm::EclIO::readBinaryInteArray(std::fstream &fileH, const int64_t size) +{ + std::function f = Opm::EclIO::flipEndianInt; + return readBinaryArray(fileH, size, Opm::EclIO::INTE, f, sizeOfInte); +} + + +std::vector Opm::EclIO::readBinaryRealArray(std::fstream& fileH, const int64_t size) +{ + std::function f = Opm::EclIO::flipEndianFloat; + return readBinaryArray(fileH, size, Opm::EclIO::REAL, f, sizeOfReal); +} + + +std::vector Opm::EclIO::readBinaryDoubArray(std::fstream& fileH, const int64_t size) +{ + std::function f = Opm::EclIO::flipEndianDouble; + return readBinaryArray(fileH, size, Opm::EclIO::DOUB, f, sizeOfDoub); +} + +std::vector Opm::EclIO::readBinaryLogiArray(std::fstream &fileH, const int64_t size) +{ + std::function f = [](unsigned int intVal) + { + bool value; + if (intVal == Opm::EclIO::true_value_ecl) { + value = true; + } else if (intVal == Opm::EclIO::false_value) { + value = false; + } else if (intVal == Opm::EclIO::true_value_ix) { + value = true; + } else { + OPM_THROW(std::runtime_error, "Error reading logi value"); + } + + return value; + }; + return readBinaryArray(fileH, size, Opm::EclIO::LOGI, f, sizeOfLogi); +} + +std::vector Opm::EclIO::readBinaryRawLogiArray(std::fstream &fileH, const int64_t size) +{ + std::function f = [](unsigned int intVal) + { + return intVal; + }; + return readBinaryArray(fileH, size, Opm::EclIO::LOGI, f, sizeOfLogi); +} + + +std::vector Opm::EclIO::readBinaryCharArray(std::fstream& fileH, const int64_t size) +{ + using Char8 = std::array; + std::function f = [](const Char8& val) + { + std::string res(val.begin(), val.end()); + return Opm::EclIO::trimr(res); + }; + return readBinaryArray(fileH, size, Opm::EclIO::CHAR, f, sizeOfChar); +} + + +std::vector Opm::EclIO::readBinaryC0nnArray(std::fstream& fileH, const int64_t size, int elementSize) +{ + std::function f = [](const std::string& val) + { + return Opm::EclIO::trimr(val); + }; + + return readBinaryArray(fileH, size, Opm::EclIO::C0NN, f, elementSize); +} + + +template +std::vector Opm::EclIO::readFormattedArray(const std::string& file_str, const int size, int64_t fromPos, + std::function& process) +{ + std::vector arr; + + arr.reserve(size); + + int64_t p1=fromPos; + + for (int i=0; i< size; i++) { + p1 = file_str.find_first_not_of(' ',p1); + int64_t p2 = file_str.find_first_of(' ', p1); + + arr.push_back(process(file_str.substr(p1, p2-p1))); + + p1 = file_str.find_first_not_of(' ',p2); + } + + return arr; +} + + +std::vector Opm::EclIO::readFormattedInteArray(const std::string& file_str, const int64_t size, int64_t fromPos) +{ + + std::function f = [](const std::string& val) + { + return std::stoi(val); + }; + + return readFormattedArray(file_str, size, fromPos, f); +} + + +std::vector Opm::EclIO::readFormattedCharArray(const std::string& file_str, const int64_t size, + int64_t fromPos, int elementSize) +{ + std::vector arr; + arr.reserve(size); + + int64_t p1=fromPos; + + for (int i=0; i< size; i++) { + p1 = file_str.find_first_of('\'',p1); + std::string value = file_str.substr(p1 + 1, elementSize); + + if (value == " ") { + arr.push_back(""); + } else { + arr.push_back(Opm::EclIO::trimr(value)); + } + + p1 = p1 + elementSize + 2; + } + + return arr; +} + + +std::vector Opm::EclIO::readFormattedRealArray(const std::string& file_str, const int64_t size, int64_t fromPos) +{ + + std::function f = [](const std::string& val) + { + // tskille: temporary fix, need to be discussed. OPM flow writes numbers + // that are outside valid range for float, and function stof will fail + double dtmpv = std::stod(val); + return dtmpv; + }; + + return readFormattedArray(file_str, size, fromPos, f); +} + +std::vector Opm::EclIO::readFormattedRealRawStrings(const std::string& file_str, const int64_t size, int64_t fromPos) +{ + + + std::function f = [](const std::string& val) + { + return val; + }; + + return readFormattedArray(file_str, size, fromPos, f); +} + + +std::vector Opm::EclIO::readFormattedLogiArray(const std::string& file_str, const int64_t size, int64_t fromPos) +{ + + std::function f = [](const std::string& val) + { + if (val[0] == 'T') { + return true; + } else if (val[0] == 'F') { + return false; + } else { + std::string message="Could not convert '" + val + "' to a bool value "; + OPM_THROW(std::invalid_argument, message); + } + }; + + return readFormattedArray(file_str, size, fromPos, f); +} + +std::vector Opm::EclIO::readFormattedDoubArray(const std::string& file_str, const int64_t size, int64_t fromPos) +{ + + std::function f = [](std::string val) + { + auto p1 = val.find_first_of("D"); + + if (p1 != std::string::npos) { + val.replace(p1,1,"E"); + } + + p1 = val.find_first_of("E"); + + if (p1 == std::string::npos) { + auto p2 = val.find_first_of("-+", 1); + + if (p2 != std::string::npos) + val = val.insert(p2,"E"); + } + return std::stod(val); + }; + + return readFormattedArray(file_str, size, fromPos, f); +} + diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/SummaryNode.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/SummaryNode.cpp index 1c1fb833af..60a0dde3fd 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/SummaryNode.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/SummaryNode.cpp @@ -15,7 +15,9 @@ You should have received a copy of the GNU General Public License along with OPM. If not, see . - */ +*/ + +#include #include #include @@ -23,8 +25,6 @@ #include #include -#include - namespace { constexpr bool use_number(Opm::EclIO::SummaryNode::Category category) { @@ -37,6 +37,7 @@ constexpr bool use_number(Opm::EclIO::SummaryNode::Category category) { return true; case Opm::EclIO::SummaryNode::Category::Field: [[fallthrough]]; case Opm::EclIO::SummaryNode::Category::Group: [[fallthrough]]; + case Opm::EclIO::SummaryNode::Category::Node: [[fallthrough]]; case Opm::EclIO::SummaryNode::Category::Miscellaneous: [[fallthrough]]; case Opm::EclIO::SummaryNode::Category::Well: return false; @@ -51,6 +52,7 @@ constexpr bool use_name(Opm::EclIO::SummaryNode::Category category) { case Opm::EclIO::SummaryNode::Category::Connection: [[fallthrough]]; case Opm::EclIO::SummaryNode::Category::Group: [[fallthrough]]; case Opm::EclIO::SummaryNode::Category::Segment: [[fallthrough]]; + case Opm::EclIO::SummaryNode::Category::Node: [[fallthrough]]; case Opm::EclIO::SummaryNode::Category::Well: return true; case Opm::EclIO::SummaryNode::Category::Aquifer: [[fallthrough]]; @@ -69,7 +71,23 @@ std::string default_number_renderer(const Opm::EclIO::SummaryNode& node) { return std::to_string(node.number); } -}; +bool is_node_keyword(const std::string& keyword) +{ + static const auto node_kw = std::unordered_set { + "GPR", + }; + + return node_kw.find(keyword) != node_kw.end(); +} + +Opm::EclIO::SummaryNode::Category +distinguish_group_from_node(const std::string& keyword) +{ + return is_node_keyword(keyword) + ? Opm::EclIO::SummaryNode::Category::Node + : Opm::EclIO::SummaryNode::Category::Group; +} +} std::string Opm::EclIO::SummaryNode::unique_key(number_renderer render_number) const { std::vector key_parts { keyword } ; @@ -120,7 +138,7 @@ bool Opm::EclIO::SummaryNode::is_user_defined() const { "SURFWNUM", } ; - static const std::regex user_defined_regex { "[ABCFGRSW]U[A-Z]+" } ; + static const std::regex user_defined_regex { "[ABCFGRSW]U[A-Z0-9_]+" } ; const bool matched { std::regex_match(keyword, user_defined_regex) } ; const bool blacklisted { udq_blacklist.find(keyword) != udq_blacklist.end() } ; @@ -145,7 +163,7 @@ Opm::EclIO::SummaryNode::Category Opm::EclIO::SummaryNode::category_from_keyword case 'B': return Category::Block; case 'C': return Category::Connection; case 'F': return Category::Field; - case 'G': return Category::Group; + case 'G': return distinguish_group_from_node(keyword); case 'R': return Category::Region; case 'S': return Category::Segment; case 'W': return Category::Well; diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/group.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/group.cpp index 0289e13c09..0974a8409d 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/group.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/group.cpp @@ -32,24 +32,42 @@ namespace RestartIO { using M = ::Opm::UnitSystem::measure; +double sgrp_value(float raw_value) { + const auto infty = 1.0e+20f; + if (std::abs(raw_value) == infty) + return 0; + else + return raw_value; +} + RstGroup::RstGroup(const ::Opm::UnitSystem& unit_system, + const RstHeader& header, const std::string* zwel, - const int *, + const int * igrp, const float * sgrp, const double * xgrp) : name(trim_copy(zwel[0])), - oil_rate_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::OilRateLimit])), - water_rate_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::WatRateLimit])), - gas_rate_limit( unit_system.to_si(M::gas_surface_rate, sgrp[VI::SGroup::GasRateLimit])), - liquid_rate_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::LiqRateLimit])), - water_surface_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::waterSurfRateLimit])), - water_reservoir_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::waterResRateLimit])), - water_reinject_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::waterReinjectionLimit])), - water_voidage_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::waterVoidageLimit])), - gas_surface_limit( unit_system.to_si(M::gas_surface_rate, sgrp[VI::SGroup::gasSurfRateLimit])), - gas_reservoir_limit( unit_system.to_si(M::geometric_volume_rate, sgrp[VI::SGroup::gasResRateLimit])), - gas_reinject_limit( unit_system.to_si(M::gas_surface_rate, sgrp[VI::SGroup::gasReinjectionLimit])), - gas_voidage_limit( unit_system.to_si(M::geometric_volume_rate, sgrp[VI::SGroup::gasVoidageLimit])), + parent_group(igrp[header.nwgmax + VI::IGroup::ParentGroup] ), + prod_active_cmode(igrp[header.nwgmax + VI::IGroup::ProdActiveCMode]), + gconprod_cmode(igrp[header.nwgmax + VI::IGroup::GConProdCMode]), + winj_cmode(igrp[header.nwgmax + VI::IGroup::WInjCMode]), + ginj_cmode(igrp[header.nwgmax + VI::IGroup::GInjCMode]), + guide_rate_def(igrp[header.nwgmax + VI::IGroup::GuideRateDef]), + // The values oil_rate_limit -> gas_voidage_limit will be used in UDA + // values. The UDA values are responsible for unit conversion and raw values + // are internalized here. + oil_rate_limit( sgrp_value(sgrp[VI::SGroup::OilRateLimit])), + water_rate_limit( sgrp_value(sgrp[VI::SGroup::WatRateLimit])), + gas_rate_limit( sgrp_value(sgrp[VI::SGroup::GasRateLimit])), + liquid_rate_limit( sgrp_value(sgrp[VI::SGroup::LiqRateLimit])), + water_surface_limit( sgrp_value(sgrp[VI::SGroup::waterSurfRateLimit])), + water_reservoir_limit( sgrp_value(sgrp[VI::SGroup::waterResRateLimit])), + water_reinject_limit( sgrp_value(sgrp[VI::SGroup::waterReinjectionLimit])), + water_voidage_limit( sgrp_value(sgrp[VI::SGroup::waterVoidageLimit])), + gas_surface_limit( sgrp_value(sgrp[VI::SGroup::gasSurfRateLimit])), + gas_reservoir_limit( sgrp_value(sgrp[VI::SGroup::gasResRateLimit])), + gas_reinject_limit( sgrp_value(sgrp[VI::SGroup::gasReinjectionLimit])), + gas_voidage_limit( sgrp_value(sgrp[VI::SGroup::gasVoidageLimit])), oil_production_rate( unit_system.to_si(M::liquid_surface_rate, xgrp[VI::XGroup::OilPrRate])), water_production_rate( unit_system.to_si(M::liquid_surface_rate, xgrp[VI::XGroup::WatPrRate])), gas_production_rate( unit_system.to_si(M::gas_surface_rate, xgrp[VI::XGroup::GasPrRate])), diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/header.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/header.cpp index 31dc2c823e..18c0509b3a 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/header.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/header.cpp @@ -23,13 +23,15 @@ #include #include #include +#include namespace VI = ::Opm::RestartIO::Helpers::VectorItems; +using M = ::Opm::UnitSystem::measure; namespace Opm { namespace RestartIO { -RstHeader::RstHeader(const std::vector& intehead, const std::vector& logihead, const std::vector& doubhead) : +RstHeader::RstHeader(const Opm::UnitSystem& unit_system, const std::vector& intehead, const std::vector& logihead, const std::vector& doubhead) : nx(intehead[VI::intehead::NX]), ny(intehead[VI::intehead::NY]), nz(intehead[VI::intehead::NZ]), @@ -84,6 +86,7 @@ RstHeader::RstHeader(const std::vector& intehead, const std::vector& ntfip(intehead[VI::intehead::NTFIP]), nmfipr(intehead[VI::intehead::NMFIPR]), ngroup(intehead[VI::intehead::NGRP]), + nwgmax(intehead[VI::intehead::NWGMAX]), // e300_radial(logihead[VI::logihead::E300Radial]), e100_radial(logihead[VI::logihead::E100Radial]), @@ -98,16 +101,19 @@ RstHeader::RstHeader(const std::vector& intehead, const std::vector& dir_eps(logihead[VI::logihead::DirEPS]), reversible_eps(logihead[VI::logihead::RevEPS]), alt_eps(logihead[VI::logihead::AltEPS]), + group_control_active(intehead[VI::intehead::NGRNPH] == 1), // - next_timestep1(doubhead[VI::doubhead::TsInit]), - next_timestep2(doubhead[VI::doubhead::TsMaxz]), - max_timestep(doubhead[VI::doubhead::TsMinz]), + next_timestep1(unit_system.to_si(M::time, doubhead[VI::doubhead::TsInit])), + next_timestep2(0), + max_timestep(unit_system.to_si(M::time, doubhead[VI::doubhead::TsMaxz])), guide_rate_a(doubhead[VI::doubhead::GRpar_a]), guide_rate_b(doubhead[VI::doubhead::GRpar_b]), guide_rate_c(doubhead[VI::doubhead::GRpar_c]), guide_rate_d(doubhead[VI::doubhead::GRpar_d]), guide_rate_e(doubhead[VI::doubhead::GRpar_e]), guide_rate_f(doubhead[VI::doubhead::GRpar_f]), + guide_rate_delay(unit_system.to_si(M::time, doubhead[VI::doubhead::GRpar_int])), + guide_rate_damping(doubhead[VI::doubhead::GRpar_damp]), udq_range(doubhead[VI::doubhead::UdqPar_2]), udq_undefined(doubhead[VI::doubhead::UdqPar_3]), udq_eps(doubhead[VI::doubhead::UdqPar_4]) diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/segment.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/segment.cpp index cf70677f24..2a5aad35c8 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/segment.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/segment.cpp @@ -23,6 +23,8 @@ #include #include +#include "src/opm/parser/eclipse/EclipseState/Schedule/MSW/icd_convert.hpp" + namespace VI = ::Opm::RestartIO::Helpers::VectorItems; namespace Opm { diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/state.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/state.cpp index 754bde1822..262846796c 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/state.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/state.cpp @@ -34,6 +34,16 @@ namespace VI = ::Opm::RestartIO::Helpers::VectorItems; namespace Opm { namespace RestartIO { +RstState::RstState(const ::Opm::UnitSystem& unit_system_, + const std::vector& intehead, + const std::vector& logihead, + const std::vector& doubhead): + unit_system(unit_system_), + header(unit_system_, intehead, logihead, doubhead) +{ + this->load_tuning(intehead, doubhead); +} + RstState::RstState(const ::Opm::UnitSystem& unit_system_, const std::vector& intehead, const std::vector& logihead, @@ -49,11 +59,9 @@ RstState::RstState(const ::Opm::UnitSystem& unit_system_, const std::vector& icon, const std::vector& scon, const std::vector& xcon): - unit_system(unit_system_), - header(intehead, logihead, doubhead) + RstState(unit_system_, intehead, logihead, doubhead) { this->add_groups(zgrp, igrp, sgrp, xgrp); - this->load_tuning(intehead, doubhead); for (int iw = 0; iw < this->header.num_wells; iw++) { std::size_t zwel_offset = iw * this->header.nzwelz; @@ -99,11 +107,9 @@ RstState::RstState(const ::Opm::UnitSystem& unit_system_, const std::vector& xcon, const std::vector& iseg, const std::vector& rseg) : - unit_system(unit_system_), - header(intehead, logihead, doubhead) + RstState(unit_system_, intehead, logihead, doubhead) { this->add_groups(zgrp, igrp, sgrp, xgrp); - this->load_tuning(intehead, doubhead); for (int iw = 0; iw < this->header.num_wells; iw++) { std::size_t zwel_offset = iw * this->header.nzwelz; @@ -181,6 +187,7 @@ void RstState::add_groups(const std::vector& zgrp, std::size_t xgrp_offset = ig * this->header.nxgrpz; this->groups.emplace_back(this->unit_system, + this->header, zgrp.data() + zgrp_offset, igrp.data() + igrp_offset, sgrp.data() + sgrp_offset, @@ -202,43 +209,47 @@ const RstWell& RstState::get_well(const std::string& wname) const { RstState RstState::load(EclIO::ERst& rst_file, int report_step) { rst_file.loadReportStepNumber(report_step); - const auto& intehead = rst_file.getRst("INTEHEAD", report_step, 0); - const auto& logihead = rst_file.getRst("LOGIHEAD", report_step, 0); - const auto& doubhead = rst_file.getRst("DOUBHEAD", report_step, 0); - - const auto& zgrp = rst_file.getRst("ZGRP", report_step, 0); - const auto& igrp = rst_file.getRst("IGRP", report_step, 0); - const auto& sgrp = rst_file.getRst("SGRP", report_step, 0); - const auto& xgrp = rst_file.getRst("XGRP", report_step, 0); - - const auto& zwel = rst_file.getRst("ZWEL", report_step, 0); - const auto& iwel = rst_file.getRst("IWEL", report_step, 0); - const auto& swel = rst_file.getRst("SWEL", report_step, 0); - const auto& xwel = rst_file.getRst("XWEL", report_step, 0); - - const auto& icon = rst_file.getRst("ICON", report_step, 0); - const auto& scon = rst_file.getRst("SCON", report_step, 0); - const auto& xcon = rst_file.getRst("XCON", report_step, 0); + const auto& intehead = rst_file.getRestartData("INTEHEAD", report_step, 0); + const auto& logihead = rst_file.getRestartData("LOGIHEAD", report_step, 0); + const auto& doubhead = rst_file.getRestartData("DOUBHEAD", report_step, 0); auto unit_id = intehead[VI::intehead::UNIT]; ::Opm::UnitSystem unit_system(unit_id); - if (rst_file.hasKey("ISEG")) { - const auto& iseg = rst_file.getRst("ISEG", report_step, 0); - const auto& rseg = rst_file.getRst("RSEG", report_step, 0); + if (intehead[VI::intehead::NWELLS] != 0) { + const auto& zgrp = rst_file.getRestartData("ZGRP", report_step, 0); + const auto& igrp = rst_file.getRestartData("IGRP", report_step, 0); + const auto& sgrp = rst_file.getRestartData("SGRP", report_step, 0); + const auto& xgrp = rst_file.getRestartData("XGRP", report_step, 0); - return RstState(unit_system, - intehead, logihead, doubhead, - zgrp, igrp, sgrp, xgrp, - zwel, iwel, swel, xwel, - icon, scon, xcon, - iseg, rseg); + const auto& zwel = rst_file.getRestartData("ZWEL", report_step, 0); + const auto& iwel = rst_file.getRestartData("IWEL", report_step, 0); + const auto& swel = rst_file.getRestartData("SWEL", report_step, 0); + const auto& xwel = rst_file.getRestartData("XWEL", report_step, 0); + + const auto& icon = rst_file.getRestartData("ICON", report_step, 0); + const auto& scon = rst_file.getRestartData("SCON", report_step, 0); + const auto& xcon = rst_file.getRestartData("XCON", report_step, 0); + + + if (rst_file.hasKey("ISEG")) { + const auto& iseg = rst_file.getRestartData("ISEG", report_step, 0); + const auto& rseg = rst_file.getRestartData("RSEG", report_step, 0); + + return RstState(unit_system, + intehead, logihead, doubhead, + zgrp, igrp, sgrp, xgrp, + zwel, iwel, swel, xwel, + icon, scon, xcon, + iseg, rseg); + } else + return RstState(unit_system, + intehead, logihead, doubhead, + zgrp, igrp, sgrp, xgrp, + zwel, iwel, swel, xwel, + icon, scon, xcon); } else - return RstState(unit_system, - intehead, logihead, doubhead, - zgrp, igrp, sgrp, xgrp, - zwel, iwel, swel, xwel, - icon, scon, xcon); + return RstState(unit_system, intehead, logihead, doubhead); } } diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/well.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/well.cpp index 7d3ca9b57b..3da024e9f9 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/well.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/io/eclipse/rst/well.cpp @@ -61,32 +61,39 @@ RstWell::RstWell(const ::Opm::UnitSystem& unit_system, ij( {iwel[VI::IWell::IHead] - 1, iwel[VI::IWell::JHead] - 1}), k1k2( std::make_pair(iwel[VI::IWell::FirstK] - 1, iwel[VI::IWell::LastK] - 1)), wtype( iwel[VI::IWell::WType], def_ecl_phase), + well_status( iwel[VI::IWell::Status]), active_control( iwel[VI::IWell::ActWCtrl]), vfp_table( iwel[VI::IWell::VFPTab]), - pred_requested_control( iwel[VI::IWell::PredReqWCtrl]), allow_xflow( iwel[VI::IWell::XFlow] == 1), + preferred_phase( iwel[VI::IWell::PreferredPhase]), hist_requested_control( iwel[VI::IWell::HistReqWCtrl]), msw_index( iwel[VI::IWell::MsWID]), completion_ordering( iwel[VI::IWell::CompOrd]), pvt_table( def_pvt_table), - orat_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::OilRateTarget]))), - wrat_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::WatRateTarget]))), - grat_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::GasRateTarget]))), - lrat_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::LiqRateTarget]))), - resv_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::ResVRateTarget]))), - thp_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::THPTarget]))), - bhp_target_float( unit_system.to_si(M::identity, swel[VI::SWell::BHPTarget])), + msw_pressure_drop_model( iwel[VI::IWell::MSW_PlossMod]), + // The values orat_target -> bhp_target_flow will be used in UDA values. The + // UDA values are responsible for unit conversion and raw values are + // internalized here. + orat_target( swel_value(swel[VI::SWell::OilRateTarget])), + wrat_target( swel_value(swel[VI::SWell::WatRateTarget])), + grat_target( swel_value(swel[VI::SWell::GasRateTarget])), + lrat_target( swel_value(swel[VI::SWell::LiqRateTarget])), + resv_target( swel_value(swel[VI::SWell::ResVRateTarget])), + thp_target( swel_value(swel[VI::SWell::THPTarget])), + bhp_target_float( swel[VI::SWell::BHPTarget]), hist_lrat_target( unit_system.to_si(M::liquid_surface_rate, swel[VI::SWell::HistLiqRateTarget])), hist_grat_target( unit_system.to_si(M::gas_surface_rate, swel[VI::SWell::HistGasRateTarget])), hist_bhp_target( unit_system.to_si(M::pressure, swel[VI::SWell::HistBHPTarget])), datum_depth( unit_system.to_si(M::length, swel[VI::SWell::DatumDepth])), drainage_radius( unit_system.to_si(M::length, swel_value(swel[VI::SWell::DrainageRadius]))), efficiency_factor( unit_system.to_si(M::identity, swel[VI::SWell::EfficiencyFactor1])), + alq_value( swel[VI::SWell::Alq_value]), oil_rate( unit_system.to_si(M::liquid_surface_rate, xwel[VI::XWell::OilPrRate])), water_rate( unit_system.to_si(M::liquid_surface_rate, xwel[VI::XWell::WatPrRate])), gas_rate( unit_system.to_si(M::gas_surface_rate, xwel[VI::XWell::GasPrRate])), liquid_rate( unit_system.to_si(M::rate, xwel[VI::XWell::LiqPrRate])), void_rate( unit_system.to_si(M::rate, xwel[VI::XWell::VoidPrRate])), + thp( unit_system.to_si(M::pressure, xwel[VI::XWell::TubHeadPr])), flow_bhp( unit_system.to_si(M::pressure, xwel[VI::XWell::FlowBHP])), wct( unit_system.to_si(M::water_cut, xwel[VI::XWell::WatCut])), gor( unit_system.to_si(M::gas_oil_ratio, xwel[VI::XWell::GORatio])), diff --git a/ThirdParty/custom-opm-common/opm-common/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp b/ThirdParty/custom-opm-common/opm-common/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp index 92c44fd7fc..24746d125c 100644 --- a/ThirdParty/custom-opm-common/opm-common/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp +++ b/ThirdParty/custom-opm-common/opm-common/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp @@ -129,7 +129,7 @@ Well::Well(const RestartIO::RstWell& rst_well, guide_rate(def_guide_rate), efficiency_factor(rst_well.efficiency_factor), solvent_fraction(def_solvent_fraction), - prediction_mode(rst_well.pred_requested_control != 0), +// prediction_mode(rst_well.pred_requested_control != 0), econ_limits(std::make_shared()), foam_properties(std::make_shared()), polymer_properties(std::make_shared()),