#7512 Support optimized summary reader

This commit is contained in:
Magne Sjaastad 2021-03-25 12:56:09 +01:00 committed by GitHub
parent 53dbb33e86
commit f5547dd551
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 2996 additions and 835 deletions

View File

@ -403,6 +403,33 @@ RiaPreferences::RiaPreferences( void )
m_multiLateralWellPattern.uiCapability()->setUiEditorTypeName( caf::PdmUiLineEditor::uiEditorTypeName() ); m_multiLateralWellPattern.uiCapability()->setUiEditorTypeName( caf::PdmUiLineEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_guiTheme, "guiTheme", "GUI theme", "", "", "" ); 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 || if ( field == &octaveShowHeaderInfoWhenExecutingScripts || field == &autocomputeDepthRelatedProperties ||
field == &loadAndShowSoil || field == &m_useShaders || field == &m_showHud || field == &loadAndShowSoil || field == &m_useShaders || field == &m_showHud ||
field == &m_appendClassNameToUiText || field == &m_appendFieldKeywordToToolTipText || field == &m_appendClassNameToUiText || field == &m_appendFieldKeywordToToolTipText || field == &m_showTestToolbar ||
field == &m_showTestToolbar || field == &m_includeFractureDebugInfoFile || field == &m_includeFractureDebugInfoFile || field == &showLasCurveWithoutTvdWarning ||
field == &showLasCurveWithoutTvdWarning || field == &holoLensDisableCertificateVerification || field == &holoLensDisableCertificateVerification || field == &m_showProjectChangedDialog ||
field == &m_showProjectChangedDialog || field == &m_searchPlotTemplateFoldersRecursively || field == &m_searchPlotTemplateFoldersRecursively || field == &m_showLegendBackground ||
field == &m_showLegendBackground || field == &m_showSummaryTimeAsLongString || field == &m_showSummaryTimeAsLongString || field == &m_showViewIdInProjectTree ||
field == &m_showViewIdInProjectTree || field == &m_useMultipleThreadsWhenLoadingSummaryData || field == &m_useMultipleThreadsWhenLoadingSummaryData || field == &m_enableFaultsByDefault ||
field == &m_enableFaultsByDefault || field == &m_showProgressBar || field == &m_openExportedPdfInViewer || field == &m_showProgressBar || field == &m_openExportedPdfInViewer || field == &m_showInfoBox ||
field == &m_showInfoBox || field == &m_showGridBox || field == &m_useUndoRedo ) field == &m_showGridBox || field == &m_useUndoRedo || field == &m_useOptimizedSummaryDataFileReader ||
field == &m_createOptimizedSummaryDataFile || field == &m_useOptimizedSummaryDataFile )
{ {
caf::PdmUiCheckBoxEditorAttribute* myAttr = dynamic_cast<caf::PdmUiCheckBoxEditorAttribute*>( attribute ); caf::PdmUiCheckBoxEditorAttribute* myAttr = dynamic_cast<caf::PdmUiCheckBoxEditorAttribute*>( attribute );
if ( myAttr ) if ( myAttr )
@ -576,6 +604,18 @@ void RiaPreferences::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering&
m_pageRightMargin.uiCapability()->setUiName( "Right Margin" + unitLabel ); m_pageRightMargin.uiCapability()->setUiName( "Right Margin" + unitLabel );
m_pageTopMargin.uiCapability()->setUiName( "Top Margin" + unitLabel ); m_pageTopMargin.uiCapability()->setUiName( "Top Margin" + unitLabel );
m_pageBottomMargin.uiCapability()->setUiName( "Bottom 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() ) else if ( uiConfigName == RiaPreferences::tabNameScripting() )
@ -1171,6 +1211,30 @@ QString RiaPreferences::octaveExecutable() const
return m_octaveExecutable().trimmed(); 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();
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

View File

@ -138,6 +138,11 @@ public:
QString pythonExecutable() const; QString pythonExecutable() const;
QString octaveExecutable() const; QString octaveExecutable() const;
// Summary readers
bool useOptimizedSummaryDataReader() const;
bool useOptimizedSummaryDataFiles() const;
bool createOptimizedSummaryDataFiles() const;
public: // Pdm Fields public: // Pdm Fields
caf::PdmField<bool> enableGrpcServer; caf::PdmField<bool> enableGrpcServer;
caf::PdmField<int> defaultGrpcPortNumber; caf::PdmField<int> defaultGrpcPortNumber;
@ -243,6 +248,11 @@ private:
// Well Path Import // Well Path Import
caf::PdmField<QString> m_multiLateralWellPattern; caf::PdmField<QString> m_multiLateralWellPattern;
// Summary data
caf::PdmField<bool> m_useOptimizedSummaryDataFileReader;
caf::PdmField<bool> m_createOptimizedSummaryDataFile;
caf::PdmField<bool> m_useOptimizedSummaryDataFile;
// 3d view // 3d view
caf::PdmField<caf::AppEnum<RiaDefines::MeshModeType>> m_defaultMeshModeType; caf::PdmField<caf::AppEnum<RiaDefines::MeshModeType>> m_defaultMeshModeType;
caf::PdmField<caf::AppEnum<RiaGuiApplication::RINavigationPolicy>> m_navigationPolicy; caf::PdmField<caf::AppEnum<RiaGuiApplication::RINavigationPolicy>> m_navigationPolicy;

View File

@ -60,6 +60,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelDeviationFrkExporter.h
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelPerfsFrkExporter.h ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelPerfsFrkExporter.h
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelAsymmetricFrkExporter.h ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelAsymmetricFrkExporter.h
${CMAKE_CURRENT_LIST_DIR}/RifSurfaceExporter.h ${CMAKE_CURRENT_LIST_DIR}/RifSurfaceExporter.h
${CMAKE_CURRENT_LIST_DIR}/RifOpmCommonSummary.h
# HDF5 file reader is directly included in ResInsight main CmakeList.txt # 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}/RifStimPlanModelPerfsFrkExporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelAsymmetricFrkExporter.cpp ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelAsymmetricFrkExporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifSurfaceExporter.cpp ${CMAKE_CURRENT_LIST_DIR}/RifSurfaceExporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifOpmCommonSummary.cpp
# HDF5 file reader is directly included in ResInsight main CmakeList.txt # HDF5 file reader is directly included in ResInsight main CmakeList.txt
#${CMAKE_CURRENT_LIST_DIR}/RifHdf5Reader.cpp #${CMAKE_CURRENT_LIST_DIR}/RifHdf5Reader.cpp

View File

@ -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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifOpmCommonSummary.h"
#include "opm/io/eclipse/ESmry.hpp"
#ifdef USE_OPENMP
#include <omp.h>
#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<Opm::EclIO::ESmry>( 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<time_t>& RifOpmCommonEclipseSummary::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{
return m_timeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifOpmCommonEclipseSummary::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* 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();
}

View File

@ -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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaDefines.h"
#include "RifEclipseSummaryAddress.h"
#include "RifSummaryReaderInterface.h"
#include <QString>
#include <QStringList>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
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<time_t>& timeSteps( const RifEclipseSummaryAddress& resultAddress ) const override;
bool values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const override;
std::string unitName( const RifEclipseSummaryAddress& resultAddress ) const override;
RiaDefines::EclipseUnitSystem unitSystem() const override;
private:
void buildMetaData();
static void increaseLodFileCount();
static RifEclipseSummaryAddress createAddressFromSummaryNode( const Opm::EclIO::SummaryNode& summaryNode,
Opm::EclIO::ESmry* summaryFile );
private:
std::unique_ptr<Opm::EclIO::ESmry> m_eSmry;
std::vector<std::string> m_eSmryKeywords;
std::map<RifEclipseSummaryAddress, size_t> m_adrToSummaryNodeIndex;
std::vector<time_t> m_timeSteps;
static size_t sm_createdLodFileCount;
bool m_useLodsmryFiles;
bool m_createLodsmryFiles;
};

View File

@ -19,10 +19,13 @@
#include "RifReaderEclipseSummary.h" #include "RifReaderEclipseSummary.h"
#include "RiaFilePathTools.h" #include "RiaFilePathTools.h"
#include "RiaLogging.h"
#include "RiaPreferences.h"
#include "RiaStdStringTools.h" #include "RiaStdStringTools.h"
#include "RiaStringEncodingTools.h" #include "RiaStringEncodingTools.h"
#include "RifEclipseSummaryTools.h" #include "RifEclipseSummaryTools.h"
#include "RifOpmCommonSummary.h"
#include "RifReaderEclipseOutput.h" #include "RifReaderEclipseOutput.h"
#include <cassert> #include <cassert>
@ -86,7 +89,7 @@ ecl_sum_type* openEclSum( const QString& inHeaderFileName, bool includeRestartFi
QString nativeHeaderFileName = QDir::toNativeSeparators( inHeaderFileName ); QString nativeHeaderFileName = QDir::toNativeSeparators( inHeaderFileName );
RifEclipseSummaryTools::findSummaryFiles( nativeHeaderFileName, &headerFileName, &dataFileNames ); RifEclipseSummaryTools::findSummaryFiles( nativeHeaderFileName, &headerFileName, &dataFileNames );
if ( headerFileName.isEmpty() || dataFileNames.size() == 0 ) return nullptr; if ( headerFileName.isEmpty() || dataFileNames.isEmpty() ) return nullptr;
assert( !headerFileName.isEmpty() ); assert( !headerFileName.isEmpty() );
assert( dataFileNames.size() > 0 ); assert( dataFileNames.size() > 0 );
@ -126,7 +129,7 @@ RifReaderEclipseSummary::RifReaderEclipseSummary()
, m_ecl_SmSpec( nullptr ) , m_ecl_SmSpec( nullptr )
, m_unitSystem( RiaDefines::EclipseUnitSystem::UNITS_METRIC ) , m_unitSystem( RiaDefines::EclipseUnitSystem::UNITS_METRIC )
{ {
m_valuesCache.reset( new ValuesCache() ); m_valuesCache = std::make_unique<ValuesCache>();
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -146,6 +149,30 @@ RifReaderEclipseSummary::~RifReaderEclipseSummary()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
bool RifReaderEclipseSummary::open( const QString& headerFileName, bool includeRestartFiles ) 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<RifOpmCommonEclipseSummary>();
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 ); assert( m_ecl_sum == nullptr );
m_ecl_sum = openEclSum( headerFileName, includeRestartFiles ); m_ecl_sum = openEclSum( headerFileName, includeRestartFiles );
@ -241,7 +268,7 @@ RifRestartFileInfo RifReaderEclipseSummary::getFileInfo( const QString& headerFi
RifRestartFileInfo fileInfo; RifRestartFileInfo fileInfo;
ecl_sum_type* ecl_sum = openEclSum( headerFileName, false ); ecl_sum_type* ecl_sum = openEclSum( headerFileName, false );
std::vector<time_t> timeSteps = getTimeSteps( ecl_sum ); std::vector<time_t> timeSteps = getTimeSteps( ecl_sum );
if ( timeSteps.size() > 0 ) if ( !timeSteps.empty() )
{ {
fileInfo.fileName = headerFileName; fileInfo.fileName = headerFileName;
fileInfo.startDate = timeSteps.front(); fileInfo.startDate = timeSteps.front();
@ -426,21 +453,32 @@ RifEclipseSummaryAddress addressFromErtSmSpecNode( const ecl::smspec_node& ertSu
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
bool RifReaderEclipseSummary::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const bool RifReaderEclipseSummary::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{ {
assert( m_ecl_sum != nullptr );
values->clear(); values->clear();
values->reserve( timeStepCount() ); values->reserve( timeStepCount() );
// assert( m_ecl_sum != nullptr );
const std::vector<double>& cachedValues = m_valuesCache->getValues( resultAddress ); const std::vector<double>& cachedValues = m_valuesCache->getValues( resultAddress );
if ( !cachedValues.empty() ) if ( !cachedValues.empty() )
{ {
values->insert( values->begin(), cachedValues.begin(), cachedValues.end() ); 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 ) ) if ( m_differenceAddresses.count( resultAddress ) )
{ {
std::string quantityName = resultAddress.quantityName(); const std::string& quantityName = resultAddress.quantityName();
auto historyQuantity = quantityName.substr( 0, quantityName.size() - differenceIdentifier().size() ) + auto historyQuantity = quantityName.substr( 0, quantityName.size() - differenceIdentifier().size() ) +
historyIdentifier(); historyIdentifier();
@ -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 ); assert( m_ecl_sum != nullptr );
if ( m_ecl_SmSpec == nullptr ) return 0; if ( m_ecl_SmSpec == nullptr ) return 0;
return ecl_sum_get_data_length( m_ecl_sum ); return static_cast<size_t>( ecl_sum_get_data_length( m_ecl_sum ) );
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -508,7 +551,7 @@ int RifReaderEclipseSummary::timeStepCount() const
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
const std::vector<time_t>& RifReaderEclipseSummary::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const const std::vector<time_t>& RifReaderEclipseSummary::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{ {
assert( m_ecl_sum != nullptr ); // assert( m_ecl_sum != nullptr );
return m_timeSteps; return m_timeSteps;
} }
@ -535,6 +578,15 @@ void RifReaderEclipseSummary::buildMetaData()
m_allResultAddresses.clear(); m_allResultAddresses.clear();
m_resultAddressToErtNodeIdx.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 ) if ( m_ecl_SmSpec )
{ {
int varCount = ecl_smspec_num_nodes( m_ecl_SmSpec ); int varCount = ecl_smspec_num_nodes( m_ecl_SmSpec );
@ -556,7 +608,7 @@ void RifReaderEclipseSummary::buildMetaData()
RifEclipseSummaryAddress adrWithoutHistory; RifEclipseSummaryAddress adrWithoutHistory;
{ {
std::string s = adr.quantityName(); const std::string& s = adr.quantityName();
if ( !RiaStdStringTools::endsWith( s, historyIdentifier() ) ) if ( !RiaStdStringTools::endsWith( s, historyIdentifier() ) )
{ {
RifEclipseSummaryAddress candidate = adr; RifEclipseSummaryAddress candidate = adr;

View File

@ -31,6 +31,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
class RifOpmCommonEclipseSummary;
//================================================================================================== //==================================================================================================
// //
// //
@ -82,7 +84,7 @@ public:
static const std::string historyIdentifier() { return "H"; } static const std::string historyIdentifier() { return "H"; }
private: private:
int timeStepCount() const; size_t timeStepCount() const;
int indexFromAddress( const RifEclipseSummaryAddress& resultAddress ) const; int indexFromAddress( const RifEclipseSummaryAddress& resultAddress ) const;
void buildMetaData(); void buildMetaData();
RifRestartFileInfo getRestartFile( const QString& headerFileName ); RifRestartFileInfo getRestartFile( const QString& headerFileName );
@ -104,6 +106,8 @@ private:
std::set<RifEclipseSummaryAddress> m_differenceAddresses; std::set<RifEclipseSummaryAddress> m_differenceAddresses;
std::unique_ptr<RifOpmCommonEclipseSummary> m_opmCommonReader;
//================================================================================================== //==================================================================================================
// //
//================================================================================================== //==================================================================================================

View File

@ -15,13 +15,15 @@
// for more details. // for more details.
// //
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
#include "RimSummaryCaseMainCollection.h" #include "RimSummaryCaseMainCollection.h"
#include "RiaLogging.h"
#include "RiaSummaryTools.h" #include "RiaSummaryTools.h"
#include "RimSummaryPlotCollection.h"
#include "RifCaseRealizationParametersReader.h" #include "RifCaseRealizationParametersReader.h"
#include "RifEclipseSummaryTools.h" #include "RifEclipseSummaryTools.h"
#include "RifOpmCommonSummary.h"
#include "RifSummaryCaseRestartSelector.h" #include "RifSummaryCaseRestartSelector.h"
#include "RimCaseDisplayNameTools.h" #include "RimCaseDisplayNameTools.h"
@ -35,8 +37,10 @@
#include "RimSummaryCaseCollection.h" #include "RimSummaryCaseCollection.h"
#include "RimSummaryCurve.h" #include "RimSummaryCurve.h"
#include "RimSummaryPlot.h" #include "RimSummaryPlot.h"
#include "RimSummaryPlotCollection.h"
#include "cafProgressInfo.h" #include "cafProgressInfo.h"
#include <QDir> #include <QDir>
CAF_PDM_SOURCE_INIT( RimSummaryCaseMainCollection, "SummaryCaseCollection" ); CAF_PDM_SOURCE_INIT( RimSummaryCaseMainCollection, "SummaryCaseCollection" );
@ -435,6 +439,8 @@ void RimSummaryCaseMainCollection::loadFileSummaryCaseData( std::vector<RimFileS
caf::ProgressInfo progInfo( fileSummaryCases.size(), "Loading Summary Cases" ); caf::ProgressInfo progInfo( fileSummaryCases.size(), "Loading Summary Cases" );
RifOpmCommonEclipseSummary::resetLodCount();
#pragma omp parallel for schedule( dynamic ) #pragma omp parallel for schedule( dynamic )
for ( int cIdx = 0; cIdx < static_cast<int>( fileSummaryCases.size() ); ++cIdx ) for ( int cIdx = 0; cIdx < static_cast<int>( fileSummaryCases.size() ); ++cIdx )
{ {
@ -447,6 +453,13 @@ void RimSummaryCaseMainCollection::loadFileSummaryCaseData( std::vector<RimFileS
progInfo.setProgress( cIdx ); progInfo.setProgress( cIdx );
} }
auto numberOfLodFilesCreated = RifOpmCommonEclipseSummary::numberOfLodFilesCreated();
if ( numberOfLodFilesCreated > 0 )
{
RiaLogging::info( QString( "Optimized Summary Reader : Converted and created %1 '*.LODSMRY' files on disk." )
.arg( numberOfLodFilesCreated ) );
}
for ( int cIdx = 0; cIdx < static_cast<int>( fileSummaryCases.size() ); ++cIdx ) for ( int cIdx = 0; cIdx < static_cast<int>( fileSummaryCases.size() ); ++cIdx )
{ {
RimFileSummaryCase* fileSummaryCase = fileSummaryCases[cIdx]; RimFileSummaryCase* fileSummaryCase = fileSummaryCases[cIdx];

View File

@ -74,6 +74,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaStatisticsTools-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanXmlReader-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanXmlReader-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RigWellPathGeometryExporter-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RigWellPathGeometryExporter-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelDeviationFrkExporter-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelDeviationFrkExporter-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifSummaryDataReader-Test.cpp
) )
if (RESINSIGHT_ENABLE_GRPC) if (RESINSIGHT_ENABLE_GRPC)

View File

@ -0,0 +1,113 @@
#include "gtest/gtest.h"
//#include "RiaTestDataDirectory.h"
#include "RifOpmCommonSummary.h"
#include "RifReaderEclipseSummary.h"
#include <chrono>
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<double> 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<double> values;
reader.values( adr, &values );
totalValuesRead += values.size();
i++;
if ( i > maxCount ) break;
}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> 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<double> 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<double> values;
reader.values( adr, &values );
totalValuesRead += values.size();
i++;
if ( i > maxCount ) break;
}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end - start;
std::cout << "LibEcl read data" << std::setw( 9 ) << totalValuesRead << "totalValueCount" << diff.count()
<< " s\n";
}
}
}

View File

@ -78,6 +78,8 @@ add_library(${PROJECT_NAME}
opm-common/src/opm/io/eclipse/EclOutput.cpp opm-common/src/opm/io/eclipse/EclOutput.cpp
opm-common/src/opm/io/eclipse/EclUtil.cpp opm-common/src/opm/io/eclipse/EclUtil.cpp
opm-common/src/opm/io/eclipse/EGrid.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 # Required for use of static function RstConnection::inverse_peaceman
opm-common/src/opm/io/eclipse/rst/connection.cpp 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/Well/WListManager.cpp
opm-common/src/opm/parser/eclipse/EclipseState/Schedule/MSW/SpiralICD.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/EclOutput.cpp
opm-common/src/opm/io/eclipse/ESmry.cpp
opm-common/src/opm/io/eclipse/EGrid.cpp
) )
foreach(fileToExclude ${UNITY_EXCLUDE_FILES}) foreach(fileToExclude ${UNITY_EXCLUDE_FILES})

View File

@ -1,6 +1,7 @@
#ifdef _WIN32 #ifdef _WIN32
#include "Substitutes.hpp" #include "Substitutes.hpp"
#include <Shlwapi.h>
int int
fnmatch(const char* pattern, const char* string, int flags) fnmatch(const char* pattern, const char* string, int flags)

View File

@ -2,10 +2,6 @@
#ifdef _WIN32 #ifdef _WIN32
#include <Shlwapi.h>
#define NOMINMAX
#include <windows.h>
#undef NOMINMAX
// IGNORE is used in InputErrorAction.hpp, as an enum value, // 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. // 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. // It is not required here, so we can undefine it.

View File

@ -20,6 +20,7 @@
#define OPM_IO_EGRID_HPP #define OPM_IO_EGRID_HPP
#include <opm/io/eclipse/EclFile.hpp> #include <opm/io/eclipse/EclFile.hpp>
#include <opm/common/utility/FileSystem.hpp>
#include <array> #include <array>
#include <iostream> #include <iostream>
@ -34,7 +35,7 @@ namespace Opm { namespace EclIO {
class EGrid : public EclFile class EGrid : public EclFile
{ {
public: 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 global_index(int i, int j, int k) const;
int active_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<int, 3> ijk_from_active_index(int actInd) const; std::array<int, 3> ijk_from_active_index(int actInd) const;
std::array<int, 3> ijk_from_global_index(int globInd) const; std::array<int, 3> ijk_from_global_index(int globInd) const;
void getCellCorners(int globindex, std::array<double,8>& X, std::array<double,8>& Y, std::array<double,8>& Z) const; void getCellCorners(int globindex, std::array<double,8>& X, std::array<double,8>& Y, std::array<double,8>& Z);
void getCellCorners(const std::array<int, 3>& ijk, std::array<double,8>& X, std::array<double,8>& Y, std::array<double,8>& Z) const; void getCellCorners(const std::array<int, 3>& ijk, std::array<double,8>& X, std::array<double,8>& Y, std::array<double,8>& Z);
int activeCells() const { return nactive; } int activeCells() const { return nactive; }
int totalNumberOfCells() const { return nijk[0] * nijk[1] * nijk[2]; } 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<int>& hostCellsGlobalIndex() const { return host_cells; }
std::vector<std::array<int, 3>> hostCellsIJK();
// zero based: i1, j1,k1, i2,j2,k2, transmisibility
using NNCentry = std::tuple<int, int, int, int, int, int, float>;
std::vector<NNCentry> get_nnc_ijk();
const std::vector<std::string>& list_of_lgrs() const { return lgr_names; }
private: private:
Opm::filesystem::path inputFileName, initFileName;
std::string m_grid_name;
bool m_radial;
std::array<int, 3> nijk; std::array<int, 3> nijk;
int nactive; std::array<int, 3> host_nijk;
int nactive, m_nncs;
mutable bool m_nncs_loaded;
std::vector<int> act_index; std::vector<int> act_index;
std::vector<int> glob_index; std::vector<int> glob_index;
std::vector<float> coord_array; std::vector<float> coord_array;
std::vector<float> zcorn_array; std::vector<float> zcorn_array;
std::vector<int> nnc1_array;
std::vector<int> nnc2_array;
std::vector<float> transnnc_array;
std::vector<int> host_cells;
std::vector<std::string> 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 }} // namespace Opm::EclIO

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_IO_EINIT_HPP
#define OPM_IO_EINIT_HPP
#include <opm/io/eclipse/EclFile.hpp>
#include <array>
#include <vector>
#include <map>
namespace Opm { namespace EclIO {
class EInit : public EclFile
{
public:
explicit EInit(const std::string& filename);
const std::vector<std::string>& list_of_lgrs() const { return lgr_names; }
std::vector<EclFile::EclEntry> list_arrays() const;
std::vector<EclFile::EclEntry> list_arrays(const std::string& grid_name) const;
const std::array<int, 3>& 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 <typename T>
const std::vector<T>& getInitData(const std::string& name, const std::string& grid_name = "global")
{
return this->ImplgetInitData<T>(name, grid_name);
}
protected:
template <typename T>
const std::vector<T>& 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<T, int>)
return getImpl(arr_ind, INTE, inte_array, "integer");
if constexpr (std::is_same_v<T, float>)
return getImpl(arr_ind, REAL, real_array, "float");
if constexpr (std::is_same_v<T, double>)
return getImpl(arr_ind, DOUB, doub_array, "double");
if constexpr (std::is_same_v<T, bool>)
return getImpl(arr_ind, LOGI, logi_array, "bool");
if constexpr (std::is_same_v<T, std::string>)
{
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<int, 3> global_nijk;
std::vector<std::array<int, 3>> lgr_nijk;
int global_nactive;
std::vector<int> lgr_nactive;
std::vector<std::string> lgr_names;
std::map<std::string,int> global_array_index;
std::vector<std::map<std::string,int>> 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

View File

@ -27,6 +27,7 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
namespace Opm { namespace EclIO { namespace OutputStream { namespace Opm { namespace EclIO { namespace OutputStream {
class Restart; class Restart;
}}} }}}
@ -37,38 +38,68 @@ class ERst : public EclFile
{ {
public: public:
explicit ERst(const std::string& filename); explicit ERst(const std::string& filename);
bool hasReportStepNumber(int number) const; bool hasReportStepNumber(int number) const;
bool hasLGR(const std::string& gridname, int reportStepNumber) const;
void loadReportStepNumber(int number); void loadReportStepNumber(int number);
template <typename T> template <typename T>
const std::vector<T>& getRst(const std::string& name, int reportStepNumber, int occurrence); const std::vector<T>& getRestartData(const std::string& name, int reportStepNumber)
{
return getRestartData<T>(name,reportStepNumber, 0);
}
template <typename T> template <typename T>
const std::vector<T>& getRst(int index, int reportStepNumber){ const std::vector<T>& getRestartData(const std::string& name, int reportStepNumber, int occurrence);
template <typename T>
const std::vector<T>& getRestartData(const std::string& name, int reportStepNumber, const std::string& lgr_name);
template <typename T>
const std::vector<T>& getRestartData(int index, int reportStepNumber)
{
auto indRange = this->getIndexRange(reportStepNumber); auto indRange = this->getIndexRange(reportStepNumber);
return this->get<T>(index + std::get<0>(indRange)); return this->get<T>(index + std::get<0>(indRange));
} }
int count(const std::string& name, int reportStepNumber) const; template <typename T>
const std::vector<T>& 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<T>(index + start_ind);
}
int occurrence_count(const std::string& name, int reportStepNumber) const;
size_t numberOfReportSteps() const { return seqnum.size(); }; size_t numberOfReportSteps() const { return seqnum.size(); };
const std::vector<int>& listOfReportStepNumbers() const { return seqnum; } const std::vector<int>& listOfReportStepNumbers() const { return seqnum; }
std::vector<EclEntry> listOfRstArrays(int reportStepNumber); std::vector<EclEntry> listOfRstArrays(int reportStepNumber);
std::vector<EclEntry> listOfRstArrays(int reportStepNumber, const std::string& lgr_name);
friend class OutputStream::Restart; friend class OutputStream::Restart;
private: private:
int nReports; int nReports;
std::vector<int> seqnum; // report step numbers, from SEQNUM array in restart file std::vector<int> seqnum; // report step numbers, from SEQNUM array in restart file
std::unordered_map<int,bool> reportLoaded; mutable std::unordered_map<int,bool> reportLoaded;
std::map<int, std::pair<int,int>> arrIndexRange; // mapping report step number to array indeces (start and end) std::map<int, std::pair<int,int>> arrIndexRange; // mapping report step number to array indeces (start and end)
std::vector<std::vector<std::string>> lgr_names; // report step numbers, from SEQNUM array in restart file
void initUnified(); void initUnified();
void initSeparate(const int number); void initSeparate(const int number);
int getArrayIndex(const std::string& name, int seqnum, int occurrence) 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<int,int> getIndexRange(int reportStepNumber) const; std::tuple<int,int> getIndexRange(int reportStepNumber) const;
std::streampos std::streampos

View File

@ -40,7 +40,7 @@ class ESmry
public: public:
// input is smspec (or fsmspec file) // 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; } int numberOfVectors() const { return nVect; }
@ -57,6 +57,11 @@ public:
void LoadData(const std::vector<std::string>& vectList) const; void LoadData(const std::vector<std::string>& vectList) const;
void LoadData() 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; } std::chrono::system_clock::time_point startdate() const { return startdat; }
const std::vector<std::string>& keywordList() const; const std::vector<std::string>& keywordList() const;
@ -65,7 +70,7 @@ public:
int timestepIdxAtReportstepStart(const int reportStep) const; 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 std::string& name) const;
const std::string& get_unit(const SummaryNode& node) const; const std::string& get_unit(const SummaryNode& node) const;
@ -73,10 +78,16 @@ public:
void write_rsm(std::ostream&) const; void write_rsm(std::ostream&) const;
void write_rsm_file(std::optional<Opm::filesystem::path> = std::nullopt) const; void write_rsm_file(std::optional<Opm::filesystem::path> = std::nullopt) const;
void ijk_from_global_index(int glob, int &i, int &j, int &k) const;
private: private:
Opm::filesystem::path inputFileName;
bool useLodsmryFile; // Added by ResInsight use
Opm::filesystem::path inputFileName, lodFileName;
int nI, nJ, nK, nSpecFiles; int nI, nJ, nK, nSpecFiles;
size_t nVect; bool fromSingleRun, lodEnabeled;
uint64_t lod_offset, lod_arr_size;
size_t nVect, nTstep;
std::vector<bool> formattedFiles; std::vector<bool> formattedFiles;
std::vector<std::string> dataFileList; std::vector<std::string> dataFileList;
@ -92,7 +103,6 @@ private:
std::vector<int> seqIndex; std::vector<int> seqIndex;
void ijk_from_global_index(int glob, int &i, int &j, int &k) const;
std::vector<SummaryNode> summaryNodes; std::vector<SummaryNode> summaryNodes;
std::unordered_map<std::string, std::string> kwunits; std::unordered_map<std::string, std::string> kwunits;
@ -129,6 +139,9 @@ private:
std::vector<std::tuple <std::string, uint64_t>> getListOfArrays(std::string filename, bool formatted); std::vector<std::tuple <std::string, uint64_t>> getListOfArrays(std::string filename, bool formatted);
std::vector<int> makeKeywPosVector(int speInd) const; std::vector<int> makeKeywPosVector(int speInd) const;
std::string read_string_from_disk(std::fstream& fileH, uint64_t size) const;
void inspect_lodsmry();
void Load_from_lodsmry(const std::vector<int>& keywIndVect) const;
}; };
}} // namespace Opm::EclIO }} // namespace Opm::EclIO

View File

@ -36,7 +36,7 @@ class EclFile
{ {
public: public:
explicit EclFile(const std::string& filename, bool preload = false); 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(); // load all data
void loadData(const std::string& arrName); // load all arrays with array name equal to arrName 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::string, eclArrType, int64_t>; using EclEntry = std::tuple<std::string, eclArrType, int64_t>;
std::vector<EclEntry> getList() const; std::vector<EclEntry> getList() const;
const std::vector<int>& getElementSizeList() const { return array_element_size; }
template <typename T> template <typename T>
const std::vector<T>& get(int arrIndex); const std::vector<T>& get(int arrIndex);
@ -66,6 +68,7 @@ public:
const std::vector<std::string>& arrayNames() const { return array_name; } const std::vector<std::string>& arrayNames() const { return array_name; }
std::size_t size() const; std::size_t size() const;
bool is_ix() const;
protected: protected:
bool formatted; bool formatted;
@ -80,6 +83,7 @@ protected:
std::vector<std::string> array_name; std::vector<std::string> array_name;
std::vector<eclArrType> array_type; std::vector<eclArrType> array_type;
std::vector<int64_t> array_size; std::vector<int64_t> array_size;
std::vector<int> array_element_size;
std::vector<uint64_t> ifStreamPos; std::vector<uint64_t> ifStreamPos;
@ -111,6 +115,9 @@ private:
void loadBinaryArray(std::fstream& fileH, std::size_t arrIndex); void loadBinaryArray(std::fstream& fileH, std::size_t arrIndex);
void loadFormattedArray(const std::string& fileStr, std::size_t arrIndex, int64_t fromPos); void loadFormattedArray(const std::string& fileStr, std::size_t arrIndex, int64_t fromPos);
std::vector<unsigned int> get_bin_logi_raw_values(int arrIndex) const;
std::vector<std::string> get_fmt_real_raw_str_values(int arrIndex) const;
}; };
}} // namespace Opm::EclIO }} // namespace Opm::EclIO

View File

@ -26,13 +26,15 @@ namespace Opm { namespace EclIO {
// type MESS have no assisiated data // type MESS have no assisiated data
enum eclArrType { enum eclArrType {
INTE, REAL, DOUB, CHAR, LOGI, MESS INTE, REAL, DOUB, CHAR, LOGI, MESS, C0NN
}; };
// named constants related to binary file format // 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 unsigned int false_value = 0x00000000;
const int sizeOfInte = 4; // number of bytes pr integer (inte) element const int sizeOfInte = 4; // number of bytes pr integer (inte) element
const int sizeOfReal = 4; // number of bytes pr float (real) 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 sizeOfDoub = 8; // number of bytes pr double (doub) element

View File

@ -47,59 +47,71 @@ public:
const std::vector<T>& data) const std::vector<T>& data)
{ {
eclArrType arrType = MESS; eclArrType arrType = MESS;
int element_size = 4;
if (typeid(T) == typeid(int)) if (typeid(T) == typeid(int))
arrType = INTE; arrType = INTE;
else if (typeid(T) == typeid(float)) else if (typeid(T) == typeid(float))
arrType = REAL; arrType = REAL;
else if (typeid(T) == typeid(double)) else if (typeid(T) == typeid(double)){
arrType = DOUB; arrType = DOUB;
else if (typeid(T) == typeid(bool)) element_size = 8;
} else if (typeid(T) == typeid(bool))
arrType = LOGI; arrType = LOGI;
else if (typeid(T) == typeid(char)) else if (typeid(T) == typeid(char))
arrType = MESS; arrType = MESS;
if (isFormatted) if (isFormatted)
{ {
writeFormattedHeader(name, data.size(), arrType); writeFormattedHeader(name, data.size(), arrType, element_size);
if (arrType != MESS) if (arrType != MESS)
writeFormattedArray(data); writeFormattedArray(data);
} }
else else
{ {
writeBinaryHeader(name, data.size(), arrType); writeBinaryHeader(name, data.size(), arrType, element_size);
if (arrType != MESS) if (arrType != MESS)
writeBinaryArray(data); 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<std::string>& data, int element_size);
void message(const std::string& msg); void message(const std::string& msg);
void flushStream(); void flushStream();
void set_ix() { ix_standard = true; }
friend class OutputStream::Restart; friend class OutputStream::Restart;
friend class OutputStream::SummarySpecification; friend class OutputStream::SummarySpecification;
private: 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 <typename T> template <typename T>
void writeBinaryArray(const std::vector<T>& data); void writeBinaryArray(const std::vector<T>& data);
void writeBinaryCharArray(const std::vector<std::string>& data); void writeBinaryCharArray(const std::vector<std::string>& data, int element_size);
void writeBinaryCharArray(const std::vector<PaddedOutputString<8>>& data); void writeBinaryCharArray(const std::vector<PaddedOutputString<8>>& 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 <typename T> template <typename T>
void writeFormattedArray(const std::vector<T>& data); void writeFormattedArray(const std::vector<T>& data);
void writeFormattedCharArray(const std::vector<std::string>& data); void writeFormattedCharArray(const std::vector<std::string>& data, int element_size);
void writeFormattedCharArray(const std::vector<PaddedOutputString<8>>& data); void writeFormattedCharArray(const std::vector<PaddedOutputString<8>>& data);
void writeArrayType(const eclArrType arrType); void writeArrayType(const eclArrType arrType);
std::string make_real_string(float value) const; std::string make_real_string_ecl(float value) const;
std::string make_doub_string(double 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; std::ofstream ofileH;
}; };

View File

@ -23,6 +23,8 @@
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector>
#include <functional>
namespace Opm { namespace EclIO { namespace Opm { namespace EclIO {
@ -31,24 +33,52 @@ namespace Opm { namespace EclIO {
float flipEndianFloat(float num); float flipEndianFloat(float num);
double flipEndianDouble(double num); double flipEndianDouble(double num);
bool isEOF(std::fstream* fileH); bool isEOF(std::fstream* fileH);
bool fileExists(const std::string& filename);
bool isFormatted(const std::string& filename);
std::tuple<int, int> block_size_data_binary(eclArrType arrType); std::tuple<int, int> block_size_data_binary(eclArrType arrType);
std::tuple<int, int, int> block_size_data_formatted(eclArrType arrType); std::tuple<int, int, int> block_size_data_formatted(eclArrType arrType);
std::string trimr(const std::string &str1); std::string trimr(const std::string &str1);
uint64_t sizeOnDiskBinary(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); uint64_t sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrType arrType, int elementSize);
void readBinaryHeader(std::fstream& fileH, std::string& tmpStrName, void readBinaryHeader(std::fstream& fileH, std::string& tmpStrName,
int& tmpSize, std::string& tmpStrType); int& tmpSize, std::string& tmpStrType);
void readBinaryHeader(std::fstream& fileH, std::string& arrName, 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, 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<typename T, typename T2>
std::vector<T> readBinaryArray(std::fstream& fileH, const int64_t size, Opm::EclIO::eclArrType type,
std::function<T(T2)>& flip, int elementSize);
std::vector<int> readBinaryInteArray(std::fstream &fileH, const int64_t size);
std::vector<float> readBinaryRealArray(std::fstream& fileH, const int64_t size);
std::vector<double> readBinaryDoubArray(std::fstream& fileH, const int64_t size);
std::vector<bool> readBinaryLogiArray(std::fstream &fileH, const int64_t size);
std::vector<unsigned int> readBinaryRawLogiArray(std::fstream &fileH, const int64_t size);
std::vector<std::string> readBinaryCharArray(std::fstream& fileH, const int64_t size);
std::vector<std::string> readBinaryC0nnArray(std::fstream& fileH, const int64_t size, int elementSize);
template<typename T>
std::vector<T> readFormattedArray(const std::string& file_str, const int size, int64_t fromPos,
std::function<T(const std::string&)>& process);
std::vector<int> readFormattedInteArray(const std::string& file_str, const int64_t size, int64_t fromPos);
std::vector<std::string> readFormattedCharArray(const std::string& file_str, const int64_t size,
int64_t fromPos, int elementSize);
std::vector<float> readFormattedRealArray(const std::string& file_str, const int64_t size, int64_t fromPos);
std::vector<std::string> readFormattedRealRawStrings(const std::string& file_str, const int64_t size, int64_t fromPos);
std::vector<bool> readFormattedLogiArray(const std::string& file_str, const int64_t size, int64_t fromPos);
std::vector<double> readFormattedDoubArray(const std::string& file_str, const int64_t size, int64_t fromPos);
}} // namespace Opm::EclIO }} // namespace Opm::EclIO

View File

@ -15,7 +15,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef OPM_IO_SUMMARYNODE_HPP #ifndef OPM_IO_SUMMARYNODE_HPP
#define OPM_IO_SUMMARYNODE_HPP #define OPM_IO_SUMMARYNODE_HPP
@ -25,11 +25,10 @@
#include <string> #include <string>
#include <unordered_set> #include <unordered_set>
namespace Opm::EclIO { namespace Opm { namespace EclIO {
struct SummaryNode { struct SummaryNode {
enum class Category { enum class Category {
Aquifer,
Well, Well,
Group, Group,
Field, Field,
@ -37,6 +36,8 @@ struct SummaryNode {
Block, Block,
Connection, Connection,
Segment, Segment,
Aquifer,
Node,
Miscellaneous, Miscellaneous,
}; };
@ -47,6 +48,7 @@ struct SummaryNode {
Pressure, Pressure,
Count, Count,
Mode, Mode,
ProdIndex,
Undefined, Undefined,
}; };
@ -56,6 +58,8 @@ struct SummaryNode {
std::string wgname; std::string wgname;
int number; int number;
std::optional<std::string> fip_region;
constexpr static int default_number { std::numeric_limits<int>::min() }; constexpr static int default_number { std::numeric_limits<int>::min() };
std::string unique_key() const; std::string unique_key() const;
@ -72,6 +76,6 @@ struct SummaryNode {
std::optional<std::string> display_number(number_renderer) const; std::optional<std::string> display_number(number_renderer) const;
}; };
} // namespace Opm::EclIO }} // namespace Opm::EclIO
#endif // OPM_IO_SUMMARYNODE_HPP #endif // OPM_IO_SUMMARYNODE_HPP

View File

@ -32,12 +32,21 @@ struct RstHeader;
struct RstGroup { struct RstGroup {
RstGroup(const UnitSystem& unit_system, RstGroup(const UnitSystem& unit_system,
const RstHeader& header,
const std::string* zwel, const std::string* zwel,
const int * igrp, const int * igrp,
const float * sgrp, const float * sgrp,
const double * xgrp); const double * xgrp);
std::string name; 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 oil_rate_limit;
float water_rate_limit; float water_rate_limit;
float gas_rate_limit; float gas_rate_limit;

View File

@ -24,10 +24,12 @@
#include <cstddef> #include <cstddef>
namespace Opm { namespace Opm {
class UnitSystem;
namespace RestartIO { namespace RestartIO {
struct RstHeader { struct RstHeader {
RstHeader(const std::vector<int>& intehead, const std::vector<bool>& logihead, const std::vector<double>& doubhead); RstHeader(const UnitSystem& unit_system, const std::vector<int>& intehead, const std::vector<bool>& logihead, const std::vector<double>& doubhead);
int nx; int nx;
int ny; int ny;
@ -82,10 +84,8 @@ struct RstHeader {
int nilbrz; int nilbrz;
int ntfip ; int ntfip ;
int nmfipr; int nmfipr;
int nrfreg;
int ntfreg;
int nplmix;
int ngroup; int ngroup;
int nwgmax;
bool e300_radial; bool e300_radial;
bool e100_radial; bool e100_radial;
@ -100,6 +100,7 @@ struct RstHeader {
bool dir_eps; bool dir_eps;
bool reversible_eps; bool reversible_eps;
bool alt_eps; bool alt_eps;
bool group_control_active;
double next_timestep1; double next_timestep1;
double next_timestep2; double next_timestep2;
@ -110,6 +111,8 @@ struct RstHeader {
double guide_rate_d; double guide_rate_d;
double guide_rate_e; double guide_rate_e;
double guide_rate_f; double guide_rate_f;
double guide_rate_delay;
double guide_rate_damping;
double udq_range; double udq_range;
double udq_undefined; double udq_undefined;
double udq_eps; double udq_eps;

View File

@ -35,6 +35,11 @@ namespace Opm {
namespace RestartIO { namespace RestartIO {
struct RstState { struct RstState {
RstState(const ::Opm::UnitSystem& unit_system,
const std::vector<int>& intehead,
const std::vector<bool>& logihead,
const std::vector<double>& doubhead);
RstState(const ::Opm::UnitSystem& unit_system, RstState(const ::Opm::UnitSystem& unit_system,
const std::vector<int>& intehead, const std::vector<int>& intehead,
const std::vector<bool>& logihead, const std::vector<bool>& logihead,

View File

@ -66,14 +66,16 @@ struct RstWell {
std::array<int, 2> ij; std::array<int, 2> ij;
std::pair<int,int> k1k2; std::pair<int,int> k1k2;
WellType wtype; WellType wtype;
int well_status;
int active_control; int active_control;
int vfp_table; int vfp_table;
int pred_requested_control;
bool allow_xflow; bool allow_xflow;
int preferred_phase;
int hist_requested_control; int hist_requested_control;
int msw_index; int msw_index;
int completion_ordering; int completion_ordering;
int pvt_table; int pvt_table;
int msw_pressure_drop_model;
float orat_target; float orat_target;
float wrat_target; float wrat_target;
@ -88,12 +90,14 @@ struct RstWell {
float datum_depth; float datum_depth;
float drainage_radius; float drainage_radius;
float efficiency_factor; float efficiency_factor;
float alq_value;
double oil_rate; double oil_rate;
double water_rate; double water_rate;
double gas_rate; double gas_rate;
double liquid_rate; double liquid_rate;
double void_rate; double void_rate;
double thp;
double flow_bhp; double flow_bhp;
double wct; double wct;
double gor; double gor;

View File

@ -16,7 +16,12 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define _USE_MATH_DEFINES
#include <cmath> // For definition of M_PI
#include <opm/io/eclipse/EGrid.hpp> #include <opm/io/eclipse/EGrid.hpp>
#include <opm/io/eclipse/EInit.hpp>
#include <opm/io/eclipse/EclUtil.hpp>
#include <opm/common/ErrorMacros.hpp> #include <opm/common/ErrorMacros.hpp>
@ -30,21 +35,86 @@
namespace Opm { namespace EclIO { namespace Opm { namespace EclIO {
EGrid::EGrid(const std::string &filename) : EclFile(filename) using NNCentry = std::tuple<int, int, int, int, int,int, float>;
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<int>("GRIDHEAD"); if (this->formattedInput())
initFileName += ".FINIT";
else
initFileName += ".INIT";
std::string lgrname = "global";
m_nncs_loaded = false;
actnum_array_index = -1;
nnc1_array_index = -1;
nnc2_array_index = -1;
m_radial = false;
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<std::string>(n);
lgrname = lgr[0];
lgr_names.push_back(lgr[0]);
}
if (array_name[n] == "NNCHEAD"){
auto nnchead = this->get<int>(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<int>(n);
nijk[0] = gridhead[1]; nijk[0] = gridhead[1];
nijk[1] = gridhead[2]; nijk[1] = gridhead[2];
nijk[2] = gridhead[3]; nijk[2] = gridhead[3];
if (file.hasKey("ACTNUM")) { if (gridhead.size() > 26)
auto actnum = get<int>("ACTNUM"); 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<int>(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<int>(actnum_array_index);
nactive = 0; nactive = 0;
for (unsigned int i = 0; i < actnum.size(); i++) { for (size_t i = 0; i < actnum.size(); i++) {
if (actnum[i] > 0) { if (actnum[i] > 0) {
act_index.push_back(nactive); act_index.push_back(nactive);
glob_index.push_back(i); glob_index.push_back(i);
@ -61,10 +131,104 @@ EGrid::EGrid(const std::string &filename) : EclFile(filename)
std::iota(glob_index.begin(), glob_index.end(), 0); std::iota(glob_index.begin(), glob_index.end(), 0);
} }
coord_array = get<float>("COORD"); if (hostnum_index > -1){
zcorn_array = get<float>("ZCORN"); 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<std::array<int, 3>> EGrid::hostCellsIJK()
{
std::vector<std::array<int, 3>> res_vect;
res_vect.reserve(host_cells.size());
for (auto val : host_cells){
std::array<int, 3> 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<NNCentry> EGrid::get_nnc_ijk()
{
if (!m_nncs_loaded)
load_nnc_data();
std::vector<NNCentry> 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<float>("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 int EGrid::global_index(int i, int j, int k) const
{ {
@ -129,12 +293,14 @@ std::array<int, 3> EGrid::ijk_from_global_index(int globInd) const
void EGrid::getCellCorners(const std::array<int, 3>& ijk, void EGrid::getCellCorners(const std::array<int, 3>& ijk,
std::array<double,8>& X, std::array<double,8>& X,
std::array<double,8>& Y, std::array<double,8>& Y,
std::array<double,8>& Z) const std::array<double,8>& Z)
{ {
if (coord_array.empty())
load_grid_data();
std::vector<int> zind; std::vector<int> zind;
std::vector<int> pind; std::vector<int> pind;
// calculate indices for grid pillars in COORD arrray // calculate indices for grid pillars in COORD arrray
pind.push_back(ijk[1]*(nijk[0]+1)*6 + ijk[0]*6); pind.push_back(ijk[1]*(nijk[0]+1)*6 + ijk[0]*6);
pind.push_back(pind[0] + 6); pind.push_back(pind[0] + 6);
@ -147,22 +313,32 @@ void EGrid::getCellCorners(const std::array<int, 3>& ijk,
zind.push_back(zind[0] + nijk[0]*2); zind.push_back(zind[0] + nijk[0]*2);
zind.push_back(zind[2] + 1); zind.push_back(zind[2] + 1);
for (int n = 0; n < 4; n++) { for (int n = 0; n < 4; n++)
zind.push_back(zind[n] + nijk[0]*nijk[1]*4); zind.push_back(zind[n] + nijk[0]*nijk[1]*4);
}
for (int n = 0; n< 8; n++){ for (int n = 0; n< 8; n++)
Z[n] = zcorn_array[zind[n]]; Z[n] = zcorn_array[zind[n]];
}
for (int n = 0; n < 4; n++) { for (int n = 0; n < 4; n++) {
double xt = coord_array[pind[n]]; double xt;
double yt = coord_array[pind[n] + 1]; double yt;
double zt = coord_array[pind[n] + 2]; double xb;
double yb;
double xb = coord_array[pind[n] + 3]; double zt = coord_array[pind[n] + 2];
double yb = coord_array[pind[n] + 4]; double zb = coord_array[pind[n] + 5];
double zb = coord_array[pind[n]+5];
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];
}
X[n] = xt + (xb-xt) / (zt-zb) * (zt - Z[n]); X[n] = xt + (xb-xt) / (zt-zb) * (zt - Z[n]);
X[n+4] = xt + (xb-xt) / (zt-zb) * (zt-Z[n+4]); X[n+4] = xt + (xb-xt) / (zt-zb) * (zt-Z[n+4]);
@ -173,8 +349,9 @@ void EGrid::getCellCorners(const std::array<int, 3>& ijk,
} }
void EGrid::getCellCorners(int globindex, std::array<double,8>& X, void EGrid::getCellCorners(int globindex, std::array<double,8>& X,
std::array<double,8>& Y, std::array<double,8>& Z) const std::array<double,8>& Y, std::array<double,8>& Z)
{ {
return getCellCorners(ijk_from_global_index(globindex),X,Y,Z); return getCellCorners(ijk_from_global_index(globindex),X,Y,Z);
} }

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <opm/io/eclipse/EInit.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <algorithm>
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<std::string>(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<int, 3>& 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<EclFile::EclEntry> EInit::list_arrays(const std::string& grid_name) const
{
std::vector<EclEntry> 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<EclFile::EclEntry> EInit::list_arrays() const
{
std::vector<EclEntry> 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

View File

@ -22,6 +22,8 @@
#include <cmath> #include <cmath>
#include <chrono> #include <chrono>
#include <fmt/format.h>
#include <opm/io/eclipse/ERsm.hpp> #include <opm/io/eclipse/ERsm.hpp>
#include <opm/io/eclipse/ESmry.hpp> #include <opm/io/eclipse/ESmry.hpp>
#include <opm/common/utility/FileSystem.hpp> #include <opm/common/utility/FileSystem.hpp>
@ -174,7 +176,8 @@ void ERsm::load_block(std::deque<std::string>& lines, std::size_t& vector_length
SummaryNode::category_from_keyword(kw_list[kw_index]), SummaryNode::category_from_keyword(kw_list[kw_index]),
SummaryNode::Type::Undefined, SummaryNode::Type::Undefined,
wgnames[kw_index], wgnames[kw_index],
make_num(nums_list[kw_index])}; make_num(nums_list[kw_index]),
""};
block_data.emplace_back( node, vector_length ); block_data.emplace_back( node, vector_length );
} }
@ -254,22 +257,30 @@ bool cmp(const ESmry& smry, const ERsm& rsm) {
const auto& summary_dates = smry.dates(); const auto& summary_dates = smry.dates();
if (rsm.has_dates()) { if (rsm.has_dates()) {
const auto& rsm_dates = rsm.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; return false;
}
for (std::size_t time_index = 0; time_index < rsm_dates.size(); time_index++) { 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 smry_ts = TimeStampUTC( std::chrono::system_clock::to_time_t(summary_dates[time_index]) );
const auto rsm_ts = rsm_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; 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; 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; return false;
} }
}
} else { } else {
const auto& rsm_days = rsm.days(); const auto& rsm_days = rsm.days();
if (rsm_days.size() != summary_dates.size()) if (rsm_days.size() != summary_dates.size())
@ -280,10 +291,12 @@ bool cmp(const ESmry& smry, const ERsm& rsm) {
using TP = time_point<system_clock>; using TP = time_point<system_clock>;
auto smry_days = duration_cast<TP::duration>(summary_dates[time_index] - summary_dates[0]).count() / 86400.0 ; auto smry_days = duration_cast<TP::duration>(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; return false;
} }
} }
}
for (const auto& node : smry.summaryNodeList()) { for (const auto& node : smry.summaryNodeList()) {
const auto& key = node.unique_key(); const auto& key = node.unique_key();
@ -309,13 +322,16 @@ bool cmp(const ESmry& smry, const ERsm& rsm) {
const auto& smry_vector = smry.get(node); const auto& smry_vector = smry.get(node);
const auto& rsm_vector = rsm.get(key); const auto& rsm_vector = rsm.get(key);
for (std::size_t index = 0; index < smry_vector.size(); index++) { for (std::size_t index = 0; index < smry_vector.size(); index++) {
const double eps = 5e-5;
const double diff = static_cast<double>(smry_vector[index]) - rsm_vector[index]; const double diff = static_cast<double>(smry_vector[index]) - rsm_vector[index];
const double sum = std::fabs(static_cast<double>(smry_vector[index])) + std::fabs(rsm_vector[index]); const double sum = std::fabs(static_cast<double>(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; return false;
} }
} }
}
return true; return true;
} }

View File

@ -28,8 +28,6 @@
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <iostream>
namespace { namespace {
int seqnumFromSeparateFilename(const std::string& filename) int seqnumFromSeparateFilename(const std::string& filename)
@ -80,9 +78,9 @@ void ERst::loadReportStepNumber(int number)
} }
std::vector<int> arrayIndexList; std::vector<int> 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); arrayIndexList.push_back(i);
} }
@ -93,6 +91,12 @@ void ERst::loadReportStepNumber(int number)
std::vector<EclFile::EclEntry> ERst::listOfRstArrays(int reportStepNumber) std::vector<EclFile::EclEntry> ERst::listOfRstArrays(int reportStepNumber)
{
return this->listOfRstArrays(reportStepNumber, "global");
}
std::vector<EclFile::EclEntry> ERst::listOfRstArrays(int reportStepNumber, const std::string& lgr_name)
{ {
std::vector<EclEntry> list; std::vector<EclEntry> list;
@ -101,19 +105,49 @@ std::vector<EclFile::EclEntry> ERst::listOfRstArrays(int reportStepNumber)
OPM_THROW(std::invalid_argument, message); OPM_THROW(std::invalid_argument, message);
} }
const auto& rng = this->arrIndexRange[reportStepNumber]; if ((lgr_name != "global") && (!this->hasLGR(lgr_name, reportStepNumber))) {
list.reserve(rng.second - rng.first); std::string message = "Trying to get list of arrays from non existing LGR " + lgr_name;
OPM_THROW(std::invalid_argument, message);
for (int i = rng.first; i < rng.second; i++) {
list.emplace_back(array_name[i], array_type[i], array_size[i]);
} }
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<int>(array_name.size()) -1 ));
return list; 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)) { if (!hasReportStepNumber(reportStepNumber)) {
std::string message = "Trying to count vectors of name " + name + " from non existing sequence " + std::to_string(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); OPM_THROW(std::invalid_argument, message);
@ -145,9 +179,14 @@ void ERst::initUnified()
auto seqn = get<int>(i); auto seqn = get<int>(i);
seqnum.push_back(seqn[0]); seqnum.push_back(seqn[0]);
firstIndex.push_back(i); 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++) { for (size_t i = 0; i < seqnum.size(); i++) {
std::pair<int,int> range; std::pair<int,int> range;
@ -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) void ERst::initSeparate(const int number)
{ {
auto& range = this->arrIndexRange[number]; auto& range = this->arrIndexRange[number];
@ -178,6 +232,41 @@ void ERst::initSeparate(const int number)
this->seqnum.assign(1, number); this->seqnum.assign(1, number);
this->nReports = 1; this->nReports = 1;
this->reportLoaded[number] = false; 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<int,int> 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<int,int> ERst::getIndexRange(int reportStepNumber) const { std::tuple<int,int> ERst::getIndexRange(int reportStepNumber) const {
@ -192,13 +281,14 @@ std::tuple<int,int> ERst::getIndexRange(int reportStepNumber) const {
return range_it->second; 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)) { if (!hasReportStepNumber(number)) {
std::string message = "Trying to get vector " + name + " from non existing sequence " + std::to_string(number); std::string message = "Trying to get vector " + name + " from non existing sequence " + std::to_string(number);
OPM_THROW(std::invalid_argument, message); OPM_THROW(std::invalid_argument, message);
} }
auto range_it = arrIndexRange.find(number); auto range_it = arrIndexRange.find(number);
std::pair<int,int> indexRange = range_it->second; std::pair<int,int> indexRange = range_it->second;
@ -218,6 +308,25 @@ int ERst::getArrayIndex(const std::string& name, int number, int occurrenc) cons
return std::distance(array_name.begin(), it); 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<int,int> 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 std::streampos
ERst::restartStepWritePosition(const int seqnumValue) const ERst::restartStepWritePosition(const int seqnumValue) const
{ {
@ -229,38 +338,74 @@ ERst::restartStepWritePosition(const int seqnumValue) const
} }
template<> template<>
const std::vector<int>& ERst::getRst<int>(const std::string& name, int reportStepNumber, int occurrence) const std::vector<int>& ERst::getRestartData<int>(const std::string& name, int reportStepNumber, int occurrence)
{ {
int ind = getArrayIndex(name, reportStepNumber, occurrence); int ind = getArrayIndex(name, reportStepNumber, occurrence);
return getImpl(ind, INTE, inte_array, "integer"); return getImpl(ind, INTE, inte_array, "integer");
} }
template<> template<>
const std::vector<float>& ERst::getRst<float>(const std::string& name, int reportStepNumber, int occurrence) const std::vector<float>& ERst::getRestartData<float>(const std::string& name, int reportStepNumber, int occurrence)
{ {
int ind = getArrayIndex(name, reportStepNumber, occurrence); int ind = getArrayIndex(name, reportStepNumber, occurrence);
return getImpl(ind, REAL, real_array, "float"); return getImpl(ind, REAL, real_array, "float");
} }
template<> template<>
const std::vector<double>& ERst::getRst<double>(const std::string& name, int reportStepNumber, int occurrence) const std::vector<double>& ERst::getRestartData<double>(const std::string& name, int reportStepNumber, int occurrence)
{ {
int ind = getArrayIndex(name, reportStepNumber, occurrence); int ind = getArrayIndex(name, reportStepNumber, occurrence);
return getImpl(ind, DOUB, doub_array, "double"); return getImpl(ind, DOUB, doub_array, "double");
} }
template<> template<>
const std::vector<bool>& ERst::getRst<bool>(const std::string& name, int reportStepNumber, int occurrence) const std::vector<bool>& ERst::getRestartData<bool>(const std::string& name, int reportStepNumber, int occurrence)
{ {
int ind = getArrayIndex(name, reportStepNumber, occurrence); int ind = getArrayIndex(name, reportStepNumber, occurrence);
return getImpl(ind, LOGI, logi_array, "bool"); return getImpl(ind, LOGI, logi_array, "bool");
} }
template<> template<>
const std::vector<std::string>& ERst::getRst<std::string>(const std::string& name, int reportStepNumber, int occurrence) const std::vector<std::string>& ERst::getRestartData<std::string>(const std::string& name, int reportStepNumber, int occurrence)
{ {
int ind = getArrayIndex(name, reportStepNumber, occurrence); int ind = getArrayIndex(name, reportStepNumber, occurrence);
return getImpl(ind, CHAR, char_array, "string"); return getImpl(ind, CHAR, char_array, "string");
} }
template<>
const std::vector<float>& ERst::getRestartData<float>(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<double>& ERst::getRestartData<double>(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<int>& ERst::getRestartData<int>(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<bool>& ERst::getRestartData<bool>(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<std::string>& ERst::getRestartData<std::string>(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 }} // namespace Opm::ecl

View File

@ -21,6 +21,7 @@
#include <opm/common/utility/TimeService.hpp> #include <opm/common/utility/TimeService.hpp>
#include <opm/io/eclipse/EclFile.hpp> #include <opm/io/eclipse/EclFile.hpp>
#include <opm/io/eclipse/EclUtil.hpp> #include <opm/io/eclipse/EclUtil.hpp>
#include <opm/io/eclipse/EclOutput.hpp>
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
@ -30,9 +31,18 @@
#include <set> #include <set>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#ifdef _WIN32
#include "cross-platform/windows/Substitutes.hpp"
#else
#include <fnmatch.h> #include <fnmatch.h>
#endif
#include <fstream> #include <fstream>
#include <cmath> #include <cmath>
#include <cstring>
#include <ciso646>
/* /*
@ -83,14 +93,17 @@ std::chrono::system_clock::time_point make_date(const std::vector<int>& datetime
namespace Opm { namespace EclIO { namespace Opm { namespace EclIO {
ESmry::ESmry(const std::string &filename, bool loadBaseRunData) : ESmry::ESmry(const std::string &filename, bool loadBaseRunData , bool uselodsmry ) :
inputFileName { filename }, inputFileName { filename },
summaryNodes { } summaryNodes { },
useLodsmryFile(uselodsmry)
{ {
fromSingleRun = !loadBaseRunData;
Opm::filesystem::path rootName = inputFileName.parent_path() / inputFileName.stem(); 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()=="") if (inputFileName.extension()=="")
inputFileName+=".SMSPEC"; inputFileName+=".SMSPEC";
@ -101,6 +114,16 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
const bool formatted = inputFileName.extension()==".SMSPEC" ? false : true; const bool formatted = inputFileName.extension()==".SMSPEC" ? false : true;
formattedFiles.push_back(formatted); 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(); Opm::filesystem::path path = Opm::filesystem::current_path();
updatePathAndRootName(path, rootName); updatePathAndRootName(path, rootName);
@ -120,28 +143,44 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
"SUMTHIN", "SUMTHIN",
} ; } ;
std::vector<EclFile> smspecList;
std::vector<std::string> vectList = {"DIMENS", "RESTART", "KEYWORDS", "NUMS", "UNITS"};
// Read data from the summary into local data members. // 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<int> vectIndices;
const std::vector<int> dimens = smspec.get<int>("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<int>(n));
smspecList.back().loadData(vectIndices);
const std::vector<int> dimens = smspecList.back().get<int>("DIMENS");
nI = dimens[1]; // This is correct -- dimens[0] is something else! nI = dimens[1]; // This is correct -- dimens[0] is something else!
nJ = dimens[2]; nJ = dimens[2];
nK = dimens[3]; nK = dimens[3];
const std::vector<std::string> restartArray = smspec.get<std::string>("RESTART"); const std::vector<std::string> restartArray = smspecList.back().get<std::string>("RESTART");
const std::vector<std::string> keywords = smspec.get<std::string>("KEYWORDS"); const std::vector<std::string> keywords = smspecList.back().get<std::string>("KEYWORDS");
const std::vector<std::string> wgnames = smspec.get<std::string>("WGNAMES"); std::vector<std::string> wgnames;
const std::vector<int> nums = smspec.get<int>("NUMS");
const std::vector<std::string> units = smspec.get<std::string>("UNITS"); if (smspecList.back().hasKey("WGNAMES"))
wgnames = smspecList.back().get<std::string>("WGNAMES");
else
wgnames = smspecList.back().get<std::string>("NAMES");
const std::vector<int> nums = smspecList.back().get<int>("NUMS");
const std::vector<std::string> units = smspecList.back().get<std::string>("UNITS");
std::vector<std::string> combindKeyList; std::vector<std::string> combindKeyList;
combindKeyList.reserve(dimens[0]); combindKeyList.reserve(dimens[0]);
this->startdat = make_date(smspec.get<int>("STARTDAT")); this->startdat = make_date(smspecList.back().get<int>("STARTDAT"));
for (unsigned int i=0; i<keywords.size(); i++) { for (unsigned int i=0; i<keywords.size(); i++) {
const std::string keyString = makeKeyString(keywords[i], wgnames[i], nums[i]); const std::string keyString = makeKeyString(keywords[i], wgnames[i], nums[i]);
@ -153,7 +192,8 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
SummaryNode::category_from_keyword(keywords[i], segmentExceptions), SummaryNode::category_from_keyword(keywords[i], segmentExceptions),
SummaryNode::Type::Undefined, SummaryNode::Type::Undefined,
wgnames[i], wgnames[i],
nums[i] nums[i],
""
}); });
keywList.insert(keyString); keywList.insert(keyString);
@ -170,7 +210,6 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
// checking if this is a restart run. Supporting nested restarts (restart, from restart, ...) // checking if this is a restart run. Supporting nested restarts (restart, from restart, ...)
// std::set keywList is storing keywords from all runs involved // std::set keywList is storing keywords from all runs involved
while ((rstRootN.string() != "") && (loadBaseRunData)) { while ((rstRootN.string() != "") && (loadBaseRunData)) {
Opm::filesystem::path rstFile = pathRstFile / rstRootN; Opm::filesystem::path rstFile = pathRstFile / rstRootN;
@ -185,20 +224,34 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
baseRunFmt = true; baseRunFmt = true;
} }
EclFile smspec_rst(rstFile.string()); smspecList.emplace_back(EclFile(rstFile.string()));
smspec_rst.loadData();
const std::vector<int> dimens = smspec_rst.get<int>("DIMENS"); auto arrays = smspecList.back().getList();
const std::vector<std::string> restartArray = smspec_rst.get<std::string>("RESTART"); std::vector<int> vectIndices;
const std::vector<std::string> keywords = smspec_rst.get<std::string>("KEYWORDS");
const std::vector<std::string> wgnames = smspec_rst.get<std::string>("WGNAMES"); for (size_t n = 0; n < arrays.size(); n++)
const std::vector<int> nums = smspec_rst.get<int>("NUMS"); if(std::find(vectList.begin(), vectList.end(), std::get<0>(arrays[n])) != vectList.end())
const std::vector<std::string> units = smspec_rst.get<std::string>("UNITS"); vectIndices.push_back(static_cast<int>(n));
smspecList.back().loadData(vectIndices);
const std::vector<int> dimens = smspecList.back().get<int>("DIMENS");
const std::vector<std::string> restartArray = smspecList.back().get<std::string>("RESTART");
const std::vector<std::string> keywords = smspecList.back().get<std::string>("KEYWORDS");
std::vector<std::string> wgnames;
if (smspecList.back().hasKey("WGNAMES"))
wgnames = smspecList.back().get<std::string>("WGNAMES");
else
wgnames = smspecList.back().get<std::string>("NAMES");
const std::vector<int> nums = smspecList.back().get<int>("NUMS");
const std::vector<std::string> units = smspecList.back().get<std::string>("UNITS");
std::vector<std::string> combindKeyList; std::vector<std::string> combindKeyList;
combindKeyList.reserve(dimens[0]); combindKeyList.reserve(dimens[0]);
this->startdat = make_date(smspec_rst.get<int>("STARTDAT")); this->startdat = make_date(smspecList.back().get<int>("STARTDAT"));
for (size_t i = 0; i < keywords.size(); i++) { for (size_t i = 0; i < keywords.size(); i++) {
const std::string keyString = makeKeyString(keywords[i], wgnames[i], nums[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::category_from_keyword(keywords[i], segmentExceptions),
SummaryNode::Type::Undefined, SummaryNode::Type::Undefined,
wgnames[i], wgnames[i],
nums[i] nums[i],
""
}); });
keywList.insert(keyString); keywList.insert(keyString);
@ -243,10 +297,7 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
auto smry = smryArray[specInd]; auto smry = smryArray[specInd];
EclFile smspec(std::get<0>(smry)); const std::vector<int> dimens = smspecList[specInd].get<int>("DIMENS");
smspec.loadData();
const std::vector<int> dimens = smspec.get<int>("DIMENS");
nI = dimens[1]; nI = dimens[1];
nJ = dimens[2]; nJ = dimens[2];
@ -254,9 +305,15 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
nParamsSpecFile[specInd] = dimens[0]; nParamsSpecFile[specInd] = dimens[0];
const std::vector<std::string> keywords = smspec.get<std::string>("KEYWORDS"); const std::vector<std::string> keywords = smspecList[specInd].get<std::string>("KEYWORDS");
const std::vector<std::string> wgnames = smspec.get<std::string>("WGNAMES"); std::vector<std::string> wgnames;
const std::vector<int> nums = smspec.get<int>("NUMS");
if (smspecList.back().hasKey("WGNAMES"))
wgnames = smspecList.back().get<std::string>("WGNAMES");
else
wgnames = smspecList.back().get<std::string>("NAMES");
const std::vector<int> nums = smspecList[specInd].get<int>("NUMS");
for (size_t i=0; i < keywords.size(); i++) { for (size_t i=0; i < keywords.size(); i++) {
const std::string keyw = makeKeyString(keywords[i], wgnames[i], nums[i]); const std::string keyw = makeKeyString(keywords[i], wgnames[i], nums[i]);
@ -288,9 +345,21 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
vectorLoaded.push_back(false); vectorLoaded.push_back(false);
} }
if (useLodsmryFile && lodEnabeled)
{
// inspecting formatted or binary lod file. lodsmry possible only if
// loadBaseRunData=false
inspect_lodsmry();
} else {
// 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.
int dataFileIndex = -1; int dataFileIndex = -1;
while (specInd >= 0){ while (specInd >= 0) {
int reportStepNumber = fromReportStepNumber; int reportStepNumber = fromReportStepNumber;
@ -318,26 +387,24 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
std::vector<std::string> resultsFileList; std::vector<std::string> resultsFileList;
if ((!use_unified) && (multFileList.size()==0)){ if ((!use_unified) && (multFileList.size()==0)) {
throw std::runtime_error("neigther unified or non-unified result files found"); throw std::runtime_error("neigther unified or non-unified result files found");
} else if ((use_unified) && (multFileList.size()>0)){ } else if ((use_unified) && (multFileList.size()>0)) {
auto time_multiple = Opm::filesystem::last_write_time(multFileList.back()); auto time_multiple = Opm::filesystem::last_write_time(multFileList.back());
auto time_unified = Opm::filesystem::last_write_time(unsmryFile); auto time_unified = Opm::filesystem::last_write_time(unsmryFile);
if (time_multiple > time_unified){ if (time_multiple > time_unified) {
resultsFileList=multFileList; resultsFileList=multFileList;
} else { } else {
resultsFileList.push_back(unsmryFile.string()); resultsFileList.push_back(unsmryFile.string());
} }
} else if (use_unified){ } else if (use_unified) {
resultsFileList.push_back(unsmryFile.string()); resultsFileList.push_back(unsmryFile.string());
} else { } else {
resultsFileList=multFileList; resultsFileList=multFileList;
} }
// make array list with reference to source files (unifed or non unified)
std::vector<ArrSourceEntry> arraySourceList; std::vector<ArrSourceEntry> arraySourceList;
for (std::string fileName : resultsFileList) for (std::string fileName : resultsFileList)
@ -360,9 +427,9 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
size_t i = std::get<0>(arraySourceList[0]) == "SEQHDR" ? 1 : 0 ; size_t i = std::get<0>(arraySourceList[0]) == "SEQHDR" ? 1 : 0 ;
while (i < arraySourceList.size()){ while (i < arraySourceList.size()) {
if (std::get<0>(arraySourceList[i]) != "MINISTEP"){ if (std::get<0>(arraySourceList[i]) != "MINISTEP") {
std::string message="Reading summary file, expecting keyword MINISTEP, found '" + std::get<0>(arraySourceList[i]) + "'"; std::string message="Reading summary file, expecting keyword MINISTEP, found '" + std::get<0>(arraySourceList[i]) + "'";
throw std::invalid_argument(message); throw std::invalid_argument(message);
} }
@ -385,7 +452,7 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
i++; i++;
if (i < arraySourceList.size()){ if (i < arraySourceList.size()) {
if (std::get<0>(arraySourceList[i]) == "SEQHDR") { if (std::get<0>(arraySourceList[i]) == "SEQHDR") {
i++; i++;
reportStepNumber++; reportStepNumber++;
@ -406,14 +473,158 @@ ESmry::ESmry(const std::string &filename, bool loadBaseRunData) :
fromReportStepNumber = toReportStepNumber; fromReportStepNumber = toReportStepNumber;
specInd--; specInd--;
nTstep = timeStepList.size();
} }
}
}
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<std::string> 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<bool> 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<uint64_t>(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<int>& 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<uint64_t>(ind);
if (formattedFiles[0])
pos = pos + static_cast<uint64_t>(ind * 31); // adding size of formatted headers
else
pos = pos + static_cast<uint64_t>(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<std::string>& vectList) const void ESmry::LoadData(const std::vector<std::string>& vectList) const
{ {
size_t nvect = vectList.size(); size_t nvect = vectList.size();
size_t ntstep = timeStepList.size();
std::vector<int> keywIndVect; std::vector<int> keywIndVect;
keywIndVect.reserve(nvect); keywIndVect.reserve(nvect);
@ -427,13 +638,30 @@ void ESmry::LoadData(const std::vector<std::string>& vectList) const
} }
for (auto ind : keywIndVect) for (auto ind : keywIndVect)
vectorData[ind].reserve(ntstep); vectorData[ind].reserve(nTstep);
if (useLodsmryFile && lodEnabeled)
{
Load_from_lodsmry(keywIndVect);
} else {
std::fstream fileH; std::fstream fileH;
auto specInd = std::get<0>(timeStepList[0]); auto specInd = std::get<0>(timeStepList[0]);
auto dataFileIndex = std::get<1>(timeStepList[0]); auto dataFileIndex = std::get<1>(timeStepList[0]);
uint64_t stepFilePos = std::get<2>(timeStepList[0]); uint64_t stepFilePos = std::get<2>(timeStepList[0]);
uint64_t blockSize_f;
{
int nLinesBlock = MaxBlockSizeReal / numColumnsReal;
int rest = MaxBlockSizeReal % numColumnsReal;
if (rest > 0)
nLinesBlock++;
blockSize_f= static_cast<uint64_t>(MaxNumBlockReal * numColumnsReal * columnWidthReal + nLinesBlock);
}
if (formattedFiles[specInd]) if (formattedFiles[specInd])
fileH.open(dataFileList[dataFileIndex], std::ios::in); fileH.open(dataFileList[dataFileIndex], std::ios::in);
@ -441,6 +669,7 @@ void ESmry::LoadData(const std::vector<std::string>& vectList) const
fileH.open(dataFileList[dataFileIndex], std::ios::in | std::ios::binary); fileH.open(dataFileList[dataFileIndex], std::ios::in | std::ios::binary);
for (auto ministep : timeStepList) { for (auto ministep : timeStepList) {
if (dataFileIndex != std::get<1>(ministep)) { if (dataFileIndex != std::get<1>(ministep)) {
fileH.close(); fileH.close();
specInd = std::get<0>(ministep); specInd = std::get<0>(ministep);
@ -455,6 +684,7 @@ void ESmry::LoadData(const std::vector<std::string>& vectList) const
stepFilePos = std::get<2>(ministep);; stepFilePos = std::get<2>(ministep);;
for (auto ind : keywIndVect) { for (auto ind : keywIndVect) {
auto it = arrayPos[specInd].find(ind); auto it = arrayPos[specInd].find(ind);
if (it == arrayPos[specInd].end()) { if (it == arrayPos[specInd].end()) {
@ -466,19 +696,11 @@ void ESmry::LoadData(const std::vector<std::string>& vectList) const
if (formattedFiles[specInd]) { if (formattedFiles[specInd]) {
uint64_t elementPos = 0; uint64_t elementPos = 0;
int nBlocks = paramPos /MaxBlockSizeReal; int nBlocks = paramPos / MaxBlockSizeReal;
int sizeOfLastBlock = paramPos % MaxBlockSizeReal; int sizeOfLastBlock = paramPos % MaxBlockSizeReal;
if (nBlocks > 0) { if (nBlocks > 0)
int nLinesBlock = MaxNumBlockReal / numColumnsReal; elementPos = static_cast<uint64_t>(nBlocks * blockSize_f);
int rest = MaxNumBlockReal % numColumnsReal;
if (rest > 0)
nLinesBlock++;
uint64_t blockSize = static_cast<uint64_t>(MaxNumBlockReal * numColumnsReal + nLinesBlock);
elementPos = static_cast<uint64_t>(nBlocks * blockSize);
}
int nLines = sizeOfLastBlock / numColumnsReal; int nLines = sizeOfLastBlock / numColumnsReal;
elementPos = stepFilePos + elementPos + static_cast<uint64_t>(sizeOfLastBlock * columnWidthReal + nLines); elementPos = stepFilePos + elementPos + static_cast<uint64_t>(sizeOfLastBlock * columnWidthReal + nLines);
@ -499,10 +721,12 @@ void ESmry::LoadData(const std::vector<std::string>& vectList) const
uint64_t nFullBlocks = static_cast<uint64_t>(paramPos/(MaxBlockSizeReal / sizeOfReal)); uint64_t nFullBlocks = static_cast<uint64_t>(paramPos/(MaxBlockSizeReal / sizeOfReal));
uint64_t elementPos = ((2 * nFullBlocks) + 1)*static_cast<uint64_t>(sizeOfInte); uint64_t elementPos = ((2 * nFullBlocks) + 1)*static_cast<uint64_t>(sizeOfInte);
elementPos += static_cast<uint64_t>(paramPos)* static_cast<uint64_t>(sizeOfReal) + stepFilePos; elementPos += static_cast<uint64_t>(paramPos)* static_cast<uint64_t>(sizeOfReal) + stepFilePos;
fileH.seekg (elementPos, fileH.beg); fileH.seekg (elementPos, fileH.beg);
float value; float value;
fileH.read(reinterpret_cast<char*>(&value), sizeOfReal); fileH.read(reinterpret_cast<char*>(&value), sizeOfReal);
vectorData[ind].push_back(Opm::EclIO::flipEndianFloat(value)); vectorData[ind].push_back(Opm::EclIO::flipEndianFloat(value));
} }
} }
@ -510,6 +734,7 @@ void ESmry::LoadData(const std::vector<std::string>& vectList) const
} }
fileH.close(); fileH.close();
}
for (auto ind : keywIndVect) for (auto ind : keywIndVect)
vectorLoaded[ind] = true; vectorLoaded[ind] = true;
@ -538,6 +763,11 @@ std::vector<int> ESmry::makeKeywPosVector(int specInd) const {
void ESmry::LoadData() const void ESmry::LoadData() const
{ {
if (useLodsmryFile && lodEnabeled) {
this ->LoadData(keyword);
} else {
std::fstream fileH; std::fstream fileH;
auto specInd = std::get<0>(timeStepList[0]); auto specInd = std::get<0>(timeStepList[0]);
@ -556,7 +786,7 @@ void ESmry::LoadData() const
if (dataFileIndex != std::get<1>(ministep)) { if (dataFileIndex != std::get<1>(ministep)) {
fileH.close(); fileH.close();
if (specInd != std::get<0>(ministep)){ if (specInd != std::get<0>(ministep)) {
specInd = std::get<0>(ministep); specInd = std::get<0>(ministep);
keywpos = makeKeywPosVector(specInd); keywpos = makeKeywPosVector(specInd);
} }
@ -574,8 +804,9 @@ void ESmry::LoadData() const
fileH.seekg (stepFilePos, fileH.beg); fileH.seekg (stepFilePos, fileH.beg);
if (formattedFiles[specInd]) { if (formattedFiles[specInd]) {
char* buffer; char* buffer;
size_t size = sizeOnDiskFormatted(nParamsSpecFile[specInd], Opm::EclIO::REAL)+1; size_t size = sizeOnDiskFormatted(nParamsSpecFile[specInd], Opm::EclIO::REAL, sizeOfReal) + 1;
buffer = new char [size]; buffer = new char [size];
fileH.read (buffer, size); fileH.read (buffer, size);
@ -587,7 +818,7 @@ void ESmry::LoadData() const
p1 = fileStr.find_first_not_of(' ',p1); p1 = fileStr.find_first_not_of(' ',p1);
int64_t p2 = fileStr.find_first_of(' ', p1); int64_t p2 = fileStr.find_first_of(' ', p1);
if (keywpos[p] > -1) { if ((keywpos[p] > -1) && (!vectorLoaded[keywpos[p]])) {
double dtmpv = std::stod(fileStr.substr(p1, p2-p1)); double dtmpv = std::stod(fileStr.substr(p1, p2-p1));
vectorData[keywpos[p]].push_back(static_cast<float>(dtmpv)); vectorData[keywpos[p]].push_back(static_cast<float>(dtmpv));
} }
@ -597,6 +828,7 @@ void ESmry::LoadData() const
} }
delete[] buffer; delete[] buffer;
} else { } else {
int64_t rest = static_cast<int64_t>(nParamsSpecFile[specInd]); int64_t rest = static_cast<int64_t>(nParamsSpecFile[specInd]);
size_t p = 0; size_t p = 0;
@ -614,7 +846,7 @@ void ESmry::LoadData() const
float value; float value;
fileH.read(reinterpret_cast<char*>(&value), sizeOfReal); fileH.read(reinterpret_cast<char*>(&value), sizeOfReal);
if (keywpos[p] > -1) if ((keywpos[p] > -1) && (!vectorLoaded[keywpos[p]]))
vectorData[keywpos[p]].push_back(Opm::EclIO::flipEndianFloat(value)); vectorData[keywpos[p]].push_back(Opm::EclIO::flipEndianFloat(value));
p++; p++;
@ -640,6 +872,7 @@ void ESmry::LoadData() const
for (size_t n=0; n < nVect; n++) for (size_t n=0; n < nVect; n++)
vectorLoaded[n] = true; vectorLoaded[n] = true;
}
} }
@ -647,24 +880,80 @@ std::vector<std::tuple <std::string, uint64_t>>
ESmry::getListOfArrays(std::string filename, bool formatted) ESmry::getListOfArrays(std::string filename, bool formatted)
{ {
std::vector<std::tuple <std::string, uint64_t>> resultVect; std::vector<std::tuple <std::string, uint64_t>> resultVect;
std::fstream fileH;
if (formatted) FILE *ptr;
fileH.open(filename, std::ios::in); char arrName[9];
else char numstr[13];
fileH.open(filename, std::ios::in | std::ios::binary);
while (!Opm::EclIO::isEOF(&fileH)) {
std::string arrName(8,' ');
Opm::EclIO::eclArrType arrType;
int64_t num; int64_t num;
if (formatted)
Opm::EclIO::readFormattedHeader(fileH,arrName,num,arrType);
else
Opm::EclIO::readBinaryHeader(fileH,arrName,num,arrType);
uint64_t filePos = fileH.tellg(); if (formatted)
ptr = fopen(filename.c_str(),"r"); // r for read, files opened as text files
else
ptr = fopen(filename.c_str(),"rb"); // r for read, b for binary
bool endOfFile = false;
while (!endOfFile)
{
Opm::EclIO::eclArrType arrType;
if (formatted)
{
fseek(ptr, 2, SEEK_CUR);
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<int64_t>(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<int64_t>(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<uint64_t>(ftell(ptr));
std::tuple <std::string, uint64_t> t1; std::tuple <std::string, uint64_t> t1;
t1 = std::make_tuple(Opm::EclIO::trimr(arrName), filePos); t1 = std::make_tuple(Opm::EclIO::trimr(arrName), filePos);
@ -672,21 +961,115 @@ ESmry::getListOfArrays(std::string filename, bool formatted)
if (num > 0) { if (num > 0) {
if (formatted) { if (formatted) {
uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType); uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType, 4);
fileH.seekg(static_cast<std::streamoff>(sizeOfNextArray), std::ios_base::cur); fseek(ptr, static_cast<long int>(sizeOfNextArray), SEEK_CUR);
} else { } else {
uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType); uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType, 4);
fileH.seekg(static_cast<std::streamoff>(sizeOfNextArray), std::ios_base::cur); fseek(ptr, static_cast<long int>(sizeOfNextArray), SEEK_CUR);
}
} }
} }
fileH.close(); if (fgetc(ptr) == EOF)
endOfFile = true;
else
fseek(ptr, -1, SEEK_CUR);
}
fclose(ptr);
return resultVect; 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<std::string> 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<bool> 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<std::string>("KEYCHECK", keycheck);
outFile.write<bool>("RSTEP", is_rstep);
for (size_t n = 0; n < vectorData.size(); n++ ) {
std::string vect_name="V" + std::to_string(n);
outFile.write<float>(vect_name, vectorData[n]);
}
}
return true;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ESmry::use_lodsmry_file(bool enable)
{
useLodsmryFile = enable;
}
std::vector<std::string> ESmry::checkForMultipleResultFiles(const Opm::filesystem::path& rootN, bool formatted) const { std::vector<std::string> ESmry::checkForMultipleResultFiles(const Opm::filesystem::path& rootN, bool formatted) const {

View File

@ -20,6 +20,7 @@
#include <opm/io/eclipse/EclUtil.hpp> #include <opm/io/eclipse/EclUtil.hpp>
#include <opm/common/ErrorMacros.hpp> #include <opm/common/ErrorMacros.hpp>
//#include <fmt/format.h>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstring> #include <cstring>
@ -34,256 +35,13 @@
#include <iostream> #include <iostream>
// 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<int>(filename[p+1])) != nullptr;
}
template<typename T, typename T2>
std::vector<T> readBinaryArray(std::fstream& fileH, const int64_t size, Opm::EclIO::eclArrType type,
std::function<T(T2)>& flip)
{
std::vector<T> 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<char*>(&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<char*>(&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<char*>(&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<int> readBinaryInteArray(std::fstream &fileH, const int64_t size)
{
std::function<int(int)> f = Opm::EclIO::flipEndianInt;
return readBinaryArray<int,int>(fileH, size, Opm::EclIO::INTE, f);
}
std::vector<float> readBinaryRealArray(std::fstream& fileH, const int64_t size)
{
std::function<float(float)> f = Opm::EclIO::flipEndianFloat;
return readBinaryArray<float,float>(fileH, size, Opm::EclIO::REAL, f);
}
std::vector<double> readBinaryDoubArray(std::fstream& fileH, const int64_t size)
{
std::function<double(double)> f = Opm::EclIO::flipEndianDouble;
return readBinaryArray<double,double>(fileH, size, Opm::EclIO::DOUB, f);
}
std::vector<bool> readBinaryLogiArray(std::fstream &fileH, const int64_t size)
{
std::function<bool(unsigned int)> 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<bool,unsigned int>(fileH, size, Opm::EclIO::LOGI, f);
}
std::vector<std::string> readBinaryCharArray(std::fstream& fileH, const int64_t size)
{
using Char8 = std::array<char, 8>;
std::function<std::string(Char8)> f = [](const Char8& val)
{
std::string res(val.begin(), val.end());
return Opm::EclIO::trimr(res);
};
return readBinaryArray<std::string,Char8>(fileH, size, Opm::EclIO::CHAR, f);
}
template<typename T>
std::vector<T> readFormattedArray(const std::string& file_str, const int size, int64_t fromPos,
std::function<T(const std::string&)>& process)
{
std::vector<T> 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<int> readFormattedInteArray(const std::string& file_str, const int64_t size, int64_t fromPos)
{
std::function<int(const std::string&)> f = [](const std::string& val)
{
return std::stoi(val);
};
return readFormattedArray(file_str, size, fromPos, f);
}
std::vector<std::string> readFormattedCharArray(const std::string& file_str, const int64_t size, int64_t fromPos)
{
std::vector<std::string> 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<float> readFormattedRealArray(const std::string& file_str, const int64_t size, int64_t fromPos)
{
std::function<float(const std::string&)> 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<float>(file_str, size, fromPos, f);
}
std::vector<bool> readFormattedLogiArray(const std::string& file_str, const int64_t size, int64_t fromPos)
{
std::function<bool(const std::string&)> 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<bool>(file_str, size, fromPos, f);
}
std::vector<double> readFormattedDoubArray(const std::string& file_str, const int64_t size, int64_t fromPos)
{
std::function<double(const std::string&)> 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<double>(file_str, size, fromPos, f);
}
} // anonymous namespace
// ==========================================================================
namespace Opm { namespace EclIO { namespace Opm { namespace EclIO {
EclFile::EclFile(const std::string& filename, bool preload) : inputFilename(filename) EclFile::EclFile(const std::string& filename, bool preload) : inputFilename(filename)
{ {
if (!fileExists(filename)){ if (!fileExists(filename))
std::string message="Could not open EclFile: " + filename; throw std::runtime_error("Can not open EclFile: {}");
OPM_THROW(std::invalid_argument, message);
}
std::fstream fileH; 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); fileH.open(filename, std::ios::in | std::ios::binary);
} }
if (!fileH) { if (!fileH)
std::string message="Could not open file: " + filename; throw std::runtime_error("Can not open EclFile: {}");
OPM_THROW(std::runtime_error, message);
}
int n = 0; int n = 0;
while (!isEOF(&fileH)) { while (!isEOF(&fileH)) {
std::string arrName(8,' '); std::string arrName(8,' ');
eclArrType arrType; eclArrType arrType;
int64_t num; int64_t num;
int sizeOfElement;
if (formatted) { if (formatted) {
readFormattedHeader(fileH,arrName,num,arrType); readFormattedHeader(fileH,arrName,num,arrType, sizeOfElement);
} else { } else {
readBinaryHeader(fileH,arrName,num,arrType); readBinaryHeader(fileH,arrName,num, arrType, sizeOfElement);
} }
array_size.push_back(num); array_size.push_back(num);
array_type.push_back(arrType); array_type.push_back(arrType);
array_name.push_back(trimr(arrName)); array_name.push_back(trimr(arrName));
array_element_size.push_back(sizeOfElement);
array_index[array_name[n]] = n; array_index[array_name[n]] = n;
uint64_t pos = fileH.tellg(); uint64_t pos = fileH.tellg();
@ -325,15 +83,14 @@ EclFile::EclFile(const std::string& filename, bool preload) : inputFilename(file
if (num > 0){ if (num > 0){
if (formatted) { if (formatted) {
uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType); uint64_t sizeOfNextArray = sizeOnDiskFormatted(num, arrType, sizeOfElement);
fileH.seekg(static_cast<std::streamoff>(sizeOfNextArray), std::ios_base::cur); fileH.seekg(static_cast<std::streamoff>(sizeOfNextArray), std::ios_base::cur);
} else { } else {
uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType); uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType, sizeOfElement);
fileH.seekg(static_cast<std::streamoff>(sizeOfNextArray), std::ios_base::cur); fileH.seekg(static_cast<std::streamoff>(sizeOfNextArray), std::ios_base::cur);
} }
} }
n++; n++;
}; };
@ -366,6 +123,9 @@ void EclFile::loadBinaryArray(std::fstream& fileH, std::size_t arrIndex)
case CHAR: case CHAR:
char_array[arrIndex] = readBinaryCharArray(fileH, array_size[arrIndex]); char_array[arrIndex] = readBinaryCharArray(fileH, array_size[arrIndex]);
break; break;
case C0NN:
char_array[arrIndex] = readBinaryC0nnArray(fileH, array_size[arrIndex], array_element_size[arrIndex]);
break;
case MESS: case MESS:
break; break;
default: 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); logi_array[arrIndex] = readFormattedLogiArray(fileStr, array_size[arrIndex], fromPos);
break; break;
case CHAR: 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; break;
case MESS: case MESS:
break; break;
@ -449,7 +212,7 @@ void EclFile::loadData(const std::string& name)
inFile.seekg(ifStreamPos[arrIndex]); inFile.seekg(ifStreamPos[arrIndex]);
char* buffer; 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]; buffer = new char [size];
inFile.read (buffer, size); inFile.read (buffer, size);
@ -494,7 +257,7 @@ void EclFile::loadData(const std::vector<int>& arrIndex)
inFile.seekg(ifStreamPos[ind]); inFile.seekg(ifStreamPos[ind]);
char* buffer; 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]; buffer = new char [size];
inFile.read (buffer, size); inFile.read (buffer, size);
@ -525,7 +288,6 @@ void EclFile::loadData(const std::vector<int>& arrIndex)
void EclFile::loadData(int arrIndex) void EclFile::loadData(int arrIndex)
{ {
if (formatted) { if (formatted) {
std::ifstream inFile(inputFilename); std::ifstream inFile(inputFilename);
@ -533,7 +295,7 @@ void EclFile::loadData(int arrIndex)
inFile.seekg(ifStreamPos[arrIndex]); inFile.seekg(ifStreamPos[arrIndex]);
char* buffer; 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]; buffer = new char [size];
inFile.read (buffer, 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<unsigned int> 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<unsigned int> raw_logi = readBinaryRawLogiArray(fileH, array_size[arrIndex]);
return raw_logi;
}
std::vector<std::string> EclFile::get_fmt_real_raw_str_values(int arrIndex) const
{
std::vector<std::string> 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<std::string> real_vect_str;
real_vect_str = readFormattedRealRawStrings(fileStr, array_size[arrIndex], 0);
delete buffer;
return real_vect_str;
}
std::vector<EclFile::EclEntry> EclFile::getList() const std::vector<EclFile::EclEntry> EclFile::getList() const
{ {
std::vector<EclEntry> list; std::vector<EclEntry> list;
@ -603,7 +468,12 @@ const std::vector<bool>& EclFile::get<bool>(int arrIndex)
template<> template<>
const std::vector<std::string>& EclFile::get<std::string>(int arrIndex) const std::vector<std::string>& EclFile::get<std::string>(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<std::string>& EclFile::get<std::string>(const std::string &nam
OPM_THROW(std::invalid_argument, message); 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");
} }

View File

@ -41,6 +41,7 @@ EclOutput::EclOutput(const std::string& filename,
: isFormatted{formatted} : isFormatted{formatted}
{ {
const auto binmode = mode | std::ios_base::binary; const auto binmode = mode | std::ios_base::binary;
ix_standard = false;
this->ofileH.open(filename, this->isFormatted ? mode : binmode); this->ofileH.open(filename, this->isFormatted ? mode : binmode);
} }
@ -50,15 +51,79 @@ template<>
void EclOutput::write<std::string>(const std::string& name, void EclOutput::write<std::string>(const std::string& name,
const std::vector<std::string>& data) const std::vector<std::string>& 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) if (isFormatted)
{ {
writeFormattedHeader(name, data.size(), CHAR); if (maximum_length > sizeOfChar){
writeFormattedCharArray(data); writeFormattedHeader(name, data.size(), C0NN, maximum_length);
writeFormattedCharArray(data, maximum_length);
} else {
writeFormattedHeader(name, data.size(), CHAR, sizeOfChar);
writeFormattedCharArray(data, sizeOfChar);
}
} }
else else
{ {
writeBinaryHeader(name, data.size(), CHAR); if (maximum_length > sizeOfChar){
writeBinaryCharArray(data); 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<std::string>& 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<size_t>(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<PaddedOutputString<8>>
const std::vector<PaddedOutputString<8>>& data) const std::vector<PaddedOutputString<8>>& data)
{ {
if (this->isFormatted) { if (this->isFormatted) {
writeFormattedHeader(name, data.size(), CHAR); writeFormattedHeader(name, data.size(), CHAR, sizeOfChar);
writeFormattedCharArray(data); writeFormattedCharArray(data);
} }
else { else {
writeBinaryHeader(name, data.size(), CHAR); writeBinaryHeader(name, data.size(), CHAR, sizeOfChar);
writeBinaryCharArray(data); writeBinaryCharArray(data);
} }
} }
@ -91,7 +156,7 @@ void EclOutput::flushStream()
this->ofileH.flush(); 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); int bhead = flipEndianInt(16);
std::string name = arrName + std::string(8 - arrName.size(),' '); std::string name = arrName + std::string(8 - arrName.size(),' ');
@ -119,6 +184,14 @@ void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclAr
ofileH.write(name.c_str(), 8); ofileH.write(name.c_str(), 8);
ofileH.write(reinterpret_cast<char*>(&flippedSize), sizeof(flippedSize)); ofileH.write(reinterpret_cast<char*>(&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) { switch(arrType) {
case INTE: case INTE:
ofileH.write("INTE", 4); ofileH.write("INTE", 4);
@ -135,6 +208,9 @@ void EclOutput::writeBinaryHeader(const std::string&arrName, int64_t size, eclAr
case CHAR: case CHAR:
ofileH.write("CHAR", 4); ofileH.write("CHAR", 4);
break; break;
case C0NN:
ofileH.write(c0nn_str.c_str(), 4);
break;
case MESS: case MESS:
ofileH.write("MESS", 4); ofileH.write("MESS", 4);
break; break;
@ -178,6 +254,8 @@ void EclOutput::writeBinaryArray(const std::vector<T>& data)
OPM_THROW(std::runtime_error, "fstream fileH not open for writing"); 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<int64_t>(sizeOfElement); rest = size * static_cast<int64_t>(sizeOfElement);
while (rest > 0) { while (rest > 0) {
if (rest > maxBlockSize) { if (rest > maxBlockSize) {
@ -203,7 +281,7 @@ void EclOutput::writeBinaryArray(const std::vector<T>& data)
value_d = flipEndianDouble(data[n]); value_d = flipEndianDouble(data[n]);
ofileH.write(reinterpret_cast<char*>(&value_d), sizeof(value_d)); ofileH.write(reinterpret_cast<char*>(&value_d), sizeof(value_d));
} else if (arrType == LOGI) { } else if (arrType == LOGI) {
intVal = data[n] ? true_value : false_value; intVal = data[n] ? logi_true_val : false_value;
ofileH.write(reinterpret_cast<char*>(&intVal), sizeOfElement); ofileH.write(reinterpret_cast<char*>(&intVal), sizeOfElement);
} else { } else {
std::cerr << "type not supported in write binaryarray\n"; std::cerr << "type not supported in write binaryarray\n";
@ -225,7 +303,7 @@ template void EclOutput::writeBinaryArray<bool>(const std::vector<bool>& data);
template void EclOutput::writeBinaryArray<char>(const std::vector<char>& data); template void EclOutput::writeBinaryArray<char>(const std::vector<char>& data);
void EclOutput::writeBinaryCharArray(const std::vector<std::string>& data) void EclOutput::writeBinaryCharArray(const std::vector<std::string>& data, int element_size)
{ {
int num,dhead; int num,dhead;
@ -234,6 +312,11 @@ void EclOutput::writeBinaryCharArray(const std::vector<std::string>& data)
auto sizeData = block_size_data_binary(CHAR); 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 sizeOfElement = std::get<0>(sizeData);
int maxBlockSize = std::get<1>(sizeData); int maxBlockSize = std::get<1>(sizeData);
int maxNumberOfElements = maxBlockSize / sizeOfElement; int maxNumberOfElements = maxBlockSize / sizeOfElement;
@ -258,7 +341,7 @@ void EclOutput::writeBinaryCharArray(const std::vector<std::string>& data)
ofileH.write(reinterpret_cast<char*>(&dhead), sizeof(dhead)); ofileH.write(reinterpret_cast<char*>(&dhead), sizeof(dhead));
for (int i = 0; i < num; i++) { 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); ofileH.write(tmpStr.c_str(), sizeOfElement);
n++; n++;
} }
@ -303,12 +386,21 @@ void EclOutput::writeBinaryCharArray(const std::vector<PaddedOutputString<8>>& 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(),' '); std::string name = arrName + std::string(8 - arrName.size(),' ');
ofileH << " '" << name << "' " << std::setw(11) << 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) { switch (arrType) {
case INTE: case INTE:
ofileH << " 'INTE'" << std::endl; ofileH << " 'INTE'" << std::endl;
@ -325,6 +417,9 @@ void EclOutput::writeFormattedHeader(const std::string& arrName, int size, eclAr
case CHAR: case CHAR:
ofileH << " 'CHAR'" << std::endl; ofileH << " 'CHAR'" << std::endl;
break; break;
case C0NN:
ofileH << " '" << c0nn_str << "'" << std::endl;
break;
case MESS: case MESS:
ofileH << " 'MESS'" << std::endl; ofileH << " 'MESS'" << std::endl;
break; 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]; char buffer [15];
std::sprintf (buffer, "%10.7E", value); std::sprintf (buffer, "%10.7E", value);
@ -367,11 +462,35 @@ std::string EclOutput::make_real_string(float value) const
} }
} }
std::string EclOutput::make_real_string_ix(float value) const
std::string EclOutput::make_doub_string(double value) const
{ {
char buffer [21]; char buffer [15];
std::sprintf (buffer, "%19.13E", value); 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) { if (value == 0.0) {
return "0.00000000000000D+00"; return "0.00000000000000D+00";
@ -388,27 +507,52 @@ std::string EclOutput::make_doub_string(double value) const
std::string tmpstr(buffer); std::string tmpstr(buffer);
int exp = value < 0.0 ? std::stoi(tmpstr.substr(17, 4)) : std::stoi(tmpstr.substr(16, 4)); 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 (value < 0.0) {
if (std::abs(exp) < 100) { if (use_exp_char) {
tmpstr = "-0." + tmpstr.substr(1, 1) + tmpstr.substr(3, 13) + "D"; tmpstr = "-0." + tmpstr.substr(1, 1) + tmpstr.substr(3, 13) + "D";
} else { } else {
tmpstr = "-0." + tmpstr.substr(1, 1) + tmpstr.substr(3, 13); tmpstr = "-0." + tmpstr.substr(1, 1) + tmpstr.substr(3, 13);
} }
} else { } else {
if (std::abs(exp) < 100) { if (use_exp_char) {
tmpstr = "0." + tmpstr.substr(0, 1) + tmpstr.substr(2, 13) + "D"; tmpstr = "0." + tmpstr.substr(0, 1) + tmpstr.substr(2, 13) + "D";
} else { } else {
tmpstr = "0." + tmpstr.substr(0, 1) + tmpstr.substr(2, 13); 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; tmpstr = tmpstr + buffer;
return tmpstr; 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 <typename T> template <typename T>
void EclOutput::writeFormattedArray(const std::vector<T>& data) void EclOutput::writeFormattedArray(const std::vector<T>& data)
@ -427,6 +571,7 @@ void EclOutput::writeFormattedArray(const std::vector<T>& data)
arrType = LOGI; arrType = LOGI;
} }
auto sizeData = block_size_data_formatted(arrType); auto sizeData = block_size_data_formatted(arrType);
int maxBlockSize = std::get<0>(sizeData); int maxBlockSize = std::get<0>(sizeData);
@ -441,10 +586,16 @@ void EclOutput::writeFormattedArray(const std::vector<T>& data)
ofileH << std::setw(columnWidth) << data[i]; ofileH << std::setw(columnWidth) << data[i];
break; break;
case REAL: 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; break;
case DOUB: 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; break;
case LOGI: case LOGI:
if (data[i]) { if (data[i]) {
@ -479,18 +630,34 @@ template void EclOutput::writeFormattedArray<bool>(const std::vector<bool>& data
template void EclOutput::writeFormattedArray<char>(const std::vector<char>& data); template void EclOutput::writeFormattedArray<char>(const std::vector<char>& data);
void EclOutput::writeFormattedCharArray(const std::vector<std::string>& data) void EclOutput::writeFormattedCharArray(const std::vector<std::string>& data, int element_size)
{ {
auto sizeData = block_size_data_formatted(CHAR); 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);
int rest = data.size();
int n = 0;
while (rest > 0) {
int size = rest;
if (size > maxBlockSize)
size = maxBlockSize;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
std::string str1(8,' '); std::string str1(element_size,' ');
str1 = data[i] + std::string(8 - data[i].size(),' '); str1 = data[n] + std::string(element_size - data[n].size(),' ');
n++;
ofileH << " '" << str1 << "'"; ofileH << " '" << str1 << "'";
if ((i+1) % nColumns == 0) { if ((i+1) % nColumns == 0) {
@ -501,8 +668,12 @@ void EclOutput::writeFormattedCharArray(const std::vector<std::string>& data)
if ((size % nColumns) != 0) { if ((size % nColumns) != 0) {
ofileH << std::endl; ofileH << std::endl;
} }
rest = (rest > maxBlockSize) ? rest - maxBlockSize : 0;
}
} }
void EclOutput::writeFormattedCharArray(const std::vector<PaddedOutputString<8>>& data) void EclOutput::writeFormattedCharArray(const std::vector<PaddedOutputString<8>>& data)
{ {
const auto sizeData = block_size_data_formatted(CHAR); const auto sizeData = block_size_data_formatted(CHAR);

View File

@ -23,10 +23,14 @@
#include <cross-platform/PortableEndian.hpp> #include <cross-platform/PortableEndian.hpp>
#include <algorithm> #include <algorithm>
#include <array>
#include <stdexcept> #include <stdexcept>
#include <cmath> #include <cmath>
#include <fstream> #include <fstream>
#include <cstring>
//temporary
#include <iostream>
int Opm::EclIO::flipEndianInt(int num) int Opm::EclIO::flipEndianInt(int num)
{ {
@ -61,6 +65,21 @@ double Opm::EclIO::flipEndianDouble(double num)
return value; 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<int>(filename[p+1])) != nullptr;
}
bool Opm::EclIO::isEOF(std::fstream* fileH) bool Opm::EclIO::isEOF(std::fstream* fileH)
{ {
int num; int num;
@ -96,6 +115,9 @@ std::tuple<int, int> Opm::EclIO::block_size_data_binary(eclArrType arrType)
case CHAR: case CHAR:
return BlockSizeTuple{sizeOfChar, MaxBlockSizeChar}; return BlockSizeTuple{sizeOfChar, MaxBlockSizeChar};
break; break;
case C0NN:
return BlockSizeTuple{sizeOfChar, MaxBlockSizeChar};
break;
case MESS: case MESS:
OPM_THROW(std::invalid_argument, "Type 'MESS' have no associated data"); OPM_THROW(std::invalid_argument, "Type 'MESS' have no associated data");
break; break;
@ -126,6 +148,9 @@ std::tuple<int, int, int> Opm::EclIO::block_size_data_formatted(eclArrType arrTy
case CHAR: case CHAR:
return BlockSizeTuple{MaxNumBlockChar,numColumnsChar, columnWidthChar}; return BlockSizeTuple{MaxNumBlockChar,numColumnsChar, columnWidthChar};
break; break;
case C0NN:
return BlockSizeTuple{MaxNumBlockChar,numColumnsChar, columnWidthChar};
break;
case MESS: case MESS:
OPM_THROW(std::invalid_argument, "Type 'MESS' have no associated data") ; OPM_THROW(std::invalid_argument, "Type 'MESS' have no associated data") ;
break; 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; uint64_t size = 0;
@ -160,6 +185,11 @@ uint64_t Opm::EclIO::sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrTyp
if (num > 0) { if (num > 0) {
auto sizeData = Opm::EclIO::block_size_data_binary(arrType); 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 sizeOfElement = std::get<0>(sizeData);
int maxBlockSize = std::get<1>(sizeData); int maxBlockSize = std::get<1>(sizeData);
int maxNumberOfElements = maxBlockSize / sizeOfElement; int maxNumberOfElements = maxBlockSize / sizeOfElement;
@ -182,7 +212,7 @@ uint64_t Opm::EclIO::sizeOnDiskBinary(int64_t num, Opm::EclIO::eclArrType arrTyp
return size; 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; uint64_t size = 0;
@ -193,6 +223,11 @@ uint64_t Opm::EclIO::sizeOnDiskFormatted(const int64_t num, Opm::EclIO::eclArrTy
} else { } else {
auto sizeData = block_size_data_formatted(arrType); 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 maxBlockSize = std::get<0>(sizeData);
int nColumns = std::get<1>(sizeData); int nColumns = std::get<1>(sizeData);
int columnWidth = std::get<2>(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, 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 tmpStrName(8,' ');
std::string tmpStrType(4,' '); std::string tmpStrType(4,' ');
@ -282,15 +317,25 @@ void Opm::EclIO::readBinaryHeader(std::fstream& fileH, std::string& arrName,
size = static_cast<int64_t>(tmpSize); size = static_cast<int64_t>(tmpSize);
} }
elementSize = 4;
arrName = tmpStrName; arrName = tmpStrName;
if (tmpStrType == "INTE") if (tmpStrType == "INTE")
arrType = Opm::EclIO::INTE; arrType = Opm::EclIO::INTE;
else if (tmpStrType == "REAL") else if (tmpStrType == "REAL")
arrType = Opm::EclIO::REAL; arrType = Opm::EclIO::REAL;
else if (tmpStrType == "DOUB") else if (tmpStrType == "DOUB"){
arrType = Opm::EclIO::DOUB; arrType = Opm::EclIO::DOUB;
else if (tmpStrType == "CHAR") elementSize = 8;
}
else if (tmpStrType == "CHAR"){
arrType = Opm::EclIO::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") else if (tmpStrType =="LOGI")
arrType = Opm::EclIO::LOGI; arrType = Opm::EclIO::LOGI;
else if (tmpStrType == "MESS") 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, 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::string line;
std::getline(fileH,line); std::getline(fileH,line);
@ -321,14 +366,24 @@ void Opm::EclIO::readFormattedHeader(std::fstream& fileH, std::string& arrName,
num = std::stol(antStr); num = std::stol(antStr);
elementSize = 4;
if (arrTypeStr == "INTE") if (arrTypeStr == "INTE")
arrType = Opm::EclIO::INTE; arrType = Opm::EclIO::INTE;
else if (arrTypeStr == "REAL") else if (arrTypeStr == "REAL")
arrType = Opm::EclIO::REAL; arrType = Opm::EclIO::REAL;
else if (arrTypeStr == "DOUB") else if (arrTypeStr == "DOUB"){
arrType = Opm::EclIO::DOUB; arrType = Opm::EclIO::DOUB;
else if (arrTypeStr == "CHAR") elementSize = 8;
}
else if (arrTypeStr == "CHAR"){
arrType = Opm::EclIO::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") else if (arrTypeStr == "LOGI")
arrType = Opm::EclIO::LOGI; arrType = Opm::EclIO::LOGI;
else if (arrTypeStr == "MESS") 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"); OPM_THROW(std::runtime_error, "Header name should be 8 characters");
} }
} }
template<typename T, typename T2>
std::vector<T> Opm::EclIO::readBinaryArray(std::fstream& fileH, const int64_t size, Opm::EclIO::eclArrType type,
std::function<T(T2)>& flip, int elementSize)
{
std::vector<T> 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<char*>(&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<T2, std::string>) {
value.resize(sizeOfElement) ;
fileH.read(&value[0], sizeOfElement);
} else
fileH.read(reinterpret_cast<char*>(&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<char*>(&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<int> Opm::EclIO::readBinaryInteArray(std::fstream &fileH, const int64_t size)
{
std::function<int(int)> f = Opm::EclIO::flipEndianInt;
return readBinaryArray<int,int>(fileH, size, Opm::EclIO::INTE, f, sizeOfInte);
}
std::vector<float> Opm::EclIO::readBinaryRealArray(std::fstream& fileH, const int64_t size)
{
std::function<float(float)> f = Opm::EclIO::flipEndianFloat;
return readBinaryArray<float,float>(fileH, size, Opm::EclIO::REAL, f, sizeOfReal);
}
std::vector<double> Opm::EclIO::readBinaryDoubArray(std::fstream& fileH, const int64_t size)
{
std::function<double(double)> f = Opm::EclIO::flipEndianDouble;
return readBinaryArray<double,double>(fileH, size, Opm::EclIO::DOUB, f, sizeOfDoub);
}
std::vector<bool> Opm::EclIO::readBinaryLogiArray(std::fstream &fileH, const int64_t size)
{
std::function<bool(unsigned int)> 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<bool,unsigned int>(fileH, size, Opm::EclIO::LOGI, f, sizeOfLogi);
}
std::vector<unsigned int> Opm::EclIO::readBinaryRawLogiArray(std::fstream &fileH, const int64_t size)
{
std::function<unsigned int(unsigned int)> f = [](unsigned int intVal)
{
return intVal;
};
return readBinaryArray<unsigned int, unsigned int>(fileH, size, Opm::EclIO::LOGI, f, sizeOfLogi);
}
std::vector<std::string> Opm::EclIO::readBinaryCharArray(std::fstream& fileH, const int64_t size)
{
using Char8 = std::array<char, 8>;
std::function<std::string(Char8)> f = [](const Char8& val)
{
std::string res(val.begin(), val.end());
return Opm::EclIO::trimr(res);
};
return readBinaryArray<std::string,Char8>(fileH, size, Opm::EclIO::CHAR, f, sizeOfChar);
}
std::vector<std::string> Opm::EclIO::readBinaryC0nnArray(std::fstream& fileH, const int64_t size, int elementSize)
{
std::function<std::string(std::string)> f = [](const std::string& val)
{
return Opm::EclIO::trimr(val);
};
return readBinaryArray<std::string,std::string>(fileH, size, Opm::EclIO::C0NN, f, elementSize);
}
template<typename T>
std::vector<T> Opm::EclIO::readFormattedArray(const std::string& file_str, const int size, int64_t fromPos,
std::function<T(const std::string&)>& process)
{
std::vector<T> 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<int> Opm::EclIO::readFormattedInteArray(const std::string& file_str, const int64_t size, int64_t fromPos)
{
std::function<int(const std::string&)> f = [](const std::string& val)
{
return std::stoi(val);
};
return readFormattedArray(file_str, size, fromPos, f);
}
std::vector<std::string> Opm::EclIO::readFormattedCharArray(const std::string& file_str, const int64_t size,
int64_t fromPos, int elementSize)
{
std::vector<std::string> 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<float> Opm::EclIO::readFormattedRealArray(const std::string& file_str, const int64_t size, int64_t fromPos)
{
std::function<float(const std::string&)> 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<float>(file_str, size, fromPos, f);
}
std::vector<std::string> Opm::EclIO::readFormattedRealRawStrings(const std::string& file_str, const int64_t size, int64_t fromPos)
{
std::function<std::string(const std::string&)> f = [](const std::string& val)
{
return val;
};
return readFormattedArray<std::string>(file_str, size, fromPos, f);
}
std::vector<bool> Opm::EclIO::readFormattedLogiArray(const std::string& file_str, const int64_t size, int64_t fromPos)
{
std::function<bool(const std::string&)> 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<bool>(file_str, size, fromPos, f);
}
std::vector<double> Opm::EclIO::readFormattedDoubArray(const std::string& file_str, const int64_t size, int64_t fromPos)
{
std::function<double(const std::string&)> 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<double>(file_str, size, fromPos, f);
}

View File

@ -15,7 +15,9 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <opm/io/eclipse/SummaryNode.hpp>
#include <numeric> #include <numeric>
#include <regex> #include <regex>
@ -23,8 +25,6 @@
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
#include <opm/io/eclipse/SummaryNode.hpp>
namespace { namespace {
constexpr bool use_number(Opm::EclIO::SummaryNode::Category category) { constexpr bool use_number(Opm::EclIO::SummaryNode::Category category) {
@ -37,6 +37,7 @@ constexpr bool use_number(Opm::EclIO::SummaryNode::Category category) {
return true; return true;
case Opm::EclIO::SummaryNode::Category::Field: [[fallthrough]]; case Opm::EclIO::SummaryNode::Category::Field: [[fallthrough]];
case Opm::EclIO::SummaryNode::Category::Group: [[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::Miscellaneous: [[fallthrough]];
case Opm::EclIO::SummaryNode::Category::Well: case Opm::EclIO::SummaryNode::Category::Well:
return false; 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::Connection: [[fallthrough]];
case Opm::EclIO::SummaryNode::Category::Group: [[fallthrough]]; case Opm::EclIO::SummaryNode::Category::Group: [[fallthrough]];
case Opm::EclIO::SummaryNode::Category::Segment: [[fallthrough]]; case Opm::EclIO::SummaryNode::Category::Segment: [[fallthrough]];
case Opm::EclIO::SummaryNode::Category::Node: [[fallthrough]];
case Opm::EclIO::SummaryNode::Category::Well: case Opm::EclIO::SummaryNode::Category::Well:
return true; return true;
case Opm::EclIO::SummaryNode::Category::Aquifer: [[fallthrough]]; 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); return std::to_string(node.number);
} }
}; bool is_node_keyword(const std::string& keyword)
{
static const auto node_kw = std::unordered_set<std::string> {
"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::string Opm::EclIO::SummaryNode::unique_key(number_renderer render_number) const {
std::vector<std::string> key_parts { keyword } ; std::vector<std::string> key_parts { keyword } ;
@ -120,7 +138,7 @@ bool Opm::EclIO::SummaryNode::is_user_defined() const {
"SURFWNUM", "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 matched { std::regex_match(keyword, user_defined_regex) } ;
const bool blacklisted { udq_blacklist.find(keyword) != udq_blacklist.end() } ; 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 'B': return Category::Block;
case 'C': return Category::Connection; case 'C': return Category::Connection;
case 'F': return Category::Field; case 'F': return Category::Field;
case 'G': return Category::Group; case 'G': return distinguish_group_from_node(keyword);
case 'R': return Category::Region; case 'R': return Category::Region;
case 'S': return Category::Segment; case 'S': return Category::Segment;
case 'W': return Category::Well; case 'W': return Category::Well;

View File

@ -32,24 +32,42 @@ namespace RestartIO {
using M = ::Opm::UnitSystem::measure; 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, RstGroup::RstGroup(const ::Opm::UnitSystem& unit_system,
const RstHeader& header,
const std::string* zwel, const std::string* zwel,
const int *, const int * igrp,
const float * sgrp, const float * sgrp,
const double * xgrp) : const double * xgrp) :
name(trim_copy(zwel[0])), name(trim_copy(zwel[0])),
oil_rate_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::OilRateLimit])), parent_group(igrp[header.nwgmax + VI::IGroup::ParentGroup] ),
water_rate_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::WatRateLimit])), prod_active_cmode(igrp[header.nwgmax + VI::IGroup::ProdActiveCMode]),
gas_rate_limit( unit_system.to_si(M::gas_surface_rate, sgrp[VI::SGroup::GasRateLimit])), gconprod_cmode(igrp[header.nwgmax + VI::IGroup::GConProdCMode]),
liquid_rate_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::LiqRateLimit])), winj_cmode(igrp[header.nwgmax + VI::IGroup::WInjCMode]),
water_surface_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::waterSurfRateLimit])), ginj_cmode(igrp[header.nwgmax + VI::IGroup::GInjCMode]),
water_reservoir_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::waterResRateLimit])), guide_rate_def(igrp[header.nwgmax + VI::IGroup::GuideRateDef]),
water_reinject_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::waterReinjectionLimit])), // The values oil_rate_limit -> gas_voidage_limit will be used in UDA
water_voidage_limit( unit_system.to_si(M::liquid_surface_rate, sgrp[VI::SGroup::waterVoidageLimit])), // values. The UDA values are responsible for unit conversion and raw values
gas_surface_limit( unit_system.to_si(M::gas_surface_rate, sgrp[VI::SGroup::gasSurfRateLimit])), // are internalized here.
gas_reservoir_limit( unit_system.to_si(M::geometric_volume_rate, sgrp[VI::SGroup::gasResRateLimit])), oil_rate_limit( sgrp_value(sgrp[VI::SGroup::OilRateLimit])),
gas_reinject_limit( unit_system.to_si(M::gas_surface_rate, sgrp[VI::SGroup::gasReinjectionLimit])), water_rate_limit( sgrp_value(sgrp[VI::SGroup::WatRateLimit])),
gas_voidage_limit( unit_system.to_si(M::geometric_volume_rate, sgrp[VI::SGroup::gasVoidageLimit])), 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])), 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])), 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])), gas_production_rate( unit_system.to_si(M::gas_surface_rate, xgrp[VI::XGroup::GasPrRate])),

View File

@ -23,13 +23,15 @@
#include <opm/output/eclipse/VectorItems/logihead.hpp> #include <opm/output/eclipse/VectorItems/logihead.hpp>
#include <opm/output/eclipse/VectorItems/doubhead.hpp> #include <opm/output/eclipse/VectorItems/doubhead.hpp>
#include <opm/common/utility/TimeService.hpp> #include <opm/common/utility/TimeService.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
namespace VI = ::Opm::RestartIO::Helpers::VectorItems; namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
using M = ::Opm::UnitSystem::measure;
namespace Opm { namespace Opm {
namespace RestartIO { namespace RestartIO {
RstHeader::RstHeader(const std::vector<int>& intehead, const std::vector<bool>& logihead, const std::vector<double>& doubhead) : RstHeader::RstHeader(const Opm::UnitSystem& unit_system, const std::vector<int>& intehead, const std::vector<bool>& logihead, const std::vector<double>& doubhead) :
nx(intehead[VI::intehead::NX]), nx(intehead[VI::intehead::NX]),
ny(intehead[VI::intehead::NY]), ny(intehead[VI::intehead::NY]),
nz(intehead[VI::intehead::NZ]), nz(intehead[VI::intehead::NZ]),
@ -84,6 +86,7 @@ RstHeader::RstHeader(const std::vector<int>& intehead, const std::vector<bool>&
ntfip(intehead[VI::intehead::NTFIP]), ntfip(intehead[VI::intehead::NTFIP]),
nmfipr(intehead[VI::intehead::NMFIPR]), nmfipr(intehead[VI::intehead::NMFIPR]),
ngroup(intehead[VI::intehead::NGRP]), ngroup(intehead[VI::intehead::NGRP]),
nwgmax(intehead[VI::intehead::NWGMAX]),
// //
e300_radial(logihead[VI::logihead::E300Radial]), e300_radial(logihead[VI::logihead::E300Radial]),
e100_radial(logihead[VI::logihead::E100Radial]), e100_radial(logihead[VI::logihead::E100Radial]),
@ -98,16 +101,19 @@ RstHeader::RstHeader(const std::vector<int>& intehead, const std::vector<bool>&
dir_eps(logihead[VI::logihead::DirEPS]), dir_eps(logihead[VI::logihead::DirEPS]),
reversible_eps(logihead[VI::logihead::RevEPS]), reversible_eps(logihead[VI::logihead::RevEPS]),
alt_eps(logihead[VI::logihead::AltEPS]), alt_eps(logihead[VI::logihead::AltEPS]),
group_control_active(intehead[VI::intehead::NGRNPH] == 1),
// //
next_timestep1(doubhead[VI::doubhead::TsInit]), next_timestep1(unit_system.to_si(M::time, doubhead[VI::doubhead::TsInit])),
next_timestep2(doubhead[VI::doubhead::TsMaxz]), next_timestep2(0),
max_timestep(doubhead[VI::doubhead::TsMinz]), max_timestep(unit_system.to_si(M::time, doubhead[VI::doubhead::TsMaxz])),
guide_rate_a(doubhead[VI::doubhead::GRpar_a]), guide_rate_a(doubhead[VI::doubhead::GRpar_a]),
guide_rate_b(doubhead[VI::doubhead::GRpar_b]), guide_rate_b(doubhead[VI::doubhead::GRpar_b]),
guide_rate_c(doubhead[VI::doubhead::GRpar_c]), guide_rate_c(doubhead[VI::doubhead::GRpar_c]),
guide_rate_d(doubhead[VI::doubhead::GRpar_d]), guide_rate_d(doubhead[VI::doubhead::GRpar_d]),
guide_rate_e(doubhead[VI::doubhead::GRpar_e]), guide_rate_e(doubhead[VI::doubhead::GRpar_e]),
guide_rate_f(doubhead[VI::doubhead::GRpar_f]), 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_range(doubhead[VI::doubhead::UdqPar_2]),
udq_undefined(doubhead[VI::doubhead::UdqPar_3]), udq_undefined(doubhead[VI::doubhead::UdqPar_3]),
udq_eps(doubhead[VI::doubhead::UdqPar_4]) udq_eps(doubhead[VI::doubhead::UdqPar_4])

View File

@ -23,6 +23,8 @@
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.hpp> #include <opm/parser/eclipse/EclipseState/Schedule/MSW/Segment.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp> #include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include "src/opm/parser/eclipse/EclipseState/Schedule/MSW/icd_convert.hpp"
namespace VI = ::Opm::RestartIO::Helpers::VectorItems; namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
namespace Opm { namespace Opm {

View File

@ -34,6 +34,16 @@ namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
namespace Opm { namespace Opm {
namespace RestartIO { namespace RestartIO {
RstState::RstState(const ::Opm::UnitSystem& unit_system_,
const std::vector<int>& intehead,
const std::vector<bool>& logihead,
const std::vector<double>& doubhead):
unit_system(unit_system_),
header(unit_system_, intehead, logihead, doubhead)
{
this->load_tuning(intehead, doubhead);
}
RstState::RstState(const ::Opm::UnitSystem& unit_system_, RstState::RstState(const ::Opm::UnitSystem& unit_system_,
const std::vector<int>& intehead, const std::vector<int>& intehead,
const std::vector<bool>& logihead, const std::vector<bool>& logihead,
@ -49,11 +59,9 @@ RstState::RstState(const ::Opm::UnitSystem& unit_system_,
const std::vector<int>& icon, const std::vector<int>& icon,
const std::vector<float>& scon, const std::vector<float>& scon,
const std::vector<double>& xcon): const std::vector<double>& xcon):
unit_system(unit_system_), RstState(unit_system_, intehead, logihead, doubhead)
header(intehead, logihead, doubhead)
{ {
this->add_groups(zgrp, igrp, sgrp, xgrp); this->add_groups(zgrp, igrp, sgrp, xgrp);
this->load_tuning(intehead, doubhead);
for (int iw = 0; iw < this->header.num_wells; iw++) { for (int iw = 0; iw < this->header.num_wells; iw++) {
std::size_t zwel_offset = iw * this->header.nzwelz; std::size_t zwel_offset = iw * this->header.nzwelz;
@ -99,11 +107,9 @@ RstState::RstState(const ::Opm::UnitSystem& unit_system_,
const std::vector<double>& xcon, const std::vector<double>& xcon,
const std::vector<int>& iseg, const std::vector<int>& iseg,
const std::vector<double>& rseg) : const std::vector<double>& rseg) :
unit_system(unit_system_), RstState(unit_system_, intehead, logihead, doubhead)
header(intehead, logihead, doubhead)
{ {
this->add_groups(zgrp, igrp, sgrp, xgrp); this->add_groups(zgrp, igrp, sgrp, xgrp);
this->load_tuning(intehead, doubhead);
for (int iw = 0; iw < this->header.num_wells; iw++) { for (int iw = 0; iw < this->header.num_wells; iw++) {
std::size_t zwel_offset = iw * this->header.nzwelz; std::size_t zwel_offset = iw * this->header.nzwelz;
@ -181,6 +187,7 @@ void RstState::add_groups(const std::vector<std::string>& zgrp,
std::size_t xgrp_offset = ig * this->header.nxgrpz; std::size_t xgrp_offset = ig * this->header.nxgrpz;
this->groups.emplace_back(this->unit_system, this->groups.emplace_back(this->unit_system,
this->header,
zgrp.data() + zgrp_offset, zgrp.data() + zgrp_offset,
igrp.data() + igrp_offset, igrp.data() + igrp_offset,
sgrp.data() + sgrp_offset, sgrp.data() + sgrp_offset,
@ -202,30 +209,32 @@ const RstWell& RstState::get_well(const std::string& wname) const {
RstState RstState::load(EclIO::ERst& rst_file, int report_step) { RstState RstState::load(EclIO::ERst& rst_file, int report_step) {
rst_file.loadReportStepNumber(report_step); rst_file.loadReportStepNumber(report_step);
const auto& intehead = rst_file.getRst<int>("INTEHEAD", report_step, 0); const auto& intehead = rst_file.getRestartData<int>("INTEHEAD", report_step, 0);
const auto& logihead = rst_file.getRst<bool>("LOGIHEAD", report_step, 0); const auto& logihead = rst_file.getRestartData<bool>("LOGIHEAD", report_step, 0);
const auto& doubhead = rst_file.getRst<double>("DOUBHEAD", report_step, 0); const auto& doubhead = rst_file.getRestartData<double>("DOUBHEAD", report_step, 0);
const auto& zgrp = rst_file.getRst<std::string>("ZGRP", report_step, 0);
const auto& igrp = rst_file.getRst<int>("IGRP", report_step, 0);
const auto& sgrp = rst_file.getRst<float>("SGRP", report_step, 0);
const auto& xgrp = rst_file.getRst<double>("XGRP", report_step, 0);
const auto& zwel = rst_file.getRst<std::string>("ZWEL", report_step, 0);
const auto& iwel = rst_file.getRst<int>("IWEL", report_step, 0);
const auto& swel = rst_file.getRst<float>("SWEL", report_step, 0);
const auto& xwel = rst_file.getRst<double>("XWEL", report_step, 0);
const auto& icon = rst_file.getRst<int>("ICON", report_step, 0);
const auto& scon = rst_file.getRst<float>("SCON", report_step, 0);
const auto& xcon = rst_file.getRst<double>("XCON", report_step, 0);
auto unit_id = intehead[VI::intehead::UNIT]; auto unit_id = intehead[VI::intehead::UNIT];
::Opm::UnitSystem unit_system(unit_id); ::Opm::UnitSystem unit_system(unit_id);
if (intehead[VI::intehead::NWELLS] != 0) {
const auto& zgrp = rst_file.getRestartData<std::string>("ZGRP", report_step, 0);
const auto& igrp = rst_file.getRestartData<int>("IGRP", report_step, 0);
const auto& sgrp = rst_file.getRestartData<float>("SGRP", report_step, 0);
const auto& xgrp = rst_file.getRestartData<double>("XGRP", report_step, 0);
const auto& zwel = rst_file.getRestartData<std::string>("ZWEL", report_step, 0);
const auto& iwel = rst_file.getRestartData<int>("IWEL", report_step, 0);
const auto& swel = rst_file.getRestartData<float>("SWEL", report_step, 0);
const auto& xwel = rst_file.getRestartData<double>("XWEL", report_step, 0);
const auto& icon = rst_file.getRestartData<int>("ICON", report_step, 0);
const auto& scon = rst_file.getRestartData<float>("SCON", report_step, 0);
const auto& xcon = rst_file.getRestartData<double>("XCON", report_step, 0);
if (rst_file.hasKey("ISEG")) { if (rst_file.hasKey("ISEG")) {
const auto& iseg = rst_file.getRst<int>("ISEG", report_step, 0); const auto& iseg = rst_file.getRestartData<int>("ISEG", report_step, 0);
const auto& rseg = rst_file.getRst<double>("RSEG", report_step, 0); const auto& rseg = rst_file.getRestartData<double>("RSEG", report_step, 0);
return RstState(unit_system, return RstState(unit_system,
intehead, logihead, doubhead, intehead, logihead, doubhead,
@ -239,6 +248,8 @@ RstState RstState::load(EclIO::ERst& rst_file, int report_step) {
zgrp, igrp, sgrp, xgrp, zgrp, igrp, sgrp, xgrp,
zwel, iwel, swel, xwel, zwel, iwel, swel, xwel,
icon, scon, xcon); icon, scon, xcon);
} else
return RstState(unit_system, intehead, logihead, doubhead);
} }
} }

View File

@ -61,32 +61,39 @@ RstWell::RstWell(const ::Opm::UnitSystem& unit_system,
ij( {iwel[VI::IWell::IHead] - 1, iwel[VI::IWell::JHead] - 1}), 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)), k1k2( std::make_pair(iwel[VI::IWell::FirstK] - 1, iwel[VI::IWell::LastK] - 1)),
wtype( iwel[VI::IWell::WType], def_ecl_phase), wtype( iwel[VI::IWell::WType], def_ecl_phase),
well_status( iwel[VI::IWell::Status]),
active_control( iwel[VI::IWell::ActWCtrl]), active_control( iwel[VI::IWell::ActWCtrl]),
vfp_table( iwel[VI::IWell::VFPTab]), vfp_table( iwel[VI::IWell::VFPTab]),
pred_requested_control( iwel[VI::IWell::PredReqWCtrl]),
allow_xflow( iwel[VI::IWell::XFlow] == 1), allow_xflow( iwel[VI::IWell::XFlow] == 1),
preferred_phase( iwel[VI::IWell::PreferredPhase]),
hist_requested_control( iwel[VI::IWell::HistReqWCtrl]), hist_requested_control( iwel[VI::IWell::HistReqWCtrl]),
msw_index( iwel[VI::IWell::MsWID]), msw_index( iwel[VI::IWell::MsWID]),
completion_ordering( iwel[VI::IWell::CompOrd]), completion_ordering( iwel[VI::IWell::CompOrd]),
pvt_table( def_pvt_table), pvt_table( def_pvt_table),
orat_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::OilRateTarget]))), msw_pressure_drop_model( iwel[VI::IWell::MSW_PlossMod]),
wrat_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::WatRateTarget]))), // The values orat_target -> bhp_target_flow will be used in UDA values. The
grat_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::GasRateTarget]))), // UDA values are responsible for unit conversion and raw values are
lrat_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::LiqRateTarget]))), // internalized here.
resv_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::ResVRateTarget]))), orat_target( swel_value(swel[VI::SWell::OilRateTarget])),
thp_target( unit_system.to_si(M::identity, swel_value(swel[VI::SWell::THPTarget]))), wrat_target( swel_value(swel[VI::SWell::WatRateTarget])),
bhp_target_float( unit_system.to_si(M::identity, swel[VI::SWell::BHPTarget])), 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_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_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])), 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])), 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]))), 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])), 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])), 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])), 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])), 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])), liquid_rate( unit_system.to_si(M::rate, xwel[VI::XWell::LiqPrRate])),
void_rate( unit_system.to_si(M::rate, xwel[VI::XWell::VoidPrRate])), 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])), flow_bhp( unit_system.to_si(M::pressure, xwel[VI::XWell::FlowBHP])),
wct( unit_system.to_si(M::water_cut, xwel[VI::XWell::WatCut])), 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])), gor( unit_system.to_si(M::gas_oil_ratio, xwel[VI::XWell::GORatio])),

View File

@ -129,7 +129,7 @@ Well::Well(const RestartIO::RstWell& rst_well,
guide_rate(def_guide_rate), guide_rate(def_guide_rate),
efficiency_factor(rst_well.efficiency_factor), efficiency_factor(rst_well.efficiency_factor),
solvent_fraction(def_solvent_fraction), 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<WellEconProductionLimits>()), econ_limits(std::make_shared<WellEconProductionLimits>()),
foam_properties(std::make_shared<WellFoamProperties>()), foam_properties(std::make_shared<WellFoamProperties>()),
polymer_properties(std::make_shared<WellPolymerProperties>()), polymer_properties(std::make_shared<WellPolymerProperties>()),