Rename ApplicationCode to ApplicationLibCode

This commit is contained in:
Gaute Lindkvist
2021-01-06 14:55:29 +01:00
parent 751df1a421
commit 81699db187
3242 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
set (SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RifTextDataTableFormatter.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseInputFileTools.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseOutputFileTools.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseRestartDataAccess.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseRestartFilesetAccess.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseSummaryTools.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseUnifiedRestartFileAccess.h
${CMAKE_CURRENT_LIST_DIR}/RifPerforationIntervalReader.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderEclipseInput.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderEclipseOutput.h
${CMAKE_CURRENT_LIST_DIR}/RifSummaryReaderInterface.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseUserDataParserTools.h
${CMAKE_CURRENT_LIST_DIR}/RifColumnBasedUserDataParser.h
${CMAKE_CURRENT_LIST_DIR}/RifKeywordVectorParser.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderObservedData.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderEclipseSummary.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderRftInterface.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderEclipseRft.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderFmuRft.h
${CMAKE_CURRENT_LIST_DIR}/RifJsonEncodeDecode.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderInterface.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderMockModel.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderSettings.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseSummaryAddress.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseSummaryAddressQMetaType.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseRftAddress.h
${CMAKE_CURRENT_LIST_DIR}/RifWellPathImporter.h
${CMAKE_CURRENT_LIST_DIR}/RifHdf5ReaderInterface.h
${CMAKE_CURRENT_LIST_DIR}/RifColumnBasedUserData.h
${CMAKE_CURRENT_LIST_DIR}/RifKeywordVectorUserData.h
${CMAKE_CURRENT_LIST_DIR}/RifDataSourceForRftPlt.h
${CMAKE_CURRENT_LIST_DIR}/RifDataSourceForRftPltQMetaType.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseUserDataKeywordTools.h
${CMAKE_CURRENT_LIST_DIR}/RifCsvUserData.h
${CMAKE_CURRENT_LIST_DIR}/RifCsvUserDataParser.h
${CMAKE_CURRENT_LIST_DIR}/RifWellMeasurementReader.h
${CMAKE_CURRENT_LIST_DIR}/RifWellPathFormationReader.h
${CMAKE_CURRENT_LIST_DIR}/RifWellPathFormationsImporter.h
${CMAKE_CURRENT_LIST_DIR}/RifElementPropertyTableReader.h
${CMAKE_CURRENT_LIST_DIR}/RifElementPropertyReader.h
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanXmlReader.h
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCaseRestartSelector.h
${CMAKE_CURRENT_LIST_DIR}/RifCaseRealizationParametersReader.h
${CMAKE_CURRENT_LIST_DIR}/RifFileParseTools.h
${CMAKE_CURRENT_LIST_DIR}/RifEnsembleStatisticsReader.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderEnsembleStatisticsRft.h
${CMAKE_CURRENT_LIST_DIR}/RifDerivedEnsembleReader.h
${CMAKE_CURRENT_LIST_DIR}/RifActiveCellsReader.h
${CMAKE_CURRENT_LIST_DIR}/RifCsvDataTableFormatter.h
${CMAKE_CURRENT_LIST_DIR}/RifEclipseInputPropertyLoader.h
${CMAKE_CURRENT_LIST_DIR}/RifSurfaceImporter.h
${CMAKE_CURRENT_LIST_DIR}/RifRoffReader.h
${CMAKE_CURRENT_LIST_DIR}/RifColorLegendData.h
${CMAKE_CURRENT_LIST_DIR}/RifElasticPropertiesReader.h
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelExporter.h
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelGeologicalFrkExporter.h
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelDeviationFrkExporter.h
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelPerfsFrkExporter.h
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelAsymmetricFrkExporter.h
${CMAKE_CURRENT_LIST_DIR}/RifSurfaceExporter.h
# HDF5 file reader is directly included in ResInsight main CmakeList.txt
#${CMAKE_CURRENT_LIST_DIR}/RifHdf5Reader.h
)
set (SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RifTextDataTableFormatter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseInputFileTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseOutputFileTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseRestartDataAccess.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseRestartFilesetAccess.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseUnifiedRestartFileAccess.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseSummaryTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RifPerforationIntervalReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderEclipseInput.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderEclipseOutput.cpp
${CMAKE_CURRENT_LIST_DIR}/RifSummaryReaderInterface.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseUserDataParserTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RifColumnBasedUserDataParser.cpp
${CMAKE_CURRENT_LIST_DIR}/RifKeywordVectorParser.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderObservedData.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderEclipseSummary.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderRftInterface.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderEclipseRft.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderFmuRft.cpp
${CMAKE_CURRENT_LIST_DIR}/RifJsonEncodeDecode.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderInterface.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderMockModel.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderSettings.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseSummaryAddress.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseRftAddress.cpp
${CMAKE_CURRENT_LIST_DIR}/RifWellPathImporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifHdf5ReaderInterface.cpp
${CMAKE_CURRENT_LIST_DIR}/RifColumnBasedUserData.cpp
${CMAKE_CURRENT_LIST_DIR}/RifKeywordVectorUserData.cpp
${CMAKE_CURRENT_LIST_DIR}/RifDataSourceForRftPlt.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseUserDataKeywordTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RifCsvUserData.cpp
${CMAKE_CURRENT_LIST_DIR}/RifCsvUserDataParser.cpp
${CMAKE_CURRENT_LIST_DIR}/RifWellMeasurementReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifWellPathFormationReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifWellPathFormationsImporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifElementPropertyTableReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifElementPropertyReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanXmlReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCaseRestartSelector.cpp
${CMAKE_CURRENT_LIST_DIR}/RifCaseRealizationParametersReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifFileParseTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEnsembleStatisticsReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifDerivedEnsembleReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifActiveCellsReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifCsvDataTableFormatter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderEnsembleStatisticsRft.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseInputPropertyLoader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifSurfaceImporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifRoffReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifColorLegendData.cpp
${CMAKE_CURRENT_LIST_DIR}/RifElasticPropertiesReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelExporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelGeologicalFrkExporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelDeviationFrkExporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelPerfsFrkExporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanModelAsymmetricFrkExporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifSurfaceExporter.cpp
# HDF5 file reader is directly included in ResInsight main CmakeList.txt
#${CMAKE_CURRENT_LIST_DIR}/RifHdf5Reader.cpp
)
list(APPEND CODE_HEADER_FILES
${SOURCE_GROUP_HEADER_FILES}
)
list(APPEND CODE_SOURCE_FILES
${SOURCE_GROUP_SOURCE_FILES}
)
source_group( "FileInterface" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )

View File

@@ -0,0 +1,139 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RifActiveCellsReader.h"
#include "ert/ecl/ecl_file.hpp"
#include "ert/ecl/ecl_grid.hpp"
#include "ert/ecl/ecl_kw_magic.hpp"
#include "cafAssert.h"
#include "RiaStringEncodingTools.h"
#include "RifEclipseOutputFileTools.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<int>> RifActiveCellsReader::activeCellsFromActnumKeyword( const ecl_file_type* ecl_file )
{
CAF_ASSERT( ecl_file );
std::vector<std::vector<int>> activeCellsAllGrids;
int actnumKeywordCount = ecl_file_get_num_named_kw( ecl_file, ACTNUM_KW );
for ( size_t gridIdx = 0; gridIdx < static_cast<size_t>( actnumKeywordCount ); gridIdx++ )
{
std::vector<int> nativeActnumvValues;
RifEclipseOutputFileTools::keywordData( ecl_file, ACTNUM_KW, gridIdx, &nativeActnumvValues );
activeCellsAllGrids.push_back( nativeActnumvValues );
}
return activeCellsAllGrids;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<int>> RifActiveCellsReader::activeCellsFromPorvKeyword( const ecl_file_type* ecl_file,
bool dualPorosity )
{
CAF_ASSERT( ecl_file );
std::vector<std::vector<int>> activeCellsAllGrids;
// Active cell count is always the same size as the number of cells in the grid
// If we have dual porosity, we have to divide by 2
//
// See documentation of active cells in top of ecl_grid.cpp
int porvKeywordCount = ecl_file_get_num_named_kw( ecl_file, PORV_KW );
for ( size_t gridIdx = 0; gridIdx < static_cast<size_t>( porvKeywordCount ); gridIdx++ )
{
std::vector<double> porvValues;
RifEclipseOutputFileTools::keywordData( ecl_file, PORV_KW, gridIdx, &porvValues );
std::vector<int> activeCellsOneGrid;
size_t activeCellCount = porvValues.size();
if ( dualPorosity )
{
activeCellCount /= 2;
}
activeCellsOneGrid.resize( activeCellCount, 0 );
for ( size_t poreValueIndex = 0; poreValueIndex < porvValues.size(); poreValueIndex++ )
{
size_t indexToCell = poreValueIndex;
if ( indexToCell >= activeCellCount )
{
indexToCell = poreValueIndex - activeCellCount;
}
if ( porvValues[poreValueIndex] > 0.0 )
{
if ( dualPorosity )
{
if ( poreValueIndex < activeCellCount )
{
activeCellsOneGrid[indexToCell] += CELL_ACTIVE_MATRIX;
}
else
{
activeCellsOneGrid[indexToCell] += CELL_ACTIVE_FRACTURE;
}
}
else
{
activeCellsOneGrid[indexToCell] = CELL_ACTIVE_MATRIX;
}
}
}
activeCellsAllGrids.push_back( activeCellsOneGrid );
}
return activeCellsAllGrids;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifActiveCellsReader::applyActiveCellsToAllGrids( ecl_grid_type* ecl_main_grid,
const std::vector<std::vector<int>>& activeCellsForAllGrids )
{
CAF_ASSERT( ecl_main_grid );
for ( int gridIndex = 0; gridIndex < static_cast<int>( activeCellsForAllGrids.size() ); gridIndex++ )
{
ecl_grid_type* currentGrid = ecl_main_grid;
if ( gridIndex > 0 )
{
currentGrid = ecl_grid_iget_lgr( ecl_main_grid, gridIndex - 1 );
}
auto activeCellsForGrid = activeCellsForAllGrids[gridIndex];
CAF_ASSERT( ecl_grid_get_global_size( currentGrid ) == static_cast<int>( activeCellsForGrid.size() ) );
int* actnum_values = activeCellsForGrid.data();
ecl_grid_reset_actnum( currentGrid, actnum_values );
}
}

View File

@@ -0,0 +1,39 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 <vector>
typedef struct ecl_grid_struct ecl_grid_type;
typedef struct ecl_file_struct ecl_file_type;
//==================================================================================================
//
//
//==================================================================================================
class RifActiveCellsReader
{
public:
static std::vector<std::vector<int>> activeCellsFromActnumKeyword( const ecl_file_type* ecl_file );
static std::vector<std::vector<int>> activeCellsFromPorvKeyword( const ecl_file_type* ecl_file, bool dualPorosity );
static void applyActiveCellsToAllGrids( ecl_grid_type* ecl_main_grid,
const std::vector<std::vector<int>>& activeCellsForAllGrids );
};

View File

@@ -0,0 +1,307 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifCaseRealizationParametersReader.h"
#include "RifFileParseTools.h"
#include "RiaLogging.h"
#include "RiaStdStringTools.h"
#include <QDir>
#include <QString>
#include <QStringList>
#include <functional>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCaseRealizationReader::RifCaseRealizationReader( const QString& fileName )
{
m_parameters = std::shared_ptr<RigCaseRealizationParameters>( new RigCaseRealizationParameters() );
m_fileName = fileName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCaseRealizationReader::~RifCaseRealizationReader()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::shared_ptr<RigCaseRealizationParameters> RifCaseRealizationReader::parameters() const
{
return m_parameters;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::shared_ptr<RifCaseRealizationReader> RifCaseRealizationReader::createReaderFromFileName( const QString& fileName )
{
std::shared_ptr<RifCaseRealizationReader> reader;
if ( fileName.endsWith( parametersFileName() ) )
{
reader.reset( new RifCaseRealizationParametersReader( fileName ) );
}
else if ( fileName.endsWith( runSpecificationFileName() ) )
{
reader.reset( new RifCaseRealizationRunspecificationReader( fileName ) );
}
return reader;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifCaseRealizationReader::parametersFileName()
{
return "parameters.txt";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifCaseRealizationReader::runSpecificationFileName()
{
return "runspecification.xml";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCaseRealizationParametersReader::RifCaseRealizationParametersReader( const QString& fileName )
: RifCaseRealizationReader( fileName )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCaseRealizationParametersReader::~RifCaseRealizationParametersReader()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifCaseRealizationParametersReader::parse()
{
QFile file( m_fileName );
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) return;
QTextStream dataStream( &file );
int lineNo = 0;
QStringList errors;
while ( !dataStream.atEnd() )
{
QString line = dataStream.readLine();
lineNo++;
QStringList cols = RifFileParseTools::splitLineAndTrim( line, QRegExp( "[ \t]" ), true );
if ( cols.size() != 2 )
{
errors << QString( "RifEnsembleParametersReader: Invalid file format in line %1" ).arg( lineNo );
continue;
}
QString& name = cols[0];
QString& strValue = cols[1];
if ( RiaStdStringTools::isNumber( strValue.toStdString(), QLocale::c().decimalPoint().toLatin1() ) )
{
bool parseOk = true;
double value = QLocale::c().toDouble( strValue, &parseOk );
if ( parseOk )
{
m_parameters->addParameter( name, value );
}
else
{
errors << QString( "RifEnsembleParametersReader: Invalid number format in line %1" ).arg( lineNo );
}
}
else
{
m_parameters->addParameter( name, strValue );
}
}
for ( const auto& s : errors )
{
RiaLogging::warning( s );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCaseRealizationRunspecificationReader::RifCaseRealizationRunspecificationReader( const QString& fileName )
: RifCaseRealizationReader( fileName )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCaseRealizationRunspecificationReader::~RifCaseRealizationRunspecificationReader()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifCaseRealizationRunspecificationReader::parse()
{
QFile file( m_fileName );
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) return;
QXmlStreamReader xml( &file );
QStringList errors;
QString paramName;
while ( !xml.atEnd() )
{
xml.readNext();
if ( xml.isStartElement() )
{
if ( xml.name() == "modifier" )
{
paramName = "";
}
if ( xml.name() == "id" )
{
paramName = xml.readElementText();
}
if ( xml.name() == "value" )
{
QString paramStrValue = xml.readElementText();
if ( paramName.isEmpty() ) continue;
if ( RiaStdStringTools::isNumber( paramStrValue.toStdString(), QLocale::c().decimalPoint().toLatin1() ) )
{
bool parseOk = true;
double value = QLocale::c().toDouble( paramStrValue, &parseOk );
if ( parseOk )
{
m_parameters->addParameter( paramName, value );
}
else
{
errors
<< QString( "RifCaseRealizationRunspecificationReader: Invalid number format in line %1" )
.arg( xml.lineNumber() );
}
}
else
{
m_parameters->addParameter( paramName, paramStrValue );
}
}
}
else if ( xml.isEndElement() )
{
if ( xml.name() == "modifier" )
{
paramName = "";
}
}
}
for ( const auto& s : errors )
{
RiaLogging::warning( s );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifCaseRealizationParametersFileLocator::locate( const QString& modelPath )
{
int MAX_LEVELS_UP = 3;
int dirLevel = 0;
QDir qdir( modelPath );
const QFileInfo dir( modelPath );
if ( dir.isFile() )
qdir.cdUp();
else if ( !dir.isDir() )
return "";
do
{
QStringList files = qdir.entryList( QDir::Files | QDir::NoDotAndDotDot );
for ( const QString& file : files )
{
if ( QString::compare( file, RifCaseRealizationReader::parametersFileName(), Qt::CaseInsensitive ) == 0 ||
QString::compare( file, RifCaseRealizationReader::runSpecificationFileName(), Qt::CaseInsensitive ) == 0 )
{
return qdir.absoluteFilePath( file );
}
}
qdir.cdUp();
} while ( dirLevel++ < MAX_LEVELS_UP );
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RifCaseRealizationParametersFileLocator::realizationNumber( const QString& modelPath )
{
QDir dir( modelPath );
QString absolutePath = dir.absolutePath();
int resultIndex = -1;
// Use parenthesis to indicate capture of sub string
QString pattern = "(realization-\\d+)";
QRegExp regexp( pattern, Qt::CaseInsensitive );
if ( regexp.indexIn( absolutePath ) )
{
QString tempText = regexp.cap( 1 );
QRegExp rx( "(\\d+)" ); // Find number
int digitPos = rx.indexIn( tempText );
if ( digitPos > -1 )
{
resultIndex = rx.cap( 0 ).toInt();
}
}
return resultIndex;
}

View File

@@ -0,0 +1,99 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaPreferences.h"
#include "RifSummaryCaseRestartSelector.h"
#include "RigCaseRealizationParameters.h"
#include <QString>
#include <QTextStream>
#include <map>
#include <memory>
#include <string>
#include <vector>
class QStringList;
class QTextStream;
class QXmlStreamReader;
class QFile;
//==================================================================================================
//
//
//==================================================================================================
class RifCaseRealizationReader
{
public:
RifCaseRealizationReader( const QString& fileName );
virtual ~RifCaseRealizationReader();
virtual void parse() = 0;
const std::shared_ptr<RigCaseRealizationParameters> parameters() const;
static std::shared_ptr<RifCaseRealizationReader> createReaderFromFileName( const QString& fileName );
static QString parametersFileName();
static QString runSpecificationFileName();
protected:
std::shared_ptr<RigCaseRealizationParameters> m_parameters;
QString m_fileName;
};
//==================================================================================================
//
//
//==================================================================================================
class RifCaseRealizationParametersReader : public RifCaseRealizationReader
{
public:
RifCaseRealizationParametersReader( const QString& fileName );
~RifCaseRealizationParametersReader() override;
void parse() override;
};
//==================================================================================================
//
//
//==================================================================================================
class RifCaseRealizationRunspecificationReader : public RifCaseRealizationReader
{
public:
RifCaseRealizationRunspecificationReader( const QString& fileName );
~RifCaseRealizationRunspecificationReader() override;
void parse() override;
};
//==================================================================================================
//
//
//==================================================================================================
class RifCaseRealizationParametersFileLocator
{
public:
static QString locate( const QString& modelPath );
static int realizationNumber( const QString& modelPath );
};

View File

@@ -0,0 +1,264 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 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 "RifColorLegendData.h"
#include "RigFormationNames.h"
#include "cafAssert.h"
#include "cafPdmUiFilePathEditor.h"
#include <QFile>
#include <QFileInfo>
#include "cvfColor3.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<RigFormationNames> RifColorLegendData::readFormationNamesFile( const QString& fileName, QString* errorMessage )
{
QFileInfo fileInfo( fileName );
if ( fileInfo.fileName() == "layer_zone_table.txt" )
{
return RifColorLegendData::readFmuFormationNameFile( fileName, errorMessage );
}
else
{
return RifColorLegendData::readLyrFormationNameFile( fileName, errorMessage );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<RigFormationNames> RifColorLegendData::readLyrFormationNameFile( const QString& fileName, QString* errorMessage )
{
cvf::ref<RigFormationNames> formationNames = new RigFormationNames;
QFile dataFile( fileName );
if ( !dataFile.open( QFile::ReadOnly ) )
{
if ( errorMessage ) ( *errorMessage ) += "Could not open file: " + fileName + "\n";
return formationNames;
}
QTextStream stream( &dataFile );
int lineNumber = 1;
while ( !stream.atEnd() )
{
QString line = stream.readLine();
QStringList lineSegs = line.split( "'", QString::KeepEmptyParts );
if ( lineSegs.size() == 0 ) continue; // Empty line
if ( lineSegs.size() == 1 ) continue; // No name present. Comment line ?
if ( lineSegs.size() == 2 )
{
if ( errorMessage ) ( *errorMessage ) += "Missing quote on line : " + QString::number( lineNumber ) + "\n";
continue; // One quote present
}
if ( lineSegs.size() == 3 ) // Normal case
{
if ( lineSegs[0].contains( "--" ) ) continue; // Comment line
QString formationName = lineSegs[1];
int commentMarkPos = lineSegs[2].indexOf( "--" );
QString numberString = lineSegs[2];
if ( commentMarkPos >= 0 ) numberString.truncate( commentMarkPos );
QString colorWord = numberString.split( " ", QString::SkipEmptyParts ).last(); // extract last word which may
// contain formation color
if ( QColor::isValidColor( colorWord ) )
numberString.remove( colorWord ); // remove color if present as last word on line
QStringList numberWords = numberString.split( QRegExp( "-" ), QString::SkipEmptyParts ); // extract words
// containing
// formation
// number(s)
if ( numberWords.size() == 2 ) // formation range with or without color at end of line
{
bool isNumber1 = false;
bool isNumber2 = false;
int startK = numberWords[0].toInt( &isNumber1 );
int endK = numberWords[1].toInt( &isNumber2 );
if ( !( isNumber2 && isNumber1 ) )
{
if ( errorMessage )
( *errorMessage ) += "Format error on line: " + QString::number( lineNumber ) + "\n";
continue;
}
int tmp = startK;
startK = tmp < endK ? tmp : endK;
endK = tmp > endK ? tmp : endK;
if ( QColor::isValidColor( colorWord ) ) // formation color present at end of line
{
cvf::Color3f formationColor;
convertStringToColor( colorWord, &formationColor );
formationNames->appendFormationRange( formationName, formationColor, startK - 1, endK - 1 );
}
else // no color present
{
formationNames->appendFormationRange( formationName, startK - 1, endK - 1 );
}
}
else if ( numberWords.size() == 1 )
{
bool isNumber1 = false;
int kLayerCount = numberWords[0].toInt( &isNumber1 );
if ( !isNumber1 )
{
if ( errorMessage )
( *errorMessage ) += "Format error on line: " + QString::number( lineNumber ) + "\n";
continue;
}
if ( QColor::isValidColor( colorWord ) ) // formation color present at end of line
{
cvf::Color3f formationColor;
convertStringToColor( colorWord, &formationColor );
formationNames->appendFormationRangeHeight( formationName, formationColor, kLayerCount );
}
else // no color present
{
formationNames->appendFormationRangeHeight( formationName, kLayerCount );
}
}
else
{
if ( errorMessage )
( *errorMessage ) += "Format error on line: " + QString::number( lineNumber ) + "\n";
}
}
++lineNumber;
}
return formationNames;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<RigFormationNames> RifColorLegendData::readFmuFormationNameFile( const QString& fileName, QString* errorMessage )
{
cvf::ref<RigFormationNames> formationNames = new RigFormationNames;
QFile dataFile( fileName );
if ( !dataFile.open( QFile::ReadOnly ) )
{
if ( errorMessage ) ( *errorMessage ) += "Could not open file: " + fileName + "\n";
return formationNames;
}
QTextStream stream( &dataFile );
int lineNumber = 1;
QString currentFormationName;
int startK = -1;
int endK = -1;
while ( !stream.atEnd() )
{
QString line = stream.readLine();
if ( line.isNull() )
{
// Make sure we append the last formation
if ( !currentFormationName.isEmpty() )
{
formationNames->appendFormationRange( currentFormationName, startK - 1, endK - 1 );
}
break;
}
else
{
QTextStream lineStream( &line );
double kLayer;
QString formationName;
lineStream >> kLayer >> formationName;
if ( lineStream.status() != QTextStream::Ok )
{
*errorMessage = QString( "Failed to parse line %1 of '%2'" ).arg( lineNumber ).arg( fileName );
return formationNames;
}
if ( formationName != currentFormationName )
{
// Append previous formation
if ( !currentFormationName.isEmpty() )
{
formationNames->appendFormationRange( currentFormationName, startK - 1, endK - 1 );
}
// Start new formation
currentFormationName = formationName;
startK = kLayer;
endK = kLayer;
}
else
{
endK = kLayer;
}
}
}
// Append previous formation at the end of the stream
if ( !currentFormationName.isEmpty() )
{
formationNames->appendFormationRange( currentFormationName, startK - 1, endK - 1 );
}
return formationNames;
}
//--------------------------------------------------------------------------------------------------
/// Conversion of a color specification from string representation to Color3f.
/// String can be in various formats according to QColor capabilities, notably
/// SVG color keyword names, c.f. https://www.w3.org/TR/SVG11/types.html#ColorKeywords,
/// or #RRGGBB used on a LYR formation data file.
//--------------------------------------------------------------------------------------------------
bool RifColorLegendData::convertStringToColor( const QString& word, cvf::Color3f* color )
{
if ( word.isEmpty() ) return false;
QColor colorQ( word );
if ( colorQ.isValid() )
{
*color = cvf::Color3f::fromByteColor( colorQ.red(), colorQ.green(), colorQ.blue() );
return true;
}
return false;
}

View File

@@ -0,0 +1,45 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cvfObject.h"
class RigFormationNames;
class QString;
namespace cvf
{
class Color3f;
}
//==================================================================================================
///
//==================================================================================================
class RifColorLegendData
{
public:
static cvf::ref<RigFormationNames> readFormationNamesFile( const QString& fileName, QString* errorMessage );
private:
static cvf::ref<RigFormationNames> readLyrFormationNameFile( const QString& fileName, QString* errorMessage );
static cvf::ref<RigFormationNames> readFmuFormationNameFile( const QString& fileName, QString* errorMessage );
static bool convertStringToColor( const QString& word, cvf::Color3f* color );
};

View File

@@ -0,0 +1,281 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifColumnBasedUserData.h"
#include "RiaDateStringParser.h"
#include "RiaLogging.h"
#include "RiaQDateTimeTools.h"
#include "RifColumnBasedUserDataParser.h"
#include "RifEclipseUserDataKeywordTools.h"
#include "RifEclipseUserDataParserTools.h"
#include "cafUtils.h"
#include <QDateTime>
#include <QFile>
#include <QTextStream>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifColumnBasedUserData::RifColumnBasedUserData()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifColumnBasedUserData::~RifColumnBasedUserData()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifColumnBasedUserData::parse( const QString& data, QString* errorText )
{
m_allResultAddresses.clear();
m_timeSteps.clear();
m_mapFromAddressToTimeStepIndex.clear();
m_mapFromAddressToResultIndex.clear();
m_parser = std::unique_ptr<RifColumnBasedUserDataParser>( new RifColumnBasedUserDataParser( data, errorText ) );
if ( !m_parser )
{
RiaLogging::error( QString( "Failed to parse file" ) );
return false;
}
buildTimeStepsAndMappings();
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifColumnBasedUserData::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{
auto search = m_mapFromAddressToResultIndex.find( resultAddress );
if ( search != m_mapFromAddressToResultIndex.end() )
{
std::pair<size_t, size_t> tableColIndices = search->second;
const Column* ci = m_parser->columnInfo( tableColIndices.first, tableColIndices.second );
if ( !ci ) return false;
if ( !ci->values.empty() )
{
values->reserve( ci->values.size() );
for ( const auto& v : ci->values )
{
values->push_back( v );
}
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<time_t>& RifColumnBasedUserData::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{
auto search = m_mapFromAddressToTimeStepIndex.find( resultAddress );
if ( search != m_mapFromAddressToTimeStepIndex.end() )
{
return m_timeSteps[search->second];
}
static std::vector<time_t> emptyVector;
return emptyVector;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RifColumnBasedUserData::unitName( const RifEclipseSummaryAddress& resultAddress ) const
{
auto search = m_mapFromAddressToResultIndex.find( resultAddress );
if ( search != m_mapFromAddressToResultIndex.end() )
{
std::pair<size_t, size_t> tableColIndices = search->second;
const Column* ci = m_parser->columnInfo( tableColIndices.first, tableColIndices.second );
if ( ci )
{
return ci->unitName;
}
}
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaEclipseUnitTools::UnitSystem RifColumnBasedUserData::unitSystem() const
{
return RiaEclipseUnitTools::UnitSystem::UNITS_UNKNOWN;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifColumnBasedUserData::buildTimeStepsAndMappings()
{
for ( size_t tableIndex = 0; tableIndex < m_parser->tableData().size(); tableIndex++ )
{
auto tableData = m_parser->tableData()[tableIndex];
std::vector<time_t> timeStepsForTable = createTimeSteps( tableData );
if ( timeStepsForTable.empty() )
{
RiaLogging::warning( QString( "Failed to find time data for table %1 in file %2" ).arg( tableIndex ) );
RiaLogging::warning( QString( "No data for this table is imported" ) );
return;
}
m_timeSteps.push_back( timeStepsForTable );
for ( size_t columIndex = 0; columIndex < tableData.columnInfos().size(); columIndex++ )
{
const Column& ci = tableData.columnInfos()[columIndex];
if ( ci.dataType == Column::NUMERIC )
{
RifEclipseSummaryAddress sumAddress = ci.summaryAddress;
m_allResultAddresses.insert( sumAddress );
m_mapFromAddressToTimeStepIndex[sumAddress] = m_timeSteps.size() - 1;
m_mapFromAddressToResultIndex[sumAddress] = std::make_pair( tableIndex, columIndex );
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<time_t> RifColumnBasedUserData::createTimeSteps( const TableData& tableData )
{
std::vector<time_t> tsVector;
size_t dateColumnIndex = tableData.columnInfos().size();
size_t daysColumnIndex = tableData.columnInfos().size();
size_t yearsColumnIndex = tableData.columnInfos().size();
size_t yearXColumnIndex = tableData.columnInfos().size();
// Find first column matching the text criteria
for ( size_t columIndex = 0; columIndex < tableData.columnInfos().size(); columIndex++ )
{
const Column& ci = tableData.columnInfos()[columIndex];
if ( dateColumnIndex == tableData.columnInfos().size() &&
RifEclipseUserDataKeywordTools::isDate( ci.summaryAddress.quantityName() ) )
{
dateColumnIndex = columIndex;
}
if ( daysColumnIndex == tableData.columnInfos().size() &&
RifEclipseUserDataKeywordTools::isTime( ci.summaryAddress.quantityName() ) &&
RifEclipseUserDataKeywordTools::isDays( ci.unitName ) )
{
daysColumnIndex = columIndex;
}
if ( yearsColumnIndex == tableData.columnInfos().size() &&
RifEclipseUserDataKeywordTools::isYears( ci.summaryAddress.quantityName() ) &&
RifEclipseUserDataKeywordTools::isYears( ci.unitName ) )
{
yearsColumnIndex = columIndex;
}
if ( yearXColumnIndex == tableData.columnInfos().size() &&
RifEclipseUserDataKeywordTools::isYearX( ci.summaryAddress.quantityName() ) &&
RifEclipseUserDataKeywordTools::isYears( ci.unitName ) )
{
yearXColumnIndex = columIndex;
}
}
// YEARX is interpreted as absolute decimal year (2014.32)
if ( tsVector.empty() && yearXColumnIndex != tableData.columnInfos().size() )
{
const Column& ci = tableData.columnInfos()[yearXColumnIndex];
for ( const auto& timeStepValue : ci.values )
{
QDateTime dateTime = RiaQDateTimeTools::fromYears( timeStepValue );
tsVector.push_back( dateTime.toTime_t() );
}
}
// DAYS is interpreted as decimal days since simulation start (23.32)
if ( tsVector.empty() && daysColumnIndex != tableData.columnInfos().size() )
{
const Column& ci = tableData.columnInfos()[daysColumnIndex];
QDateTime simulationStartDate = tableData.findFirstDate();
for ( const auto& timeStepValue : ci.values )
{
QDateTime dateTime = RiaQDateTimeTools::addDays( simulationStartDate, timeStepValue );
tsVector.push_back( dateTime.toTime_t() );
}
}
// YEARS is interpreted as decimal years since simulation start (23.32)
if ( tsVector.empty() && yearsColumnIndex != tableData.columnInfos().size() )
{
const Column& ci = tableData.columnInfos()[yearsColumnIndex];
QDateTime simulationStartDate = tableData.findFirstDate();
for ( const auto& timeStepValue : ci.values )
{
QDateTime dateTime = RiaQDateTimeTools::addYears( simulationStartDate, timeStepValue );
tsVector.push_back( dateTime.toTime_t() );
}
}
// DATE is interpreted as date string (6-NOV-1997)
if ( tsVector.empty() && dateColumnIndex != tableData.columnInfos().size() )
{
const Column& ci = tableData.columnInfos()[dateColumnIndex];
QString dateFormat;
for ( auto s : ci.textValues )
{
QDateTime dt = RiaDateStringParser::parseDateString( s );
tsVector.push_back( dt.toTime_t() );
}
}
return tsVector;
}

View File

@@ -0,0 +1,62 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifSummaryReaderInterface.h"
#include <map>
#include <memory>
#include <vector>
class QString;
class RifColumnBasedUserDataParser;
class RifEclipseSummaryAddress;
class TableData;
//==================================================================================================
//
//
//==================================================================================================
class RifColumnBasedUserData : public RifSummaryReaderInterface
{
public:
RifColumnBasedUserData();
~RifColumnBasedUserData() override;
bool parse( const QString& data, QString* errorText = nullptr );
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;
RiaEclipseUnitTools::UnitSystem unitSystem() const override;
private:
void buildTimeStepsAndMappings();
static std::vector<time_t> createTimeSteps( const TableData& table );
private:
std::unique_ptr<RifColumnBasedUserDataParser> m_parser;
std::vector<std::vector<time_t>> m_timeSteps;
std::map<RifEclipseSummaryAddress, size_t> m_mapFromAddressToTimeStepIndex;
std::map<RifEclipseSummaryAddress, std::pair<size_t, size_t>> m_mapFromAddressToResultIndex;
};

View File

@@ -0,0 +1,147 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifColumnBasedUserDataParser.h"
#include "RifEclipseUserDataKeywordTools.h"
#include "RifEclipseUserDataParserTools.h"
#include "RiaDateStringParser.h"
#include "RiaLogging.h"
#include "cvfAssert.h"
#include <QString>
#include <QStringList>
#include <QTextStream>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifColumnBasedUserDataParser::RifColumnBasedUserDataParser( const QString& data, QString* errorText )
: m_errorText( errorText )
{
parseTableData( data );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<TableData>& RifColumnBasedUserDataParser::tableData() const
{
return m_tableDatas;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const Column* RifColumnBasedUserDataParser::columnInfo( size_t tableIndex, size_t columnIndex ) const
{
if ( tableIndex >= m_tableDatas.size() ) return nullptr;
if ( columnIndex >= m_tableDatas[tableIndex].columnInfos().size() ) return nullptr;
return &( m_tableDatas[tableIndex].columnInfos()[columnIndex] );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifColumnBasedUserDataParser::parseTableData( const QString& data )
{
std::string stdData = data.toStdString();
bool isFixedWidth = RifEclipseUserDataParserTools::isFixedWidthHeader( stdData );
std::stringstream streamData;
streamData.str( stdData );
std::vector<TableData> rawTables;
do
{
std::vector<std::string> errorStrings;
TableData table;
if ( isFixedWidth )
{
auto columnInfos = RifEclipseUserDataParserTools::columnInfoForFixedColumnWidth( streamData );
table = TableData( "", "", columnInfos );
}
else
{
table = RifEclipseUserDataParserTools::tableDataFromText( streamData, &errorStrings );
}
if ( m_errorText )
{
for ( auto s : errorStrings )
{
QString errorText = QString( "\n%1" ).arg( QString::fromStdString( s ) );
m_errorText->append( errorText );
}
}
std::vector<Column>& columnInfos = table.columnInfos();
int columnCount = static_cast<int>( columnInfos.size() );
if ( columnCount == 0 ) break;
int stepTypeIndex = -1;
for ( size_t i = 0; i < columnInfos.size(); i++ )
{
if ( RifEclipseUserDataKeywordTools::isStepType( columnInfos[i].summaryAddress.quantityName() ) )
{
stepTypeIndex = static_cast<int>( i );
}
}
std::string line;
std::getline( streamData, line );
do
{
QString qLine = QString::fromStdString( line );
QStringList entries = qLine.split( " ", QString::SkipEmptyParts );
if ( stepTypeIndex > -1 && (unsigned int)entries.size() < columnInfos.size() )
{
entries.insert( stepTypeIndex, " " );
}
if ( entries.size() < columnCount ) break;
for ( int i = 0; i < columnCount; i++ )
{
if ( columnInfos[i].dataType == Column::TEXT )
{
columnInfos[i].textValues.push_back( entries[i].toStdString() );
}
else
{
double entry = entries[i].toDouble();
columnInfos[i].values.push_back( entry );
}
}
} while ( std::getline( streamData, line ) );
rawTables.push_back( table );
} while ( streamData.good() );
m_tableDatas = RifEclipseUserDataParserTools::mergeEqualTimeSteps( rawTables );
}

View File

@@ -0,0 +1,48 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifEclipseSummaryAddress.h"
#include <QPointer>
#include <QString>
#include <vector>
class Column;
class TableData;
//==================================================================================================
///
//==================================================================================================
class RifColumnBasedUserDataParser
{
public:
RifColumnBasedUserDataParser( const QString& data, QString* errorText = nullptr );
const std::vector<TableData>& tableData() const;
const Column* columnInfo( size_t tableIndex, size_t columnIndex ) const;
private:
void parseTableData( const QString& data );
private:
std::vector<TableData> m_tableDatas;
QString* m_errorText;
};

View File

@@ -0,0 +1,138 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RifCsvDataTableFormatter.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvDataTableFormatter::RifCsvDataTableFormatter( QTextStream& out, const QString fieldSeparator )
: m_out( out )
, m_fieldSeparator( fieldSeparator )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvDataTableFormatter& RifCsvDataTableFormatter::header( const std::vector<RifTextDataTableColumn>& tableHeader )
{
outputBuffer();
m_columnHeaders = tableHeader;
return *this;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvDataTableFormatter& RifCsvDataTableFormatter::add( const QString& str )
{
QString quotedString = "\"" + str + "\"";
m_lineBuffer.push_back( quotedString );
return *this;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvDataTableFormatter& RifCsvDataTableFormatter::add( double num )
{
size_t column = m_lineBuffer.size();
m_lineBuffer.push_back( RifTextDataTableFormatter::format( num, m_columnHeaders[column].doubleFormat ) );
return *this;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvDataTableFormatter& RifCsvDataTableFormatter::add( int num )
{
m_lineBuffer.push_back( RifTextDataTableFormatter::format( num ) );
return *this;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvDataTableFormatter& RifCsvDataTableFormatter::add( size_t num )
{
m_lineBuffer.push_back( RifTextDataTableFormatter::format( num ) );
return *this;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifCsvDataTableFormatter::rowCompleted()
{
RifTextDataTableLine line;
line.data = m_lineBuffer;
line.lineType = CONTENTS;
line.appendTextSet = false;
m_buffer.push_back( line );
m_lineBuffer.clear();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifCsvDataTableFormatter::tableCompleted()
{
outputBuffer();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifCsvDataTableFormatter::outputBuffer()
{
if ( !m_columnHeaders.empty() )
{
for ( size_t i = 0; i < m_columnHeaders.size(); i++ )
{
m_out << m_columnHeaders[i].title;
if ( i < m_columnHeaders.size() - 1 )
{
m_out << m_fieldSeparator;
}
}
m_out << "\n";
}
for ( const auto& line : m_buffer )
{
if ( line.lineType == CONTENTS )
{
QString lineText;
for ( size_t i = 0; i < line.data.size(); i++ )
{
lineText += line.data[i];
if ( i < line.data.size() - 1 )
{
lineText += m_fieldSeparator;
}
}
m_out << lineText << "\n";
}
}
m_columnHeaders.clear();
m_buffer.clear();
}

View File

@@ -0,0 +1,50 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RifTextDataTableFormatter.h"
//==================================================================================================
//
// CSV text formatter using the same pattern as RifEclipseDataTableFormatter so it will be easy to switch formatters
//
//==================================================================================================
class RifCsvDataTableFormatter
{
public:
RifCsvDataTableFormatter( QTextStream& out, const QString fieldSeparator = "," );
RifCsvDataTableFormatter& header( const std::vector<RifTextDataTableColumn>& tableHeader );
RifCsvDataTableFormatter& add( const QString& str );
RifCsvDataTableFormatter& add( double num );
RifCsvDataTableFormatter& add( int num );
RifCsvDataTableFormatter& add( size_t num );
void rowCompleted();
void tableCompleted();
private:
void outputBuffer();
private:
QTextStream& m_out;
std::vector<RifTextDataTableColumn> m_columnHeaders;
std::vector<RifTextDataTableLine> m_buffer;
std::vector<QString> m_lineBuffer;
QString m_fieldSeparator;
};

View File

@@ -0,0 +1,168 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifCsvUserData.h"
#include "RiaDateStringParser.h"
#include "RiaLogging.h"
#include "RiaQDateTimeTools.h"
#include "RifCsvUserDataParser.h"
#include "RifEclipseUserDataKeywordTools.h"
#include "RifEclipseUserDataParserTools.h"
#include "cafUtils.h"
#include <QDateTime>
#include <QFile>
#include <QTextStream>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvUserData::RifCsvUserData()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvUserData::~RifCsvUserData()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifCsvUserData::parse( const QString& fileName, const AsciiDataParseOptions& parseOptions, QString* errorText )
{
m_allResultAddresses.clear();
m_mapFromAddressToResultIndex.clear();
m_parser = std::unique_ptr<RifCsvUserDataFileParser>( new RifCsvUserDataFileParser( fileName, errorText ) );
if ( !m_parser->parse( parseOptions ) )
{
RiaLogging::error( QString( "Failed to parse file" ) );
return false;
}
buildTimeStepsAndMappings();
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifCsvUserData::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{
auto search = m_mapFromAddressToResultIndex.find( resultAddress );
if ( search != m_mapFromAddressToResultIndex.end() )
{
size_t columnIndex = search->second;
const Column* ci = m_parser->columnInfo( columnIndex );
if ( !ci ) return false;
values->clear();
values->reserve( ci->values.size() );
for ( double val : ci->values )
{
values->push_back( val );
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<time_t>& RifCsvUserData::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{
// First, check whether date time values exist for the current address
auto search = m_mapFromAddressToResultIndex.find( resultAddress );
if ( search != m_mapFromAddressToResultIndex.end() )
{
size_t index = m_mapFromAddressToResultIndex.at( resultAddress );
if ( !m_parser->tableData().columnInfos()[index].dateTimeValues.empty() )
{
return m_parser->tableData().columnInfos()[index].dateTimeValues;
}
}
// Then check for a separate date time column
int index = m_parser->tableData().dateTimeColumnIndex();
if ( index >= 0 )
{
return m_parser->tableData().columnInfos()[index].dateTimeValues;
}
static std::vector<time_t> emptyVector;
return emptyVector;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RifCsvUserData::unitName( const RifEclipseSummaryAddress& resultAddress ) const
{
auto search = m_mapFromAddressToResultIndex.find( resultAddress );
if ( search != m_mapFromAddressToResultIndex.end() )
{
size_t columnIndex = search->second;
const Column* ci = m_parser->columnInfo( columnIndex );
if ( ci )
{
return ci->unitName;
}
}
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaEclipseUnitTools::UnitSystem RifCsvUserData::unitSystem() const
{
return RiaEclipseUnitTools::UnitSystem::UNITS_UNKNOWN;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifCsvUserData::buildTimeStepsAndMappings()
{
auto tableData = m_parser->tableData();
for ( size_t columnIndex = 0; columnIndex < tableData.columnInfos().size(); columnIndex++ )
{
const Column& ci = tableData.columnInfos()[columnIndex];
if ( ci.dataType == Column::NUMERIC )
{
RifEclipseSummaryAddress sumAddress = ci.summaryAddress;
m_allResultAddresses.insert( sumAddress );
if ( sumAddress.isErrorResult() ) m_allErrorAddresses.insert( sumAddress );
m_mapFromAddressToResultIndex[sumAddress] = columnIndex;
}
}
}

View File

@@ -0,0 +1,62 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifSummaryReaderInterface.h"
#include "SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.h"
#include <map>
#include <memory>
#include <vector>
class QString;
class RifCsvUserDataParser;
class RifEclipseSummaryAddress;
class TableData;
//==================================================================================================
//
//
//==================================================================================================
class RifCsvUserData : public RifSummaryReaderInterface
{
public:
RifCsvUserData();
~RifCsvUserData() override;
bool parse( const QString& fileName, const AsciiDataParseOptions& parseOptions, QString* errorText = nullptr );
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;
RiaEclipseUnitTools::UnitSystem unitSystem() const override;
private:
void buildTimeStepsAndMappings();
private:
std::unique_ptr<RifCsvUserDataParser> m_parser;
std::map<RifEclipseSummaryAddress, size_t> m_mapFromAddressToResultIndex;
};

View File

@@ -0,0 +1,864 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifCsvUserDataParser.h"
#include "RifEclipseUserDataKeywordTools.h"
#include "RifEclipseUserDataParserTools.h"
#include "RifFileParseTools.h"
#include "RiaDateStringParser.h"
#include "RiaLogging.h"
#include "RiaQDateTimeTools.h"
#include "RiaStdStringTools.h"
#include "RiaTextStringTools.h"
#include "SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.h"
#include "cvfAssert.h"
#include <QFile>
#include <QString>
#include <QTextStream>
#include <algorithm>
#include <cmath>
#include <limits>
#include <utility>
//--------------------------------------------------------------------------------------------------
/// Internal constants
//--------------------------------------------------------------------------------------------------
#define DOUBLE_INF std::numeric_limits<double>::infinity()
#define ISO_DATE_FORMAT "yyyy-MM-dd"
#define TIME_FORMAT "hh:mm:ss"
using Sample = std::pair<time_t, double>;
using SampleList = std::vector<Sample>;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
enum class CsvLineBasedColumnType
{
DATE,
VECTOR,
VALUE,
ERROR_VALUE,
COMMENTS
};
const std::vector<QString> CSV_LINE_BASED_COL_NAMES = { "DATE", "VECTOR", "VALUE", "ERROR", "COMMENTS" };
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvUserDataParser::RifCsvUserDataParser( QString* errorText )
: m_errorText( errorText )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvUserDataParser::~RifCsvUserDataParser()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifCsvUserDataParser::parse( const AsciiDataParseOptions& parseOptions )
{
if ( determineCsvLayout() == LineBased ) return parseLineBasedData();
return parseColumnBasedData( parseOptions );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const TableData& RifCsvUserDataParser::tableData() const
{
return m_tableData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const Column* RifCsvUserDataParser::columnInfo( size_t columnIndex ) const
{
if ( columnIndex >= m_tableData.columnInfos().size() ) return nullptr;
return &( m_tableData.columnInfos()[columnIndex] );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const Column* RifCsvUserDataParser::dateTimeColumn() const
{
for ( const Column& col : m_tableData.columnInfos() )
{
if ( col.dataType == Column::DATETIME )
{
return &col;
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> RifCsvUserDataParser::parseLineBasedHeader( QStringList headerCols )
{
std::vector<int> colIndexes;
for ( int i = 0; i < (int)CSV_LINE_BASED_COL_NAMES.size(); i++ )
{
for ( int j = 0; j < (int)headerCols.size(); j++ )
{
if ( headerCols[j] == CSV_LINE_BASED_COL_NAMES[i] )
{
colIndexes.push_back( j );
break;
}
}
if ( i < 3 && (int)colIndexes.size() < i + 1 ) return {};
}
return colIndexes;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifCsvUserDataParser::parseColumnInfo( const AsciiDataParseOptions& parseOptions )
{
QTextStream* dataStream = openDataStream();
std::vector<Column> columnInfoList;
bool result = parseColumnInfo( dataStream, parseOptions, &columnInfoList );
if ( result )
{
m_tableData = TableData( "", "", columnInfoList );
}
closeDataStream();
return result;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifCsvUserDataParser::previewText( int lineCount, const AsciiDataParseOptions& parseOptions )
{
QTextStream* stream = openDataStream();
if ( !stream ) return "";
QString preview;
QTextStream outStream( &preview );
int iLine = 0;
bool header = true;
int timeColumnIndex = -1;
outStream << "<Table>";
outStream << "<Style> th, td {padding-right: 15px;} </Style>";
while ( iLine < lineCount && !stream->atEnd() )
{
QString line = stream->readLine();
if ( line.isEmpty() ) continue;
outStream << "<tr>";
int iCol = 0;
QStringList cols = RifFileParseTools::splitLineAndTrim( line, parseOptions.cellSeparator );
for ( const QString& cellData : cols )
{
if ( cellData == parseOptions.timeSeriesColumnName && header )
{
timeColumnIndex = iCol;
}
outStream << ( header ? "<th" : "<td" );
if ( iCol == timeColumnIndex )
{
outStream << " style=\"background-color: #FFFFD0;\"";
}
outStream << ">";
outStream << cellData;
if ( iCol < cols.size() - 1 && ( parseOptions.cellSeparator == ";" || parseOptions.cellSeparator == "," ) )
{
outStream << parseOptions.cellSeparator;
}
outStream << ( header ? "</th>" : "</td>" );
iCol++;
}
outStream << "</tr>";
header = false;
iLine++;
}
outStream << "</Table>";
closeDataStream();
return preview;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList RifCsvUserDataParser::timeColumnPreviewData( int lineCount, const AsciiDataParseOptions& parseOptions )
{
QStringList timeStrings;
QTextStream* stream = openDataStream();
if ( stream )
{
int timeColumnIndex = -1;
int iLine = 0;
while ( iLine < lineCount && !stream->atEnd() )
{
QString line = stream->readLine();
if ( line.isEmpty() ) continue;
int iCol = 0;
QStringList cols = RifFileParseTools::splitLineAndTrim( line, parseOptions.cellSeparator );
for ( const QString& cellData : cols )
{
if ( cellData == parseOptions.timeSeriesColumnName && iLine == 0 )
{
timeColumnIndex = iCol;
}
if ( iLine > 0 && timeColumnIndex != -1 && timeColumnIndex == iCol )
{
timeStrings.push_back( cellData );
}
iCol++;
}
iLine++;
}
}
closeDataStream();
return timeStrings;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvUserDataParser::CsvLayout RifCsvUserDataParser::determineCsvLayout()
{
QTextStream* dataStream = openDataStream();
QString firstLine;
QStringList headers;
while ( !dataStream->atEnd() )
{
firstLine = dataStream->readLine();
if ( firstLine.isEmpty() ) continue;
headers = firstLine.split( ';' );
if ( headers.size() < 3 || headers.size() > 5 ) continue;
break;
}
closeDataStream();
if ( headers.contains( CSV_LINE_BASED_COL_NAMES[(size_t)CsvLineBasedColumnType::DATE] ) &&
headers.contains( CSV_LINE_BASED_COL_NAMES[(size_t)CsvLineBasedColumnType::VECTOR] ) &&
headers.contains( CSV_LINE_BASED_COL_NAMES[(size_t)CsvLineBasedColumnType::VALUE] ) )
return LineBased;
return ColumnBased;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifCsvUserDataParser::parseColumnInfo( QTextStream* dataStream,
const AsciiDataParseOptions& parseOptions,
std::vector<Column>* columnInfoList )
{
bool headerFound = false;
if ( !columnInfoList ) return false;
columnInfoList->clear();
while ( !headerFound )
{
QString line = dataStream->readLine();
if ( line.trimmed().isEmpty() ) continue;
QStringList lineColumns = RifFileParseTools::splitLineAndTrim( line, parseOptions.cellSeparator );
int colCount = lineColumns.size();
for ( int iCol = 0; iCol < colCount; iCol++ )
{
QString colName = RiaTextStringTools::trimAndRemoveDoubleSpaces( lineColumns[iCol] );
RifEclipseSummaryAddress addr = RifEclipseSummaryAddress::fromEclipseTextAddress( colName.toStdString() );
Column col = Column::createColumnInfoFromCsvData( addr, "" );
columnInfoList->push_back( col );
}
headerFound = true;
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifCsvUserDataParser::parseColumnBasedData( const AsciiDataParseOptions& parseOptions )
{
bool errors = false;
enum
{
FIRST_DATA_ROW,
DATA_ROW
} parseState = FIRST_DATA_ROW;
int colCount;
std::vector<Column> columnInfoList;
QTextStream* dataStream = openDataStream();
// Parse header
if ( !parseColumnInfo( dataStream, parseOptions, &columnInfoList ) )
{
if ( m_errorText ) m_errorText->append( "CSV import: Failed to parse header columns" );
return false;
}
colCount = (int)columnInfoList.size();
while ( !dataStream->atEnd() && !errors )
{
QString line = dataStream->readLine();
if ( line.trimmed().isEmpty() ) continue;
QStringList lineColumns = RifFileParseTools::splitLineAndTrim( line, parseOptions.cellSeparator );
if ( lineColumns.size() != colCount )
{
if ( m_errorText ) m_errorText->append( "CSV import: Varying number of columns" );
errors = true;
break;
}
else if ( parseState == FIRST_DATA_ROW )
{
for ( int iCol = 0; iCol < colCount; iCol++ )
{
std::string colData = lineColumns[iCol].toStdString();
Column& col = columnInfoList[iCol];
// Determine column data type
if ( col.dataType == Column::NONE )
{
if ( QString::fromStdString( col.summaryAddress.quantityName() ) == parseOptions.timeSeriesColumnName )
{
col.dataType = Column::DATETIME;
}
else
{
if ( parseOptions.assumeNumericDataColumns ||
RiaStdStringTools::isNumber( colData, parseOptions.locale.decimalPoint().toLatin1() ) )
{
col.dataType = Column::NUMERIC;
}
else
{
col.dataType = Column::TEXT;
}
}
}
}
parseState = DATA_ROW;
}
if ( parseState == DATA_ROW )
{
for ( int iCol = 0; iCol < colCount; iCol++ )
{
QString& colData = lineColumns[iCol];
Column& col = columnInfoList[iCol];
try
{
if ( col.dataType == Column::NUMERIC )
{
bool parseOk = true;
double value = parseOptions.locale.toDouble( colData, &parseOk );
if ( !parseOk )
{
// Find the error reason, wrong decimal sign or something else
if ( RiaStdStringTools::isNumber( colData.toStdString(), '.' ) ||
RiaStdStringTools::isNumber( colData.toStdString(), ',' ) )
{
if ( m_errorText )
m_errorText->append(
QString( "CSV import: Failed to parse numeric value in column %1\n" )
.arg( QString::number( iCol + 1 ) ) );
throw 0;
}
// Add nullptr value
value = HUGE_VAL;
}
col.values.push_back( value );
}
else if ( col.dataType == Column::TEXT )
{
col.textValues.push_back( colData.toStdString() );
}
else if ( col.dataType == Column::DATETIME )
{
QDateTime dt;
dt = tryParseDateTime( colData.toStdString(), parseOptions.dateTimeFormat );
if ( !dt.isValid() && !parseOptions.useCustomDateTimeFormat )
{
// Try to match date format only
if ( parseOptions.dateFormat != parseOptions.dateTimeFormat )
{
dt = tryParseDateTime( colData.toStdString(), parseOptions.dateFormat );
}
if ( !dt.isValid() && !parseOptions.fallbackDateTimeFormat.isEmpty() )
{
dt = tryParseDateTime( colData.toStdString(), parseOptions.fallbackDateTimeFormat );
}
}
if ( !dt.isValid() )
{
if ( m_errorText ) m_errorText->append( "CSV import: Failed to parse date time value" );
throw 0;
}
col.dateTimeValues.push_back( dt.toTime_t() );
}
}
catch ( ... )
{
errors = true;
break;
}
}
}
}
closeDataStream();
if ( !errors )
{
TableData td( "", "", columnInfoList );
m_tableData = td;
}
return !errors;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifCsvUserDataParser::parseLineBasedData()
{
QTextStream* dataStream = openDataStream();
std::map<RifEclipseSummaryAddress, std::vector<std::pair<time_t, double>>> addressesAndData;
std::vector<int> colIndexes;
// Parse header
int lineCount = 0;
bool headerFound = false;
bool expectErrorValue = false;
while ( !dataStream->atEnd() )
{
lineCount++;
QString line = dataStream->readLine();
if ( line.trimmed().isEmpty() ) continue;
QStringList dataItems = RifFileParseTools::splitLineAndTrim( line, ";" );
if ( dataItems.size() < 3 || dataItems.size() > 5 ) continue;
if ( !headerFound )
{
colIndexes = parseLineBasedHeader( dataItems );
if ( !colIndexes.empty() )
{
headerFound = true;
expectErrorValue = colIndexes.size() > (size_t)CsvLineBasedColumnType::ERROR_VALUE &&
colIndexes[(size_t)CsvLineBasedColumnType::ERROR_VALUE] >= 0;
}
continue;
}
if ( dataItems.size() != (int)colIndexes.size() ) continue;
{
auto textAddr = dataItems[colIndexes[(size_t)CsvLineBasedColumnType::VECTOR]];
auto addr = RifEclipseSummaryAddress::fromEclipseTextAddress( textAddr.toStdString() );
auto errAddr = addr;
errAddr.setAsErrorResult();
if ( !addr.isValid() ) continue;
// VECTOR
{
if ( addressesAndData.find( addr ) == addressesAndData.end() )
{
addressesAndData.insert( std::make_pair( addr, std::vector<Sample>() ) );
}
// Create error address if error value is expected
if ( expectErrorValue )
{
if ( addressesAndData.find( errAddr ) == addressesAndData.end() )
{
addressesAndData.insert( std::make_pair( errAddr, std::vector<Sample>() ) );
}
}
}
// DATE
QDateTime dateTime;
{
auto dateText = dataItems[colIndexes[(size_t)CsvLineBasedColumnType::DATE]].toStdString();
dateTime = tryParseDateTime( dateText, ISO_DATE_FORMAT );
if ( !dateTime.isValid() )
{
// Try to match date and time
dateTime = tryParseDateTime( dateText, QString( ISO_DATE_FORMAT ) + " " + TIME_FORMAT );
}
if ( !dateTime.isValid() )
{
if ( m_errorText )
m_errorText->append( QString( "CSV import: Failed to parse date time value in line %1" )
.arg( QString::number( lineCount ) ) );
throw 0;
}
}
// VALUE
{
bool parseOk = true;
double value =
QLocale::c().toDouble( dataItems[colIndexes[(size_t)CsvLineBasedColumnType::VALUE]], &parseOk );
if ( !parseOk )
{
if ( m_errorText )
m_errorText->append( QString( "CSV import: Failed to parse numeric value in line %1\n" )
.arg( QString::number( lineCount ) ) );
throw 0;
}
auto& samples = addressesAndData[addr];
samples.push_back( std::make_pair( dateTime.toTime_t(), value ) );
}
// ERROR VALUE
if ( expectErrorValue )
{
bool parseOk = true;
double value = QLocale::c().toDouble( dataItems[colIndexes[(size_t)CsvLineBasedColumnType::ERROR_VALUE]],
&parseOk );
if ( !parseOk ) value = DOUBLE_INF;
auto& samples = addressesAndData[errAddr];
samples.push_back( std::make_pair( dateTime.toTime_t(), value ) );
}
}
}
closeDataStream();
{
std::vector<Column> columnInfoList;
for ( const auto& item : addressesAndData )
{
auto samples = item.second;
// Sort samples by time
std::sort( samples.begin(), samples.end(), []( const Sample& s1, const Sample& s2 ) {
return s1.first < s2.first;
} );
// Copy
Column c = Column::createColumnInfoFromCsvData( item.first, "" );
c.dataType = Column::NUMERIC;
for ( const auto& sample : samples )
{
c.dateTimeValues.push_back( sample.first );
c.values.push_back( sample.second );
}
columnInfoList.push_back( c );
}
TableData td( "", "", columnInfoList );
m_tableData = td;
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QDateTime RifCsvUserDataParser::tryParseDateTime( const std::string& colData, const QString& format )
{
return RiaQDateTimeTools::fromString( QString::fromStdString( colData ), format );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifCsvUserDataParser::tryDetermineCellSeparator()
{
QTextStream* dataStream = openDataStream();
if ( !dataStream )
{
return "";
}
std::vector<QString> lines;
int iLine = 0;
while ( iLine < 10 && !dataStream->atEnd() )
{
QString line = dataStream->readLine();
if ( line.isEmpty() ) continue;
lines.push_back( line );
iLine++;
}
closeDataStream();
// Try different cell separators
int totColumnCountTab = 0;
int totColumnCountSemicolon = 0;
int totColumnCountComma = 0;
for ( const QString& line : lines )
{
totColumnCountTab += RifFileParseTools::splitLineAndTrim( line, "\t" ).size();
totColumnCountSemicolon += RifFileParseTools::splitLineAndTrim( line, ";" ).size();
totColumnCountComma += RifFileParseTools::splitLineAndTrim( line, "," ).size();
}
double avgColumnCountTab = (double)totColumnCountTab / lines.size();
double avgColumnCountSemicolon = (double)totColumnCountSemicolon / lines.size();
double avgColumnCountComma = (double)totColumnCountComma / lines.size();
// Select the one having highest average
double maxAvg = std::max( std::max( avgColumnCountTab, avgColumnCountSemicolon ), avgColumnCountComma );
if ( maxAvg == avgColumnCountTab ) return "\t";
if ( maxAvg == avgColumnCountSemicolon ) return ";";
if ( maxAvg == avgColumnCountComma ) return ",";
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifCsvUserDataParser::tryDetermineDecimalSeparator( const QString& cellSeparator )
{
QTextStream* dataStream = openDataStream();
int iLine = 0;
int successfulParsesDot = 0;
int successfulParsesComma = 0;
while ( iLine < 10 && !dataStream->atEnd() )
{
QString line = dataStream->readLine();
if ( line.isEmpty() ) continue;
for ( const QString& cellData : RifFileParseTools::splitLineAndTrim( line, cellSeparator ) )
{
bool parseOk;
QLocale locale;
locale = localeFromDecimalSeparator( "." );
locale.toDouble( cellData, &parseOk );
if ( parseOk ) successfulParsesDot++;
locale = localeFromDecimalSeparator( "," );
locale.toDouble( cellData, &parseOk );
if ( parseOk ) successfulParsesComma++;
}
iLine++;
}
closeDataStream();
if ( successfulParsesComma > successfulParsesDot )
return ",";
else
return ".";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QLocale RifCsvUserDataParser::localeFromDecimalSeparator( const QString& decimalSeparator )
{
if ( decimalSeparator == "," )
{
return QLocale::Norwegian;
}
return QLocale::c();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvUserDataFileParser::RifCsvUserDataFileParser( const QString& fileName, QString* errorText )
: RifCsvUserDataParser( errorText )
{
m_fileName = fileName;
m_file = nullptr;
m_textStream = nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvUserDataFileParser::~RifCsvUserDataFileParser()
{
if ( m_textStream )
{
delete m_textStream;
}
closeFile();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QTextStream* RifCsvUserDataFileParser::openDataStream()
{
if ( !openFile() ) return nullptr;
m_textStream = new QTextStream( m_file );
return m_textStream;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifCsvUserDataFileParser::closeDataStream()
{
if ( m_textStream )
{
delete m_textStream;
m_textStream = nullptr;
}
closeFile();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifCsvUserDataFileParser::openFile()
{
if ( !m_file )
{
m_file = new QFile( m_fileName );
if ( !m_file->open( QIODevice::ReadOnly | QIODevice::Text ) )
{
RiaLogging::error( QString( "Failed to open %1" ).arg( m_fileName ) );
delete m_file;
m_file = nullptr;
return false;
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifCsvUserDataFileParser::closeFile()
{
if ( m_file )
{
m_file->close();
delete m_file;
m_file = nullptr;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvUserDataPastedTextParser::RifCsvUserDataPastedTextParser( const QString& text, QString* errorText )
: RifCsvUserDataParser( errorText )
{
m_text = text;
m_textStream = nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifCsvUserDataPastedTextParser::~RifCsvUserDataPastedTextParser()
{
if ( m_textStream )
{
delete m_textStream;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QTextStream* RifCsvUserDataPastedTextParser::openDataStream()
{
if ( m_textStream )
{
delete m_textStream;
}
m_textStream = new QTextStream( &m_text );
return m_textStream;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifCsvUserDataPastedTextParser::closeDataStream()
{
if ( m_textStream )
{
delete m_textStream;
m_textStream = nullptr;
}
}

View File

@@ -0,0 +1,129 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifEclipseSummaryAddress.h"
#include "RifEclipseUserDataParserTools.h"
#include <QDateTime>
#include <QFile>
#include <QLocale>
#include <QPointer>
#include <QString>
#include <QStringList>
#include <QTextStream>
#include <vector>
class Column;
class AsciiDataParseOptions;
//==================================================================================================
///
//==================================================================================================
class RifCsvUserDataParser
{
public:
enum CsvLayout
{
ColumnBased,
LineBased
};
public:
RifCsvUserDataParser( QString* errorText = nullptr );
virtual ~RifCsvUserDataParser();
bool parse( const AsciiDataParseOptions& parseOptions );
const TableData& tableData() const;
const Column* columnInfo( size_t columnIndex ) const;
const Column* dateTimeColumn() const;
bool parseColumnInfo( const AsciiDataParseOptions& parseOptions );
QString previewText( int lineCount, const AsciiDataParseOptions& parseOptions );
QStringList timeColumnPreviewData( int lineCount, const AsciiDataParseOptions& parseOptions );
CsvLayout determineCsvLayout();
QString tryDetermineCellSeparator();
QString tryDetermineDecimalSeparator( const QString& cellSeparator );
static QLocale localeFromDecimalSeparator( const QString& decimalSeparator );
protected:
virtual QTextStream* openDataStream() = 0;
virtual void closeDataStream() = 0;
private:
std::vector<int> parseLineBasedHeader( QStringList headerCols );
bool parseColumnInfo( QTextStream* dataStream,
const AsciiDataParseOptions& parseOptions,
std::vector<Column>* columnInfoList );
bool parseColumnBasedData( const AsciiDataParseOptions& parseOptions );
bool parseLineBasedData();
static QDateTime tryParseDateTime( const std::string& colData, const QString& format );
private:
TableData m_tableData;
QString* m_errorText;
};
//==================================================================================================
///
//==================================================================================================
class RifCsvUserDataFileParser : public RifCsvUserDataParser
{
public:
RifCsvUserDataFileParser( const QString& fileName, QString* errorText = nullptr );
~RifCsvUserDataFileParser() override;
protected:
QTextStream* openDataStream() override;
void closeDataStream() override;
private:
bool openFile();
void closeFile();
private:
QString m_fileName;
QFile* m_file;
QTextStream* m_textStream;
};
//==================================================================================================
///
//==================================================================================================
class RifCsvUserDataPastedTextParser : public RifCsvUserDataParser
{
public:
RifCsvUserDataPastedTextParser( const QString& text, QString* errorText = nullptr );
~RifCsvUserDataPastedTextParser() override;
protected:
QTextStream* openDataStream() override;
void closeDataStream() override;
private:
QString m_text;
QTextStream* m_textStream;
};

View File

@@ -0,0 +1,296 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifDataSourceForRftPlt.h"
#include "RimEclipseCase.h"
#include "RimObservedFmuRftData.h"
#include "RimSummaryCase.h"
#include "RimSummaryCaseCollection.h"
#include "RimWellLogFile.h"
#include "RimEclipseResultCase.h"
#include "cafAppEnum.h"
#include "cvfAssert.h"
#include <QString>
#include <QTextStream>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifDataSourceForRftPlt::RifDataSourceForRftPlt()
: m_sourceType( SourceType::NONE )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifDataSourceForRftPlt::RifDataSourceForRftPlt( SourceType sourceType, RimEclipseCase* eclCase )
{
CVF_ASSERT( sourceType == SourceType::RFT || sourceType == SourceType::GRID );
CVF_ASSERT( eclCase != nullptr );
m_sourceType = sourceType;
m_eclCase = eclCase;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifDataSourceForRftPlt::RifDataSourceForRftPlt( SourceType sourceType, RimWellLogFile* wellLogFile )
{
CVF_ASSERT( sourceType == SourceType::OBSERVED );
m_sourceType = sourceType;
m_wellLogFile = wellLogFile;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifDataSourceForRftPlt::RifDataSourceForRftPlt( SourceType sourceType, RimSummaryCaseCollection* ensemble )
{
CVF_ASSERT( sourceType == SourceType::ENSEMBLE_RFT );
m_sourceType = sourceType;
m_ensemble = ensemble;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifDataSourceForRftPlt::RifDataSourceForRftPlt( SourceType sourceType,
RimSummaryCase* summaryCase,
RimSummaryCaseCollection* ensemble )
{
CVF_ASSERT( sourceType == SourceType::SUMMARY_RFT );
m_sourceType = sourceType;
m_summaryCase = summaryCase;
m_ensemble = ensemble;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifDataSourceForRftPlt::RifDataSourceForRftPlt( SourceType sourceType, RimObservedFmuRftData* observedFmuRftData )
{
CVF_ASSERT( sourceType == SourceType::OBSERVED_FMU_RFT );
m_sourceType = sourceType;
m_observedFmuRftData = observedFmuRftData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifDataSourceForRftPlt::SourceType RifDataSourceForRftPlt::sourceType() const
{
return m_sourceType;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEclipseCase* RifDataSourceForRftPlt::eclCase() const
{
return m_eclCase;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderRftInterface* RifDataSourceForRftPlt::rftReader() const
{
if ( m_sourceType == RFT )
{
auto eclResCase = dynamic_cast<RimEclipseResultCase*>( m_eclCase.p() );
if ( eclResCase ) return eclResCase->rftReader();
}
else if ( m_sourceType == SUMMARY_RFT )
{
if ( m_summaryCase ) return m_summaryCase->rftReader();
}
else if ( m_sourceType == ENSEMBLE_RFT )
{
if ( m_ensemble ) return m_ensemble->rftStatisticsReader();
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryCaseCollection* RifDataSourceForRftPlt::ensemble() const
{
return m_ensemble;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryCase* RifDataSourceForRftPlt::summaryCase() const
{
return m_summaryCase;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimWellLogFile* RifDataSourceForRftPlt::wellLogFile() const
{
return m_wellLogFile;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimObservedFmuRftData* RifDataSourceForRftPlt::observedFmuRftData() const
{
return m_observedFmuRftData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifDataSourceForRftPlt::sourceTypeUiText( SourceType sourceType )
{
switch ( sourceType )
{
case SourceType::RFT:
return QString( "RFT File Cases" );
case SourceType::GRID:
return QString( "Grid Cases" );
case SourceType::OBSERVED:
return QString( "Observed Data" );
case SourceType::ENSEMBLE_RFT:
return QString( "Ensembles with RFT Data" );
case SourceType::SUMMARY_RFT:
return QString( "Summary case with RFT Data" );
case SourceType::OBSERVED_FMU_RFT:
return QString( "Observed FMU data" );
}
return QString();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool operator==( const RifDataSourceForRftPlt& addr1, const RifDataSourceForRftPlt& addr2 )
{
return addr1.sourceType() == addr2.sourceType() && addr1.eclCase() == addr2.eclCase() &&
addr1.wellLogFile() == addr2.wellLogFile() && addr1.summaryCase() == addr2.summaryCase() &&
addr1.ensemble() == addr2.ensemble() && addr1.observedFmuRftData() == addr2.observedFmuRftData();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QTextStream& operator<<( QTextStream& str, const RifDataSourceForRftPlt& addr )
{
// Not implemented
CVF_ASSERT( false );
return str;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QTextStream& operator>>( QTextStream& str, RifDataSourceForRftPlt& source )
{
// Not implemented
CVF_ASSERT( false );
return str;
}
//--------------------------------------------------------------------------------------------------
/// This sort order controls the plot order in PLT plot. (Layer-wise)
/// Observed data is supposed to be the bottom layers (first)
//--------------------------------------------------------------------------------------------------
bool operator<( const RifDataSourceForRftPlt& addr1, const RifDataSourceForRftPlt& addr2 )
{
if ( addr1.m_sourceType != addr2.m_sourceType )
{
return addr1.m_sourceType < addr2.m_sourceType;
}
if ( addr1.m_sourceType == RifDataSourceForRftPlt::NONE ) return false; //
if ( addr1.m_sourceType == RifDataSourceForRftPlt::OBSERVED )
{
if ( addr1.wellLogFile() && addr2.wellLogFile() )
{
return addr1.wellLogFile()->fileName() < addr2.wellLogFile()->fileName();
}
return addr1.wellLogFile() < addr2.wellLogFile();
}
else if ( addr1.m_sourceType == RifDataSourceForRftPlt::SUMMARY_RFT )
{
if ( addr1.summaryCase() && addr2.summaryCase() )
{
if ( addr1.summaryCase()->displayCaseName() == addr2.summaryCase()->displayCaseName() )
{
if ( addr1.ensemble() && addr2.ensemble() )
{
return addr1.ensemble()->name() < addr2.ensemble()->name();
}
return addr1.ensemble() < addr2.ensemble();
}
return addr1.summaryCase()->displayCaseName() < addr2.summaryCase()->displayCaseName();
}
return addr1.summaryCase() < addr2.summaryCase();
}
else if ( addr1.m_sourceType == RifDataSourceForRftPlt::ENSEMBLE_RFT )
{
if ( addr1.ensemble() && addr2.ensemble() )
{
return addr1.ensemble()->name() < addr2.ensemble()->name();
}
return addr1.ensemble() < addr2.ensemble();
}
else if ( addr1.m_sourceType == RifDataSourceForRftPlt::OBSERVED_FMU_RFT )
{
if ( addr1.observedFmuRftData() && addr2.observedFmuRftData() )
{
return addr1.observedFmuRftData()->name() < addr2.observedFmuRftData()->name();
}
return addr1.observedFmuRftData() < addr2.observedFmuRftData();
}
else
{
if ( addr1.eclCase() && addr2.eclCase() )
{
return addr1.eclCase()->caseId() < addr2.eclCase()->caseId();
}
return addr1.eclCase() < addr2.eclCase();
}
}
#if 0
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool operator<(const RifWellRftAddress& addr1, const RifWellRftAddress& addr2)
{
return (addr1.m_sourceType < addr2.m_sourceType) ||
(addr1.m_sourceType == addr2.m_sourceType &&
addr1.eclCase() != nullptr && addr2.eclCase() != nullptr ? addr1.eclCase()->caseId() < addr2.eclCase()->caseId() :
addr1.wellLogFile() != nullptr && addr2.wellLogFile() != nullptr ? addr1.wellLogFile()->fileName() < addr2.wellLogFile()->fileName() :
addr1.wellLogFile() < addr2.wellLogFile());
}
#endif

View File

@@ -0,0 +1,89 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimViewWindow.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmPointer.h"
#include "cafPdmPtrField.h"
#include <QDate>
#include <QMetaType>
#include <QPointer>
class RimWellLogFile;
class RimEclipseCase;
class RifReaderRftInterface;
class RimSummaryCase;
class RimSummaryCaseCollection;
class RimObservedFmuRftData;
//==================================================================================================
///
///
//==================================================================================================
class RifDataSourceForRftPlt
{
public:
enum SourceType
{
NONE,
OBSERVED,
RFT,
GRID,
ENSEMBLE_RFT,
SUMMARY_RFT,
OBSERVED_FMU_RFT
};
RifDataSourceForRftPlt();
RifDataSourceForRftPlt( SourceType sourceType, RimEclipseCase* eclCase );
RifDataSourceForRftPlt( SourceType sourceType, RimSummaryCaseCollection* ensemble );
RifDataSourceForRftPlt( SourceType sourceType, RimSummaryCase* summaryCase, RimSummaryCaseCollection* ensemble );
RifDataSourceForRftPlt( SourceType sourceType, RimWellLogFile* wellLogFile = nullptr );
RifDataSourceForRftPlt( SourceType sourceType, RimObservedFmuRftData* observedFmuRftData );
SourceType sourceType() const;
RimEclipseCase* eclCase() const;
RifReaderRftInterface* rftReader() const;
RimSummaryCaseCollection* ensemble() const;
RimSummaryCase* summaryCase() const;
RimWellLogFile* wellLogFile() const;
RimObservedFmuRftData* observedFmuRftData() const;
static QString sourceTypeUiText( SourceType sourceType );
friend QTextStream& operator>>( QTextStream& str, RifDataSourceForRftPlt& addr );
friend bool operator<( const RifDataSourceForRftPlt& addr1, const RifDataSourceForRftPlt& addr2 );
private:
SourceType m_sourceType;
caf::PdmPointer<RimEclipseCase> m_eclCase;
caf::PdmPointer<RimSummaryCase> m_summaryCase;
caf::PdmPointer<RimSummaryCaseCollection> m_ensemble;
caf::PdmPointer<RimWellLogFile> m_wellLogFile;
caf::PdmPointer<RimObservedFmuRftData> m_observedFmuRftData;
};
bool operator==( const RifDataSourceForRftPlt& addr1, const RifDataSourceForRftPlt& addr2 );
QTextStream& operator<<( QTextStream& str, const RifDataSourceForRftPlt& addr );
QTextStream& operator>>( QTextStream& str, RifDataSourceForRftPlt& addr );
bool operator<( const RifDataSourceForRftPlt& addr1, const RifDataSourceForRftPlt& addr2 );

View File

@@ -0,0 +1,23 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifDataSourceForRftPlt.h"
#include <QMetaType>
Q_DECLARE_METATYPE( RifDataSourceForRftPlt );

View File

@@ -0,0 +1,104 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifDerivedEnsembleReader.h"
#include "RimDerivedSummaryCase.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifDerivedEnsembleReader::RifDerivedEnsembleReader( RimDerivedSummaryCase* derivedCase,
RifSummaryReaderInterface* sourceSummaryReader1,
RifSummaryReaderInterface* sourceSummaryReader2 )
{
CVF_ASSERT( derivedCase );
m_derivedCase = derivedCase;
if ( sourceSummaryReader1 )
{
m_allResultAddresses = sourceSummaryReader1->allResultAddresses();
m_allErrorAddresses = sourceSummaryReader1->allErrorAddresses();
}
if ( sourceSummaryReader2 )
{
for ( auto a : sourceSummaryReader2->allResultAddresses() )
{
m_allResultAddresses.insert( a );
}
for ( auto a : sourceSummaryReader2->allErrorAddresses() )
{
m_allErrorAddresses.insert( a );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<time_t>& RifDerivedEnsembleReader::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{
if ( !resultAddress.isValid() )
{
static std::vector<time_t> empty;
return empty;
}
if ( m_derivedCase->needsCalculation( resultAddress ) )
{
m_derivedCase->calculate( resultAddress );
}
return m_derivedCase->timeSteps( resultAddress );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifDerivedEnsembleReader::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{
if ( !resultAddress.isValid() ) return false;
if ( m_derivedCase->needsCalculation( resultAddress ) )
{
m_derivedCase->calculate( resultAddress );
}
auto dataValues = m_derivedCase->values( resultAddress );
values->clear();
values->reserve( dataValues.size() );
for ( auto val : dataValues )
values->push_back( val );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RifDerivedEnsembleReader::unitName( const RifEclipseSummaryAddress& resultAddress ) const
{
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaEclipseUnitTools::UnitSystem RifDerivedEnsembleReader::unitSystem() const
{
return RiaEclipseUnitTools::UnitSystem::UNITS_UNKNOWN;
}

View File

@@ -0,0 +1,44 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifEclipseSummaryAddress.h"
#include "RifSummaryReaderInterface.h"
class RimDerivedSummaryCase;
class RimSummaryCase;
//==================================================================================================
///
//==================================================================================================
class RifDerivedEnsembleReader : public RifSummaryReaderInterface
{
public:
RifDerivedEnsembleReader( RimDerivedSummaryCase* derivedCase,
RifSummaryReaderInterface* sourceSummaryReader1,
RifSummaryReaderInterface* sourceSummaryReader2 );
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;
RiaEclipseUnitTools::UnitSystem unitSystem() const override;
private:
RimDerivedSummaryCase* m_derivedCase;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,179 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "cvfCollection.h"
#include "cvfObject.h"
#include "RiaEclipseUnitTools.h"
#include "RifReaderInterface.h"
#include "RigFault.h"
#include "ert/ecl/ecl_kw.h"
#include <map>
#include <QString>
class RigEclipseCaseData;
class QFile;
//--------------------------------------------------------------------------------------------------
/// Structure used to cache file position of keywords
//--------------------------------------------------------------------------------------------------
struct RifKeywordAndFilePos
{
QString keyword;
qint64 filePos;
};
//==================================================================================================
//
// Class for access to Eclipse "keyword" files using libecl
//
//==================================================================================================
class RifEclipseInputFileTools : public cvf::Object
{
public:
RifEclipseInputFileTools();
~RifEclipseInputFileTools() override;
static bool
openGridFile( const QString& fileName, RigEclipseCaseData* eclipseCase, bool readFaultData, QString* errorMessages );
static bool exportGrid( const QString& gridFileName,
RigEclipseCaseData* eclipseCase,
bool exportInLocalCoordinates,
const cvf::UByteArray* cellVisibilityOverrideForActnum = nullptr,
const cvf::Vec3st& min = cvf::Vec3st::ZERO,
const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED,
const cvf::Vec3st& refinement = cvf::Vec3st( 1, 1, 1 ) );
static bool exportKeywords( const QString& resultFileName,
RigEclipseCaseData* eclipseCase,
const std::vector<QString>& keywords,
const QString& fileWriteMode,
const cvf::Vec3st& min = cvf::Vec3st::ZERO,
const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED,
const cvf::Vec3st& refinement = cvf::Vec3st( 1, 1, 1 ) );
static void saveFault( QString completeFilename,
const RigMainGrid* mainGrid,
const std::vector<RigFault::FaultFace>& faultFaces,
QString faultName,
const cvf::Vec3st& min = cvf::Vec3st::ZERO,
const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED,
const cvf::Vec3st& refinement = cvf::Vec3st( 1, 1, 1 ) );
static void saveFault( QTextStream& stream,
const RigMainGrid* mainGrid,
const std::vector<RigFault::FaultFace>& faultFaces,
QString faultName,
const cvf::Vec3st& min = cvf::Vec3st::ZERO,
const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED,
const cvf::Vec3st& refinement = cvf::Vec3st( 1, 1, 1 ) );
static void saveFaults( QTextStream& stream,
const RigMainGrid* mainGrid,
const cvf::Vec3st& min = cvf::Vec3st::ZERO,
const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED,
const cvf::Vec3st& refinement = cvf::Vec3st( 1, 1, 1 ) );
// Returns map of assigned resultName and Eclipse Keyword.
static std::map<QString, QString> readProperties( const QString& fileName, RigEclipseCaseData* eclipseCase );
static bool readProperty( const QString& fileName,
RigEclipseCaseData* eclipseCase,
const QString& eclipseKeyWord,
const QString& resultName );
static void readFaultsInGridSection( const QString& fileName,
cvf::Collection<RigFault>* faults,
std::vector<QString>* filenamesWithFaults,
const QString& faultIncludeFileAbsolutePathPrefix );
static void readFaults( const QString& fileName,
const std::vector<RifKeywordAndFilePos>& fileKeywords,
cvf::Collection<RigFault>* faults );
static void parseAndReadFaults( const QString& fileName, cvf::Collection<RigFault>* faults );
static void readFaults( QFile& data, qint64 filePos, cvf::Collection<RigFault>* faults, bool* isEditKeywordDetected );
static void findKeywordsOnFile( const QString& fileName, std::vector<RifKeywordAndFilePos>* keywords );
static void parseAndReadPathAliasKeyword( const QString& fileName,
std::vector<std::pair<QString, QString>>* pathAliasDefinitions );
static bool
readFaultsAndParseIncludeStatementsRecursively( QFile& file,
qint64 startPos,
const std::vector<std::pair<QString, QString>>& pathAliasDefinitions,
cvf::Collection<RigFault>* faults,
std::vector<QString>* filenamesWithFaults,
bool* isEditKeywordDetected,
const QString& faultIncludeFileAbsolutePathPrefix );
static bool readKeywordAndParseIncludeStatementsRecursively(
const QString& keyword,
const QString& keywordToStopParsing,
QFile& file,
qint64 startPos,
const std::vector<std::pair<QString, QString>>& pathAliasDefinitions,
QStringList* keywordDataContent,
std::vector<QString>* filenamesContainingKeyword,
bool* isEditKeywordDetected,
const QString& faultIncludeFileAbsolutePathPrefix // rename to
// includeStatementAbsolutePathPrefix
);
static void readKeywordDataContent( QFile& data, qint64 filePos, QStringList* textContent, bool* isEditKeywordDetected );
static RiaEclipseUnitTools::UnitSystem readUnitSystem( QFile& file, qint64 gridunitPos );
static cvf::StructGridInterface::FaceEnum faceEnumFromText( const QString& faceString );
private:
static bool readDataFromKeyword( ecl_kw_type* eclipseKeywordData,
RigEclipseCaseData* caseData,
const QString& resultName,
QString* errMsg );
static void findGridKeywordPositions( const std::vector<RifKeywordAndFilePos>& keywords,
qint64* coordPos,
qint64* zcornPos,
qint64* specgridPos,
qint64* actnumPos,
qint64* mapaxesPos,
qint64* gridunitPos );
static size_t findFaultByName( const cvf::Collection<RigFault>& faults, const QString& name );
static qint64 findKeyword( const QString& keyword, QFile& file, qint64 startPos );
static bool isValidDataKeyword( const QString& keyword );
static void writeFaultLine( QTextStream& stream,
QString faultName,
size_t i,
size_t j,
size_t startK,
size_t endK,
cvf::StructGridInterface::FaceType faceType );
static QString faultFaceText( cvf::StructGridInterface::FaceType faceType );
private:
static const std::vector<QString>& invalidPropertyDataKeywords();
};

View File

@@ -0,0 +1,292 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RifEclipseInputPropertyLoader.h"
#include "RifEclipseInputFileTools.h"
#include "RifReaderEclipseInput.h"
#include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigMainGrid.h"
#include "RimEclipseInputProperty.h"
#include "RimEclipseInputPropertyCollection.h"
#include "RimTools.h"
#include "cafProgressInfo.h"
#include <QFileInfo>
//--------------------------------------------------------------------------------------------------
/// Loads input property data from the gridFile and additional files
/// Creates new InputProperties if necessary, and flags the unused ones as obsolete
//--------------------------------------------------------------------------------------------------
void RifEclipseInputPropertyLoader::loadAndSyncronizeInputProperties( RimEclipseInputPropertyCollection* inputPropertyCollection,
RigEclipseCaseData* eclipseCaseData,
const std::vector<QString>& filenames,
bool allowImportOfFaults )
{
CVF_ASSERT( inputPropertyCollection );
CVF_ASSERT( eclipseCaseData );
CVF_ASSERT( eclipseCaseData->mainGrid()->gridPointDimensions() != cvf::Vec3st( 0, 0, 0 ) );
size_t inputPropCount = inputPropertyCollection->inputProperties.size();
caf::ProgressInfo progInfo( static_cast<int>( filenames.size() * inputPropCount ), "Reading Input properties" );
int i = 0;
for ( const QString& filename : filenames )
{
int progress = static_cast<int>( i * inputPropCount );
progInfo.setProgressDescription( filename );
QFileInfo fileNameInfo( filename );
bool isExistingFile = fileNameInfo.exists();
// Find all the keywords present on the file
std::set<QString> fileKeywordSet = extractKeywordsOnFile( filenames[i], isExistingFile );
readDataForEachInputProperty( inputPropertyCollection,
eclipseCaseData,
filename,
isExistingFile,
allowImportOfFaults,
&fileKeywordSet,
&progInfo,
progress );
progInfo.setProgress( static_cast<int>( progress + inputPropCount ) );
// Check if there are more known property keywords left on file.
// If it is, read them and create inputProperty objects
readInputPropertiesForRemainingKeywords( inputPropertyCollection, eclipseCaseData, filename, &fileKeywordSet );
i++;
}
// All input properties still unknown at this stage is missing a file
setResolvedState( inputPropertyCollection, RimEclipseInputProperty::UNKNOWN, RimEclipseInputProperty::FILE_MISSING );
}
//--------------------------------------------------------------------------------------------------
/// Loads input property data from additional files.
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputPropertyLoader::readInputPropertiesFromFiles( RimEclipseInputPropertyCollection* inputPropertyCollection,
RigEclipseCaseData* eclipseCaseData,
bool importFaults,
const std::vector<QString>& filenames )
{
for ( const QString& propertyFileName : filenames )
{
std::map<QString, QString> readProperties =
RifEclipseInputFileTools::readProperties( propertyFileName, eclipseCaseData );
std::map<QString, QString>::iterator it;
for ( it = readProperties.begin(); it != readProperties.end(); ++it )
{
RimEclipseInputProperty* inputProperty = new RimEclipseInputProperty;
inputProperty->resultName = it->first;
inputProperty->eclipseKeyword = it->second;
inputProperty->fileName = propertyFileName;
inputProperty->resolvedState = RimEclipseInputProperty::RESOLVED;
inputPropertyCollection->inputProperties.push_back( inputProperty );
}
if ( importFaults )
{
bool anyFaultsImported = importFaultsFromFile( eclipseCaseData, propertyFileName );
if ( anyFaultsImported )
{
RimEclipseInputProperty* inputProperty = new RimEclipseInputProperty;
inputProperty->resultName = "FAULTS";
inputProperty->eclipseKeyword = "FAULTS";
inputProperty->fileName = propertyFileName;
inputProperty->resolvedState = RimEclipseInputProperty::RESOLVED;
inputPropertyCollection->inputProperties.push_back( inputProperty );
}
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputPropertyLoader::importFaultsFromFile( RigEclipseCaseData* eclipseCaseData, const QString& fileName )
{
cvf::Collection<RigFault> faultCollectionFromFile;
RifEclipseInputFileTools::parseAndReadFaults( fileName, &faultCollectionFromFile );
if ( faultCollectionFromFile.empty() )
{
return false;
}
cvf::Collection<RigFault> faults;
{
cvf::Collection<RigFault> faultCollection = eclipseCaseData->mainGrid()->faults();
for ( size_t i = 0; i < faultCollection.size(); i++ )
{
RigFault* f = faultCollection.at( i );
if ( f->name() == RiaDefines::undefinedGridFaultName() || f->name() == RiaDefines::undefinedGridFaultName() )
{
// Do not include undefined grid faults, as these are recomputed based on the imported faults from filesa
continue;
}
faults.push_back( f );
}
}
for ( size_t i = 0; i < faultCollectionFromFile.size(); i++ )
{
RigFault* faultFromFile = faultCollectionFromFile.at( i );
bool existFaultWithSameName = false;
for ( size_t j = 0; j < faults.size(); j++ )
{
RigFault* existingFault = faults.at( j );
if ( existingFault->name() == faultFromFile->name() )
{
existFaultWithSameName = true;
}
}
if ( !existFaultWithSameName )
{
faults.push_back( faultFromFile );
}
}
eclipseCaseData->mainGrid()->setFaults( faults );
return true;
}
//--------------------------------------------------------------------------------------------------
/// Extract keywords from a input property file.
//--------------------------------------------------------------------------------------------------
std::set<QString> RifEclipseInputPropertyLoader::extractKeywordsOnFile( const QString& filename, bool isExistingFile )
{
std::set<QString> fileKeywordSet;
if ( isExistingFile )
{
std::vector<RifKeywordAndFilePos> fileKeywords;
RifEclipseInputFileTools::findKeywordsOnFile( filename, &fileKeywords );
for ( const RifKeywordAndFilePos& fileKeyword : fileKeywords )
{
fileKeywordSet.insert( fileKeyword.keyword );
}
}
return fileKeywordSet;
}
//--------------------------------------------------------------------------------------------------
/// Change the resolved state of all matching input properties in a collection.
//--------------------------------------------------------------------------------------------------
void RifEclipseInputPropertyLoader::setResolvedState( RimEclipseInputPropertyCollection* inputPropertyCollection,
RimEclipseInputProperty::ResolveState currentState,
RimEclipseInputProperty::ResolveState newState )
{
for ( RimEclipseInputProperty* inputProperty : inputPropertyCollection->inputProperties )
{
if ( inputProperty->resolvedState() == currentState )
{
inputProperty->resolvedState = newState;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputPropertyLoader::readDataForEachInputProperty( RimEclipseInputPropertyCollection* inputPropertyCollection,
RigEclipseCaseData* eclipseCaseData,
const QString& filename,
bool isExistingFile,
bool allowImportOfFaults,
std::set<QString>* fileKeywordSet,
caf::ProgressInfo* progressInfo,
int progressOffset )
{
// Find the input property objects referring to the file
std::vector<RimEclipseInputProperty*> ipsUsingThisFile = inputPropertyCollection->findInputProperties( filename );
// Read property data for each inputProperty
int progress = 0;
for ( RimEclipseInputProperty* inputProperty : ipsUsingThisFile )
{
if ( !isExistingFile )
{
inputProperty->resolvedState = RimEclipseInputProperty::FILE_MISSING;
}
else
{
inputProperty->resolvedState = RimEclipseInputProperty::KEYWORD_NOT_IN_FILE;
QString kw = inputProperty->eclipseKeyword();
if ( kw == "FAULTS" )
{
if ( allowImportOfFaults )
{
importFaultsFromFile( eclipseCaseData, filename );
}
}
else
{
if ( fileKeywordSet->count( kw ) )
{
if ( RifEclipseInputFileTools::readProperty( filename, eclipseCaseData, kw, inputProperty->resultName ) )
{
inputProperty->resolvedState = RimEclipseInputProperty::RESOLVED;
}
}
fileKeywordSet->erase( kw );
}
}
progressInfo->setProgress( static_cast<int>( progressOffset + progress ) );
progress++;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputPropertyLoader::readInputPropertiesForRemainingKeywords( RimEclipseInputPropertyCollection* inputPropertyCollection,
RigEclipseCaseData* eclipseCaseData,
const QString& filename,
std::set<QString>* fileKeywordSet )
{
for ( const QString& fileKeyword : *fileKeywordSet )
{
QString resultName =
eclipseCaseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->makeResultNameUnique( fileKeyword );
if ( RifEclipseInputFileTools::readProperty( filename, eclipseCaseData, fileKeyword, resultName ) )
{
RimEclipseInputProperty* inputProperty = new RimEclipseInputProperty;
inputProperty->resultName = resultName;
inputProperty->eclipseKeyword = fileKeyword;
inputProperty->fileName = filename;
inputProperty->resolvedState = RimEclipseInputProperty::RESOLVED;
inputPropertyCollection->inputProperties.push_back( inputProperty );
}
}
}

View File

@@ -0,0 +1,78 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RimEclipseInputProperty.h"
#include <set>
#include <vector>
#include <QString>
class RimEclipseInputPropertyCollection;
class RigEclipseCaseData;
namespace caf
{
class ProgressInfo;
}
//==================================================================================================
//
//
//
//==================================================================================================
class RifEclipseInputPropertyLoader
{
public:
static void loadAndSyncronizeInputProperties( RimEclipseInputPropertyCollection* inputPropertyCollection,
RigEclipseCaseData* eclipseCaseData,
const std::vector<QString>& filenames,
bool allowImportOfFaults );
static bool readInputPropertiesFromFiles( RimEclipseInputPropertyCollection* inputPropertyCollection,
RigEclipseCaseData* eclipseCaseData,
bool importFaults,
const std::vector<QString>& filenames );
static bool importFaultsFromFile( RigEclipseCaseData* eclipseCase, const QString& fileName );
private:
// Hide constructor to prevent instantiation
RifEclipseInputPropertyLoader();
static std::set<QString> extractKeywordsOnFile( const QString& filename, bool isExistingFile );
static void setResolvedState( RimEclipseInputPropertyCollection* inputPropertyCollection,
RimEclipseInputProperty::ResolveState currentState,
RimEclipseInputProperty::ResolveState newState );
static void readDataForEachInputProperty( RimEclipseInputPropertyCollection* inputPropertyCollection,
RigEclipseCaseData* eclipseCaseData,
const QString& filename,
bool isExistingFile,
bool allowImportOfFaults,
std::set<QString>* fileKeywordSet,
caf::ProgressInfo* progressInfo,
int progressOffset );
static void readInputPropertiesForRemainingKeywords( RimEclipseInputPropertyCollection* inputPropertyCollection,
RigEclipseCaseData* eclipseCaseData,
const QString& filename,
std::set<QString>* fileKeywordSet );
};

View File

@@ -0,0 +1,710 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RifEclipseOutputFileTools.h"
#include "RiaQDateTimeTools.h"
#include "RiaStringEncodingTools.h"
#include "RifEclipseRestartFilesetAccess.h"
#include "RifEclipseUnifiedRestartFileAccess.h"
#include "ert/ecl/ecl_file.h"
#include "ert/ecl/ecl_grid.h"
#include "ert/ecl/ecl_kw_magic.h"
#include "ert/ecl/ecl_nnc_data.h"
#include "ert/ecl/ecl_nnc_geometry.h"
#include "cafProgressInfo.h"
#include "cvfMath.h"
#include <QCryptographicHash>
#include <QDebug>
#include <QFileInfo>
#include <algorithm>
#include <cassert>
//--------------------------------------------------------------------------------------------------
/// Constructor
//--------------------------------------------------------------------------------------------------
RifEclipseOutputFileTools::RifEclipseOutputFileTools()
{
}
//--------------------------------------------------------------------------------------------------
/// Destructor
//--------------------------------------------------------------------------------------------------
RifEclipseOutputFileTools::~RifEclipseOutputFileTools()
{
}
struct KeywordItemCounter
{
KeywordItemCounter( const std::string& keyword, size_t aggregatedItemCount )
: m_keyword( keyword )
, m_aggregatedItemCount( aggregatedItemCount )
, m_reportStepCount( 1 )
{
}
bool operator==( const std::string& rhs ) const { return this->m_keyword == rhs; }
std::string m_keyword;
size_t m_aggregatedItemCount;
size_t m_reportStepCount;
};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseOutputFileTools::findKeywordsAndItemCount( std::vector<ecl_file_type*> ecl_files,
QStringList* resultNames,
std::vector<size_t>* resultDataItemCounts )
{
std::vector<RifRestartReportStep> reportSteps;
RifEclipseOutputFileTools::createReportStepsMetaData( ecl_files, &reportSteps );
std::vector<KeywordItemCounter> foundKeywords;
for ( auto reportStep : reportSteps )
{
for ( auto keywordItemCount : reportStep.m_keywords.keywordsWithAggregatedItemCount() )
{
auto it = std::find( foundKeywords.begin(), foundKeywords.end(), keywordItemCount.first );
if ( it == foundKeywords.end() )
{
foundKeywords.push_back( KeywordItemCounter( keywordItemCount.first, keywordItemCount.second ) );
}
else
{
it->m_aggregatedItemCount += keywordItemCount.second;
it->m_reportStepCount++;
}
}
}
for ( auto stdKeyword : foundKeywords )
{
resultNames->push_back( QString::fromStdString( stdKeyword.m_keyword ) );
resultDataItemCounts->push_back( stdKeyword.m_aggregatedItemCount );
}
}
void getDayMonthYear( const ecl_kw_type* intehead_kw, int* day, int* month, int* year )
{
assert( day && month && year );
*day = ecl_kw_iget_int( intehead_kw, INTEHEAD_DAY_INDEX );
*month = ecl_kw_iget_int( intehead_kw, INTEHEAD_MONTH_INDEX );
*year = ecl_kw_iget_int( intehead_kw, INTEHEAD_YEAR_INDEX );
}
//--------------------------------------------------------------------------------------------------
/// Get list of time step texts (dates)
//--------------------------------------------------------------------------------------------------
void RifEclipseOutputFileTools::timeSteps( const ecl_file_type* ecl_file,
std::vector<QDateTime>* timeSteps,
std::vector<double>* daysSinceSimulationStart,
size_t* perTimeStepHeaderKeywordCount )
{
if ( !ecl_file ) return;
CVF_ASSERT( timeSteps && daysSinceSimulationStart );
timeSteps->clear();
daysSinceSimulationStart->clear();
// Get the number of occurrences of the INTEHEAD keyword
int numINTEHEAD = ecl_file_get_num_named_kw( ecl_file, INTEHEAD_KW );
// Get the number of occurrences of the DOUBHEAD keyword
int numDOUBHEAD = ecl_file_get_num_named_kw( ecl_file, DOUBHEAD_KW );
std::vector<double> dayValues( numINTEHEAD, 0.0 ); // Init fraction to zero
// Read out fraction of day if number of keywords are identical
if ( numINTEHEAD == numDOUBHEAD )
{
for ( int i = 0; i < numDOUBHEAD; i++ )
{
ecl_kw_type* kwDOUBHEAD = ecl_file_iget_named_kw( ecl_file, DOUBHEAD_KW, i );
if ( kwDOUBHEAD )
{
dayValues[i] = ecl_kw_iget_double( kwDOUBHEAD, DOUBHEAD_DAYS_INDEX );
}
}
}
bool useStartOfSimulationDate = true;
{
// See https://github.com/OPM/ResInsight/issues/4770
std::set<std::tuple<int, int, int>> uniqueDays;
for ( int i = 0; i < numINTEHEAD; i++ )
{
ecl_kw_type* kwINTEHEAD = ecl_file_iget_named_kw( ecl_file, INTEHEAD_KW, i );
CVF_ASSERT( kwINTEHEAD );
int day = 0;
int month = 0;
int year = 0;
getDayMonthYear( kwINTEHEAD, &day, &month, &year );
uniqueDays.insert( std::make_tuple( day, month, year ) );
}
std::set<double> uniqueDayValues;
for ( auto dayValue : dayValues )
{
uniqueDayValues.insert( dayValue );
}
if ( uniqueDays.size() == 1 && uniqueDayValues.size() == 1 )
{
int day = 0;
int month = 0;
int year = 0;
std::tie( day, month, year ) = *( uniqueDays.begin() );
QDateTime reportDateTime = RiaQDateTimeTools::createUtcDateTime( QDate( year, month, day ) );
timeSteps->push_back( reportDateTime );
daysSinceSimulationStart->push_back( *uniqueDayValues.begin() );
// Early return, we have only one unique time step
// This state has been seen for cases with one file for each time step
// See https://github.com/OPM/ResInsight/issues/4904
return;
}
// Some simulations might end up with wrong data reported for day/month/year. If this situation is detected,
// base all time step on double values and use start of simulation as first date
// See https://github.com/OPM/ResInsight/issues/4850
if ( uniqueDays.size() == dayValues.size() ) useStartOfSimulationDate = false;
}
std::set<QDateTime> existingTimesteps;
for ( int i = 0; i < numINTEHEAD; i++ )
{
ecl_kw_type* kwINTEHEAD = nullptr;
if ( useStartOfSimulationDate )
{
kwINTEHEAD = ecl_file_iget_named_kw( ecl_file, INTEHEAD_KW, 0 );
}
else
{
kwINTEHEAD = ecl_file_iget_named_kw( ecl_file, INTEHEAD_KW, i );
}
CVF_ASSERT( kwINTEHEAD );
int day = 0;
int month = 0;
int year = 0;
getDayMonthYear( kwINTEHEAD, &day, &month, &year );
QDateTime reportDateTime = RiaQDateTimeTools::createUtcDateTime( QDate( year, month, day ) );
CVF_ASSERT( reportDateTime.isValid() );
double dayDoubleValue = dayValues[i];
int dayValue = cvf::Math::floor( dayDoubleValue );
if ( useStartOfSimulationDate )
{
reportDateTime = reportDateTime.addDays( dayValue );
}
double dayFraction = dayDoubleValue - dayValue;
double milliseconds = dayFraction * 24.0 * 60.0 * 60.0 * 1000.0;
reportDateTime = reportDateTime.addMSecs( milliseconds );
if ( existingTimesteps.insert( reportDateTime ).second )
{
timeSteps->push_back( reportDateTime );
daysSinceSimulationStart->push_back( dayDoubleValue );
}
}
if ( perTimeStepHeaderKeywordCount )
{
// 6X simulator can report more then one keyword block per time step. Report the total number of keywords per
// time steps to be able to read data from correct index
//
// See https://github.com/OPM/ResInsight/issues/5763
//
*perTimeStepHeaderKeywordCount = numINTEHEAD / timeSteps->size();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseOutputFileTools::keywordData( const ecl_file_type* ecl_file,
const QString& keyword,
size_t fileKeywordOccurrence,
std::vector<double>* values )
{
bool result = false;
#pragma omp critical( critical_section_keywordData_double )
{
ecl_kw_type* kwData = ecl_file_iget_named_kw( ecl_file,
RiaStringEncodingTools::toNativeEncoded( keyword ).data(),
static_cast<int>( fileKeywordOccurrence ) );
if ( kwData )
{
size_t numValues = ecl_kw_get_size( kwData );
std::vector<double> doubleData;
doubleData.resize( numValues );
ecl_kw_get_data_as_double( kwData, doubleData.data() );
values->insert( values->end(), doubleData.begin(), doubleData.end() );
result = true;
}
}
return result;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseOutputFileTools::keywordData( const ecl_file_type* ecl_file,
const QString& keyword,
size_t fileKeywordOccurrence,
std::vector<int>* values )
{
bool result = false;
#pragma omp critical( critical_section_keywordData_int )
{
ecl_kw_type* kwData = ecl_file_iget_named_kw( ecl_file,
RiaStringEncodingTools::toNativeEncoded( keyword ).data(),
static_cast<int>( fileKeywordOccurrence ) );
if ( kwData )
{
size_t numValues = ecl_kw_get_size( kwData );
std::vector<int> integerData;
integerData.resize( numValues );
ecl_kw_get_memcpy_int_data( kwData, integerData.data() );
values->insert( values->end(), integerData.begin(), integerData.end() );
result = true;
}
}
return result;
}
//--------------------------------------------------------------------------------------------------
/// Get first occurrence of file of given type in given list of filenames, as filename or nullptr if not found
//--------------------------------------------------------------------------------------------------
QString RifEclipseOutputFileTools::firstFileNameOfType( const QStringList& fileSet, ecl_file_enum fileType )
{
int i;
for ( i = 0; i < fileSet.count(); i++ )
{
bool formatted = false;
int reportNumber = -1;
if ( ecl_util_get_file_type( RiaStringEncodingTools::toNativeEncoded( fileSet.at( i ) ).data(),
&formatted,
&reportNumber ) == fileType )
{
return fileSet.at( i );
}
}
return QString();
}
//--------------------------------------------------------------------------------------------------
/// Get all files of the given type from the provided list of filenames
//--------------------------------------------------------------------------------------------------
QStringList RifEclipseOutputFileTools::filterFileNamesOfType( const QStringList& fileSet, ecl_file_enum fileType )
{
QStringList fileNames;
int i;
for ( i = 0; i < fileSet.count(); i++ )
{
bool formatted = false;
int reportNumber = -1;
if ( ecl_util_get_file_type( RiaStringEncodingTools::toNativeEncoded( fileSet.at( i ) ).data(),
&formatted,
&reportNumber ) == fileType )
{
fileNames.append( fileSet.at( i ) );
}
}
return fileNames;
}
//-------------------------------------------------------------------------------------------------------
/// Check if libecl accepts the file name. libecl refuses to open files with mixed case in the file name.
//-------------------------------------------------------------------------------------------------------
bool RifEclipseOutputFileTools::isValidEclipseFileName( const QString& fileName )
{
QString fileNameBase = QFileInfo( fileName ).completeBaseName();
return ecl_util_valid_basename( RiaStringEncodingTools::toNativeEncoded( fileNameBase ).data() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QByteArray RifEclipseOutputFileTools::md5sum( const QString& fileName )
{
QFile file( fileName );
if ( file.open( QFile::ReadOnly ) )
{
QCryptographicHash hash( QCryptographicHash::Md5 );
QByteArray fileContent = file.readAll();
if ( !fileContent.isEmpty() )
{
hash.addData( fileContent );
return hash.result();
}
}
return QByteArray();
}
//--------------------------------------------------------------------------------------------------
/// Get set of Eclipse files based on an input file and its path
//--------------------------------------------------------------------------------------------------
bool RifEclipseOutputFileTools::findSiblingFilesWithSameBaseName( const QString& fullPathFileName,
QStringList* baseNameFiles )
{
CVF_ASSERT( baseNameFiles );
baseNameFiles->clear();
QString filePath = QFileInfo( fullPathFileName ).absoluteFilePath();
filePath = QFileInfo( filePath ).path();
QString fileNameBase = QFileInfo( fullPathFileName ).completeBaseName();
stringlist_type* eclipseFiles = stringlist_alloc_new();
ecl_util_select_filelist( RiaStringEncodingTools::toNativeEncoded( filePath ).data(),
RiaStringEncodingTools::toNativeEncoded( fileNameBase ).data(),
ECL_OTHER_FILE,
false,
eclipseFiles );
int i;
for ( i = 0; i < stringlist_get_size( eclipseFiles ); i++ )
{
baseNameFiles->append( RiaStringEncodingTools::fromNativeEncoded( stringlist_safe_iget( eclipseFiles, i ) ) );
}
stringlist_free( eclipseFiles );
return baseNameFiles->count() > 0;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseOutputFileTools::readGridDimensions( const QString& gridFileName,
std::vector<std::vector<int>>& gridDimensions )
{
ecl_grid_type* grid = ecl_grid_alloc( RiaStringEncodingTools::toNativeEncoded( gridFileName ).data() ); // bootstrap
// ecl_grid
// instance
stringlist_type* lgr_names = ecl_grid_alloc_lgr_name_list( grid ); // get a list of all the lgr names.
// printf("grid:%s has %d a total of %d lgr's \n", grid_filename , stringlist_get_size( lgr_names ));
for ( int lgr_nr = 0; lgr_nr < stringlist_get_size( lgr_names ); lgr_nr++ )
{
ecl_grid_type* lgr_grid = ecl_grid_get_lgr( grid,
stringlist_iget( lgr_names,
lgr_nr ) ); // get the ecl_grid instance of the lgr
// - by name.
int nx, ny, nz, active_size;
ecl_grid_get_dims( lgr_grid, &nx, &ny, &nz, &active_size ); // get some size info from this lgr.
std::vector<int> values;
values.push_back( nx );
values.push_back( ny );
values.push_back( nz );
values.push_back( active_size );
gridDimensions.push_back( values );
}
ecl_grid_free( grid );
stringlist_free( lgr_names );
}
//--------------------------------------------------------------------------------------------------
/// Returns the following integer values from the first INTEHEAD keyword found
/// 1 : METRIC
/// 2 : FIELD
/// 3 : LAB
/// -1 : No INTEHEAD keyword found
//--------------------------------------------------------------------------------------------------
int RifEclipseOutputFileTools::readUnitsType( const ecl_file_type* ecl_file )
{
int unitsType = -1;
if ( ecl_file )
{
ecl_kw_type* kwINTEHEAD = ecl_file_iget_named_kw( ecl_file, INTEHEAD_KW, 0 );
if ( kwINTEHEAD )
{
unitsType = ecl_kw_iget_int( kwINTEHEAD, INTEHEAD_UNIT_INDEX );
}
}
return unitsType;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<RifEclipseRestartDataAccess> RifEclipseOutputFileTools::createDynamicResultAccess( const QString& fileName )
{
QStringList filesWithSameBaseName;
RifEclipseOutputFileTools::findSiblingFilesWithSameBaseName( fileName, &filesWithSameBaseName );
cvf::ref<RifEclipseRestartDataAccess> resultsAccess;
// Look for unified restart file
QString unrstFileName =
RifEclipseOutputFileTools::firstFileNameOfType( filesWithSameBaseName, ECL_UNIFIED_RESTART_FILE );
if ( unrstFileName.size() > 0 )
{
resultsAccess = new RifEclipseUnifiedRestartFileAccess();
resultsAccess->setRestartFiles( QStringList( unrstFileName ) );
}
else
{
// Look for set of restart files (one file per time step)
QStringList restartFiles =
RifEclipseOutputFileTools::filterFileNamesOfType( filesWithSameBaseName, ECL_RESTART_FILE );
if ( restartFiles.size() > 0 )
{
resultsAccess = new RifEclipseRestartFilesetAccess();
resultsAccess->setRestartFiles( restartFiles );
}
}
return resultsAccess;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifEclipseOutputFileTools::createIndexFileName( const QString& resultFileName )
{
QFileInfo fi( resultFileName );
QString indexFileName = fi.path() + "/" + fi.completeBaseName() + ".RESINSIGHT_IDX";
return indexFileName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RiaDefines::PhaseType> RifEclipseOutputFileTools::findAvailablePhases( const ecl_file_type* ecl_file )
{
std::set<RiaDefines::PhaseType> phaseTypes;
if ( ecl_file )
{
const ecl_kw_type* intehead = ecl_file_iget_named_kw( ecl_file, INTEHEAD_KW, 0 );
if ( intehead )
{
int phases = ecl_kw_iget_int( intehead, INTEHEAD_PHASE_INDEX );
if ( phases & ECL_OIL_PHASE )
{
phaseTypes.insert( RiaDefines::PhaseType::OIL_PHASE );
}
if ( phases & ECL_GAS_PHASE )
{
phaseTypes.insert( RiaDefines::PhaseType::GAS_PHASE );
}
if ( phases & ECL_WATER_PHASE )
{
phaseTypes.insert( RiaDefines::PhaseType::WATER_PHASE );
}
}
}
return phaseTypes;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseOutputFileTools::transferNncFluxData( const ecl_grid_type* grid,
const ecl_file_view_type* summaryView,
std::vector<double>* waterFlux,
std::vector<double>* oilFlux,
std::vector<double>* gasFlux )
{
ecl_nnc_geometry_type* nnc_geo = ecl_nnc_geometry_alloc( grid );
if ( nnc_geo )
{
ecl_nnc_data_type* waterFluxData = ecl_nnc_data_alloc_wat_flux( grid, nnc_geo, summaryView );
if ( waterFluxData )
{
const double* waterFluxValues = ecl_nnc_data_get_values( waterFluxData );
waterFlux->insert( waterFlux->end(),
&waterFluxValues[0],
&waterFluxValues[ecl_nnc_data_get_size( waterFluxData )] );
ecl_nnc_data_free( waterFluxData );
}
ecl_nnc_data_type* oilFluxData = ecl_nnc_data_alloc_oil_flux( grid, nnc_geo, summaryView );
if ( oilFluxData )
{
const double* oilFluxValues = ecl_nnc_data_get_values( oilFluxData );
oilFlux->insert( oilFlux->end(), &oilFluxValues[0], &oilFluxValues[ecl_nnc_data_get_size( oilFluxData )] );
ecl_nnc_data_free( oilFluxData );
}
ecl_nnc_data_type* gasFluxData = ecl_nnc_data_alloc_gas_flux( grid, nnc_geo, summaryView );
if ( gasFluxData )
{
const double* gasFluxValues = ecl_nnc_data_get_values( gasFluxData );
gasFlux->insert( gasFlux->end(), &gasFluxValues[0], &gasFluxValues[ecl_nnc_data_get_size( gasFluxData )] );
ecl_nnc_data_free( gasFluxData );
}
ecl_nnc_geometry_free( nnc_geo );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseOutputFileTools::isExportedFromIntersect( const ecl_file_type* ecl_file )
{
// This code is taken from ecl_file_get_ecl_version() in ecl_file.cpp
ecl_kw_type* intehead_kw = ecl_file_iget_named_kw( ecl_file, INTEHEAD_KW, 0 );
if ( !intehead_kw ) return false;
int int_value = ecl_kw_iget_int( intehead_kw, INTEHEAD_IPROG_INDEX );
if ( int_value == INTEHEAD_INTERSECT_VALUE )
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
/// Convenience method to hide C fopen calls in #pragma declarations to avoid warnings on Windows
//--------------------------------------------------------------------------------------------------
FILE* RifEclipseOutputFileTools::fopen( const QString& filePath, const QString& mode )
{
#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable : 4996 )
#endif
FILE* filePtr = std::fopen( RiaStringEncodingTools::toNativeEncoded( filePath ).data(),
RiaStringEncodingTools::toNativeEncoded( mode ).data() );
#ifdef _MSC_VER
#pragma warning( pop )
#endif
return filePtr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseOutputFileTools::createReportStepsMetaData( std::vector<ecl_file_type*> ecl_files,
std::vector<RifRestartReportStep>* reportSteps )
{
if ( !reportSteps ) return;
for ( auto ecl_file : ecl_files )
{
if ( !ecl_file ) continue;
int reportStepCount = ecl_file_get_num_named_kw( ecl_file, INTEHEAD_KW );
for ( int reportStepIndex = 0; reportStepIndex < reportStepCount; reportStepIndex++ )
{
ecl_file_view_type* rst_view = ecl_file_get_global_view( ecl_file );
if ( !rst_view ) continue;
ecl_rsthead_type* restart_header = ecl_rsthead_alloc( rst_view, reportStepIndex );
if ( restart_header )
{
ecl_file_push_block( ecl_file );
{
ecl_file_select_block( ecl_file, INTEHEAD_KW, reportStepIndex );
RifRestartReportStep reportStep;
// Set Date
{
QDateTime reportDateTime(
QDate( restart_header->year, restart_header->month, restart_header->day ) );
reportStep.dateTime = reportDateTime;
}
// Find number of keywords within this report step
int numKeywords = ecl_file_get_num_distinct_kw( ecl_file );
for ( int iKey = 0; iKey < numKeywords; iKey++ )
{
const char* kw = ecl_file_iget_distinct_kw( ecl_file, iKey );
int namedKeywordCount = ecl_file_get_num_named_kw( ecl_file, kw );
for ( int iOcc = 0; iOcc < namedKeywordCount; iOcc++ )
{
ecl_data_type dataType = ecl_file_iget_named_data_type( ecl_file, kw, iOcc );
ecl_type_enum dataTypeEmum = ecl_type_get_type( dataType );
if ( dataTypeEmum != ECL_DOUBLE_TYPE && dataTypeEmum != ECL_FLOAT_TYPE &&
dataTypeEmum != ECL_INT_TYPE )
{
continue;
}
int itemCount = ecl_file_iget_named_size( ecl_file, kw, iOcc );
reportStep.m_keywords.appendKeyword( kw, itemCount, iOcc );
}
}
reportSteps->push_back( reportStep );
}
ecl_file_pop_block( ecl_file );
ecl_rsthead_free( restart_header );
}
}
}
}

View File

@@ -0,0 +1,99 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RifEclipseRestartDataAccess.h"
#include "ert/ecl/ecl_util.h"
#include "cvfObject.h"
#include <QDateTime>
#include <QString>
#include <QStringList>
#include <vector>
typedef struct ecl_file_struct ecl_file_type;
class RifEclipseRestartDataAccess;
class QByteArray;
//==================================================================================================
//
//
//
//==================================================================================================
class RifEclipseOutputFileTools
{
public:
RifEclipseOutputFileTools();
virtual ~RifEclipseOutputFileTools();
static void findKeywordsAndItemCount( std::vector<ecl_file_type*> ecl_files,
QStringList* resultNames,
std::vector<size_t>* resultDataItemCounts );
static bool keywordData( const ecl_file_type* ecl_file,
const QString& keyword,
size_t fileKeywordOccurrence,
std::vector<double>* values );
static bool keywordData( const ecl_file_type* ecl_file,
const QString& keyword,
size_t fileKeywordOccurrence,
std::vector<int>* values );
static void timeSteps( const ecl_file_type* ecl_file,
std::vector<QDateTime>* timeSteps,
std::vector<double>* daysSinceSimulationStart,
size_t* perTimeStepHeaderKeywordCount );
static bool isValidEclipseFileName( const QString& fileName );
static QByteArray md5sum( const QString& fileName );
static bool findSiblingFilesWithSameBaseName( const QString& fileName, QStringList* fileSet );
static QString firstFileNameOfType( const QStringList& fileSet, ecl_file_enum fileType );
static QStringList filterFileNamesOfType( const QStringList& fileSet, ecl_file_enum fileType );
static void readGridDimensions( const QString& gridFileName, std::vector<std::vector<int>>& gridDimensions );
static int readUnitsType( const ecl_file_type* ecl_file );
static cvf::ref<RifEclipseRestartDataAccess> createDynamicResultAccess( const QString& fileName );
static QString createIndexFileName( const QString& resultFileName );
static std::set<RiaDefines::PhaseType> findAvailablePhases( const ecl_file_type* ecl_file );
static void transferNncFluxData( const ecl_grid_type* grid,
const ecl_file_view_type* summaryView,
std::vector<double>* waterFlux,
std::vector<double>* oilFlux,
std::vector<double>* gasFlux );
static bool isExportedFromIntersect( const ecl_file_type* ecl_file );
static FILE* fopen( const QString& filePath, const QString& mode );
private:
static void createReportStepsMetaData( std::vector<ecl_file_type*> ecl_files,
std::vector<RifRestartReportStep>* reportSteps );
};

View File

@@ -0,0 +1,102 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS
//
// 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 "RifEclipseRestartDataAccess.h"
//--------------------------------------------------------------------------------------------------
/// Constructor
//--------------------------------------------------------------------------------------------------
RifEclipseRestartDataAccess::RifEclipseRestartDataAccess()
{
}
//--------------------------------------------------------------------------------------------------
/// Destructor
//--------------------------------------------------------------------------------------------------
RifEclipseRestartDataAccess::~RifEclipseRestartDataAccess()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifRestartReportKeywords::RifRestartReportKeywords()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifRestartReportKeywords::appendKeyword( const std::string& keyword, size_t itemCount, int globalIndex )
{
m_keywordNameAndItemCount.push_back( RifKeywordLocation( keyword, itemCount, globalIndex ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::pair<std::string, size_t>> RifRestartReportKeywords::keywordsWithAggregatedItemCount()
{
std::vector<std::pair<std::string, size_t>> tmp;
for ( auto uni : uniqueKeywords() )
{
size_t sum = 0;
for ( auto loc : objectsForKeyword( uni ) )
{
sum += loc.itemCount();
}
tmp.push_back( std::make_pair( uni, sum ) );
}
return tmp;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RifKeywordLocation> RifRestartReportKeywords::objectsForKeyword( const std::string& keyword )
{
std::vector<RifKeywordLocation> tmp;
for ( auto a : m_keywordNameAndItemCount )
{
if ( a.keyword() == keyword )
{
tmp.push_back( a );
}
}
return tmp;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<std::string> RifRestartReportKeywords::uniqueKeywords()
{
std::set<std::string> unique;
for ( auto a : m_keywordNameAndItemCount )
{
unique.insert( a.keyword() );
}
return unique;
}

View File

@@ -0,0 +1,115 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "cvfObject.h"
#include <QDateTime>
#include <QStringList>
#include <vector>
#include "ert/ecl_well/well_info.hpp"
#include "RifReaderInterface.h"
class RifKeywordLocation
{
public:
RifKeywordLocation( const std::string& keyword, size_t itemCount, int indexWithinReportStep )
: m_keyword( keyword )
, m_itemCount( itemCount )
, m_indexWithinReportStep( indexWithinReportStep )
{
}
std::string keyword() const { return m_keyword; }
size_t itemCount() const { return m_itemCount; }
int indexWithinReportStep() const { return m_indexWithinReportStep; }
private:
std::string m_keyword;
size_t m_itemCount;
int m_indexWithinReportStep;
};
class RifRestartReportKeywords
{
public:
RifRestartReportKeywords();
void appendKeyword( const std::string& keyword, size_t itemCount, int globalIndex );
std::vector<std::pair<std::string, size_t>> keywordsWithAggregatedItemCount();
private:
std::vector<RifKeywordLocation> objectsForKeyword( const std::string& keyword );
std::set<std::string> uniqueKeywords();
private:
std::vector<RifKeywordLocation> m_keywordNameAndItemCount;
};
class RifRestartReportStep
{
public:
// int globalIndex;
QDateTime dateTime;
RifRestartReportKeywords m_keywords;
};
//==================================================================================================
//
// Abstract class for results access
//
//==================================================================================================
class RifEclipseRestartDataAccess : public cvf::Object
{
public:
RifEclipseRestartDataAccess();
~RifEclipseRestartDataAccess() override;
virtual bool open() = 0;
virtual void setRestartFiles( const QStringList& fileSet ) = 0;
virtual void close() = 0;
virtual void setTimeSteps( const std::vector<QDateTime>& timeSteps ){};
virtual size_t timeStepCount() = 0;
virtual void timeSteps( std::vector<QDateTime>* timeSteps, std::vector<double>* daysSinceSimulationStart ) = 0;
virtual std::vector<int> reportNumbers() = 0;
virtual void resultNames( QStringList* resultNames, std::vector<size_t>* resultDataItemCounts ) = 0;
virtual bool results( const QString& resultName, size_t timeStep, size_t gridCount, std::vector<double>* values ) = 0;
virtual bool dynamicNNCResults( const ecl_grid_type* grid,
size_t timeStep,
std::vector<double>* waterFlux,
std::vector<double>* oilFlux,
std::vector<double>* gasFlux ) = 0;
virtual void readWellData( well_info_type* well_info, bool importCompleteMswData ) = 0;
virtual int readUnitsType() = 0;
virtual std::set<RiaDefines::PhaseType> availablePhases() const = 0;
virtual void updateFromGridCount( size_t gridCount ){};
};

View File

@@ -0,0 +1,359 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RifEclipseRestartFilesetAccess.h"
#include "RiaStringEncodingTools.h"
#include "RifEclipseOutputFileTools.h"
#include "cafProgressInfo.h"
#include "ert/ecl/ecl_file.h"
#include "ert/ecl/ecl_nnc_data.h"
#include "ert/ecl/ecl_nnc_geometry.h"
//--------------------------------------------------------------------------------------------------
/// Constructor
//--------------------------------------------------------------------------------------------------
RifEclipseRestartFilesetAccess::RifEclipseRestartFilesetAccess()
: RifEclipseRestartDataAccess()
{
}
//--------------------------------------------------------------------------------------------------
/// Destructor
//--------------------------------------------------------------------------------------------------
RifEclipseRestartFilesetAccess::~RifEclipseRestartFilesetAccess()
{
for ( size_t i = 0; i < m_ecl_files.size(); i++ )
{
if ( m_ecl_files[i] )
{
ecl_file_close( m_ecl_files[i] );
}
m_ecl_files[i] = nullptr;
}
}
//--------------------------------------------------------------------------------------------------
/// Open files
//--------------------------------------------------------------------------------------------------
bool RifEclipseRestartFilesetAccess::open()
{
if ( m_fileNames.size() > 0 )
{
caf::ProgressInfo progInfo( m_fileNames.size(), "" );
int i;
for ( i = 0; i < m_fileNames.size(); i++ )
{
progInfo.setProgressDescription( m_fileNames[i] );
openTimeStep( i );
progInfo.incrementProgress();
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseRestartFilesetAccess::setRestartFiles( const QStringList& fileSet )
{
close();
m_ecl_files.clear();
m_fileNames = fileSet;
m_fileNames.sort(); // To make sure they are sorted in increasing *.X000N order. Hack. Should probably be actual
// time stored on file.
for ( int i = 0; i < m_fileNames.size(); i++ )
{
m_ecl_files.push_back( nullptr );
}
CVF_ASSERT( m_fileNames.size() == static_cast<int>( m_ecl_files.size() ) );
}
//--------------------------------------------------------------------------------------------------
/// Close files
//--------------------------------------------------------------------------------------------------
void RifEclipseRestartFilesetAccess::close()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseRestartFilesetAccess::setTimeSteps( const std::vector<QDateTime>& timeSteps )
{
CVF_ASSERT( (size_t)m_fileNames.size() == timeSteps.size() );
m_timeSteps = timeSteps;
}
//--------------------------------------------------------------------------------------------------
/// Get the number of time steps
//--------------------------------------------------------------------------------------------------
size_t RifEclipseRestartFilesetAccess::timeStepCount()
{
return m_timeSteps.size();
}
//--------------------------------------------------------------------------------------------------
/// Get the time steps
//--------------------------------------------------------------------------------------------------
void RifEclipseRestartFilesetAccess::timeSteps( std::vector<QDateTime>* timeSteps,
std::vector<double>* daysSinceSimulationStart )
{
if ( m_timeSteps.size() == 0 )
{
size_t numSteps = m_fileNames.size();
size_t i;
for ( i = 0; i < numSteps; i++ )
{
std::vector<QDateTime> stepTime;
std::vector<double> stepDays;
openTimeStep( i );
size_t perTimeStepEmptyKeywords = 0;
RifEclipseOutputFileTools::timeSteps( m_ecl_files[i], &stepTime, &stepDays, &perTimeStepEmptyKeywords );
if ( stepTime.size() == 1 )
{
m_timeSteps.push_back( stepTime[0] );
m_daysSinceSimulationStart.push_back( stepDays[0] );
}
else
{
m_timeSteps.push_back( QDateTime() );
m_daysSinceSimulationStart.push_back( 0.0 );
}
}
}
*timeSteps = m_timeSteps;
*daysSinceSimulationStart = m_daysSinceSimulationStart;
}
//--------------------------------------------------------------------------------------------------
/// Get list of result names
//--------------------------------------------------------------------------------------------------
void RifEclipseRestartFilesetAccess::resultNames( QStringList* resultNames, std::vector<size_t>* resultDataItemCounts )
{
CVF_ASSERT( timeStepCount() > 0 );
for ( int i = 0; i < m_fileNames.size(); i++ )
{
openTimeStep( i );
}
RifEclipseOutputFileTools::findKeywordsAndItemCount( m_ecl_files, resultNames, resultDataItemCounts );
}
//--------------------------------------------------------------------------------------------------
/// Get result values for given time step
//--------------------------------------------------------------------------------------------------
bool RifEclipseRestartFilesetAccess::results( const QString& resultName,
size_t timeStep,
size_t gridCount,
std::vector<double>* values )
{
if ( timeStep >= timeStepCount() )
{
return false;
}
openTimeStep( timeStep );
if ( !m_ecl_files[timeStep] )
{
return false;
}
size_t fileGridCount = ecl_file_get_num_named_kw( m_ecl_files[timeStep], resultName.toLatin1().data() );
// No results for this result variable for current time step found
if ( fileGridCount == 0 ) return true;
// Result handling depends on presents of result values for all grids
if ( fileGridCount < gridCount )
{
return false;
}
// NB : 6X simulator can report multiple keywords for one time step. The additional keywords do not contain and
// data imported by ResInsight. We read all blocks of data, also empty to simplify the logic.
// See https://github.com/OPM/ResInsight/issues/5763
for ( size_t i = 0; i < fileGridCount; i++ )
{
std::vector<double> gridValues;
if ( !RifEclipseOutputFileTools::keywordData( m_ecl_files[timeStep], resultName, i, &gridValues ) )
{
return false;
}
values->insert( values->end(), gridValues.begin(), gridValues.end() );
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseRestartFilesetAccess::dynamicNNCResults( const ecl_grid_type* grid,
size_t timeStep,
std::vector<double>* waterFlux,
std::vector<double>* oilFlux,
std::vector<double>* gasFlux )
{
if ( timeStep > timeStepCount() )
{
return false;
}
openTimeStep( timeStep );
if ( !m_ecl_files[timeStep] )
{
return false;
}
ecl_file_view_type* summaryView = ecl_file_get_global_view( m_ecl_files[timeStep] );
RifEclipseOutputFileTools::transferNncFluxData( grid, summaryView, waterFlux, oilFlux, gasFlux );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseRestartFilesetAccess::readWellData( well_info_type* well_info, bool importCompleteMswData )
{
if ( !well_info ) return;
for ( size_t i = 0; i < m_ecl_files.size(); i++ )
{
openTimeStep( i );
if ( m_ecl_files[i] )
{
int reportNumber = RifEclipseRestartFilesetAccess::reportNumber( m_ecl_files[i] );
if ( reportNumber != -1 )
{
well_info_add_wells( well_info, m_ecl_files[i], reportNumber, importCompleteMswData );
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseRestartFilesetAccess::openTimeStep( size_t timeStep )
{
CVF_ASSERT( timeStep < m_ecl_files.size() );
if ( m_ecl_files[timeStep] == nullptr )
{
int index = static_cast<int>( timeStep );
ecl_file_type* ecl_file =
ecl_file_open( RiaStringEncodingTools::toNativeEncoded( m_fileNames[index] ).data(), ECL_FILE_CLOSE_STREAM );
m_ecl_files[timeStep] = ecl_file;
if ( ecl_file )
{
auto phases = RifEclipseOutputFileTools::findAvailablePhases( ecl_file );
m_availablePhases.insert( phases.begin(), phases.end() );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RifEclipseRestartFilesetAccess::reportNumber( const ecl_file_type* ecl_file )
{
if ( !ecl_file ) return -1;
const char* eclFileName = ecl_file_get_src_file( ecl_file );
QString fileNameUpper( eclFileName );
fileNameUpper = fileNameUpper.toUpper();
// Convert to upper case, as ecl_util_filename_report_nr does not handle lower case file extensions
int reportNumber = ecl_util_filename_report_nr( RiaStringEncodingTools::toNativeEncoded( fileNameUpper ).data() );
return reportNumber;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RifEclipseRestartFilesetAccess::readUnitsType()
{
ecl_file_type* ecl_file = nullptr;
if ( m_ecl_files.size() > 0 )
{
openTimeStep( 0 );
ecl_file = m_ecl_files[0];
}
return RifEclipseOutputFileTools::readUnitsType( ecl_file );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RiaDefines::PhaseType> RifEclipseRestartFilesetAccess::availablePhases() const
{
return m_availablePhases;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> RifEclipseRestartFilesetAccess::reportNumbers()
{
std::vector<int> reportNr;
for ( const auto* ecl_file : m_ecl_files )
{
if ( ecl_file )
{
int reportNumber = RifEclipseRestartFilesetAccess::reportNumber( ecl_file );
if ( reportNumber != -1 )
{
reportNr.push_back( reportNumber );
}
}
}
return reportNr;
}

View File

@@ -0,0 +1,74 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RifEclipseRestartDataAccess.h"
#include <vector>
class RifEclipseOutputFileTools;
//==================================================================================================
//
// Class for access to results from a set of restart files
//
//==================================================================================================
class RifEclipseRestartFilesetAccess : public RifEclipseRestartDataAccess
{
public:
RifEclipseRestartFilesetAccess();
~RifEclipseRestartFilesetAccess() override;
bool open() override;
void setRestartFiles( const QStringList& fileSet ) override;
void close() override;
void setTimeSteps( const std::vector<QDateTime>& timeSteps ) override;
size_t timeStepCount() override;
void timeSteps( std::vector<QDateTime>* timeSteps, std::vector<double>* daysSinceSimulationStart ) override;
std::vector<int> reportNumbers() override;
void resultNames( QStringList* resultNames, std::vector<size_t>* resultDataItemCounts ) override;
bool results( const QString& resultName, size_t timeStep, size_t gridCount, std::vector<double>* values ) override;
bool dynamicNNCResults( const ecl_grid_type* grid,
size_t timeStep,
std::vector<double>* waterFlux,
std::vector<double>* oilFlux,
std::vector<double>* gasFlux ) override;
void readWellData( well_info_type* well_info, bool importCompleteMswData ) override;
int readUnitsType() override;
std::set<RiaDefines::PhaseType> availablePhases() const override;
private:
void openTimeStep( size_t timeStep );
static int reportNumber( const ecl_file_type* ecl_file );
private:
QStringList m_fileNames;
std::vector<QDateTime> m_timeSteps;
std::vector<double> m_daysSinceSimulationStart;
std::vector<ecl_file_type*> m_ecl_files;
std::set<RiaDefines::PhaseType> m_availablePhases;
};

View File

@@ -0,0 +1,54 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifEclipseRftAddress.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseRftAddress::RifEclipseRftAddress( QString wellName, QDateTime timeStep, RftWellLogChannelType wellLogChannelName )
: m_wellName( wellName )
, m_wellLogChannel( wellLogChannelName )
{
m_timeStep = timeStep;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool operator==( const RifEclipseRftAddress& first, const RifEclipseRftAddress& second )
{
if ( first.wellName() != second.wellName() ) return false;
if ( first.timeStep() != second.timeStep() ) return false;
if ( first.wellLogChannel() != second.wellLogChannel() ) return false;
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool operator<( const RifEclipseRftAddress& first, const RifEclipseRftAddress& second )
{
if ( first.wellName() != second.wellName() ) return ( first.wellName() < second.wellName() );
if ( first.timeStep() != second.timeStep() ) return ( first.timeStep() < second.timeStep() );
if ( first.wellLogChannel() != second.wellLogChannel() )
return ( first.wellLogChannel() < second.wellLogChannel() );
return false;
}

View File

@@ -0,0 +1,83 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <set>
#include <string>
#include <vector>
#include <QDateTime>
//==================================================================================================
///
///
//==================================================================================================
class RifEclipseRftAddress
{
public:
enum RftWellLogChannelType
{
NONE,
TVD,
PRESSURE,
SWAT,
SOIL,
SGAS,
WRAT,
ORAT,
GRAT,
MD,
PRESSURE_P10,
PRESSURE_P50,
PRESSURE_P90,
PRESSURE_MEAN,
PRESSURE_ERROR
};
public:
RifEclipseRftAddress( QString wellName, QDateTime timeStep, RftWellLogChannelType wellLogChannel );
const QString& wellName() const { return m_wellName; }
QDateTime timeStep() const { return m_timeStep; }
const RftWellLogChannelType& wellLogChannel() const { return m_wellLogChannel; }
static std::set<RftWellLogChannelType> rftPlotChannelTypes()
{
return {RifEclipseRftAddress::PRESSURE,
RifEclipseRftAddress::PRESSURE_ERROR,
RifEclipseRftAddress::PRESSURE_MEAN,
RifEclipseRftAddress::PRESSURE_P10,
RifEclipseRftAddress::PRESSURE_P50,
RifEclipseRftAddress::PRESSURE_P90};
}
static std::set<RftWellLogChannelType> pltPlotChannelTypes()
{
return {RifEclipseRftAddress::ORAT, RifEclipseRftAddress::WRAT, RifEclipseRftAddress::GRAT};
}
private:
QString m_wellName;
QDateTime m_timeStep;
RftWellLogChannelType m_wellLogChannel;
};
bool operator==( const RifEclipseRftAddress& first, const RifEclipseRftAddress& second );
bool operator<( const RifEclipseRftAddress& first, const RifEclipseRftAddress& second );

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,240 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <map>
#include <set>
#include <string>
#include <vector>
class QTextStream;
class QString;
#define ENSEMBLE_STAT_P10_QUANTITY_NAME "P10"
#define ENSEMBLE_STAT_P50_QUANTITY_NAME "P50"
#define ENSEMBLE_STAT_P90_QUANTITY_NAME "P90"
#define ENSEMBLE_STAT_MEAN_QUANTITY_NAME "MEAN"
//==================================================================================================
//
//
//==================================================================================================
class RifEclipseSummaryAddress
{
public:
// Based on list in ecl_smspec.c and list of types taken from Eclipse Reference Manual ecl_rm_2011.1.pdf
enum SummaryVarCategory : int8_t
{
SUMMARY_INVALID,
SUMMARY_FIELD,
SUMMARY_AQUIFER,
SUMMARY_NETWORK,
SUMMARY_MISC,
SUMMARY_REGION,
SUMMARY_REGION_2_REGION,
SUMMARY_WELL_GROUP,
SUMMARY_WELL,
SUMMARY_WELL_COMPLETION,
SUMMARY_WELL_LGR,
SUMMARY_WELL_COMPLETION_LGR,
SUMMARY_WELL_SEGMENT,
SUMMARY_BLOCK,
SUMMARY_BLOCK_LGR,
SUMMARY_CALCULATED,
SUMMARY_IMPORTED,
SUMMARY_ENSEMBLE_STATISTICS
};
enum SummaryIdentifierType
{
INPUT_REGION_NUMBER,
INPUT_REGION_2_REGION,
INPUT_WELL_NAME,
INPUT_WELL_GROUP_NAME,
INPUT_CELL_IJK,
INPUT_LGR_NAME,
INPUT_SEGMENT_NUMBER,
INPUT_AQUIFER_NUMBER,
INPUT_VECTOR_NAME,
INPUT_ID
};
public:
RifEclipseSummaryAddress()
: m_variableCategory( RifEclipseSummaryAddress::SUMMARY_INVALID )
, m_regionNumber( -1 )
, m_regionNumber2( -1 )
, m_wellSegmentNumber( -1 )
, m_cellI( -1 )
, m_cellJ( -1 )
, m_cellK( -1 )
, m_aquiferNumber( -1 )
, m_isErrorResult( false )
, m_id( -1 )
{
}
RifEclipseSummaryAddress( SummaryVarCategory category,
const std::string& quantityName,
int16_t regionNumber,
int16_t regionNumber2,
const std::string& wellGroupName,
const std::string& wellName,
int16_t wellSegmentNumber,
const std::string& lgrName,
int32_t cellI,
int32_t cellJ,
int32_t cellK,
int16_t aquiferNumber,
bool isErrorResult,
int32_t id )
: m_variableCategory( category )
, m_quantityName( quantityName )
, m_regionNumber( regionNumber )
, m_regionNumber2( regionNumber2 )
, m_wellGroupName( wellGroupName )
, m_wellName( wellName )
, m_wellSegmentNumber( wellSegmentNumber )
, m_lgrName( lgrName )
, m_cellI( cellI )
, m_cellJ( cellJ )
, m_cellK( cellK )
, m_aquiferNumber( aquiferNumber )
, m_isErrorResult( isErrorResult )
, m_id( id )
{
}
RifEclipseSummaryAddress( SummaryVarCategory category, std::map<SummaryIdentifierType, std::string>& identifiers );
// Static specialized creation methods
static RifEclipseSummaryAddress fromEclipseTextAddress( const std::string& textAddress );
static SummaryVarCategory identifyCategory( const std::string& quantityName );
static RifEclipseSummaryAddress fieldAddress( const std::string& quantityName );
static RifEclipseSummaryAddress aquiferAddress( const std::string& quantityName, int aquiferNumber );
static RifEclipseSummaryAddress networkAddress( const std::string& quantityName );
static RifEclipseSummaryAddress miscAddress( const std::string& quantityName );
static RifEclipseSummaryAddress regionAddress( const std::string& quantityName, int regionNumber );
static RifEclipseSummaryAddress
regionToRegionAddress( const std::string& quantityName, int regionNumber, int region2Number );
static RifEclipseSummaryAddress wellGroupAddress( const std::string& quantityName, const std::string& wellGroupName );
static RifEclipseSummaryAddress wellAddress( const std::string& quantityName, const std::string& wellName );
static RifEclipseSummaryAddress
wellCompletionAddress( const std::string& quantityName, const std::string& wellName, int i, int j, int k );
static RifEclipseSummaryAddress
wellLgrAddress( const std::string& quantityName, const std::string& lgrName, const std::string& wellName );
static RifEclipseSummaryAddress wellCompletionLgrAddress( const std::string& quantityName,
const std::string& lgrName,
const std::string& wellName,
int i,
int j,
int k );
static RifEclipseSummaryAddress
wellSegmentAddress( const std::string& quantityName, const std::string& wellName, int segmentNumber );
static RifEclipseSummaryAddress blockAddress( const std::string& quantityName, int i, int j, int k );
static RifEclipseSummaryAddress
blockLgrAddress( const std::string& quantityName, const std::string& lgrName, int i, int j, int k );
static RifEclipseSummaryAddress calculatedAddress( const std::string& quantityName, int id );
static RifEclipseSummaryAddress importedAddress( const std::string& quantityName );
static RifEclipseSummaryAddress ensembleStatisticsAddress( const std::string& quantityName,
const std::string& dataQuantityName );
static std::string generateStringFromAddresses( const std::vector<RifEclipseSummaryAddress>& addressVector,
const std::string jointString = "; " );
static bool isDependentOnWellName( SummaryVarCategory category );
// Access methods
SummaryVarCategory category() const { return m_variableCategory; }
const std::string& quantityName() const { return m_quantityName; }
bool isHistoryQuantity() const;
int regionNumber() const { return m_regionNumber; }
int regionNumber2() const { return m_regionNumber2; }
const std::string& wellGroupName() const { return m_wellGroupName; }
const std::string& wellName() const { return m_wellName; }
int wellSegmentNumber() const { return m_wellSegmentNumber; }
const std::string& lgrName() const { return m_lgrName; }
int cellI() const { return m_cellI; }
int cellJ() const { return m_cellJ; }
int cellK() const { return m_cellK; }
int aquiferNumber() const { return m_aquiferNumber; }
int id() const { return m_id; }
std::string blockAsString() const;
const std::string ensembleStatisticsQuantityName() const;
// Derived properties
std::string uiText() const;
std::string itemUiText() const;
std::string addressComponentUiText( RifEclipseSummaryAddress::SummaryIdentifierType itemTypeInput ) const;
bool isUiTextMatchingFilterText( const QString& filterString ) const;
bool isValid() const;
void setQuantityName( const std::string& quantity ) { m_quantityName = quantity; }
void setWellName( const std::string& wellName ) { m_wellName = wellName; }
void setWellGroupName( const std::string& wellGroupName ) { m_wellGroupName = wellGroupName; }
void setRegion( int region ) { m_regionNumber = (int16_t)region; }
void setAquiferNumber( int aquiferNumber ) { m_aquiferNumber = (int16_t)aquiferNumber; }
void setCellIjk( const std::string& uiText );
void setWellSegmentNumber( int segment ) { m_wellSegmentNumber = (int16_t)segment; }
void setAsErrorResult() { m_isErrorResult = true; }
bool isErrorResult() const { return m_isErrorResult; }
void setId( int id ) { m_id = id; }
bool hasAccumulatedData() const;
static QString baseQuantityName( const QString& quantityName );
private:
bool isValidEclipseCategory() const;
static std::tuple<int32_t, int32_t, int32_t> ijkTupleFromUiText( const std::string& s );
std::string formatUiTextRegionToRegion() const;
std::pair<int16_t, int16_t> regionToRegionPairFromUiText( const std::string& s );
std::string m_quantityName;
std::string m_wellGroupName;
std::string m_wellName;
std::string m_lgrName;
int32_t m_cellI;
int32_t m_cellJ;
int32_t m_cellK;
int16_t m_regionNumber;
int16_t m_regionNumber2;
int16_t m_wellSegmentNumber;
int16_t m_aquiferNumber;
SummaryVarCategory m_variableCategory;
bool m_isErrorResult;
int32_t m_id;
};
bool operator==( const RifEclipseSummaryAddress& first, const RifEclipseSummaryAddress& second );
bool operator!=( const RifEclipseSummaryAddress& first, const RifEclipseSummaryAddress& second );
bool operator<( const RifEclipseSummaryAddress& first, const RifEclipseSummaryAddress& second );
QTextStream& operator<<( QTextStream& str, const RifEclipseSummaryAddress& sobj );
QTextStream& operator>>( QTextStream& str, RifEclipseSummaryAddress& sobj );

View File

@@ -0,0 +1,23 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifEclipseSummaryAddress.h"
#include <QMetaType>
Q_DECLARE_METATYPE( RifEclipseSummaryAddress );

View File

@@ -0,0 +1,195 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifEclipseSummaryTools.h"
#include "RiaFilePathTools.h"
#include "RiaStringEncodingTools.h"
#include "RiaSummaryCurveAnalyzer.h"
#include "RifReaderEclipseSummary.h"
#include "cafAppEnum.h"
#include "ert/ecl/ecl_util.h"
#include <QDir>
#include <QString>
#include <QStringList>
#include <iostream>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseSummaryTools::findSummaryHeaderFile( const QString& inputFile, QString* headerFile, bool* isFormatted )
{
findSummaryHeaderFileInfo( inputFile, headerFile, nullptr, nullptr, isFormatted );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseSummaryTools::findSummaryFiles( const QString& inputFile, QString* headerFile, QStringList* dataFiles )
{
dataFiles->clear();
headerFile->clear();
char* myPath = nullptr;
char* myBase = nullptr;
char* myExtension = nullptr;
util_alloc_file_components( RiaStringEncodingTools::toNativeEncoded( inputFile ).data(), &myPath, &myBase, &myExtension );
QString path;
if ( myPath ) path = RiaStringEncodingTools::fromNativeEncoded( myPath );
QString base;
if ( myBase ) base = RiaStringEncodingTools::fromNativeEncoded( myBase );
std::string extension;
if ( myExtension ) extension = myExtension;
free( myExtension );
free( myBase );
free( myPath );
if ( path.isEmpty() || base.isEmpty() ) return;
char* myHeaderFile = nullptr;
stringlist_type* summary_file_list = stringlist_alloc_new();
ecl_util_alloc_summary_files( RiaStringEncodingTools::toNativeEncoded( path ).data(),
RiaStringEncodingTools::toNativeEncoded( base ).data(),
extension.data(),
&myHeaderFile,
summary_file_list );
if ( myHeaderFile )
{
( *headerFile ) = RiaStringEncodingTools::fromNativeEncoded( myHeaderFile );
free( myHeaderFile );
}
if ( stringlist_get_size( summary_file_list ) > 0 )
{
for ( int i = 0; i < stringlist_get_size( summary_file_list ); i++ )
{
dataFiles->push_back( RiaStringEncodingTools::fromNativeEncoded( stringlist_iget( summary_file_list, i ) ) );
}
}
stringlist_free( summary_file_list );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifEclipseSummaryTools::findGridCaseFileFromSummaryHeaderFile( const QString& summaryHeaderFile )
{
char* myPath = nullptr;
char* myBase = nullptr;
util_alloc_file_components( RiaStringEncodingTools::toNativeEncoded( QDir::toNativeSeparators( summaryHeaderFile ) ).data(),
&myPath,
&myBase,
nullptr );
char* caseFile = ecl_util_alloc_exfilename( myPath, myBase, ECL_EGRID_FILE, true, -1 );
if ( !caseFile )
{
caseFile = ecl_util_alloc_exfilename( myPath, myBase, ECL_EGRID_FILE, false, -1 );
}
QString gridCaseFile;
if ( caseFile ) gridCaseFile = caseFile;
free( caseFile );
free( myBase );
free( myPath );
return RiaFilePathTools::toInternalSeparator( gridCaseFile );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseSummaryTools::dumpMetaData( RifSummaryReaderInterface* readerEclipseSummary )
{
std::set<RifEclipseSummaryAddress> addresses = readerEclipseSummary->allResultAddresses();
for ( int category = 0; category < RifEclipseSummaryAddress::SUMMARY_BLOCK_LGR; category++ )
{
RifEclipseSummaryAddress::SummaryVarCategory categoryEnum =
RifEclipseSummaryAddress::SummaryVarCategory( category );
std::vector<RifEclipseSummaryAddress> catAddresses =
RiaSummaryCurveAnalyzer::addressesForCategory( addresses, categoryEnum );
if ( catAddresses.size() > 0 )
{
std::cout << caf::AppEnum<RifEclipseSummaryAddress::SummaryVarCategory>::uiText( categoryEnum ).toStdString()
<< " count : " << catAddresses.size() << std::endl;
for ( size_t i = 0; i < catAddresses.size(); i++ )
{
std::cout << catAddresses[i].quantityName() << " " << catAddresses[i].regionNumber() << " "
<< catAddresses[i].regionNumber2() << " " << catAddresses[i].wellGroupName() << " "
<< catAddresses[i].wellName() << " " << catAddresses[i].wellSegmentNumber() << " "
<< catAddresses[i].lgrName() << " " << catAddresses[i].cellI() << " "
<< catAddresses[i].cellJ() << " " << catAddresses[i].cellK() << std::endl;
}
std::cout << std::endl;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseSummaryTools::findSummaryHeaderFileInfo( const QString& inputFile,
QString* headerFile,
QString* path,
QString* base,
bool* isFormatted )
{
char* myPath = nullptr;
char* myBase = nullptr;
bool formattedFile = true;
util_alloc_file_components( RiaStringEncodingTools::toNativeEncoded( QDir::toNativeSeparators( inputFile ) ).data(),
&myPath,
&myBase,
nullptr );
char* myHeaderFile = ecl_util_alloc_exfilename( myPath, myBase, ECL_SUMMARY_HEADER_FILE, true, -1 );
if ( !myHeaderFile )
{
myHeaderFile = ecl_util_alloc_exfilename( myPath, myBase, ECL_SUMMARY_HEADER_FILE, false, -1 );
if ( myHeaderFile )
{
formattedFile = false;
}
}
if ( myHeaderFile && headerFile ) *headerFile = RiaFilePathTools::toInternalSeparator( myHeaderFile );
if ( myPath && path ) *path = RiaFilePathTools::toInternalSeparator( myPath );
if ( myBase && base ) *base = RiaFilePathTools::toInternalSeparator( myBase );
if ( isFormatted ) *isFormatted = formattedFile;
free( myHeaderFile );
free( myBase );
free( myPath );
}

View File

@@ -0,0 +1,50 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifEclipseSummaryAddress.h"
#include <string>
#include <vector>
class RifSummaryReaderInterface;
class QStringList;
class QString;
//==================================================================================================
//
//
//
//==================================================================================================
class RifEclipseSummaryTools
{
public:
static void findSummaryHeaderFile( const QString& inputFile, QString* headerFile, bool* isFormatted );
static QString findGridCaseFileFromSummaryHeaderFile( const QString& summaryHeaderFile );
static void findSummaryFiles( const QString& inputFile, QString* headerFile, QStringList* dataFiles );
static void dumpMetaData( RifSummaryReaderInterface* readerEclipseSummary );
private:
static void findSummaryHeaderFileInfo( const QString& inputFile,
QString* headerFile,
QString* path,
QString* base,
bool* isFormatted );
};

View File

@@ -0,0 +1,371 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RifEclipseUnifiedRestartFileAccess.h"
#include "RiaApplication.h"
#include "RiaLogging.h"
#include "RiaPreferences.h"
#include "RiaStringEncodingTools.h"
#include "RifEclipseOutputFileTools.h"
#include "RifReaderSettings.h"
#include "ert/ecl/ecl_file.h"
#include "ert/ecl/ecl_kw_magic.h"
#include "ert/ecl/ecl_nnc_data.h"
#include "ert/ecl/ecl_nnc_geometry.h"
#include "cafUtils.h"
#include <QFileInfo>
// #include "cvfTrace.h"
//--------------------------------------------------------------------------------------------------
/// Constructor
//--------------------------------------------------------------------------------------------------
RifEclipseUnifiedRestartFileAccess::RifEclipseUnifiedRestartFileAccess()
: RifEclipseRestartDataAccess()
, m_ecl_file( nullptr )
, m_perTimeStepHeaderCount( 0 )
, m_noDataGridCount( 0 )
{
}
//--------------------------------------------------------------------------------------------------
/// Destructor
//--------------------------------------------------------------------------------------------------
RifEclipseUnifiedRestartFileAccess::~RifEclipseUnifiedRestartFileAccess()
{
if ( m_ecl_file )
{
ecl_file_close( m_ecl_file );
}
}
//--------------------------------------------------------------------------------------------------
/// Open file
//--------------------------------------------------------------------------------------------------
bool RifEclipseUnifiedRestartFileAccess::open()
{
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUnifiedRestartFileAccess::openFile()
{
if ( !m_ecl_file )
{
QString indexFileName = RifEclipseOutputFileTools::createIndexFileName( m_filename );
if ( useResultIndexFile() )
{
if ( caf::Utils::fileExists( indexFileName ) )
{
QFileInfo indexFileInfo( indexFileName );
QFileInfo resultFileInfo( m_filename );
if ( resultFileInfo.lastModified() < indexFileInfo.lastModified() )
{
m_ecl_file = ecl_file_fast_open( RiaStringEncodingTools::toNativeEncoded( m_filename ).data(),
RiaStringEncodingTools::toNativeEncoded( indexFileName ).data(),
ECL_FILE_CLOSE_STREAM );
if ( !m_ecl_file )
{
RiaLogging::error( QString( "Failed to open file %1 using index file." ).arg( m_filename ) );
RiaLogging::info( QString( "Will try to open file without index file." ) );
}
else
{
RiaLogging::info( QString( "Imported file %1 using index file." ).arg( m_filename ) );
}
}
}
}
if ( !m_ecl_file )
{
m_ecl_file =
ecl_file_open( RiaStringEncodingTools::toNativeEncoded( m_filename ).data(), ECL_FILE_CLOSE_STREAM );
if ( !m_ecl_file )
{
RiaLogging::error( QString( "Failed to open file %1" ).arg( m_filename ) );
}
else
{
if ( useResultIndexFile() )
{
QFileInfo fi( indexFileName );
QString resultPath = fi.absolutePath();
if ( caf::Utils::isFolderWritable( resultPath ) )
{
bool success =
ecl_file_write_index( m_ecl_file,
RiaStringEncodingTools::toNativeEncoded( indexFileName ).data() );
if ( success )
{
RiaLogging::info( QString( "Exported index file to %1 " ).arg( indexFileName ) );
}
else
{
RiaLogging::info( QString( "Failed to exported index file to %1 " ).arg( indexFileName ) );
}
}
}
}
}
}
if ( !m_ecl_file ) return false;
m_availablePhases = RifEclipseOutputFileTools::findAvailablePhases( m_ecl_file );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUnifiedRestartFileAccess::useResultIndexFile() const
{
RiaPreferences* prefs = RiaApplication::instance()->preferences();
const RifReaderSettings* readerSettings = prefs->readerSettings();
return readerSettings->useResultIndexFile();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseUnifiedRestartFileAccess::extractTimestepsFromEclipse()
{
m_timeSteps.clear();
m_daysSinceSimulationStart.clear();
m_reportNr.clear();
if ( openFile() )
{
RifEclipseOutputFileTools::timeSteps( m_ecl_file, &m_timeSteps, &m_daysSinceSimulationStart, &m_perTimeStepHeaderCount );
// Taken from well_info_add_UNRST_wells
int num_blocks = ecl_file_get_num_named_kw( m_ecl_file, SEQNUM_KW );
int block_nr;
for ( block_nr = 0; block_nr < num_blocks; block_nr++ )
{
ecl_file_push_block( m_ecl_file ); // <-------------------------------------------------------
{ //
ecl_file_subselect_block( m_ecl_file, SEQNUM_KW, block_nr ); // Ensure that the status
{ // is not changed as a side
const ecl_kw_type* seqnum_kw = ecl_file_iget_named_kw( m_ecl_file, SEQNUM_KW, 0 ); // effect.
int report_nr = ecl_kw_iget_int( seqnum_kw, 0 ); //
m_reportNr.push_back( report_nr );
} //
} //
ecl_file_pop_block( m_ecl_file ); // <-------------------------------------------------------
}
}
}
//--------------------------------------------------------------------------------------------------
/// Close file
//--------------------------------------------------------------------------------------------------
void RifEclipseUnifiedRestartFileAccess::close()
{
m_timeSteps.clear();
m_daysSinceSimulationStart.clear();
}
//--------------------------------------------------------------------------------------------------
/// Get the number of time steps
//--------------------------------------------------------------------------------------------------
size_t RifEclipseUnifiedRestartFileAccess::timeStepCount()
{
if ( m_timeSteps.size() == 0 )
{
extractTimestepsFromEclipse();
}
return m_timeSteps.size();
}
//--------------------------------------------------------------------------------------------------
/// Get the time steps
//--------------------------------------------------------------------------------------------------
void RifEclipseUnifiedRestartFileAccess::timeSteps( std::vector<QDateTime>* timeSteps,
std::vector<double>* daysSinceSimulationStart )
{
if ( m_timeSteps.size() == 0 )
{
extractTimestepsFromEclipse();
}
*timeSteps = m_timeSteps;
*daysSinceSimulationStart = m_daysSinceSimulationStart;
}
//--------------------------------------------------------------------------------------------------
/// Get list of result names
//--------------------------------------------------------------------------------------------------
void RifEclipseUnifiedRestartFileAccess::resultNames( QStringList* resultNames, std::vector<size_t>* resultDataItemCounts )
{
if ( openFile() )
{
std::vector<ecl_file_type*> filesUsedToFindAvailableKeywords;
filesUsedToFindAvailableKeywords.push_back( m_ecl_file );
RifEclipseOutputFileTools::findKeywordsAndItemCount( filesUsedToFindAvailableKeywords,
resultNames,
resultDataItemCounts );
}
}
//--------------------------------------------------------------------------------------------------
/// Get result values for given time step
//--------------------------------------------------------------------------------------------------
bool RifEclipseUnifiedRestartFileAccess::results( const QString& resultName,
size_t timeStep,
size_t gridCount,
std::vector<double>* values )
{
if ( !openFile() )
{
return false;
}
ecl_file_push_block( m_ecl_file );
for ( size_t i = 0; i < gridCount; i++ )
{
ecl_file_select_block( m_ecl_file, INTEHEAD_KW, static_cast<int>( timeStep * ( gridCount + m_noDataGridCount ) + i ) );
int namedKeywordCount = ecl_file_get_num_named_kw( m_ecl_file, resultName.toLatin1().data() );
for ( int iOcc = 0; iOcc < namedKeywordCount; iOcc++ )
{
std::vector<double> partValues;
RifEclipseOutputFileTools::keywordData( m_ecl_file, resultName, iOcc, &partValues );
values->insert( values->end(), partValues.begin(), partValues.end() );
}
}
ecl_file_pop_block( m_ecl_file );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUnifiedRestartFileAccess::dynamicNNCResults( const ecl_grid_type* grid,
size_t timeStep,
std::vector<double>* waterFlux,
std::vector<double>* oilFlux,
std::vector<double>* gasFlux )
{
if ( timeStep > timeStepCount() )
{
return false;
}
if ( !openFile() )
{
return false;
}
ecl_file_view_type* summaryView = ecl_file_get_restart_view( m_ecl_file, static_cast<int>( timeStep ), 0, 0, 0 );
RifEclipseOutputFileTools::transferNncFluxData( grid, summaryView, waterFlux, oilFlux, gasFlux );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseUnifiedRestartFileAccess::readWellData( well_info_type* well_info, bool importCompleteMswData )
{
if ( !well_info ) return;
if ( openFile() )
{
// cvf::Trace::show("well_info_add_UNRST_wells Start"); // Use for profiling
well_info_add_UNRST_wells( well_info, m_ecl_file, importCompleteMswData );
// cvf::Trace::show("well_info_add_UNRST_wells End"); // Use for profiling
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseUnifiedRestartFileAccess::setRestartFiles( const QStringList& fileSet )
{
m_filename = fileSet[0];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RifEclipseUnifiedRestartFileAccess::readUnitsType()
{
openFile();
return RifEclipseOutputFileTools::readUnitsType( m_ecl_file );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RiaDefines::PhaseType> RifEclipseUnifiedRestartFileAccess::availablePhases() const
{
return m_availablePhases;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseUnifiedRestartFileAccess::updateFromGridCount( size_t gridCount )
{
if ( m_perTimeStepHeaderCount > gridCount )
{
// 6x simulator can report multiple keywords per time step. Use the keyword count to
// find correct index in the restart file
// https://github.com/OPM/ResInsight/issues/5763
//
m_noDataGridCount = m_perTimeStepHeaderCount - gridCount;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> RifEclipseUnifiedRestartFileAccess::reportNumbers()
{
if ( m_timeSteps.size() == 0 )
{
extractTimestepsFromEclipse();
}
return m_reportNr;
}

View File

@@ -0,0 +1,82 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RifEclipseRestartDataAccess.h"
class RifEclipseOutputFileTools;
// typedef struct ecl_file_struct ecl_file_type;
#include "ert/ecl_well/well_info.hpp"
//==================================================================================================
//
// Class for access to results from a unified restart file
//
//==================================================================================================
class RifEclipseUnifiedRestartFileAccess : public RifEclipseRestartDataAccess
{
public:
RifEclipseUnifiedRestartFileAccess();
~RifEclipseUnifiedRestartFileAccess() override;
void setRestartFiles( const QStringList& fileSet ) override;
bool open() override;
void close() override;
size_t timeStepCount() override;
void timeSteps( std::vector<QDateTime>* timeSteps, std::vector<double>* daysSinceSimulationStart ) override;
std::vector<int> reportNumbers() override;
void resultNames( QStringList* resultNames, std::vector<size_t>* resultDataItemCounts ) override;
bool results( const QString& resultName, size_t timeStep, size_t gridCount, std::vector<double>* values ) override;
bool dynamicNNCResults( const ecl_grid_type* grid,
size_t timeStep,
std::vector<double>* waterFlux,
std::vector<double>* oilFlux,
std::vector<double>* gasFlux ) override;
void readWellData( well_info_type* well_info, bool importCompleteMswData ) override;
int readUnitsType() override;
std::set<RiaDefines::PhaseType> availablePhases() const override;
void updateFromGridCount( size_t gridCount ) override;
private:
bool openFile();
bool useResultIndexFile() const;
void extractTimestepsFromEclipse();
private:
QString m_filename;
ecl_file_type* m_ecl_file;
size_t m_perTimeStepHeaderCount;
size_t m_noDataGridCount;
std::vector<QDateTime> m_timeSteps;
std::vector<double> m_daysSinceSimulationStart;
std::vector<int> m_reportNr;
std::set<RiaDefines::PhaseType> m_availablePhases;
};

View File

@@ -0,0 +1,375 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifEclipseUserDataKeywordTools.h"
#include "RiaLogging.h"
#include "RiaStdStringTools.h"
#include "RifEclipseUserDataParserTools.h"
#include <QStringList>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<size_t> RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword( const std::string& identifier )
{
if ( identifier.size() < 2 ) return {};
char firstLetter = identifier[0];
switch ( firstLetter )
{
case 'B':
return { 3 }; // Block triplet
case 'C':
return { 1, 3 }; // Well Name and completion triplet
case 'G':
return { 1 }; // Group
case 'R':
return { 1 }; // Region number
case 'S':
return { 1, 1 }; // Well name and segment number
case 'W':
return { 1 }; // Well Name
}
std::string firstTwoLetters = identifier.substr( 0, 2 );
if ( firstTwoLetters == "LB" )
return { 1, 3 }; // LGR name and block triplet
else if ( firstTwoLetters == "LC" )
return { 1, 1, 3 }; // LGR name, well name and block triplet
else if ( firstTwoLetters == "LW" )
return { 1, 1 }; // LGR name and well name
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<std::string>>
RifEclipseUserDataKeywordTools::buildColumnHeaderText( const std::vector<std::string>& quantityNames,
const std::vector<std::vector<std::string>>& restOfHeaderRows,
std::vector<std::string>* errorText )
{
std::vector<std::vector<std::string>> tableHeaderText;
std::vector<size_t> headerLineWordIndices( restOfHeaderRows.size(), 0 );
for ( size_t i = 0; i < quantityNames.size(); i++ )
{
std::vector<std::string> columnHeaderText;
auto quantityName = quantityNames[i];
columnHeaderText.push_back( quantityName );
auto itemCountPerLine = RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword( quantityName );
if ( itemCountPerLine.size() > restOfHeaderRows.size() )
{
std::string text = "Detected too few header lines";
if ( errorText ) errorText->push_back( text );
return std::vector<std::vector<std::string>>();
}
for ( size_t lineIdx = 0; lineIdx < itemCountPerLine.size(); lineIdx++ )
{
auto line = restOfHeaderRows[lineIdx];
for ( size_t itemIndex = 0; itemIndex < itemCountPerLine[lineIdx]; itemIndex++ )
{
size_t wordIndex = headerLineWordIndices[lineIdx];
if ( wordIndex >= line.size() )
{
std::string text = "Detected too few items for header line";
if ( errorText ) errorText->push_back( text );
return std::vector<std::vector<std::string>>();
}
auto word = line[wordIndex];
columnHeaderText.push_back( word );
headerLineWordIndices[lineIdx]++;
}
}
tableHeaderText.push_back( columnHeaderText );
}
return tableHeaderText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataKeywordTools::isTime( const std::string& identifier )
{
return ( identifier == "TIME" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataKeywordTools::isDate( const std::string& identifier )
{
return ( identifier == "DATE" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataKeywordTools::isDays( const std::string& identifier )
{
return ( identifier.find( "DAYS" ) != std::string::npos );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataKeywordTools::isYears( const std::string& identifier )
{
return ( identifier.find( "YEARS" ) != std::string::npos );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataKeywordTools::isYearX( const std::string& identifier )
{
return ( identifier.find( "YEARX" ) != std::string::npos );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddress RifEclipseUserDataKeywordTools::makeAndFillAddress( const std::string quantityName,
const std::vector<std::string>& columnHeaderText )
{
RifEclipseSummaryAddress::SummaryVarCategory category = RifEclipseSummaryAddress::identifyCategory( quantityName );
if ( category == RifEclipseSummaryAddress::SUMMARY_INVALID )
{
return RifEclipseSummaryAddress::importedAddress( quantityName );
}
int regionNumber = -1;
int regionNumber2 = -1;
std::string wellGroupName = "";
std::string wellName = "";
int wellSegmentNumber = -1;
std::string lgrName = "";
int cellI = -1;
int cellJ = -1;
int cellK = -1;
int aquiferNumber = -1;
bool isErrorResult = false;
int id = -1;
switch ( category )
{
case RifEclipseSummaryAddress::SUMMARY_FIELD:
break;
case RifEclipseSummaryAddress::SUMMARY_AQUIFER:
{
if ( columnHeaderText.size() > 0 )
{
aquiferNumber = RiaStdStringTools::toInt( columnHeaderText[0] );
}
break;
}
case RifEclipseSummaryAddress::SUMMARY_NETWORK:
break;
case RifEclipseSummaryAddress::SUMMARY_MISC:
break;
case RifEclipseSummaryAddress::SUMMARY_REGION:
{
if ( columnHeaderText.size() > 0 )
{
regionNumber = RiaStdStringTools::toInt( columnHeaderText[0] );
}
break;
}
case RifEclipseSummaryAddress::SUMMARY_REGION_2_REGION:
break;
case RifEclipseSummaryAddress::SUMMARY_WELL_GROUP:
{
if ( columnHeaderText.size() > 0 )
{
wellGroupName = columnHeaderText[0];
}
break;
}
case RifEclipseSummaryAddress::SUMMARY_WELL:
{
if ( columnHeaderText.size() > 0 )
{
wellName = columnHeaderText[0];
}
break;
}
case RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION:
{
if ( columnHeaderText.size() > 1 )
{
wellName = columnHeaderText[0];
RifEclipseUserDataKeywordTools::extractThreeInts( &cellI, &cellJ, &cellK, columnHeaderText[1] );
}
break;
}
break;
case RifEclipseSummaryAddress::SUMMARY_WELL_LGR:
if ( columnHeaderText.size() > 1 )
{
wellName = columnHeaderText[0];
lgrName = columnHeaderText[1];
}
break;
case RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION_LGR:
if ( columnHeaderText.size() > 2 )
{
wellName = columnHeaderText[0];
lgrName = columnHeaderText[1];
RifEclipseUserDataKeywordTools::extractThreeInts( &cellI, &cellJ, &cellK, columnHeaderText[2] );
}
break;
case RifEclipseSummaryAddress::SUMMARY_WELL_SEGMENT:
if ( columnHeaderText.size() > 1 )
{
wellName = columnHeaderText[0];
wellSegmentNumber = RiaStdStringTools::toInt( columnHeaderText[1] );
}
break;
case RifEclipseSummaryAddress::SUMMARY_BLOCK:
if ( columnHeaderText.size() > 0 )
{
RifEclipseUserDataKeywordTools::extractThreeInts( &cellI, &cellJ, &cellK, columnHeaderText[0] );
}
break;
case RifEclipseSummaryAddress::SUMMARY_BLOCK_LGR:
if ( columnHeaderText.size() > 1 )
{
lgrName = columnHeaderText[0];
RifEclipseUserDataKeywordTools::extractThreeInts( &cellI, &cellJ, &cellK, columnHeaderText[1] );
}
break;
case RifEclipseSummaryAddress::SUMMARY_CALCULATED:
break;
default:
break;
}
return RifEclipseSummaryAddress( category,
quantityName,
regionNumber,
regionNumber2,
wellGroupName,
wellName,
wellSegmentNumber,
lgrName,
cellI,
cellJ,
cellK,
aquiferNumber,
isErrorResult,
id );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataKeywordTools::isStepType( const std::string& identifier )
{
return ( identifier.find( "STEPTYPE" ) != std::string::npos );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RifEclipseUserDataKeywordTools::computeRequiredHeaderLineCount( const std::vector<std::string>& words )
{
size_t maxHeaderLinesFromKeywords = 0;
for ( auto w : words )
{
if ( knownKeywordsWithZeroRequiredHeaderLines( w ) ) continue;
auto linesForKeyword = RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword( w ).size();
if ( linesForKeyword > maxHeaderLinesFromKeywords )
{
maxHeaderLinesFromKeywords = linesForKeyword;
}
}
// Quantity and unit, scaling is optional
return 1 + maxHeaderLinesFromKeywords;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataKeywordTools::knownKeywordsWithZeroRequiredHeaderLines( const std::string& identifier )
{
if ( identifier.find( "DAY" ) != std::string::npos ) return true;
if ( identifier.find( "MONTH" ) != std::string::npos ) return true;
if ( identifier.find( "YEAR" ) != std::string::npos ) return true;
if ( identifier.find( "DATE" ) != std::string::npos ) return true;
if ( identifier.find( "TIME" ) != std::string::npos ) return true;
if ( identifier.find( "ELAPSED" ) != std::string::npos ) return true;
if ( identifier.find( "NEWTON" ) != std::string::npos ) return true;
if ( identifier.find( "NLINSMIN" ) != std::string::npos ) return true;
if ( identifier.find( "NLINSMAX" ) != std::string::npos ) return true;
if ( identifier.find( "MLINEARS" ) != std::string::npos ) return true;
if ( identifier.find( "MSUMLINS" ) != std::string::npos ) return true;
if ( identifier.find( "MSUMNEWT" ) != std::string::npos ) return true;
if ( identifier.find( "TCPU" ) != std::string::npos ) return true;
if ( identifier.find( "TCPUTS" ) != std::string::npos ) return true;
if ( identifier.find( "TCPUDAY" ) != std::string::npos ) return true;
if ( identifier.find( "TELAPLIN" ) != std::string::npos ) return true;
if ( identifier.find( "STEPTYPE" ) != std::string::npos ) return true;
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseUserDataKeywordTools::extractThreeInts( int* cellI, int* cellJ, int* cellK, const std::string& line )
{
std::vector<std::string> words = RiaStdStringTools::splitStringBySpace( line );
if ( words.size() > 2 )
{
*cellI = RiaStdStringTools::toInt( words[0] );
*cellJ = RiaStdStringTools::toInt( words[1] );
*cellK = RiaStdStringTools::toInt( words[2] );
}
}

View File

@@ -0,0 +1,53 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifEclipseUserDataParserTools.h"
#include <string>
#include <vector>
//==================================================================================================
///
//==================================================================================================
class RifEclipseUserDataKeywordTools
{
public:
static std::vector<size_t> requiredItemsPerLineForKeyword( const std::string& identifier );
static std::vector<std::vector<std::string>>
buildColumnHeaderText( const std::vector<std::string>& quantityNames,
const std::vector<std::vector<std::string>>& restOfHeaderRows,
std::vector<std::string>* errorText = nullptr );
static bool isTime( const std::string& identifier );
static bool isDate( const std::string& identifier );
static bool isDays( const std::string& identifier );
static bool isYears( const std::string& identifier );
static bool isYearX( const std::string& identifier );
static RifEclipseSummaryAddress makeAndFillAddress( const std::string quantityName,
const std::vector<std::string>& columnHeaderText );
static bool isStepType( const std::string& identifier );
static size_t computeRequiredHeaderLineCount( const std::vector<std::string>& words );
static bool knownKeywordsWithZeroRequiredHeaderLines( const std::string& identifier );
static void extractThreeInts( int* i, int* j, int* k, const std::string& line );
};

View File

@@ -0,0 +1,940 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifEclipseUserDataParserTools.h"
#include "RiaDateStringParser.h"
#include "RiaLogging.h"
#include "RiaQDateTimeTools.h"
#include "RiaStdStringTools.h"
#include "RifEclipseUserDataKeywordTools.h"
#include "cvfAssert.h"
#include <QString>
#include <QStringList>
#include <QTextStream>
#include <algorithm>
#include <numeric>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::isLineSkippable( const std::string& line )
{
std::size_t found = line.find_first_not_of( " " );
if ( found == std::string::npos )
{
// Line with only spaces
return true;
}
if ( line[found] == '-' )
{
// Comments start with -
return true;
}
if ( line[found] == '1' && found == 0 && line.find_first_not_of( "1 ", 1 ) == std::string::npos )
{
// Single 1 at start of file
return true;
}
std::string str( line );
if ( str.find( "SUMMARY" ) < str.size() )
{
return true;
}
if ( str.find( "PAGE" ) < str.size() )
{
return true;
}
if ( str.find( "NULL" ) < str.size() )
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::isAComment( const std::string& word )
{
if ( word.find( "--" ) != std::string::npos )
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::string> RifEclipseUserDataParserTools::splitLineAndRemoveComments( const std::string& line )
{
std::istringstream iss( line );
std::vector<std::string> words{ std::istream_iterator<std::string>{ iss }, std::istream_iterator<std::string>{} };
for ( auto wordsIterator = words.begin(); wordsIterator != words.end(); ++wordsIterator )
{
if ( isAComment( *wordsIterator ) )
{
words.erase( wordsIterator, words.end() );
break;
}
}
return words;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::keywordParser( const std::string& line,
std::string& origin,
std::string& dateFormat,
std::string& startDate )
{
std::vector<std::string> words = splitLineAndRemoveComments( line );
if ( words.size() < 2 ) return false;
if ( words[0] == "ORIGIN" )
{
origin = words[1];
return true;
}
else if ( words[0] == "STARTDATE" )
{
words.erase( words.begin() );
for ( size_t i = 0; i < words.size(); i++ )
{
std::string s = words[i];
startDate += s;
if ( i < words.size() - 1 )
{
startDate += " ";
}
}
return true;
}
else if ( words[0] == "DATEFORMAT" )
{
dateFormat = words[1];
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RifEclipseUserDataParserTools::splitLineToDoubles( const std::string& line )
{
std::vector<double> values;
QString s = QString::fromStdString( line );
QStringList words = s.split( " " );
bool ok = false;
for ( auto w : words )
{
double val = w.toDouble( &ok );
if ( ok )
{
values.push_back( val );
}
}
return values;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::isANumber( const std::string& line )
{
try
{
std::stod( line );
}
catch ( ... )
{
return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::string> RifEclipseUserDataParserTools::headerReader( std::stringstream& streamData, std::string& line )
{
std::vector<std::string> header;
while ( !isANumber( line ) && !streamData.eof() )
{
header.push_back( line );
std::getline( streamData, line );
}
return header;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::hasTimeUnit( const std::string& word )
{
if ( word == "DAYS" || word == "DAY" || word == "YEARS" || word == "YEAR" || word == "DATE" || word == "DATES" )
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::hasOnlyValidDoubleValues( const std::vector<std::string>& words,
std::vector<double>* doubleValues )
{
bool onlyValidValues = true;
for ( const auto& word : words )
{
if ( word.find_first_not_of( "0123456789.eE-+" ) != std::string::npos )
{
onlyValidValues = false;
}
else
{
double doubleVal = RiaStdStringTools::toDouble( word );
doubleValues->push_back( doubleVal );
}
}
return onlyValidValues;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::isValidTableData( size_t columnCount, const std::string& line )
{
std::vector<std::string> words = splitLineAndRemoveComments( line );
if ( words.size() != columnCount ) return false;
std::vector<double> doubleValues;
RifEclipseUserDataParserTools::hasOnlyValidDoubleValues( words, &doubleValues );
if ( doubleValues.size() == columnCount ) return true;
size_t columnsWithDate = 0;
for ( auto w : words )
{
if ( RiaDateStringParser::parseDateString( w ).isValid() )
{
columnsWithDate++;
}
}
if ( columnsWithDate == 1 && doubleValues.size() == columnCount - 1 )
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TableData RifEclipseUserDataParserTools::tableDataFromText( std::stringstream& streamData,
std::vector<std::string>* errorText )
{
TableData emptyTable;
std::string origin = "";
std::string dateFormat = "";
std::string startDate = "";
std::string firstLine;
std::getline( streamData, firstLine );
while ( isLineSkippable( firstLine ) || keywordParser( firstLine, origin, dateFormat, startDate ) )
{
if ( !streamData.good() )
{
// End of file
return emptyTable;
}
std::getline( streamData, firstLine );
}
std::vector<std::string> quantityNames = splitLineAndRemoveComments( firstLine );
size_t columnCount = quantityNames.size();
if ( columnCount == 0 )
{
if ( errorText ) errorText->push_back( "No quantities detected in table" );
return emptyTable;
}
std::vector<std::vector<std::string>> allHeaderRows;
{
std::stringstream::pos_type posAtStartOfFirstLine = streamData.tellg();
std::string secondLine;
std::getline( streamData, firstLine );
std::stringstream::pos_type posAtStartOfSecondLine = streamData.tellg();
std::getline( streamData, secondLine );
bool header = true;
while ( header )
{
if ( isValidTableData( columnCount, firstLine ) && isValidTableData( columnCount, secondLine ) )
{
header = false;
break;
}
else
{
std::vector<std::string> words = splitLineAndRemoveComments( firstLine );
if ( words.size() > 0 )
{
allHeaderRows.push_back( words );
}
}
posAtStartOfFirstLine = posAtStartOfSecondLine;
firstLine = secondLine;
posAtStartOfSecondLine = streamData.tellg();
std::getline( streamData, secondLine );
if ( !streamData.good() )
{
header = false;
}
}
streamData.seekg( posAtStartOfFirstLine );
}
std::vector<std::string> unitNames;
std::vector<double> scaleFactors;
std::vector<std::vector<std::string>> headerRows;
for ( const auto& rowWords : allHeaderRows )
{
bool excludeFromHeader = false;
if ( rowWords.size() == columnCount )
{
if ( unitNames.size() == 0 )
{
for ( const std::string& word : rowWords )
{
if ( hasTimeUnit( word ) )
{
unitNames = rowWords;
excludeFromHeader = true;
}
}
}
if ( scaleFactors.size() == 0 )
{
std::vector<double> values;
if ( hasOnlyValidDoubleValues( rowWords, &values ) )
{
scaleFactors = values;
excludeFromHeader = true;
}
}
}
if ( !excludeFromHeader )
{
headerRows.push_back( rowWords );
}
}
if ( columnCount != unitNames.size() )
{
if ( errorText ) errorText->push_back( "Number of quantities is different from number of units" );
return emptyTable;
}
std::vector<Column> columnInfos;
// Create string vectors for each column
{
std::vector<std::string> parserErrors;
std::vector<std::vector<std::string>> tableHeaderText =
RifEclipseUserDataKeywordTools::buildColumnHeaderText( quantityNames, headerRows, &parserErrors );
if ( parserErrors.size() > 0 )
{
if ( errorText ) errorText->insert( errorText->end(), parserErrors.begin(), parserErrors.end() );
return emptyTable;
}
// For each column header, create rif adress and date time
for ( size_t i = 0; i < tableHeaderText.size(); i++ )
{
auto columnText = tableHeaderText[i];
if ( columnText.size() == 0 )
{
if ( errorText ) errorText->push_back( "Detected column with no content" );
continue;
}
std::string quantity = columnText[0];
std::string unit = unitNames[i];
std::vector<std::string> columnHeader;
if ( columnText.size() > 1 )
columnHeader.insert( columnHeader.begin(), columnText.begin() + 1, columnText.end() );
RifEclipseSummaryAddress adr = RifEclipseUserDataKeywordTools::makeAndFillAddress( quantity, columnHeader );
Column ci = Column::createColumnInfoFromRsmData( quantity, unit, adr );
columnInfos.push_back( ci );
}
}
return TableData( origin, startDate, columnInfos );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::isFixedWidthHeader( const std::string& lines )
{
std::stringstream streamData( lines );
std::vector<std::string> headerLines = RifEclipseUserDataParserTools::findValidHeaderLines( streamData );
if ( headerLines.size() > 1 )
{
std::vector<size_t> firstLine = RifEclipseUserDataParserTools::columnIndexForWords( headerLines[0] );
for ( auto line : headerLines )
{
std::vector<size_t> columnIndicesForLine = RifEclipseUserDataParserTools::columnIndexForWords( line );
for ( auto index : columnIndicesForLine )
{
if ( std::find( firstLine.begin(), firstLine.end(), index ) == firstLine.end() )
{
return false;
}
}
}
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<Column> RifEclipseUserDataParserTools::columnInfoForFixedColumnWidth( std::stringstream& streamData )
{
auto headerLines = RifEclipseUserDataParserTools::findValidHeaderLines( streamData );
auto columnHeaders = RifEclipseUserDataParserTools::splitIntoColumnHeaders( headerLines );
return RifEclipseUserDataParserTools::columnInfoFromColumnHeaders( columnHeaders );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::string> RifEclipseUserDataParserTools::findValidHeaderLines( std::stringstream& streamData )
{
std::vector<std::string> headerLines;
std::stringstream::pos_type posAtTableDataStart = streamData.tellg();
size_t columnCount = 0;
std::string line;
bool continueParsing = true;
bool hasStepType = false;
size_t minimunRequiredExtraHeaderLines = 0;
while ( continueParsing )
{
posAtTableDataStart = streamData.tellg();
if ( !std::getline( streamData, line ) )
{
continueParsing = false;
}
else
{
if ( !RifEclipseUserDataParserTools::isLineSkippable( line ) )
{
auto words = RifEclipseUserDataParserTools::splitLineAndRemoveComments( line );
if ( !hasStepType )
{
for ( size_t i = 0; i < words.size(); i++ )
{
if ( RifEclipseUserDataKeywordTools::isStepType( words[i] ) )
{
hasStepType = true;
}
}
}
if ( isUnitText( line ) )
{
minimunRequiredExtraHeaderLines += 1;
}
if ( isScalingText( line ) )
{
minimunRequiredExtraHeaderLines += 1;
}
if ( columnCount == 0 )
{
// Fist line with valid header data defines the number of columns
columnCount = words.size();
minimunRequiredExtraHeaderLines =
RifEclipseUserDataKeywordTools::computeRequiredHeaderLineCount( words );
headerLines.push_back( line );
}
else if ( headerLines.size() < minimunRequiredExtraHeaderLines )
{
headerLines.push_back( line );
}
else
{
std::vector<double> doubleValues = RifEclipseUserDataParserTools::splitLineToDoubles( line );
if ( doubleValues.size() < columnCount && words.size() < columnCount )
{
if ( hasStepType && ( words.size() + 1 == columnCount ) )
{
continueParsing = false;
}
else
{
// Consider a line with double values less than column count as a table header
headerLines.push_back( line );
}
}
else
{
continueParsing = false;
}
}
}
}
}
streamData.seekg( posAtTableDataStart );
return headerLines;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<std::string>>
RifEclipseUserDataParserTools::splitIntoColumnHeaders( const std::vector<std::string>& headerLines )
{
std::vector<std::vector<std::string>> headerLinesPerColumn;
if ( headerLines.size() > 0 )
{
std::vector<size_t> columnOffsets = RifEclipseUserDataParserTools::columnIndexForWords( headerLines[0] );
if ( columnOffsets.size() > 0 )
{
headerLinesPerColumn.resize( columnOffsets.size() );
for ( auto headerLine : headerLines )
{
for ( size_t i = 0; i < columnOffsets.size(); i++ )
{
size_t colStart = columnOffsets[i];
size_t columnWidth = std::string::npos;
if ( i < columnOffsets.size() - 1 )
{
columnWidth = columnOffsets[i + 1] - colStart;
}
else
{
if ( headerLine.size() > colStart )
{
columnWidth = headerLine.size() - colStart;
}
}
std::string subString;
if ( columnWidth != std::string::npos && colStart < headerLine.size() &&
colStart + columnWidth <= headerLine.size() )
{
subString = headerLine.substr( colStart, columnWidth );
}
subString = trimString( subString );
headerLinesPerColumn[i].push_back( subString );
}
}
}
}
return headerLinesPerColumn;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<Column>
RifEclipseUserDataParserTools::columnInfoFromColumnHeaders( const std::vector<std::vector<std::string>>& columnData )
{
std::vector<Column> table;
bool isUnitsDetected = false;
bool isScalingDetected = false;
for ( auto columnLines : columnData )
{
if ( columnLines.size() > 1 && isUnitText( columnLines[1] ) )
{
isUnitsDetected = true;
}
if ( columnLines.size() > 2 && isScalingText( columnLines[2] ) )
{
isScalingDetected = true;
}
}
for ( auto columnLines : columnData )
{
if ( columnLines.size() == 0 ) continue;
std::string quantity = columnLines[0];
std::string unit;
size_t startIndex = 1;
if ( isUnitsDetected )
{
unit = columnLines[1];
startIndex = 2;
}
if ( isScalingDetected )
{
// std::string scaling = columnLines[2];
startIndex = 3;
}
std::vector<std::string> restOfHeader;
for ( size_t i = startIndex; i < columnLines.size(); i++ )
{
restOfHeader.push_back( columnLines[i] );
}
RifEclipseSummaryAddress adr = RifEclipseUserDataKeywordTools::makeAndFillAddress( quantity, restOfHeader );
Column ci = Column::createColumnInfoFromRsmData( quantity, unit, adr );
table.push_back( ci );
}
return table;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<size_t> RifEclipseUserDataParserTools::columnIndexForWords( const std::string& line )
{
std::vector<size_t> columnOffsets;
std::size_t offset = line.find_first_not_of( " " );
while ( offset != std::string::npos )
{
columnOffsets.push_back( offset );
offset = line.find_first_of( " ", offset );
offset = line.find_first_not_of( " ", offset );
}
return columnOffsets;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<TableData> RifEclipseUserDataParserTools::mergeEqualTimeSteps( const std::vector<TableData>& tables )
{
if ( tables.size() < 2 )
{
return tables;
}
if ( tables[0].columnInfos().size() == 0 ) return tables;
QDateTime firstTableStartTime;
for ( auto c : tables[0].columnInfos() )
{
if ( c.summaryAddress.quantityName() == "DATE" )
{
if ( c.itemCount() > 0 )
{
firstTableStartTime = RiaDateStringParser::parseDateString( c.textValues[0] );
}
}
}
if ( !firstTableStartTime.isValid() )
{
return tables;
}
std::vector<TableData> largeTables;
largeTables.push_back( tables[0] );
TableData& firstTable = largeTables[0];
size_t itemsInFirstTable = tables[0].columnInfos()[0].itemCount();
for ( size_t i = 1; i < tables.size(); i++ )
{
bool isDatesEqual = true;
if ( firstTableStartTime.isValid() )
{
QDateTime tableFirstTime;
for ( auto& c : tables[i].columnInfos() )
{
if ( c.summaryAddress.quantityName() == "DATE" )
{
if ( c.itemCount() > 0 )
{
tableFirstTime = RiaDateStringParser::parseDateString( c.textValues[0] );
}
}
}
if ( firstTableStartTime != tableFirstTime )
{
isDatesEqual = false;
}
}
if ( tables[i].columnInfos().size() > 0 && tables[i].columnInfos()[0].itemCount() == itemsInFirstTable &&
isDatesEqual )
{
for ( auto& c : tables[i].columnInfos() )
{
if ( c.summaryAddress.quantityName() != "DATE" )
{
firstTable.columnInfos().push_back( c );
}
}
}
else
{
largeTables.push_back( tables[i] );
}
}
return largeTables;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RifEclipseUserDataParserTools::trimString( const std::string& s )
{
auto sCopy = s.substr( 0, s.find_last_not_of( ' ' ) + 1 );
if ( sCopy.size() > 0 )
{
sCopy = sCopy.substr( sCopy.find_first_not_of( ' ' ) );
}
return sCopy;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::isUnitText( const std::string& word )
{
if ( hasTimeUnit( word ) ) return true;
if ( word.find( "BARSA" ) != std::string::npos ) return true;
if ( word.find( "SM3" ) != std::string::npos ) return true;
if ( word.find( "RM3" ) != std::string::npos ) return true;
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::isScalingText( const std::string& word )
{
return word.find_first_of( '*' ) != std::string::npos;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string Column::columnName() const
{
return summaryAddress.uiText();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t Column::itemCount() const
{
switch ( dataType )
{
case NUMERIC:
return values.size();
case TEXT:
return textValues.size();
case DATETIME:
return dateTimeValues.size();
default:
return 0;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Column Column::createColumnInfoFromRsmData( const std::string& quantity,
const std::string& unit,
const RifEclipseSummaryAddress& addr )
{
Column ci( addr, unit );
if ( RifEclipseUserDataKeywordTools::isDate( quantity ) )
{
ci.dataType = TEXT;
}
else if ( RifEclipseUserDataKeywordTools::isStepType( quantity ) )
{
ci.dataType = TEXT;
}
else
{
ci.dataType = NUMERIC;
}
return ci;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Column Column::createColumnInfoFromCsvData( const RifEclipseSummaryAddress& addr, const std::string& unit )
{
Column col( addr, unit );
return col;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<QDateTime> Column::qDateTimeValues() const
{
std::vector<QDateTime> output;
for ( auto t : dateTimeValues )
output.push_back( RiaQDateTimeTools::fromTime_t( t ) );
return output;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int TableData::dateTimeColumnIndex() const
{
return m_dateTimeColumnIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QDateTime TableData::findFirstDate() const
{
QDateTime dt = RiaQDateTimeTools::epoch();
for ( auto ci : m_columnInfos )
{
if ( RifEclipseUserDataKeywordTools::isDate( ci.summaryAddress.quantityName() ) )
{
if ( ci.itemCount() > 0 )
{
std::string firstDateString = ci.textValues[0];
QDateTime candidate = RiaDateStringParser::parseDateString( firstDateString );
if ( candidate.isValid() )
{
dt = candidate;
}
}
}
}
return dt;
}

View File

@@ -0,0 +1,164 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifEclipseSummaryAddress.h"
#include <QDateTime>
#include <QLocale>
#include <QString>
#include <sstream>
#include <string>
#include <vector>
//==================================================================================================
///
//==================================================================================================
class Column
{
public:
enum DataType
{
NONE,
NUMERIC,
TEXT,
DATETIME
};
Column()
: scaleFactor( 1.0 )
, dataType( NONE )
{
}
Column( const RifEclipseSummaryAddress& adr, const std::string& unit )
: summaryAddress( adr )
, scaleFactor( 1.0 )
, unitName( unit )
, dataType( NONE )
{
}
std::string columnName() const;
size_t itemCount() const;
public:
static Column createColumnInfoFromRsmData( const std::string& quantity,
const std::string& unit,
const RifEclipseSummaryAddress& addr );
static Column createColumnInfoFromCsvData( const RifEclipseSummaryAddress& addr, const std::string& unit );
RifEclipseSummaryAddress summaryAddress;
std::string unitName;
double scaleFactor;
DataType dataType;
// Data containers
std::vector<double> values;
std::vector<std::string> textValues;
// std::vector<QDateTime> dateTimeValues;
std::vector<time_t> dateTimeValues;
std::vector<QDateTime> qDateTimeValues() const;
};
//==================================================================================================
///
//==================================================================================================
class TableData
{
public:
TableData() {}
TableData( const std::string& origin, const std::string& startDate, const std::vector<Column>& columnInfos )
: m_origin( origin )
, m_startDate( startDate )
, m_dateTimeColumnIndex( -1 )
, m_columnInfos( columnInfos )
{
for ( size_t i = 0; i < columnInfos.size(); i++ )
{
if ( columnInfos[i].dataType == Column::DATETIME )
{
m_dateTimeColumnIndex = (int)i;
break;
}
}
}
std::string origin() const { return m_origin; }
std::string startDate() const { return m_startDate; }
std::vector<Column>& columnInfos() { return m_columnInfos; }
const std::vector<Column>& columnInfos() const { return m_columnInfos; }
int dateTimeColumnIndex() const;
QDateTime findFirstDate() const;
private:
std::string m_origin;
std::string m_startDate;
int m_dateTimeColumnIndex;
std::vector<Column> m_columnInfos;
};
//==================================================================================================
///
//==================================================================================================
class RifEclipseUserDataParserTools
{
public:
static bool isLineSkippable( const std::string& line );
static bool isAComment( const std::string& word );
static std::vector<std::string> splitLineAndRemoveComments( const std::string& line );
static std::vector<double> splitLineToDoubles( const std::string& line );
static bool
keywordParser( const std::string& line, std::string& origin, std::string& dateFormat, std::string& startDate );
static bool isANumber( const std::string& line );
static std::vector<std::string> headerReader( std::stringstream& streamData, std::string& line );
static bool hasTimeUnit( const std::string& line );
static bool hasOnlyValidDoubleValues( const std::vector<std::string>& words,
std::vector<double>* doubleValues = nullptr );
static bool isValidTableData( size_t columnCount, const std::string& line );
static TableData tableDataFromText( std::stringstream& data, std::vector<std::string>* errorText = nullptr );
// Fixed width functions
static bool isFixedWidthHeader( const std::string& lines );
static std::vector<Column> columnInfoForFixedColumnWidth( std::stringstream& streamData );
static std::vector<std::string> findValidHeaderLines( std::stringstream& streamData );
static std::vector<std::vector<std::string>> splitIntoColumnHeaders( const std::vector<std::string>& headerLines );
static std::vector<Column> columnInfoFromColumnHeaders( const std::vector<std::vector<std::string>>& columnData );
static std::vector<size_t> columnIndexForWords( const std::string& line );
static std::vector<TableData> mergeEqualTimeSteps( const std::vector<TableData>& tables );
static bool isUnitText( const std::string& word );
static bool isScalingText( const std::string& word );
private:
static std::string trimString( const std::string& s );
};

View File

@@ -0,0 +1,188 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 "RifElasticPropertiesReader.h"
#include "RifFileParseTools.h"
#include <QFileInfo>
#include <QTextStream>
//==================================================================================================
///
//==================================================================================================
void RifElasticPropertiesReader::readElasticProperties( std::vector<RifElasticProperties>& elasticProperties,
const QStringList& filePaths,
const QString& separator )
{
for ( const QString& filePath : filePaths )
{
try
{
readElasticProperties( elasticProperties, filePath, separator );
}
catch ( FileParseException& )
{
// Delete all facies properties and rethrow exception
elasticProperties.clear();
throw;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifElasticPropertiesReader::readElasticProperties( std::vector<RifElasticProperties>& elasticProperties,
const QString& filePath,
const QString& separator )
{
QFile file( filePath );
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
throw FileParseException( QString( "Unable to open file: %1" ).arg( filePath ) );
}
QTextStream in( &file );
int lineNumber = 1;
while ( !in.atEnd() )
{
QString line = in.readLine();
if ( !isEmptyLine( line ) && !isCommentLine( line ) )
{
RifElasticProperties faciesProp = parseElasticProperties( line, lineNumber, filePath, separator );
elasticProperties.push_back( faciesProp );
}
lineNumber++;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifElasticProperties RifElasticPropertiesReader::parseElasticProperties( const QString& line,
int lineNumber,
const QString& filePath,
const QString& separator )
{
QStringList tokens = tokenize( line, separator );
// Plus one to allow trailing separator
const int expectedTokens = 13;
if ( !( tokens.size() == expectedTokens || tokens.size() == expectedTokens + 1 ) )
{
throw FileParseException( QString( "Incomplete data on line %1: %2" ).arg( lineNumber ).arg( filePath ) );
}
// Check for unexpected empty tokens
QStringList nameOfNonEmptyTokens;
nameOfNonEmptyTokens << "Field Name"
<< "Formation Name"
<< "Facies Name"
<< "Porosity"
<< "Young's Modulus"
<< "Poisson's Ratio"
<< "K-Ic"
<< "Proppant Embedment"
<< "Biot Coefficient"
<< "k0"
<< "Fluid Loss Coefficient"
<< "Spurt Loss"
<< "Immobile Fluid Saturation";
verifyNonEmptyTokens( tokens, nameOfNonEmptyTokens, lineNumber, filePath );
RifElasticProperties elasticProperties;
elasticProperties.fieldName = tokens[0];
elasticProperties.formationName = tokens[1];
elasticProperties.faciesName = tokens[2];
elasticProperties.porosity = parseDouble( tokens[3], "Porosity", lineNumber, filePath );
elasticProperties.youngsModulus = parseDouble( tokens[4], "Young's Modulus", lineNumber, filePath );
elasticProperties.poissonsRatio = parseDouble( tokens[5], "Poisson's Ratio", lineNumber, filePath );
elasticProperties.K_Ic = parseDouble( tokens[6], "K-Ic", lineNumber, filePath );
elasticProperties.proppantEmbedment = parseDouble( tokens[7], "Proppant Embedment", lineNumber, filePath );
elasticProperties.biotCoefficient = parseDouble( tokens[8], "Biot Coefficient", lineNumber, filePath );
elasticProperties.k0 = parseDouble( tokens[9], "k0", lineNumber, filePath );
elasticProperties.fluidLossCoefficient = parseDouble( tokens[10], "Fluid Loss Coefficient", lineNumber, filePath );
elasticProperties.spurtLoss = parseDouble( tokens[11], "Spurt Loss", lineNumber, filePath );
elasticProperties.immobileFluidSaturation =
parseDouble( tokens[12], "Immobile Fluid Saturation", lineNumber, filePath );
return elasticProperties;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList RifElasticPropertiesReader::tokenize( const QString& line, const QString& separator )
{
return RifFileParseTools::splitLineAndTrim( line, separator );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RifElasticPropertiesReader::parseDouble( const QString& token,
const QString& propertyName,
int lineNumber,
const QString& filePath )
{
bool isOk = false;
double value = token.toDouble( &isOk );
if ( !isOk )
{
throw FileParseException(
QString( "Invalid number for '%1' on line %2: %3" ).arg( propertyName ).arg( lineNumber ).arg( filePath ) );
}
return value;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifElasticPropertiesReader::isEmptyLine( const QString& line )
{
return line.trimmed().isEmpty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifElasticPropertiesReader::isCommentLine( const QString& line )
{
return line.trimmed().startsWith( "#" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifElasticPropertiesReader::verifyNonEmptyTokens( const QStringList& tokens,
const QStringList& nameOfNonEmptyTokens,
int lineNumber,
const QString& filePath )
{
for ( int i = 0; i < nameOfNonEmptyTokens.size(); ++i )
{
if ( tokens[i].isEmpty() )
{
throw FileParseException(
QString( "Unexpected empty '%1' on line %2: %3" ).arg( nameOfNonEmptyTokens[i] ).arg( lineNumber ).arg( filePath ) );
}
}
}

View File

@@ -0,0 +1,68 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 <vector>
#include <QString>
struct RifElasticProperties
{
QString fieldName;
QString formationName;
QString faciesName;
double porosity;
double youngsModulus;
double poissonsRatio;
double K_Ic;
double proppantEmbedment;
double biotCoefficient;
double k0;
double fluidLossCoefficient;
double spurtLoss;
double immobileFluidSaturation;
};
//==================================================================================================
///
//==================================================================================================
class RifElasticPropertiesReader
{
public:
static void readElasticProperties( std::vector<RifElasticProperties>& elasticProperties,
const QStringList& filePaths,
const QString& separator = "," );
private:
static void readElasticProperties( std::vector<RifElasticProperties>& elasticProperties,
const QString& filePath,
const QString& separator );
static RifElasticProperties
parseElasticProperties( const QString& line, int lineNumber, const QString& filePath, const QString& separator );
static QStringList tokenize( const QString& line, const QString& separator );
static void verifyNonEmptyTokens( const QStringList& tokens,
const QStringList& nameOfNonEmptyTokens,
int lineNumber,
const QString& filePath );
static double parseDouble( const QString& token, const QString& propertyName, int lineNumber, const QString& filePath );
static bool isEmptyLine( const QString& line );
static bool isCommentLine( const QString& line );
};

View File

@@ -0,0 +1,239 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- 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 "RifElementPropertyReader.h"
#include "RiaLogging.h"
#include "cvfAssert.h"
#include <cmath>
#include <QString>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifElementPropertyReader::RifElementPropertyReader( const std::vector<int>& elementIdxToId )
: m_elementIdxToId( elementIdxToId )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifElementPropertyReader::~RifElementPropertyReader()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifElementPropertyReader::addFile( const std::string& fileName )
{
RifElementPropertyMetadata metaData = RifElementPropertyTableReader::readMetadata( QString::fromStdString( fileName ) );
for ( QString field : metaData.dataColumns )
{
m_fieldsMetaData[field.toStdString()] = metaData;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifElementPropertyReader::removeFile( const std::string& fileName )
{
std::map<std::string, RifElementPropertyMetadata> tempMetaData;
for ( std::pair<std::string, RifElementPropertyMetadata> metaData : m_fieldsMetaData )
{
if ( metaData.second.fileName.toStdString() != fileName )
{
tempMetaData[metaData.first] = metaData.second;
}
}
m_fieldsMetaData.swap( tempMetaData );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::string> RifElementPropertyReader::scalarElementFields() const
{
std::vector<std::string> fields;
for ( const std::pair<const std::string, RifElementPropertyMetadata>& field : m_fieldsMetaData )
{
fields.push_back( field.first );
}
return fields;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::map<std::string, std::vector<float>>
RifElementPropertyReader::readAllElementPropertiesInFileContainingField( const std::string& fieldName )
{
std::map<std::string, std::vector<float>> fieldAndData;
if ( m_fieldsMetaData.find( fieldName ) == m_fieldsMetaData.end() )
{
return fieldAndData;
}
RifElementPropertyTable table;
RifElementPropertyTableReader::readData( &m_fieldsMetaData[fieldName], &table );
CVF_ASSERT( m_fieldsMetaData[fieldName].dataColumns.size() == table.data.size() );
for ( size_t i = 0; i < table.data.size(); i++ )
{
CVF_ASSERT( table.data[i].size() == table.elementIds.size() );
}
const std::vector<int>& elementIdsFromFile = table.elementIds;
if ( elementIdsFromFile == m_elementIdxToId )
{
for ( size_t i = 0; i < table.data.size(); i++ )
{
const std::string& currentFieldFromFile = m_fieldsMetaData[fieldName].dataColumns[i].toStdString();
if ( currentFieldFromFile == "MODULUS" )
{
const std::vector<float>& currentColumn = table.data[i];
std::vector<float> tempResult( currentColumn.size(), 0 );
for ( float resultItem : currentColumn )
{
tempResult[i] = resultItem * 0.000000001;
}
fieldAndData[currentFieldFromFile].swap( tempResult );
}
else
{
fieldAndData[currentFieldFromFile] = table.data[i];
}
}
}
else if ( elementIdsFromFile.size() > m_elementIdxToId.size() && elementIdsFromFile.size() > m_elementIdToIdx.size() )
{
RifElementPropertyReader::outputWarningAboutWrongFileData();
return fieldAndData;
}
else
{
if ( m_elementIdToIdx.empty() )
{
makeElementIdToIdxMap();
}
std::vector<int> fileIdxToElementIdx;
fileIdxToElementIdx.reserve( elementIdsFromFile.size() );
for ( int elementId : elementIdsFromFile )
{
std::unordered_map<int /*elm ID*/, int /*elm idx*/>::const_iterator it = m_elementIdToIdx.find( elementId );
if ( it == m_elementIdToIdx.end() )
{
RifElementPropertyReader::outputWarningAboutWrongFileData();
return fieldAndData;
}
fileIdxToElementIdx.push_back( it->second );
}
for ( size_t i = 0; i < table.data.size(); i++ )
{
std::string currentFieldFromFile = m_fieldsMetaData[fieldName].dataColumns[i].toStdString();
const std::vector<float>& currentColumn = table.data[i];
std::vector<float> tempResult( m_elementIdToIdx.size(), HUGE_VAL );
if ( currentFieldFromFile == "MODULUS" )
{
for ( size_t j = 0; j < currentColumn.size(); j++ )
{
tempResult[fileIdxToElementIdx[j]] = currentColumn[j] * 0.000000001;
}
}
else
{
for ( size_t j = 0; j < currentColumn.size(); j++ )
{
tempResult[fileIdxToElementIdx[j]] = currentColumn[j];
}
}
fieldAndData[currentFieldFromFile].swap( tempResult );
}
}
return fieldAndData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::string> RifElementPropertyReader::fieldsInFile( const std::string& fileName ) const
{
std::vector<std::string> fields;
for ( std::pair<std::string, RifElementPropertyMetadata> metaData : m_fieldsMetaData )
{
if ( metaData.second.fileName.toStdString() == fileName )
{
for ( const QString& column : metaData.second.dataColumns )
{
fields.push_back( column.toStdString() );
}
}
}
return fields;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifElementPropertyReader::makeElementIdToIdxMap()
{
m_elementIdToIdx.reserve( m_elementIdxToId.size() );
for ( size_t i = 0; i < m_elementIdxToId.size(); i++ )
{
m_elementIdToIdx[m_elementIdxToId[i]] = (int)i;
}
std::vector<int> tempVectorForDeletion;
m_elementIdxToId.swap( tempVectorForDeletion );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifElementPropertyReader::outputWarningAboutWrongFileData()
{
QString warningText = QString( "The chosen result property does not fit the model" );
RiaLogging::errorInMessageBox( nullptr, "Element Property Reader", warningText );
}

View File

@@ -0,0 +1,58 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- 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 "RifElementPropertyTableReader.h"
#include "cvfObject.h"
#include "cvfVector3.h"
#include <map>
#include <string>
#include <unordered_map>
#include <vector>
//==================================================================================================
//
//
//==================================================================================================
class RifElementPropertyReader : public cvf::Object
{
public:
RifElementPropertyReader( const std::vector<int>& elementIdxToId );
~RifElementPropertyReader() override;
void addFile( const std::string& fileName );
void removeFile( const std::string& fileName );
std::vector<std::string> scalarElementFields() const;
std::map<std::string, std::vector<float>> readAllElementPropertiesInFileContainingField( const std::string& fieldName );
std::vector<std::string> fieldsInFile( const std::string& fileName ) const;
private:
void makeElementIdToIdxMap();
static void outputWarningAboutWrongFileData();
private:
std::map<std::string, RifElementPropertyMetadata> m_fieldsMetaData;
std::vector<int> m_elementIdxToId;
std::unordered_map<int, int> m_elementIdToIdx;
};

View File

@@ -0,0 +1,236 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifElementPropertyTableReader.h"
#include "RifFileParseTools.h"
#include "RiaLogging.h"
#include "RiuMainWindow.h"
#include <QFile>
#include <QStringList>
#include <QTextStream>
#include <algorithm>
#include <cctype>
#include <string>
//--------------------------------------------------------------------------------------------------
/// Internal functions
//--------------------------------------------------------------------------------------------------
static QFile* openFile( const QString& fileName );
static void closeFile( QFile* file );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifElementPropertyMetadata RifElementPropertyTableReader::readMetadata( const QString& fileName )
{
RifElementPropertyMetadata metadata;
QFile* file = nullptr;
try
{
file = openFile( fileName );
if ( file )
{
QTextStream stream( file );
bool metadataBlockFound = false;
int maxLinesToRead = 50;
int lineNo = 0;
while ( lineNo < maxLinesToRead )
{
QString line = stream.readLine();
lineNo++;
if ( line.toUpper().startsWith( "*DISTRIBUTION TABLE" ) )
{
metadataBlockFound = true;
continue;
}
else if ( line.toUpper().startsWith( "*DISTRIBUTION" ) )
{
metadata.fileName = fileName;
break;
}
if ( !metadataBlockFound || line.startsWith( "*" ) ) continue;
QStringList cols = RifFileParseTools::splitLineAndTrim( line, ",", true );
for ( QString s : cols )
{
metadata.dataColumns.push_back( s );
}
}
closeFile( file );
}
}
catch ( ... )
{
closeFile( file );
throw;
}
return metadata;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifElementPropertyTableReader::readData( const RifElementPropertyMetadata* metadata, RifElementPropertyTable* table )
{
CVF_ASSERT( metadata && table );
int expectedColumnCount = (int)metadata->dataColumns.size() + 1;
QFile* file = nullptr;
try
{
file = openFile( metadata->fileName );
if ( file && expectedColumnCount > 0 )
{
QTextStream stream( file );
bool dataBlockFound = false;
bool completeDataLineFound = false;
int lineNo = 0;
QStringList collectedCols;
// Init data vectors
table->elementIds.clear();
table->data = std::vector<std::vector<float>>( metadata->dataColumns.size() );
while ( !stream.atEnd() )
{
QString line = stream.readLine();
if ( !line.startsWith( "*" ) )
{
if ( collectedCols.size() > 0 && collectedCols.size() != 8 )
{
if ( dataBlockFound )
{
throw FileParseException(
QString( "Number of columns mismatch at %1:%2" ).arg( metadata->fileName ).arg( lineNo ) );
}
collectedCols.clear();
}
collectedCols << RifFileParseTools::splitLineAndTrim( line, ",", true );
}
else
{
collectedCols.clear();
}
lineNo++;
if ( !completeDataLineFound )
{
if ( !line.startsWith( "*" ) && !line.startsWith( "," ) && collectedCols.size() == expectedColumnCount )
{
completeDataLineFound = true;
dataBlockFound = true;
}
else if ( collectedCols.size() > expectedColumnCount )
{
throw FileParseException(
QString( "Number of columns mismatch at %1:%2" ).arg( metadata->fileName ).arg( lineNo ) );
}
else
{
continue;
}
}
QStringList cols = collectedCols;
for ( int c = 0; c < expectedColumnCount; c++ )
{
bool parseOk;
if ( c == 0 )
{
// Remove elementId column prefix
QStringList parts = cols[0].split( "." );
int elementId = parts.last().toInt( &parseOk );
if ( !parseOk )
{
throw FileParseException(
QString( "Parse failed at %1:%2" ).arg( metadata->fileName ).arg( lineNo ) );
}
table->elementIds.push_back( elementId );
}
else
{
float value = cols[c].toFloat( &parseOk );
if ( !parseOk )
{
throw FileParseException(
QString( "Parse failed at %1:%2" ).arg( metadata->fileName ).arg( lineNo ) );
}
table->data[c - 1].push_back( value );
}
}
collectedCols.clear();
completeDataLineFound = false;
}
table->hasData = true;
}
closeFile( file );
}
catch ( ... )
{
closeFile( file );
throw;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QFile* openFile( const QString& fileName )
{
QFile* file;
file = new QFile( fileName );
if ( !file->open( QIODevice::ReadOnly | QIODevice::Text ) )
{
RiaLogging::error( QString( "Failed to open %1" ).arg( fileName ) );
delete file;
return nullptr;
}
return file;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void closeFile( QFile* file )
{
if ( file )
{
file->close();
delete file;
}
}

View File

@@ -0,0 +1,67 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <map>
#include <utility>
#include <vector>
#include "cvfObject.h"
#include <QString>
class RifElementPropertyTable;
class RifElementPropertyMetadata;
//==================================================================================================
///
//==================================================================================================
class RifElementPropertyTableReader : cvf::Object
{
public:
static RifElementPropertyMetadata readMetadata( const QString& filePath );
static void readData( const RifElementPropertyMetadata* metadata, RifElementPropertyTable* table );
};
//==================================================================================================
///
//==================================================================================================
class RifElementPropertyMetadata
{
public:
QString fileName;
std::vector<QString> dataColumns;
};
//==================================================================================================
///
//==================================================================================================
class RifElementPropertyTable
{
public:
RifElementPropertyTable()
: hasData( false )
{
}
RifElementPropertyMetadata metadata;
bool hasData;
std::vector<int> elementIds;
std::vector<std::vector<float>> data;
};

View File

@@ -0,0 +1,118 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifEnsembleStatisticsReader.h"
#include "RimEnsembleCurveSet.h"
#include "RimEnsembleStatisticsCase.h"
#include "RimSummaryCaseCollection.h"
static const std::vector<time_t> EMPTY_TIME_STEPS_VECTOR;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEnsembleStatisticsReader::RifEnsembleStatisticsReader( RimEnsembleStatisticsCase* ensStatCase )
{
CVF_ASSERT( ensStatCase );
m_ensembleStatCase = ensStatCase;
m_allResultAddresses = std::set<RifEclipseSummaryAddress>(
{ RifEclipseSummaryAddress::ensembleStatisticsAddress( ENSEMBLE_STAT_P10_QUANTITY_NAME, "" ),
RifEclipseSummaryAddress::ensembleStatisticsAddress( ENSEMBLE_STAT_P50_QUANTITY_NAME, "" ),
RifEclipseSummaryAddress::ensembleStatisticsAddress( ENSEMBLE_STAT_P90_QUANTITY_NAME, "" ),
RifEclipseSummaryAddress::ensembleStatisticsAddress( ENSEMBLE_STAT_MEAN_QUANTITY_NAME, "" ) } );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<time_t>& RifEnsembleStatisticsReader::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{
if ( !validateAddress( resultAddress ) ) return EMPTY_TIME_STEPS_VECTOR;
return m_ensembleStatCase->timeSteps();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEnsembleStatisticsReader::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{
if ( !validateAddress( resultAddress ) ) return false;
const std::vector<double>* sourceData = nullptr;
auto quantityName = resultAddress.ensembleStatisticsQuantityName();
if ( quantityName == ENSEMBLE_STAT_P10_QUANTITY_NAME )
sourceData = &m_ensembleStatCase->p10();
else if ( quantityName == ENSEMBLE_STAT_P50_QUANTITY_NAME )
sourceData = &m_ensembleStatCase->p50();
else if ( quantityName == ENSEMBLE_STAT_P90_QUANTITY_NAME )
sourceData = &m_ensembleStatCase->p90();
else if ( quantityName == ENSEMBLE_STAT_MEAN_QUANTITY_NAME )
sourceData = &m_ensembleStatCase->mean();
if ( !sourceData ) return false;
values->clear();
values->reserve( sourceData->size() );
for ( auto val : *sourceData )
values->push_back( val );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RifEnsembleStatisticsReader::unitName( const RifEclipseSummaryAddress& resultAddress ) const
{
std::string retval;
// The stat case does not have a unit set, so pick up the unit from one of the input cases, if possible
auto cases = m_ensembleStatCase->curveSet()->summaryCaseCollection()->allSummaryCases();
if ( cases.size() > 0 )
{
// get rid of the stats part of the quantity name
QString qName = QString::fromStdString( resultAddress.quantityName() );
std::string orgQName = qName.split( ":" )[1].toStdString();
RifEclipseSummaryAddress address = RifEclipseSummaryAddress( resultAddress );
address.setQuantityName( orgQName );
retval = cases[0]->summaryReader()->unitName( address );
}
return retval;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaEclipseUnitTools::UnitSystem RifEnsembleStatisticsReader::unitSystem() const
{
return m_ensembleStatCase->unitSystem();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEnsembleStatisticsReader::validateAddress( const RifEclipseSummaryAddress& address ) const
{
return address.category() == RifEclipseSummaryAddress::SUMMARY_ENSEMBLE_STATISTICS && !address.quantityName().empty();
}

View File

@@ -0,0 +1,45 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifEclipseSummaryAddress.h"
#include "RifSummaryReaderInterface.h"
class RimEnsembleStatisticsCase;
//==================================================================================================
///
//==================================================================================================
class RifEnsembleStatisticsReader : public RifSummaryReaderInterface
{
public:
RifEnsembleStatisticsReader( RimEnsembleStatisticsCase* ensStatCase );
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;
RiaEclipseUnitTools::UnitSystem unitSystem() const override;
private:
bool validateAddress( const RifEclipseSummaryAddress& address ) const;
private:
RimEnsembleStatisticsCase* m_ensembleStatCase;
};

View File

@@ -0,0 +1,46 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifFileParseTools.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList RifFileParseTools::splitLineAndTrim( const QString& line, const QString& separator, bool skipEmptyParts )
{
QStringList cols =
line.trimmed().split( separator, skipEmptyParts ? QString::SkipEmptyParts : QString::KeepEmptyParts );
for ( QString& col : cols )
{
col = col.trimmed();
}
return cols;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList RifFileParseTools::splitLineAndTrim( const QString& line, const QRegExp& regexp, bool skipEmptyParts )
{
QStringList cols = line.trimmed().split( regexp, skipEmptyParts ? QString::SkipEmptyParts : QString::KeepEmptyParts );
for ( QString& col : cols )
{
col = col.trimmed();
}
return cols;
}

View File

@@ -0,0 +1,46 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <QRegExp>
#include <QString>
#include <QStringList>
//==================================================================================================
///
//==================================================================================================
class RifFileParseTools
{
public:
static QStringList splitLineAndTrim( const QString& line, const QString& separator, bool skipEmptyParts = false );
static QStringList splitLineAndTrim( const QString& line, const QRegExp& regexp, bool skipEmptyParts = false );
};
//==================================================================================================
///
//==================================================================================================
class FileParseException
{
public:
FileParseException( const QString& message )
: message( message )
{
}
QString message;
};

View File

@@ -0,0 +1,414 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifHdf5Reader.h"
#include "RiaLogging.h"
#include "RiaQDateTimeTools.h"
#include "H5Cpp.h"
#include "H5Exception.h"
#include "cvfAssert.h"
#include "cvfMath.h"
#include <QDateTime>
#include <QDir>
#include <QStringList>
#include <algorithm>
//--------------------------------------------------------------------------------------------------
/// May reduce constructor content upon discussion of overlying framework.
///
/// std::string dateString = getStringAttribute(file, "/KaseStudy/TransientSections", "initial_date");
/// QDateTime initalDateTime = sourSimDateTimeToQDateTime(dateString); // may rearrange/change to be a call in
/// timeSteps()
//--------------------------------------------------------------------------------------------------
RifHdf5Reader::RifHdf5Reader( const QString& fileName )
: m_fileName( fileName )
, m_fileStrategy( 0 )
{
try
{
H5::H5File file( fileName.toStdString().c_str(), H5F_ACC_RDONLY ); // evt fileName.toLatin1().data()
m_fileStrategy = getIntAttribute( file, "/", "file_strategy" ); // fileStrategy == 1 means one time step per file
if ( m_fileStrategy == 1 )
{
m_timeStepFileNames = getSourSimTimeStepFileNames( fileName );
}
}
catch ( ... ) // catch any failure
{
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifHdf5Reader::~RifHdf5Reader()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifHdf5Reader::dynamicResult( const QString& result, size_t stepIndex, std::vector<double>* values ) const
{
if ( m_fileStrategy != 1 ) return false; // NB: currently incapable of handling all results in one sourres file
try
{
QStringList props = propertyNames();
QStringList::iterator it = std::find( props.begin(), props.end(), result );
int propIdx = ( it != props.end() ) ? it - props.begin() : 0; // index to 'result' in QStringList props (usually
// size_t but int gave no warning)
H5::Exception::dontPrint(); // Turn off auto-printing of failures to handle the errors appropriately
std::string fileName = m_timeStepFileNames[stepIndex];
std::string timeStepGroup = "/Timestep_" + getTimeStepNumberAs5DigitString( fileName );
H5::H5File file( fileName.c_str(), H5F_ACC_RDONLY );
std::string groupName = timeStepGroup + "/GridFunctions/GridPart_00000/GridFunction_" +
IntTo5DigitString( propIdx + 1 ); // adjust to HDF5 one based indexing
getElementResultValues( file, groupName, values );
return true;
}
catch ( ... ) // catch any failure
{
RiaLogging::error( QString( "Failed to read SourSimRL dynamic results" ) );
return false;
}
}
//--------------------------------------------------------------------------------------------------
/// Qt alternative fileName.toLatin1().data()
//--------------------------------------------------------------------------------------------------
std::vector<QDateTime> RifHdf5Reader::timeSteps() const
{
std::vector<QDateTime> times;
if ( m_fileStrategy != 1 ) return times; // NB: currently incapable of handling all results in one sourres file
try
{
H5::H5File mainFile( m_fileName.toStdString().c_str(),
H5F_ACC_RDONLY ); // initial date part is an attribute of SourSimRL main file
std::string dateString = getStringAttribute( mainFile, "/KaseStudy/TransientSections", "initial_date" );
QDateTime dtInitial = sourSimDateTimeToQDateTime( dateString );
for ( size_t i = 0; i < m_timeStepFileNames.size(); i++ )
{
std::string fileName = m_timeStepFileNames[i];
std::string timeStepGroup = "/Timestep_" + getTimeStepNumberAs5DigitString( fileName );
H5::H5File file( fileName.c_str(), H5F_ACC_RDONLY );
double timeStepValue = getDoubleAttribute( file,
timeStepGroup,
"timestep" ); // Assumes only one time step per file
int timeStepDays = cvf::Math::floor( timeStepValue );
double fractionOfDay = timeStepValue - timeStepDays;
double milliseconds = fractionOfDay * 24.0 * 60.0 * 60.0 * 1000.0;
QDateTime dt = dtInitial;
dt = RiaQDateTimeTools::addDays( dt, timeStepDays );
dt = RiaQDateTimeTools::addMSecs( dt, milliseconds );
times.push_back( dt );
}
}
catch ( ... ) // catch any failure
{
times.clear();
RiaLogging::error( QString( "Failed to read SourSimRL time steps" ) );
}
return times;
}
//---------------------------------------------------------------------------------------------------
/// Result variables of first timestep listed by HDF5 subgroups to the following base group:
/// "/Timestep_00001/GridFunctions/GridPart_00000"
/// According to sourres file description, it seems safe to assume equal presence for all time steps.
//---------------------------------------------------------------------------------------------------
QStringList RifHdf5Reader::propertyNames() const
{
QStringList propNames;
if ( m_fileStrategy != 1 ) return propNames; // NB: currently incapable of handling all results in one sourres file
if ( m_timeStepFileNames.empty() )
{
RiaLogging::error( QString( "Failed to read properties. Transient data does not exist." ) );
return propNames;
}
std::string fileName = m_timeStepFileNames[0]; // assume the result variables to be identical across time steps =>
// extract names from first time step file
std::string groupName = "/Timestep_" + getTimeStepNumberAs5DigitString( fileName ) + "/GridFunctions/GridPart_00000";
try
{
H5::H5File file( fileName.c_str(), H5F_ACC_RDONLY );
std::vector<std::string> resultNames = getResultNames( file, groupName );
for ( const std::string& s : resultNames )
{
propNames.push_back( s.c_str() );
}
}
catch ( ... ) // catch any failure
{
propNames.clear();
RiaLogging::error( QString( "Failed to read properties from file : '%1'" ).arg( fileName.c_str() ) );
}
return propNames;
}
//=========================== PRIVATE METHODS =====================================================
//
//
//
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::string> RifHdf5Reader::getSourSimTimeStepFileNames( const QString& fileName ) const
{
QFileInfo fi( fileName );
QString name = fi.fileName();
QString dir = fi.path();
QDir baseDir( dir );
baseDir.setFilter( QDir::Files );
QStringList nameFilters;
nameFilters << name + ".?????";
baseDir.setNameFilters( nameFilters );
QStringList fileNames = baseDir.entryList();
std::vector<std::string> timeStepFileNames;
for ( int i = 0; i < fileNames.size(); i++ )
{
std::string fullPath = dir.toStdString() + "/" + fileNames[i].toStdString();
timeStepFileNames.push_back( fullPath );
}
return timeStepFileNames;
}
//--------------------------------------------------------------------------------------------------
/// Build a QDateTime based on a SourSimRL HDF date attribute
/// Did not succeed with QDateTime dt = QDateTime::fromString(dateString, "YYYY MM DD hh mm ss");
/// Thus a conversion of substrings via integers
//--------------------------------------------------------------------------------------------------
QDateTime RifHdf5Reader::sourSimDateTimeToQDateTime( std::string dateString ) const
{
int year = std::stoi( dateString.substr( 0, 4 ) );
int month = std::stoi( dateString.substr( 5, 2 ) );
int day = std::stoi( dateString.substr( 8, 2 ) );
int hours = std::stoi( dateString.substr( 11, 2 ) );
int minutes = std::stoi( dateString.substr( 14, 2 ) );
int seconds = std::stoi( dateString.substr( 17, 2 ) );
QDate d( year, month, day );
QTime t( hours, minutes, seconds );
QDateTime dt = RiaQDateTimeTools::createUtcDateTime( d, t );
return dt;
}
//--------------------------------------------------------------------------------------------------
/// Build a string based on an int that consists of exactly 5 characters for HDF5 numbering
//--------------------------------------------------------------------------------------------------
std::string RifHdf5Reader::getTimeStepNumberAs5DigitString( std::string fileName ) const
{
return fileName.substr( fileName.size() - 5 ); // extract the 5 last characters/digits
}
//--------------------------------------------------------------------------------------------------
/// Build a string based on an int that consists of exactly 5 characters for HDF5 numbering
//--------------------------------------------------------------------------------------------------
std::string RifHdf5Reader::IntTo5DigitString( int i ) const
{
std::string numString = "00000" + std::to_string( i );
return numString.substr( numString.size() - 5 ); // extract the 5 last characters/digits
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RifHdf5Reader::getIntAttribute( H5::H5File file, std::string groupName, std::string attributeName ) const
{
try
{
H5::Group group = file.openGroup( groupName.c_str() );
H5::Attribute attr = group.openAttribute( attributeName.c_str() );
int value = 0;
H5::DataType type = attr.getDataType();
attr.read( type, &value );
return value;
}
catch ( ... )
{
return 0;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RifHdf5Reader::getDoubleAttribute( H5::H5File file, std::string groupName, std::string attributeName ) const
{
try
{
H5::Group group = file.openGroup( groupName.c_str() );
H5::Attribute attr = group.openAttribute( attributeName.c_str() );
double value = 0.0;
H5::DataType type = attr.getDataType();
attr.read( type, &value );
return value;
}
catch ( ... )
{
return 0.0;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RifHdf5Reader::getStringAttribute( H5::H5File file, std::string groupName, std::string attributeName ) const
{
try
{
H5::Group group = file.openGroup( groupName.c_str() );
H5::Attribute attr = group.openAttribute( attributeName.c_str() );
std::string stringAttribute( 1024, '\0' );
H5::DataType nameType = attr.getDataType();
attr.read( nameType, &stringAttribute[0] );
return stringAttribute;
}
catch ( ... )
{
return "";
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::string> RifHdf5Reader::getSubGroupNames( H5::H5File file, std::string baseGroupName ) const
{
H5::Group baseGroup = file.openGroup( baseGroupName.c_str() );
std::vector<std::string> subGroupNames;
hsize_t groupSize = baseGroup.getNumObjs();
for ( hsize_t i = 0; i < groupSize; i++ )
{
std::string nodeName( 1024, '\0' );
ssize_t slen = baseGroup.getObjnameByIdx( i, &nodeName[0], 1023 );
nodeName.resize( slen + 1 );
subGroupNames.push_back( nodeName );
}
return subGroupNames;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::string> RifHdf5Reader::getResultNames( H5::H5File file, std::string baseGroupName ) const
{
std::vector<std::string> subGroupNames = getSubGroupNames( file, baseGroupName );
std::vector<std::string> resultNames;
for ( std::vector<std::string>::iterator it = subGroupNames.begin(); it != subGroupNames.end(); it++ )
{
std::string groupName = baseGroupName + "/" + *it;
std::string name = getStringAttribute( file, groupName, "name" );
resultNames.push_back( name );
}
return resultNames;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifHdf5Reader::getElementResultValues( H5::H5File file, std::string groupName, std::vector<double>* resultValues ) const
{
H5::Group group = file.openGroup( groupName.c_str() );
H5::DataSet dataset = H5::DataSet( group.openDataSet( "values" ) );
hsize_t dims[2];
H5::DataSpace dataspace = dataset.getSpace();
dataspace.getSimpleExtentDims( dims, nullptr );
( *resultValues ).resize( dims[0] );
dataset.read( resultValues->data(), H5::PredType::NATIVE_DOUBLE );
}

View File

@@ -0,0 +1,60 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifHdf5ReaderInterface.h"
#include <QString>
#include "H5Cpp.h"
//==================================================================================================
//
//
//==================================================================================================
class RifHdf5Reader : public RifHdf5ReaderInterface
{
public:
explicit RifHdf5Reader( const QString& fileName );
~RifHdf5Reader() override;
std::vector<QDateTime> timeSteps() const override;
QStringList propertyNames() const override;
bool dynamicResult( const QString& result, size_t stepIndex, std::vector<double>* values ) const override;
private:
std::vector<std::string> getSourSimTimeStepFileNames( const QString& fileName ) const;
QDateTime sourSimDateTimeToQDateTime( std::string dateString ) const;
std::string getTimeStepNumberAs5DigitString( std::string fileName ) const;
std::string IntTo5DigitString( int i ) const;
int getIntAttribute( H5::H5File file, std::string groupName, std::string attributeName ) const;
double getDoubleAttribute( H5::H5File file, std::string groupName, std::string attributeName ) const;
std::string getStringAttribute( H5::H5File file, std::string groupName, std::string attributeName ) const;
std::vector<std::string> getSubGroupNames( H5::H5File file, std::string baseGroupName ) const;
std::vector<std::string> getResultNames( H5::H5File file, std::string baseGroupName ) const;
void getElementResultValues( H5::H5File file, std::string groupName, std::vector<double>* resultValues ) const;
private:
QString m_fileName; // name of SourSimRL main file given by user
int m_fileStrategy; // SourSimRL file strategy, fileStrategy == 1 means one time step per file
std::vector<std::string> m_timeStepFileNames; // files containing transient SourSimRL results, one time step per file
};

View File

@@ -0,0 +1,19 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifHdf5ReaderInterface.h"

View File

@@ -0,0 +1,40 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
class QString;
class QDateTime;
class QStringList;
#include <cstddef>
#include <vector>
//==================================================================================================
//
//
//==================================================================================================
class RifHdf5ReaderInterface
{
public:
virtual ~RifHdf5ReaderInterface() = default;
virtual std::vector<QDateTime> timeSteps() const = 0;
virtual QStringList propertyNames() const = 0;
virtual bool dynamicResult( const QString& result, size_t stepIndex, std::vector<double>* values ) const = 0;
};

View File

@@ -0,0 +1,151 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011-2013 Statoil ASA, Ceetron AS
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
// Json parser based on code example found on:
// http://stackoverflow.com/questions/4169988/easiest-way-to-parse-json-in-qt-4-7
#include "RifJsonEncodeDecode.h"
#include <QtCore/QFile>
#include <QtCore/QString>
#include <QtScript/QScriptEngine>
#include <QtScript/QScriptValueIterator>
namespace ResInsightInternalJson
{
QMap<QString, QVariant> JsonReader::decodeFile( QString filePath )
{
QFile file;
file.setFileName( filePath );
file.open( QIODevice::ReadOnly );
QByteArray byteArray = file.readAll();
file.close();
QString jsonString( byteArray );
Json json;
return json.decode( jsonString );
}
#if IMPL_DUMP_TO_FILE
void JsonReader::dumpToFile( std::vector<cvf::Vec3d>& points, QString filePath )
{
QFile file;
file.setFileName( filePath );
file.open( QIODevice::WriteOnly );
for ( size_t idx = 0; idx < points.size(); idx++ )
{
cvf::Vec3d point = points[idx];
QString string;
string.sprintf( "(%0.10e, %0.10e, %0.10e)\n", point.x(), point.y(), point.z() );
QByteArray byteArray( string.toLatin1() );
file.write( byteArray );
}
file.close();
}
#endif
QString Json::encode( const QMap<QString, QVariant>& map, bool prettify )
{
QScriptEngine engine;
if ( prettify )
{
engine.evaluate( "function toString() { return JSON.stringify(this, null, ' ') }" );
}
else
{
engine.evaluate( "function toString() { return JSON.stringify(this) }" );
}
QScriptValue toString = engine.globalObject().property( "toString" );
QScriptValue obj = encodeInner( map, &engine );
return toString.call( obj ).toString();
}
QMap<QString, QVariant> Json::decode( const QString& jsonStr )
{
QScriptValue object;
QScriptEngine engine;
object = engine.evaluate( "(" + jsonStr + ")" );
return decodeInner( object );
}
QScriptValue Json::encodeInner( const QMap<QString, QVariant>& map, QScriptEngine* engine )
{
QScriptValue obj = engine->newObject();
QMapIterator<QString, QVariant> i( map );
while ( i.hasNext() )
{
i.next();
if ( i.value().type() == QVariant::String )
obj.setProperty( i.key(), i.value().toString() );
else if ( i.value().type() == QVariant::Int )
obj.setProperty( i.key(), i.value().toInt() );
else if ( i.value().type() == QVariant::Double )
obj.setProperty( i.key(), i.value().toDouble() );
else if ( i.value().type() == QVariant::List )
obj.setProperty( i.key(), qScriptValueFromSequence( engine, i.value().toList() ) );
else if ( i.value().type() == QVariant::Map )
obj.setProperty( i.key(), encodeInner( i.value().toMap(), engine ) );
}
return obj;
}
QMap<QString, QVariant> Json::decodeInner( QScriptValue object )
{
QMap<QString, QVariant> map;
QScriptValueIterator it( object );
while ( it.hasNext() )
{
it.next();
if ( it.value().isArray() )
map.insert( it.name(), QVariant( decodeInnerToList( it.value() ) ) );
else if ( it.value().isNumber() )
map.insert( it.name(), QVariant( it.value().toNumber() ) );
else if ( it.value().isString() )
map.insert( it.name(), QVariant( it.value().toString() ) );
else if ( it.value().isNull() )
map.insert( it.name(), QVariant() );
else if ( it.value().isObject() )
map.insert( it.name(), QVariant( decodeInner( it.value() ) ) );
}
return map;
}
QList<QVariant> Json::decodeInnerToList( QScriptValue arrayValue )
{
QList<QVariant> list;
QScriptValueIterator it( arrayValue );
while ( it.hasNext() )
{
it.next();
if ( it.name() == "length" ) continue;
if ( it.value().isArray() )
list.append( QVariant( decodeInnerToList( it.value() ) ) );
else if ( it.value().isNumber() )
list.append( QVariant( it.value().toNumber() ) );
else if ( it.value().isString() )
list.append( QVariant( it.value().toString() ) );
else if ( it.value().isNull() )
list.append( QVariant() );
else if ( it.value().isObject() )
list.append( QVariant( decodeInner( it.value() ) ) );
}
return list;
}
} // namespace ResInsightInternalJson

View File

@@ -0,0 +1,65 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011-2013 Statoil ASA, Ceetron AS
//
// 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
// Json parser based on code example found on:
// http://stackoverflow.com/questions/4169988/easiest-way-to-parse-json-in-qt-4-7
//#define IMPL_DUMP_TO_FILE
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QVariant>
#include <QtScript/QScriptValue>
#if IMPL_DUMP_TO_FILE
#include <cvfVector3.h>
#include <vector>
#endif
class QScriptEngine;
// Encapsulate the JSON code in a namespace to avoid issues with JSON classes used in opm-parser
namespace ResInsightInternalJson
{
class JsonReader
{
public:
QMap<QString, QVariant> decodeFile( QString filePath );
#if IMPL_DUMP_TO_FILE
void dumpToFile( std::vector<cvf::Vec3d>& points, QString filePath );
#endif
};
class Json
{
public:
Json(){};
QString encode( const QMap<QString, QVariant>& map, bool prettify );
QMap<QString, QVariant> decode( const QString& jsonStr );
private:
QScriptValue encodeInner( const QMap<QString, QVariant>& map, QScriptEngine* engine );
QMap<QString, QVariant> decodeInner( QScriptValue object );
QList<QVariant> decodeInnerToList( QScriptValue arrayValue );
};
} // namespace ResInsightInternalJson

View File

@@ -0,0 +1,101 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifKeywordVectorParser.h"
#include "RiaStdStringTools.h"
#include "RifEclipseUserDataParserTools.h"
#include "cvfAssert.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifKeywordVectorParser::RifKeywordVectorParser( const QString& data )
{
parseData( data );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<KeywordBasedVector>& RifKeywordVectorParser::keywordBasedVectors() const
{
return m_keywordBasedVectors;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifKeywordVectorParser::canBeParsed( const QString& data )
{
std::stringstream streamData;
streamData.str( data.toStdString() );
std::string line;
std::getline( streamData, line );
while ( streamData.good() )
{
if ( RifEclipseUserDataParserTools::isAComment( line ) )
{
std::getline( streamData, line );
}
else if ( line.find( "VECTOR" ) == 0 )
{
return true;
}
else
{
return false;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifKeywordVectorParser::parseData( const QString& data )
{
std::stringstream streamData;
streamData.str( data.toStdString() );
std::string line;
std::getline( streamData, line );
do
{
while ( RifEclipseUserDataParserTools::isLineSkippable( line ) && !streamData.eof() )
{
std::getline( streamData, line );
}
KeywordBasedVector keywordBasedVector;
keywordBasedVector.header = RifEclipseUserDataParserTools::headerReader( streamData, line );
if ( keywordBasedVector.header.empty() ) break;
while ( RifEclipseUserDataParserTools::isANumber( line ) )
{
keywordBasedVector.values.push_back( RiaStdStringTools::toDouble( line ) );
std::getline( streamData, line );
}
m_keywordBasedVectors.push_back( keywordBasedVector );
} while ( !streamData.eof() );
}

View File

@@ -0,0 +1,47 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <QString>
#include <vector>
struct KeywordBasedVector
{
std::vector<std::string> header;
std::vector<double> values;
};
//==================================================================================================
///
//==================================================================================================
class RifKeywordVectorParser
{
public:
RifKeywordVectorParser( const QString& data );
const std::vector<KeywordBasedVector>& keywordBasedVectors() const;
static bool canBeParsed( const QString& data );
private:
void parseData( const QString& data );
private:
std::vector<KeywordBasedVector> m_keywordBasedVectors;
};

View File

@@ -0,0 +1,282 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifKeywordVectorUserData.h"
#include "RiaLogging.h"
#include "RiaQDateTimeTools.h"
#include "RifEclipseSummaryAddress.h"
#include "RifEclipseUserDataParserTools.h"
#include "RifKeywordVectorParser.h"
#include "cafUtils.h"
#include <QDateTime>
#include <QFile>
#include <QStringList>
#include <QTextStream>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifKeywordVectorUserData::RifKeywordVectorUserData()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifKeywordVectorUserData::~RifKeywordVectorUserData()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifKeywordVectorUserData::parse( const QString& data, const QString& customWellName )
{
m_allResultAddresses.clear();
m_timeSteps.clear();
m_parser = std::unique_ptr<RifKeywordVectorParser>( new RifKeywordVectorParser( data ) );
if ( !m_parser )
{
RiaLogging::error( QString( "Failed to parse file" ) );
return false;
}
std::vector<std::map<QString, QString>> keyValuePairVector;
for ( const KeywordBasedVector& keywordVector : m_parser->keywordBasedVectors() )
{
std::map<QString, QString> keyValuePairs;
for ( auto s : keywordVector.header )
{
QString ss = QString::fromStdString( s );
QStringList entries = ss.split( " " );
if ( entries.size() == 2 )
{
keyValuePairs[entries[0]] = entries[1];
}
}
keyValuePairVector.push_back( keyValuePairs );
}
// Find all time vectors
std::map<QString, size_t> mapFromOriginToTimeStepIndex;
for ( size_t i = 0; i < keyValuePairVector.size(); i++ )
{
const std::map<QString, QString>& keyValuePairs = keyValuePairVector[i];
if ( isTimeHeader( keyValuePairs ) )
{
std::vector<time_t> ts;
{
QDateTime startDate;
QString startDateString = valueForKey( keyValuePairs, "STARTDATE" );
if ( !startDateString.isEmpty() )
{
QString dateFormatString = valueForKey( keyValuePairs, "DATEFORMAT" );
if ( dateFormatString.isEmpty() )
{
dateFormatString = "DD MM YYYY";
}
startDate = RiaQDateTimeTools::fromString( startDateString, dateFormatString );
}
else
{
startDate = RiaQDateTimeTools::epoch();
}
QString unitText = valueForKey( keyValuePairs, "UNITS" );
if ( unitText == "DAY" || unitText == "DAYS" )
{
for ( const auto& timeStepValue : m_parser->keywordBasedVectors()[i].values )
{
QDateTime dateTime = RiaQDateTimeTools::addDays( startDate, timeStepValue );
ts.push_back( dateTime.toTime_t() );
}
}
else if ( unitText == "YEAR" || unitText == "YEARS" )
{
for ( const auto& timeStepValue : m_parser->keywordBasedVectors()[i].values )
{
QDateTime dateTime = RiaQDateTimeTools::fromYears( timeStepValue );
ts.push_back( dateTime.toTime_t() );
}
}
}
m_timeSteps.push_back( ts );
QString originText = valueForKey( keyValuePairs, "ORIGIN" );
mapFromOriginToTimeStepIndex[originText] = m_timeSteps.size() - 1;
}
}
// Find all data vectors having a reference to a time step vector
for ( size_t i = 0; i < keyValuePairVector.size(); i++ )
{
const std::map<QString, QString>& keyValuePairs = keyValuePairVector[i];
if ( !isTimeHeader( keyValuePairs ) )
{
if ( isVectorHeader( keyValuePairs ) )
{
QString originText = valueForKey( keyValuePairs, "ORIGIN" );
auto timeStepIndexIterator = mapFromOriginToTimeStepIndex.find( originText );
if ( timeStepIndexIterator != mapFromOriginToTimeStepIndex.end() )
{
QString vectorText = valueForKey( keyValuePairs, "VECTOR" );
QString wellName = originText;
if ( customWellName.size() > 0 )
{
wellName = customWellName;
}
RifEclipseSummaryAddress addr( RifEclipseSummaryAddress::SUMMARY_WELL,
vectorText.toStdString(),
-1,
-1,
"",
wellName.toStdString(),
-1,
"",
-1,
-1,
-1,
-1,
false,
-1 );
m_allResultAddresses.insert( addr );
m_mapFromAddressToTimeIndex[addr] = timeStepIndexIterator->second;
m_mapFromAddressToVectorIndex[addr] = i;
}
}
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifKeywordVectorUserData::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{
auto search = m_mapFromAddressToVectorIndex.find( resultAddress );
if ( search == m_mapFromAddressToVectorIndex.end() ) return false;
for ( const auto& v : m_parser->keywordBasedVectors()[search->second].values )
{
values->push_back( v );
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<time_t>& RifKeywordVectorUserData::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{
auto timeIndexIterator = m_mapFromAddressToTimeIndex.find( resultAddress );
if ( timeIndexIterator != m_mapFromAddressToTimeIndex.end() )
{
return m_timeSteps[timeIndexIterator->second];
}
static std::vector<time_t> emptyVector;
return emptyVector;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RifKeywordVectorUserData::unitName( const RifEclipseSummaryAddress& resultAddress ) const
{
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaEclipseUnitTools::UnitSystem RifKeywordVectorUserData::unitSystem() const
{
return RiaEclipseUnitTools::UnitSystem::UNITS_UNKNOWN;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifKeywordVectorUserData::isTimeHeader( const std::map<QString, QString>& header )
{
for ( const auto& keyValue : header )
{
if ( keyValue.first == "VECTOR" && keyValue.second == "YEARX" )
{
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifKeywordVectorUserData::isVectorHeader( const std::map<QString, QString>& header )
{
for ( const auto& keyValue : header )
{
if ( keyValue.first == "VECTOR" )
{
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifKeywordVectorUserData::valueForKey( const std::map<QString, QString>& header, const QString& key )
{
auto it = header.find( key );
if ( it != header.end() )
{
return it->second;
}
return "";
}

View File

@@ -0,0 +1,65 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifSummaryReaderInterface.h"
#include <map>
#include <memory>
#include <string>
#include <vector>
class QDateTime;
class QString;
class RifKeywordVectorParser;
class RifEclipseSummaryAddress;
//==================================================================================================
//
//
//==================================================================================================
class RifKeywordVectorUserData : public RifSummaryReaderInterface
{
public:
RifKeywordVectorUserData();
~RifKeywordVectorUserData() override;
bool parse( const QString& data, const QString& customWellName );
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;
RiaEclipseUnitTools::UnitSystem unitSystem() const override;
private:
static bool isTimeHeader( const std::map<QString, QString>& header );
static bool isVectorHeader( const std::map<QString, QString>& header );
static QString valueForKey( const std::map<QString, QString>& header, const QString& key );
private:
std::unique_ptr<RifKeywordVectorParser> m_parser;
std::vector<std::vector<time_t>> m_timeSteps;
std::map<RifEclipseSummaryAddress, size_t> m_mapFromAddressToVectorIndex;
std::map<RifEclipseSummaryAddress, size_t> m_mapFromAddressToTimeIndex;
};

View File

@@ -0,0 +1,130 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifPerforationIntervalReader.h"
#include <QDate>
#include <QFile>
const QString PERFORATION_KEY( "perforation" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::map<QString, std::vector<RifPerforationInterval>>
RifPerforationIntervalReader::readPerforationIntervals( const QStringList& filePaths )
{
std::map<QString, std::vector<RifPerforationInterval>> perforationIntervals;
foreach ( QString filePath, filePaths )
{
readFileIntoMap( filePath, &perforationIntervals );
}
return perforationIntervals;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::map<QString, std::vector<RifPerforationInterval>>
RifPerforationIntervalReader::readPerforationIntervals( const QString& filePath )
{
std::map<QString, std::vector<RifPerforationInterval>> perforationIntervals;
readFileIntoMap( filePath, &perforationIntervals );
return perforationIntervals;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifPerforationIntervalReader::readFileIntoMap( const QString& filePath,
std::map<QString, std::vector<RifPerforationInterval>>* perforations )
{
QFile data( filePath );
if ( !data.open( QFile::ReadOnly ) )
{
return;
}
QString wellName;
do
{
QString line = data.readLine();
if ( line.startsWith( "--" ) )
{
// Skip comment
continue;
}
// Replace any tabs with spaces to enable splitting on spaces
line.replace( "\t", " " );
QStringList parts = line.split( " ", QString::SkipEmptyParts );
if ( line.startsWith( "WELLNAME" ) )
{
// Save current well name
if ( parts.size() > 1 )
{
wellName = parts[1].trimmed();
}
}
else if ( parts.size() >= 6 )
{
RifPerforationInterval interval;
int mdStartIndex;
if ( parts[3] == PERFORATION_KEY )
{
interval.date = QDate::fromString( QString( "%1 %2 %3" ).arg( parts[0] ).arg( parts[1] ).arg( parts[2] ),
"dd MMM yyyy" );
interval.startOfHistory = false;
mdStartIndex = 4;
}
else if ( parts[1] == PERFORATION_KEY )
{
interval.startOfHistory = true;
mdStartIndex = 2;
}
else
{
continue;
}
interval.startMD = parts[mdStartIndex].toDouble();
interval.endMD = parts[mdStartIndex + 1].toDouble();
interval.diameter = parts[mdStartIndex + 2].toDouble();
interval.skinFactor = parts[mdStartIndex + 3].toDouble();
auto match = perforations->find( wellName );
if ( match == perforations->end() )
{
( *perforations )[wellName] = std::vector<RifPerforationInterval>();
}
( *perforations )[wellName].push_back( interval );
}
} while ( !data.atEnd() );
}

View File

@@ -0,0 +1,49 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimPerforationInterval.h"
#include <map>
#include <QString>
struct RifPerforationInterval
{
double startMD;
double endMD;
double diameter;
double skinFactor;
bool startOfHistory;
QDate date;
};
//==================================================================================================
///
//==================================================================================================
class RifPerforationIntervalReader
{
public:
static std::map<QString, std::vector<RifPerforationInterval>> readPerforationIntervals( const QStringList& filePaths );
static std::map<QString, std::vector<RifPerforationInterval>> readPerforationIntervals( const QString& filePath );
private:
static void readFileIntoMap( const QString& filePath,
std::map<QString, std::vector<RifPerforationInterval>>* perforations );
};

View File

@@ -0,0 +1,87 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RifReaderEclipseInput.h"
#include "RiaLogging.h"
#include "RifEclipseInputFileTools.h"
#include "RigEclipseCaseData.h"
#include "RigMainGrid.h"
//==================================================================================================
//
// Class RifReaderEclipseInput
//
//==================================================================================================
//--------------------------------------------------------------------------------------------------
/// Constructor
//--------------------------------------------------------------------------------------------------
RifReaderEclipseInput::RifReaderEclipseInput()
{
}
//--------------------------------------------------------------------------------------------------
/// Destructor
//--------------------------------------------------------------------------------------------------
RifReaderEclipseInput::~RifReaderEclipseInput()
{
}
//--------------------------------------------------------------------------------------------------
/// Open file and read geometry into given reservoir object
//--------------------------------------------------------------------------------------------------
bool RifReaderEclipseInput::open( const QString& fileName, RigEclipseCaseData* eclipseCase )
{
CVF_ASSERT( eclipseCase );
// Should we handle gridless properties ?
// If so, they must match dimensions, and a grid afterwards must match dimension
// Add file:
// Open file
// If we do not have any grid data,
// Search for grid keywords
// If grid data found
// Read grid keywords,
// produce ecl_grid,
// Transfer data to RigReservoir
// if not
// find include
// else
// Search through file for property keywords
// If found,
// read them,
// create InputProperty object
bool isOk = false;
if ( eclipseCase->mainGrid()->gridPointDimensions() == cvf::Vec3st( 0, 0, 0 ) )
{
QString errorMesssages;
isOk = RifEclipseInputFileTools::openGridFile( fileName, eclipseCase, isFaultImportEnabled(), &errorMesssages );
if ( !isOk )
{
RiaLogging::error( errorMesssages );
}
}
return isOk;
}

View File

@@ -0,0 +1,48 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS
//
// 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 "RifReaderInterface.h"
//==================================================================================================
//
// File interface for Eclipse output files
//
//==================================================================================================
class RifReaderEclipseInput : public RifReaderInterface
{
public:
RifReaderEclipseInput();
~RifReaderEclipseInput() override;
// Virtual interface implementation
bool open( const QString& fileName, RigEclipseCaseData* eclipseCase ) override;
bool staticResult( const QString& result, RiaDefines::PorosityModelType matrixOrFracture, std::vector<double>* values ) override
{
return false;
}
bool dynamicResult( const QString& result,
RiaDefines::PorosityModelType matrixOrFracture,
size_t stepIndex,
std::vector<double>* values ) override
{
return false;
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,148 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RifReaderInterface.h"
#include "cvfCollection.h"
#include "cvfVector3.h"
#include <memory>
class RifEclipseOutputFileTools;
class RifEclipseRestartDataAccess;
class RifHdf5ReaderInterface;
class RigActiveCellInfo;
class RigFault;
class RigEclipseTimeStepInfo;
class RigGridBase;
class RigMainGrid;
class QDateTime;
struct RigWellResultPoint;
typedef struct ecl_grid_struct ecl_grid_type;
typedef struct ecl_file_struct ecl_file_type;
typedef struct well_conn_struct well_conn_type;
//==================================================================================================
//
// File interface for Eclipse output files
//
//==================================================================================================
class RifReaderEclipseOutput : public RifReaderInterface
{
public:
RifReaderEclipseOutput();
~RifReaderEclipseOutput() override;
bool open( const QString& fileName, RigEclipseCaseData* eclipseCase ) override;
void setHdf5FileName( const QString& fileName );
void setFileDataAccess( RifEclipseRestartDataAccess* restartDataAccess );
static const size_t* eclipseCellIndexMapping();
bool openAndReadActiveCellData( const QString& fileName,
const std::vector<QDateTime>& mainCaseTimeSteps,
RigEclipseCaseData* eclipseCase );
bool staticResult( const QString& result,
RiaDefines::PorosityModelType matrixOrFracture,
std::vector<double>* values ) override;
bool dynamicResult( const QString& result,
RiaDefines::PorosityModelType matrixOrFracture,
size_t stepIndex,
std::vector<double>* values ) override;
void sourSimRlResult( const QString& result, size_t stepIndex, std::vector<double>* values );
std::vector<QDateTime> allTimeSteps() const;
static bool transferGeometry( const ecl_grid_type* mainEclGrid, RigEclipseCaseData* eclipseCase );
static bool exportGrid( const QString& gridFileName,
RigEclipseCaseData* eclipseCase,
const cvf::Vec3st& min,
const cvf::Vec3st& max,
const cvf::Vec3st& refinement );
static void transferCoarseningInfo( const ecl_grid_type* eclGrid, RigGridBase* grid );
static void importEquilData( const QString& deckFileName,
const QString& includeStatementAbsolutePathPrefix,
RigEclipseCaseData* eclipseCase );
std::set<RiaDefines::PhaseType> availablePhases() const override;
// Load main, it is up to the consumer to release the memory using
//
// ecl_grid_type* myGrid = loadMainGrid();
// free(myGrid);
//
ecl_grid_type* loadAllGrids() const;
void updateFromGridCount( size_t gridCount ) override;
private:
bool readActiveCellInfo();
void buildMetaData( ecl_grid_type* grid );
void readWellCells( const ecl_grid_type* mainEclGrid, bool importCompleteMswData );
std::string ertGridName( size_t gridNr );
RigWellResultPoint createWellResultPoint( const RigGridBase* grid,
const well_conn_type* ert_connection,
int ertBranchId,
int ertSegmentId,
const char* wellName );
void importFaults( const QStringList& fileSet, cvf::Collection<RigFault>* faults );
void openInitFile();
void extractResultValuesBasedOnPorosityModel( RiaDefines::PorosityModelType matrixOrFracture,
std::vector<double>* values,
const std::vector<double>& fileValues );
void transferStaticNNCData( const ecl_grid_type* mainEclGrid, ecl_file_type* init_file, RigMainGrid* mainGrid );
void transferDynamicNNCData( const ecl_grid_type* mainEclGrid, RigMainGrid* mainGrid );
void ensureDynamicResultAccessIsPresent();
QStringList validKeywordsForPorosityModel( const QStringList& keywords,
const std::vector<size_t>& keywordDataItemCounts,
const RigActiveCellInfo* activeCellInfo,
const RigActiveCellInfo* fractureActiveCellInfo,
RiaDefines::PorosityModelType matrixOrFracture,
size_t timeStepCount ) const;
std::vector<RigEclipseTimeStepInfo> createFilteredTimeStepInfos();
static bool isEclipseAndSoursimTimeStepsEqual( const QDateTime& eclipseDateTime, const QDateTime& sourSimDateTime );
private:
QString m_fileName; // Name of file used to start accessing Eclipse output files
QStringList m_filesWithSameBaseName; // Set of files in filename's path with same base name as filename
RigEclipseCaseData* m_eclipseCase;
ecl_file_type* m_ecl_init_file; // File access to static results
mutable cvf::ref<RifEclipseRestartDataAccess> m_dynamicResultsAccess; // File access to dynamic results
std::unique_ptr<RifHdf5ReaderInterface> m_hdfReaderInterface;
};

View File

@@ -0,0 +1,441 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifReaderEclipseRft.h"
#include "RiaLogging.h"
#include "RiaQDateTimeTools.h"
#include "RiaStringEncodingTools.h"
#include "cafVecIjk.h"
#include "ert/ecl/ecl_rft_file.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderEclipseRft::RifReaderEclipseRft( const QString& fileName )
: m_fileName( fileName )
, m_ecl_rft_file( nullptr )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderEclipseRft::~RifReaderEclipseRft()
{
if ( m_ecl_rft_file )
{
ecl_rft_file_free( m_ecl_rft_file );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseRft::open()
{
if ( m_fileName.isEmpty() ) return;
RiaLogging::info( QString( "Opening file '%1'" ).arg( m_fileName ) );
m_ecl_rft_file = ecl_rft_file_alloc_case( RiaStringEncodingTools::toNativeEncoded( m_fileName ).data() );
if ( m_ecl_rft_file == nullptr )
{
RiaLogging::warning( QString( "Libecl could not find/open file '%'" ).arg( m_fileName ) );
return;
}
int fileSize = ecl_rft_file_get_size( m_ecl_rft_file );
m_eclipseRftAddresses.clear();
for ( int i = 0; i < fileSize; i++ )
{
ecl_rft_node_type* node = ecl_rft_file_iget_node( m_ecl_rft_file, i );
std::string wellNameStdString = ecl_rft_node_get_well_name( node );
QString wellName( wellNameStdString.c_str() );
m_wellNames.insert( wellName );
time_t timeStepTime_t = ecl_rft_node_get_date( node );
QDateTime timeStep = RiaQDateTimeTools::createUtcDateTime();
timeStep.setTime_t( timeStepTime_t );
RifEclipseRftAddress addressPressure( wellName, timeStep, RifEclipseRftAddress::PRESSURE );
m_eclipseRftAddresses.insert( addressPressure );
m_rftAddressToLibeclNodeIdx[addressPressure] = i;
RifEclipseRftAddress addressDepth( wellName, timeStep, RifEclipseRftAddress::TVD );
m_eclipseRftAddresses.insert( addressDepth );
m_rftAddressToLibeclNodeIdx[addressDepth] = i;
if ( ecl_rft_node_is_RFT( node ) )
{
RifEclipseRftAddress addressSwat( wellName, timeStep, RifEclipseRftAddress::SWAT );
m_eclipseRftAddresses.insert( addressSwat );
m_rftAddressToLibeclNodeIdx[addressSwat] = i;
RifEclipseRftAddress addressSoil( wellName, timeStep, RifEclipseRftAddress::SOIL );
m_eclipseRftAddresses.insert( addressSoil );
m_rftAddressToLibeclNodeIdx[addressSoil] = i;
RifEclipseRftAddress addressSgas( wellName, timeStep, RifEclipseRftAddress::SGAS );
m_eclipseRftAddresses.insert( addressSgas );
m_rftAddressToLibeclNodeIdx[addressSgas] = i;
}
else if ( ecl_rft_node_is_PLT( node ) )
{
RifEclipseRftAddress addressWrat( wellName, timeStep, RifEclipseRftAddress::WRAT );
m_eclipseRftAddresses.insert( addressWrat );
m_rftAddressToLibeclNodeIdx[addressWrat] = i;
RifEclipseRftAddress addressOrat( wellName, timeStep, RifEclipseRftAddress::ORAT );
m_eclipseRftAddresses.insert( addressOrat );
m_rftAddressToLibeclNodeIdx[addressOrat] = i;
RifEclipseRftAddress addressGrat( wellName, timeStep, RifEclipseRftAddress::GRAT );
m_eclipseRftAddresses.insert( addressGrat );
m_rftAddressToLibeclNodeIdx[addressGrat] = i;
}
}
return;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RifEclipseRftAddress> RifReaderEclipseRft::eclipseRftAddresses()
{
if ( !m_ecl_rft_file )
{
open();
}
return m_eclipseRftAddresses;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseRft::values( const RifEclipseRftAddress& rftAddress, std::vector<double>* values )
{
CVF_ASSERT( values );
if ( !m_ecl_rft_file )
{
open();
}
values->clear();
int index = indexFromAddress( rftAddress );
if ( index < 0 ) return;
ecl_rft_node_type* node = ecl_rft_file_iget_node( m_ecl_rft_file, index );
RifEclipseRftAddress::RftWellLogChannelType wellLogChannelName = rftAddress.wellLogChannel();
switch ( wellLogChannelName )
{
case RifEclipseRftAddress::TVD:
{
for ( int i = 0; i < ecl_rft_node_get_size( node ); i++ )
{
values->push_back( ecl_rft_node_iget_depth( node, i ) );
}
break;
}
case RifEclipseRftAddress::PRESSURE:
{
for ( int i = 0; i < ecl_rft_node_get_size( node ); i++ )
{
values->push_back( ecl_rft_node_iget_pressure( node, i ) );
}
break;
}
case RifEclipseRftAddress::SWAT:
{
for ( int i = 0; i < ecl_rft_node_get_size( node ); i++ )
{
values->push_back( ecl_rft_node_iget_swat( node, i ) );
}
break;
}
case RifEclipseRftAddress::SOIL:
{
for ( int i = 0; i < ecl_rft_node_get_size( node ); i++ )
{
values->push_back( ecl_rft_node_iget_soil( node, i ) );
}
break;
}
case RifEclipseRftAddress::SGAS:
{
for ( int i = 0; i < ecl_rft_node_get_size( node ); i++ )
{
values->push_back( ecl_rft_node_iget_sgas( node, i ) );
}
break;
}
case RifEclipseRftAddress::WRAT:
{
for ( int i = 0; i < ecl_rft_node_get_size( node ); i++ )
{
values->push_back( ecl_rft_node_iget_wrat( node, i ) );
}
break;
}
case RifEclipseRftAddress::ORAT:
{
for ( int i = 0; i < ecl_rft_node_get_size( node ); i++ )
{
values->push_back( ecl_rft_node_iget_orat( node, i ) );
}
break;
}
case RifEclipseRftAddress::GRAT:
{
for ( int i = 0; i < ecl_rft_node_get_size( node ); i++ )
{
values->push_back( ecl_rft_node_iget_grat( node, i ) );
}
break;
}
default:
break;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseRft::cellIndices( const RifEclipseRftAddress& rftAddress, std::vector<caf::VecIjk>* indices )
{
CVF_ASSERT( indices );
if ( !m_ecl_rft_file )
{
open();
}
indices->clear();
int index = indexFromAddress( rftAddress );
if ( index < 0 ) return;
ecl_rft_node_type* node = ecl_rft_file_iget_node( m_ecl_rft_file, index );
for ( int cellIdx = 0; cellIdx < ecl_rft_node_get_size( node ); cellIdx++ )
{
int i, j, k;
ecl_rft_node_iget_ijk( node, cellIdx, &i, &j, &k );
caf::VecIjk ijk( (size_t)i, (size_t)j, (size_t)k );
indices->push_back( ijk );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime>
RifReaderEclipseRft::availableTimeSteps( const QString& wellName,
const RifEclipseRftAddress::RftWellLogChannelType& wellLogChannelName )
{
if ( !m_ecl_rft_file )
{
open();
}
std::set<QDateTime> timeSteps;
if ( wellName == "" ) return timeSteps;
for ( const RifEclipseRftAddress& address : m_eclipseRftAddresses )
{
if ( address.wellName() == wellName && address.wellLogChannel() == wellLogChannelName )
{
timeSteps.insert( address.timeStep() );
}
}
return timeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime>
RifReaderEclipseRft::availableTimeSteps( const QString& wellName,
const std::set<RifEclipseRftAddress::RftWellLogChannelType>& relevantChannels )
{
if ( !m_ecl_rft_file )
{
open();
}
std::set<QDateTime> timeSteps;
if ( wellName == "" ) return timeSteps;
for ( const RifEclipseRftAddress& address : m_eclipseRftAddresses )
{
if ( address.wellName() == wellName && relevantChannels.count( address.wellLogChannel() ) )
{
timeSteps.insert( address.timeStep() );
}
}
return timeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime> RifReaderEclipseRft::availableTimeSteps( const QString& wellName )
{
auto wellLogChannels = availableWellLogChannels( wellName );
return availableTimeSteps( wellName, wellLogChannels );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RifEclipseRftAddress::RftWellLogChannelType> RifReaderEclipseRft::availableWellLogChannels( const QString& wellName )
{
if ( !m_ecl_rft_file )
{
open();
}
std::set<RifEclipseRftAddress::RftWellLogChannelType> wellLogChannelNames;
if ( wellName == "" ) return wellLogChannelNames;
bool pressureFound = false;
bool rftFound = false;
bool pltFound = false;
for ( const RifEclipseRftAddress& address : m_eclipseRftAddresses )
{
if ( address.wellName() == wellName )
{
RifEclipseRftAddress::RftWellLogChannelType name = address.wellLogChannel();
if ( !pressureFound )
{
if ( name == RifEclipseRftAddress::PRESSURE )
{
pressureFound = true;
if ( rftFound && pltFound ) break;
}
}
if ( !rftFound )
{
if ( name == RifEclipseRftAddress::RftWellLogChannelType::SWAT )
{
rftFound = true;
if ( pltFound && pressureFound ) break;
continue;
}
}
if ( !pltFound )
{
if ( name == RifEclipseRftAddress::RftWellLogChannelType::WRAT )
{
pltFound = true;
if ( rftFound && pressureFound ) break;
}
}
}
}
if ( pressureFound )
{
wellLogChannelNames.insert( RifEclipseRftAddress::PRESSURE );
}
if ( rftFound )
{
wellLogChannelNames.insert( RifEclipseRftAddress::RftWellLogChannelType::SWAT );
wellLogChannelNames.insert( RifEclipseRftAddress::RftWellLogChannelType::SOIL );
wellLogChannelNames.insert( RifEclipseRftAddress::RftWellLogChannelType::SGAS );
}
if ( pltFound )
{
wellLogChannelNames.insert( RifEclipseRftAddress::RftWellLogChannelType::WRAT );
wellLogChannelNames.insert( RifEclipseRftAddress::RftWellLogChannelType::ORAT );
wellLogChannelNames.insert( RifEclipseRftAddress::RftWellLogChannelType::GRAT );
}
return wellLogChannelNames;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QString> RifReaderEclipseRft::wellNames()
{
if ( !m_ecl_rft_file )
{
open();
}
return m_wellNames;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderEclipseRft::wellHasRftData( QString wellName )
{
if ( !m_ecl_rft_file )
{
open();
}
for ( const QString& name : wellNames() )
{
if ( name == wellName )
{
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RifReaderEclipseRft::indexFromAddress( const RifEclipseRftAddress& rftAddress ) const
{
auto it = m_rftAddressToLibeclNodeIdx.find( rftAddress );
if ( it != m_rftAddressToLibeclNodeIdx.end() )
{
return it->second;
}
return -1;
}

View File

@@ -0,0 +1,74 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifReaderRftInterface.h"
#include <map>
#include <string>
#include <vector>
#include "cvfObject.h"
#include <QDateTime>
namespace caf
{
class VecIjk;
}
//==================================================================================================
//
//
//==================================================================================================
class RifReaderEclipseRft : public RifReaderRftInterface, public cvf::Object
{
public:
RifReaderEclipseRft( const QString& fileName );
~RifReaderEclipseRft() override;
std::set<RifEclipseRftAddress> eclipseRftAddresses() override;
void values( const RifEclipseRftAddress& rftAddress, std::vector<double>* values ) override;
void cellIndices( const RifEclipseRftAddress& rftAddress, std::vector<caf::VecIjk>* indices );
std::set<QDateTime> availableTimeSteps( const QString& wellName ) override;
std::set<QDateTime>
availableTimeSteps( const QString& wellName,
const std::set<RifEclipseRftAddress::RftWellLogChannelType>& relevantChannels ) override;
std::set<QDateTime> availableTimeSteps( const QString& wellName,
const RifEclipseRftAddress::RftWellLogChannelType& wellLogChannelName ) override;
std::set<RifEclipseRftAddress::RftWellLogChannelType> availableWellLogChannels( const QString& wellName ) override;
std::set<QString> wellNames() override;
bool wellHasRftData( QString wellName );
private:
void open();
int indexFromAddress( const RifEclipseRftAddress& rftAddress ) const;
private:
// Taken from ecl_rft_file.h and ecl_rft_node.h
typedef struct ecl_rft_file_struct ecl_rft_file_type;
QString m_fileName;
ecl_rft_file_type* m_ecl_rft_file;
std::set<RifEclipseRftAddress> m_eclipseRftAddresses;
std::set<QString> m_wellNames;
std::map<RifEclipseRftAddress, int> m_rftAddressToLibeclNodeIdx;
};

View File

@@ -0,0 +1,679 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifReaderEclipseSummary.h"
#include "RiaFilePathTools.h"
#include "RiaStdStringTools.h"
#include "RiaStringEncodingTools.h"
#include "RifEclipseSummaryTools.h"
#include "RifReaderEclipseOutput.h"
#include <cassert>
#include <string>
#include <QDateTime>
#include <QDir>
#include <QString>
#include <QStringList>
#include "ert/ecl/ecl_file.h"
#include "ert/ecl/ecl_kw.h"
#include "ert/ecl/ecl_kw_magic.h"
#include "ert/ecl/ecl_sum.h"
#include "ert/ecl/smspec_node.hpp"
std::vector<time_t> getTimeSteps( ecl_sum_type* ecl_sum )
{
std::vector<time_t> timeSteps;
if ( ecl_sum )
{
time_t_vector_type* steps = ecl_sum_alloc_time_vector( ecl_sum, false );
if ( steps )
{
for ( int i = 0; i < time_t_vector_size( steps ); i++ )
{
timeSteps.push_back( time_t_vector_iget( steps, i ) );
}
time_t_vector_free( steps );
}
}
return timeSteps;
}
RiaEclipseUnitTools::UnitSystem readUnitSystem( ecl_sum_type* ecl_sum )
{
ert_ecl_unit_enum eclUnitEnum = ecl_sum_get_unit_system( ecl_sum );
switch ( eclUnitEnum )
{
case ECL_METRIC_UNITS:
return RiaEclipseUnitTools::UnitSystem::UNITS_METRIC;
case ECL_FIELD_UNITS:
return RiaEclipseUnitTools::UnitSystem::UNITS_FIELD;
case ECL_LAB_UNITS:
return RiaEclipseUnitTools::UnitSystem::UNITS_LAB;
default:
return RiaEclipseUnitTools::UnitSystem::UNITS_UNKNOWN;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ecl_sum_type* openEclSum( const QString& inHeaderFileName, bool includeRestartFiles )
{
QString headerFileName;
QStringList dataFileNames;
QString nativeHeaderFileName = QDir::toNativeSeparators( inHeaderFileName );
RifEclipseSummaryTools::findSummaryFiles( nativeHeaderFileName, &headerFileName, &dataFileNames );
if ( headerFileName.isEmpty() || dataFileNames.size() == 0 ) return nullptr;
assert( !headerFileName.isEmpty() );
assert( dataFileNames.size() > 0 );
stringlist_type* dataFiles = stringlist_alloc_new();
for ( int i = 0; i < dataFileNames.size(); i++ )
{
stringlist_append_copy( dataFiles, RiaStringEncodingTools::toNativeEncoded( dataFileNames[i] ).data() );
}
bool lazyLoad = true;
std::string itemSeparatorInVariableNames = ":";
ecl_sum_type* ecl_sum = ecl_sum_fread_alloc( RiaStringEncodingTools::toNativeEncoded( headerFileName ).data(),
dataFiles,
itemSeparatorInVariableNames.data(),
includeRestartFiles,
lazyLoad,
ECL_FILE_CLOSE_STREAM );
stringlist_free( dataFiles );
return ecl_sum;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void closeEclSum( ecl_sum_type* ecl_sum )
{
if ( ecl_sum ) ecl_sum_free( ecl_sum );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderEclipseSummary::RifReaderEclipseSummary()
: m_ecl_sum( nullptr )
, m_ecl_SmSpec( nullptr )
, m_unitSystem( RiaEclipseUnitTools::UnitSystem::UNITS_METRIC )
{
m_valuesCache.reset( new ValuesCache() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderEclipseSummary::~RifReaderEclipseSummary()
{
if ( m_ecl_sum )
{
ecl_sum_free( m_ecl_sum );
m_ecl_sum = nullptr;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderEclipseSummary::open( const QString& headerFileName, bool includeRestartFiles )
{
assert( m_ecl_sum == nullptr );
m_ecl_sum = openEclSum( headerFileName, includeRestartFiles );
if ( m_ecl_sum )
{
m_timeSteps.clear();
m_ecl_SmSpec = ecl_sum_get_smspec( m_ecl_sum );
m_timeSteps = getTimeSteps( m_ecl_sum );
m_unitSystem = readUnitSystem( m_ecl_sum );
buildMetaData();
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RifRestartFileInfo> RifReaderEclipseSummary::getRestartFiles( const QString& headerFileName, bool* hasWarnings )
{
CVF_ASSERT( hasWarnings );
std::vector<RifRestartFileInfo> restartFiles;
m_warnings.clear();
*hasWarnings = false;
std::set<QString> restartFilesOpened;
RifRestartFileInfo currFile;
currFile.fileName = headerFileName;
while ( !currFile.fileName.isEmpty() )
{
// Due to a weakness in libecl regarding restart summary header file selection,
// do some extra checking
{
QString formattedHeaderExtension = ".FSMSPEC";
QString nonformattedHeaderExtension = ".SMSPEC";
QString formattedDataFileExtension = ".FUNSMRY";
if ( currFile.fileName.endsWith( nonformattedHeaderExtension, Qt::CaseInsensitive ) )
{
QString formattedHeaderFile = currFile.fileName;
formattedHeaderFile.replace( nonformattedHeaderExtension, formattedHeaderExtension, Qt::CaseInsensitive );
QString formattedDateFile = currFile.fileName;
formattedDateFile.replace( nonformattedHeaderExtension, formattedDataFileExtension, Qt::CaseInsensitive );
QFileInfo nonformattedHeaderFileInfo = QFileInfo( currFile.fileName );
QFileInfo formattedHeaderFileInfo = QFileInfo( formattedHeaderFile );
QFileInfo formattedDateFileInfo = QFileInfo( formattedDateFile );
if ( formattedHeaderFileInfo.lastModified() < nonformattedHeaderFileInfo.lastModified() &&
formattedHeaderFileInfo.exists() && !formattedDateFileInfo.exists() )
{
m_warnings.push_back(
QString( "RifReaderEclipseSummary: Formatted summary header file without an\n" ) +
QString( "associated data file detected.\n" ) +
QString( "This may cause a failure reading summary origin data.\n" ) +
QString( "To avoid this problem, please delete or rename the.FSMSPEC file." ) );
*hasWarnings = true;
break;
}
}
QString prevFile = currFile.fileName;
currFile = getRestartFile( currFile.fileName );
// Fix to stop potential infinite loop
if ( currFile.fileName == prevFile )
{
m_warnings.push_back( "RifReaderEclipseSummary: Restart file reference loop detected" );
*hasWarnings = true;
break;
}
else if ( restartFilesOpened.count( currFile.fileName ) != 0u )
{
m_warnings.push_back( "RifReaderEclipseSummary: Same restart file being opened multiple times" );
*hasWarnings = true;
}
restartFilesOpened.insert( currFile.fileName );
}
if ( !currFile.fileName.isEmpty() ) restartFiles.push_back( currFile );
}
return restartFiles;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifRestartFileInfo RifReaderEclipseSummary::getFileInfo( const QString& headerFileName )
{
RifRestartFileInfo fileInfo;
ecl_sum_type* ecl_sum = openEclSum( headerFileName, false );
std::vector<time_t> timeSteps = getTimeSteps( ecl_sum );
if ( timeSteps.size() > 0 )
{
fileInfo.fileName = headerFileName;
fileInfo.startDate = timeSteps.front();
fileInfo.endDate = timeSteps.back();
}
closeEclSum( ecl_sum );
return fileInfo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string stringFromPointer( const char* pointerToChar )
{
std::string myString;
// NB! Assigning a null pointer to a std::string causes runtime crash
if ( pointerToChar )
{
myString = pointerToChar;
}
return myString;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddress addressFromErtSmSpecNode( const ecl::smspec_node& ertSumVarNode )
{
if ( ertSumVarNode.get_var_type() == ECL_SMSPEC_INVALID_VAR )
{
return RifEclipseSummaryAddress();
}
RifEclipseSummaryAddress::SummaryVarCategory sumCategory( RifEclipseSummaryAddress::SUMMARY_INVALID );
std::string quantityName;
int regionNumber( -1 );
int regionNumber2( -1 );
std::string wellGroupName;
std::string wellName;
int wellSegmentNumber( -1 );
std::string lgrName;
int cellI( -1 );
int cellJ( -1 );
int cellK( -1 );
int aquiferNumber( -1 );
bool isErrorResult( false );
int id( -1 );
quantityName = stringFromPointer( ertSumVarNode.get_keyword() );
switch ( ertSumVarNode.get_var_type() )
{
case ECL_SMSPEC_AQUIFER_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_AQUIFER;
aquiferNumber = ertSumVarNode.get_num();
}
break;
case ECL_SMSPEC_WELL_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL;
wellName = stringFromPointer( ertSumVarNode.get_wgname() );
}
break;
case ECL_SMSPEC_REGION_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_REGION;
regionNumber = ertSumVarNode.get_num();
}
break;
case ECL_SMSPEC_FIELD_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_FIELD;
}
break;
case ECL_SMSPEC_GROUP_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_GROUP;
wellGroupName = stringFromPointer( ertSumVarNode.get_wgname() );
}
break;
case ECL_SMSPEC_BLOCK_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_BLOCK;
auto ijk = ertSumVarNode.get_ijk();
cellI = ijk[0];
cellJ = ijk[1];
cellK = ijk[2];
}
break;
case ECL_SMSPEC_COMPLETION_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION;
wellName = stringFromPointer( ertSumVarNode.get_wgname() );
auto ijk = ertSumVarNode.get_ijk();
cellI = ijk[0];
cellJ = ijk[1];
cellK = ijk[2];
}
break;
case ECL_SMSPEC_LOCAL_BLOCK_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_BLOCK_LGR;
lgrName = stringFromPointer( ertSumVarNode.get_lgr_name() );
auto ijk = ertSumVarNode.get_lgr_ijk();
cellI = ijk[0];
cellJ = ijk[1];
cellK = ijk[2];
}
break;
case ECL_SMSPEC_LOCAL_COMPLETION_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION_LGR;
wellName = stringFromPointer( ertSumVarNode.get_wgname() );
lgrName = stringFromPointer( ertSumVarNode.get_lgr_name() );
auto ijk = ertSumVarNode.get_lgr_ijk();
cellI = ijk[0];
cellJ = ijk[1];
cellK = ijk[2];
}
break;
case ECL_SMSPEC_LOCAL_WELL_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_LGR;
wellName = stringFromPointer( ertSumVarNode.get_wgname() );
lgrName = stringFromPointer( ertSumVarNode.get_lgr_name() );
}
break;
case ECL_SMSPEC_NETWORK_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_NETWORK;
}
break;
case ECL_SMSPEC_REGION_2_REGION_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_REGION_2_REGION;
regionNumber = ertSumVarNode.get_R1();
regionNumber2 = ertSumVarNode.get_R2();
}
break;
case ECL_SMSPEC_SEGMENT_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_SEGMENT;
wellName = stringFromPointer( ertSumVarNode.get_wgname() );
wellSegmentNumber = ertSumVarNode.get_num();
}
break;
case ECL_SMSPEC_MISC_VAR:
{
sumCategory = RifEclipseSummaryAddress::SUMMARY_MISC;
}
break;
default:
CVF_ASSERT( false );
break;
}
return RifEclipseSummaryAddress( sumCategory,
quantityName,
regionNumber,
regionNumber2,
wellGroupName,
wellName,
wellSegmentNumber,
lgrName,
cellI,
cellJ,
cellK,
aquiferNumber,
isErrorResult,
id );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderEclipseSummary::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{
assert( m_ecl_sum != nullptr );
values->clear();
values->reserve( timeStepCount() );
const std::vector<double>& cachedValues = m_valuesCache->getValues( resultAddress );
if ( !cachedValues.empty() )
{
values->insert( values->begin(), cachedValues.begin(), cachedValues.end() );
}
else if ( m_ecl_SmSpec )
{
if ( m_differenceAddresses.count( resultAddress ) )
{
std::string quantityName = resultAddress.quantityName();
auto historyQuantity = quantityName.substr( 0, quantityName.size() - differenceIdentifier().size() ) +
historyIdentifier();
RifEclipseSummaryAddress nativeAdrNoHistory = resultAddress;
nativeAdrNoHistory.setQuantityName( historyQuantity );
auto quantityNoHistory = quantityName.substr( 0, historyQuantity.size() - 1 );
RifEclipseSummaryAddress nativeAdrHistory = resultAddress;
nativeAdrHistory.setQuantityName( quantityNoHistory );
std::vector<double> nativeValues;
std::vector<double> historyValues;
if ( !this->values( nativeAdrHistory, &nativeValues ) ) return false;
if ( !this->values( nativeAdrNoHistory, &historyValues ) ) return false;
if ( nativeValues.size() != historyValues.size() ) return false;
for ( size_t i = 0; i < nativeValues.size(); i++ )
{
double diff = nativeValues[i] - historyValues[i];
values->push_back( diff );
m_valuesCache->insertValues( resultAddress, *values );
}
return true;
}
int variableIndex = indexFromAddress( resultAddress );
if ( variableIndex < 0 ) return false;
const ecl::smspec_node& ertSumVarNode = ecl_smspec_iget_node_w_node_index( m_ecl_SmSpec, variableIndex );
int paramsIndex = ertSumVarNode.get_params_index();
double_vector_type* dataValues = ecl_sum_alloc_data_vector( m_ecl_sum, paramsIndex, false );
if ( dataValues )
{
int dataSize = double_vector_size( dataValues );
const double* dataPtr = double_vector_get_const_ptr( dataValues );
values->insert( values->end(), dataPtr, dataPtr + dataSize );
double_vector_free( dataValues );
m_valuesCache->insertValues( resultAddress, *values );
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RifReaderEclipseSummary::timeStepCount() const
{
assert( m_ecl_sum != nullptr );
if ( m_ecl_SmSpec == nullptr ) return 0;
return ecl_sum_get_data_length( m_ecl_sum );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<time_t>& RifReaderEclipseSummary::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{
assert( m_ecl_sum != nullptr );
return m_timeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RifReaderEclipseSummary::indexFromAddress( const RifEclipseSummaryAddress& resultAddress ) const
{
auto it = m_resultAddressToErtNodeIdx.find( resultAddress );
if ( it != m_resultAddressToErtNodeIdx.end() )
{
return it->second;
}
return -1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseSummary::buildMetaData()
{
m_allResultAddresses.clear();
m_resultAddressToErtNodeIdx.clear();
if ( m_ecl_SmSpec )
{
int varCount = ecl_smspec_num_nodes( m_ecl_SmSpec );
for ( int i = 0; i < varCount; i++ )
{
const ecl::smspec_node& ertSumVarNode = ecl_smspec_iget_node_w_node_index( m_ecl_SmSpec, i );
RifEclipseSummaryAddress addr = addressFromErtSmSpecNode( ertSumVarNode );
m_allResultAddresses.insert( addr );
m_resultAddressToErtNodeIdx[addr] = i;
}
}
bool addDifferenceVectors = true;
if ( addDifferenceVectors )
{
for ( const auto& adr : m_allResultAddresses )
{
RifEclipseSummaryAddress adrWithHistory;
RifEclipseSummaryAddress adrWithoutHistory;
{
std::string s = adr.quantityName();
if ( !RiaStdStringTools::endsWith( s, historyIdentifier() ) )
{
RifEclipseSummaryAddress candidate = adr;
candidate.setQuantityName( s + historyIdentifier() );
if ( m_allResultAddresses.count( candidate ) )
{
adrWithHistory = candidate;
adrWithoutHistory = adr;
}
}
}
if ( adrWithoutHistory.isValid() && adrWithHistory.isValid() )
{
RifEclipseSummaryAddress candidate = adr;
std::string s = candidate.quantityName() + differenceIdentifier();
candidate.setQuantityName( s );
m_allResultAddresses.insert( candidate );
m_differenceAddresses.insert( candidate );
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifRestartFileInfo RifReaderEclipseSummary::getRestartFile( const QString& headerFileName )
{
ecl_sum_type* ecl_sum = openEclSum( headerFileName, true );
const ecl_smspec_type* smspec = ecl_sum ? ecl_sum_get_smspec( ecl_sum ) : nullptr;
const char* rstCase = smspec ? ecl_smspec_get_restart_case( smspec ) : nullptr;
QString restartCase =
rstCase ? RiaFilePathTools::canonicalPath( RiaStringEncodingTools::fromNativeEncoded( rstCase ) ) : "";
closeEclSum( ecl_sum );
if ( !restartCase.isEmpty() )
{
QString path = QFileInfo( restartCase ).dir().path();
QString restartBase = QDir( restartCase ).dirName();
char* smspec_header = ecl_util_alloc_exfilename( path.toStdString().data(),
restartBase.toStdString().data(),
ECL_SUMMARY_HEADER_FILE,
false /*unformatted*/,
0 );
QString restartFileName =
RiaFilePathTools::toInternalSeparator( RiaStringEncodingTools::fromNativeEncoded( smspec_header ) );
free( smspec_header );
return getFileInfo( restartFileName );
}
return RifRestartFileInfo();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RifReaderEclipseSummary::unitName( const RifEclipseSummaryAddress& resultAddress ) const
{
if ( !m_ecl_SmSpec ) return "";
int variableIndex = indexFromAddress( resultAddress );
if ( variableIndex < 0 ) return "";
const ecl::smspec_node& ertSumVarNode = ecl_smspec_iget_node_w_node_index( m_ecl_SmSpec, variableIndex );
return ertSumVarNode.get_unit();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaEclipseUnitTools::UnitSystem RifReaderEclipseSummary::unitSystem() const
{
return m_unitSystem;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<double> RifReaderEclipseSummary::ValuesCache::EMPTY_VECTOR;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderEclipseSummary::ValuesCache::ValuesCache()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderEclipseSummary::ValuesCache::~ValuesCache()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseSummary::ValuesCache::insertValues( const RifEclipseSummaryAddress& address,
const std::vector<double>& values )
{
m_cachedValues[address] = values;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<double>& RifReaderEclipseSummary::ValuesCache::getValues( const RifEclipseSummaryAddress& address ) const
{
if ( m_cachedValues.find( address ) != m_cachedValues.end() )
{
return m_cachedValues.at( address );
}
return EMPTY_VECTOR;
}

View File

@@ -0,0 +1,126 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaEclipseUnitTools.h"
#include "RifEclipseSummaryAddress.h"
#include "RifSummaryReaderInterface.h"
#include <QString>
#include <QStringList>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
//==================================================================================================
//
//
//==================================================================================================
class RifRestartFileInfo
{
public:
RifRestartFileInfo()
: startDate( 0 )
, endDate( 0 )
{
}
RifRestartFileInfo( const QString& _fileName, time_t _startDate, time_t _endDate )
: fileName( _fileName )
, startDate( _startDate )
, endDate( _endDate )
{
}
bool valid() { return !fileName.isEmpty(); }
QString fileName;
time_t startDate;
time_t endDate;
};
//==================================================================================================
//
//
//==================================================================================================
class RifReaderEclipseSummary : public RifSummaryReaderInterface
{
public:
RifReaderEclipseSummary();
~RifReaderEclipseSummary() override;
bool open( const QString& headerFileName, bool includeRestartFiles );
std::vector<RifRestartFileInfo> getRestartFiles( const QString& headerFileName, bool* hasWarnings );
RifRestartFileInfo getFileInfo( const QString& headerFileName );
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;
RiaEclipseUnitTools::UnitSystem unitSystem() const override;
QStringList warnings() const { return m_warnings; }
static std::string differenceIdentifier() { return "_DIFF"; }
static const std::string historyIdentifier() { return "H"; }
private:
int timeStepCount() const;
int indexFromAddress( const RifEclipseSummaryAddress& resultAddress ) const;
void buildMetaData();
RifRestartFileInfo getRestartFile( const QString& headerFileName );
private:
// Taken from ecl_sum.h
typedef struct ecl_sum_struct ecl_sum_type;
typedef struct ecl_smspec_struct ecl_smspec_type;
ecl_sum_type* m_ecl_sum;
const ecl_smspec_type* m_ecl_SmSpec;
std::vector<time_t> m_timeSteps;
RiaEclipseUnitTools::UnitSystem m_unitSystem;
std::map<RifEclipseSummaryAddress, int> m_resultAddressToErtNodeIdx;
QStringList m_warnings;
std::set<RifEclipseSummaryAddress> m_differenceAddresses;
//==================================================================================================
//
//==================================================================================================
class ValuesCache
{
static const std::vector<double> EMPTY_VECTOR;
public:
ValuesCache();
~ValuesCache();
void insertValues( const RifEclipseSummaryAddress& address, const std::vector<double>& values );
const std::vector<double>& getValues( const RifEclipseSummaryAddress& address ) const;
private:
std::map<const RifEclipseSummaryAddress, std::vector<double>> m_cachedValues;
};
std::unique_ptr<ValuesCache> m_valuesCache;
};

View File

@@ -0,0 +1,271 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RifReaderEnsembleStatisticsRft.h"
#include "RiaCurveMerger.h"
#include "RiaWeightedMeanCalculator.h"
#include "RigStatisticsMath.h"
#include "RimSummaryCase.h"
#include "RimSummaryCaseCollection.h"
#include "cafAssert.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderEnsembleStatisticsRft::RifReaderEnsembleStatisticsRft( const RimSummaryCaseCollection* summaryCaseCollection )
: m_summaryCaseCollection( summaryCaseCollection )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RifEclipseRftAddress> RifReaderEnsembleStatisticsRft::eclipseRftAddresses()
{
std::set<RifEclipseRftAddress> allAddresses;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
if ( summaryCase->rftReader() )
{
std::set<RifEclipseRftAddress> addresses = summaryCase->rftReader()->eclipseRftAddresses();
allAddresses.insert( addresses.begin(), addresses.end() );
}
}
std::set<RifEclipseRftAddress> statisticsAddresses;
for ( const RifEclipseRftAddress& regularAddress : allAddresses )
{
if ( regularAddress.wellLogChannel() == RifEclipseRftAddress::TVD )
{
statisticsAddresses.insert( regularAddress );
}
else if ( regularAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE )
{
std::set<RifEclipseRftAddress::RftWellLogChannelType> statChannels = { RifEclipseRftAddress::PRESSURE_P10,
RifEclipseRftAddress::PRESSURE_P50,
RifEclipseRftAddress::PRESSURE_P90,
RifEclipseRftAddress::PRESSURE_MEAN };
for ( auto channel : statChannels )
{
statisticsAddresses.insert(
RifEclipseRftAddress( regularAddress.wellName(), regularAddress.timeStep(), channel ) );
}
}
}
return statisticsAddresses;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEnsembleStatisticsRft::values( const RifEclipseRftAddress& rftAddress, std::vector<double>* values )
{
CAF_ASSERT( rftAddress.wellLogChannel() == RifEclipseRftAddress::TVD ||
rftAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE_MEAN ||
rftAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE_P10 ||
rftAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE_P50 ||
rftAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE_P90 ||
rftAddress.wellLogChannel() == RifEclipseRftAddress::PRESSURE_ERROR );
auto it = m_cachedValues.find( rftAddress );
if ( it == m_cachedValues.end() )
{
calculateStatistics( rftAddress );
}
*values = m_cachedValues[rftAddress];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime> RifReaderEnsembleStatisticsRft::availableTimeSteps( const QString& wellName )
{
std::set<QDateTime> allTimeSteps;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
if ( summaryCase->rftReader() )
{
std::set<QDateTime> timeSteps = summaryCase->rftReader()->availableTimeSteps( wellName );
allTimeSteps.insert( timeSteps.begin(), timeSteps.end() );
}
}
return allTimeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime>
RifReaderEnsembleStatisticsRft::availableTimeSteps( const QString& wellName,
const RifEclipseRftAddress::RftWellLogChannelType& wellLogChannelName )
{
std::set<QDateTime> allTimeSteps;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
if ( summaryCase->rftReader() )
{
std::set<QDateTime> timeSteps = summaryCase->rftReader()->availableTimeSteps( wellName, wellLogChannelName );
allTimeSteps.insert( timeSteps.begin(), timeSteps.end() );
}
}
return allTimeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime> RifReaderEnsembleStatisticsRft::availableTimeSteps(
const QString& wellName,
const std::set<RifEclipseRftAddress::RftWellLogChannelType>& relevantChannels )
{
std::set<QDateTime> allTimeSteps;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
if ( summaryCase->rftReader() )
{
std::set<QDateTime> timeSteps = summaryCase->rftReader()->availableTimeSteps( wellName, relevantChannels );
allTimeSteps.insert( timeSteps.begin(), timeSteps.end() );
}
}
return allTimeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RifEclipseRftAddress::RftWellLogChannelType>
RifReaderEnsembleStatisticsRft::availableWellLogChannels( const QString& wellName )
{
std::set<RifEclipseRftAddress::RftWellLogChannelType> allWellLogChannels;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
if ( summaryCase->rftReader() )
{
std::set<RifEclipseRftAddress::RftWellLogChannelType> wellLogChannels =
summaryCase->rftReader()->availableWellLogChannels( wellName );
allWellLogChannels.insert( wellLogChannels.begin(), wellLogChannels.end() );
}
}
return allWellLogChannels;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QString> RifReaderEnsembleStatisticsRft::wellNames()
{
std::set<QString> allWellNames;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
if ( summaryCase->rftReader() )
{
std::set<QString> wellNames = summaryCase->rftReader()->wellNames();
allWellNames.insert( wellNames.begin(), wellNames.end() );
}
}
return allWellNames;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEnsembleStatisticsRft::calculateStatistics( const RifEclipseRftAddress& rftAddress )
{
const QString& wellName = rftAddress.wellName();
const QDateTime& timeStep = rftAddress.timeStep();
RifEclipseRftAddress depthAddress( wellName, timeStep, RifEclipseRftAddress::TVD );
RifEclipseRftAddress pressAddress( wellName, timeStep, RifEclipseRftAddress::PRESSURE );
RifEclipseRftAddress p10Address( wellName, timeStep, RifEclipseRftAddress::PRESSURE_P10 );
RifEclipseRftAddress p50Address( wellName, timeStep, RifEclipseRftAddress::PRESSURE_P50 );
RifEclipseRftAddress p90Address( wellName, timeStep, RifEclipseRftAddress::PRESSURE_P90 );
RifEclipseRftAddress meanAddress( wellName, timeStep, RifEclipseRftAddress::PRESSURE_MEAN );
RiaCurveMerger<double> curveMerger;
RiaWeightedMeanCalculator<size_t> dataSetSizeCalc;
for ( RimSummaryCase* summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
RifReaderRftInterface* reader = summaryCase->rftReader();
if ( reader )
{
std::vector<double> depths;
std::vector<double> pressures;
reader->values( depthAddress, &depths );
reader->values( pressAddress, &pressures );
if ( !depths.empty() && !pressures.empty() )
{
dataSetSizeCalc.addValueAndWeight( depths.size(), 1.0 );
curveMerger.addCurveData( depths, pressures );
}
}
}
curveMerger.computeInterpolatedValues( false );
clearData( wellName, timeStep );
const std::vector<double>& allDepths = curveMerger.allXValues();
if ( !allDepths.empty() )
{
// Make sure we end up with approximately the same amount of points as originally
// Since allDepths contain *valid* values, it can potentially be smaller than the mean.
// Thus we need to ensure sizeMultiplier is at least 1.
size_t sizeMultiplier = std::max( (size_t)1, allDepths.size() / dataSetSizeCalc.weightedMean() );
for ( size_t depthIdx = 0; depthIdx < allDepths.size(); depthIdx += sizeMultiplier )
{
std::vector<double> pressuresAtDepth;
pressuresAtDepth.reserve( curveMerger.curveCount() );
for ( size_t curveIdx = 0; curveIdx < curveMerger.curveCount(); ++curveIdx )
{
const std::vector<double>& curvePressures = curveMerger.interpolatedYValuesForAllXValues( curveIdx );
pressuresAtDepth.push_back( curvePressures[depthIdx] );
}
double p10, p50, p90, mean;
RigStatisticsMath::calculateStatisticsCurves( pressuresAtDepth, &p10, &p50, &p90, &mean );
m_cachedValues[depthAddress].push_back( allDepths[depthIdx] );
if ( p10 != HUGE_VAL ) m_cachedValues[p10Address].push_back( p10 );
if ( p50 != HUGE_VAL ) m_cachedValues[p50Address].push_back( p50 );
if ( p90 != HUGE_VAL ) m_cachedValues[p90Address].push_back( p90 );
if ( mean != HUGE_VAL ) m_cachedValues[meanAddress].push_back( mean );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEnsembleStatisticsRft::clearData( const QString& wellName, const QDateTime& timeStep )
{
for ( auto it = m_cachedValues.begin(); it != m_cachedValues.end(); )
{
if ( it->first.wellName() == wellName && it->first.timeStep() == timeStep )
{
it = m_cachedValues.erase( it );
}
else
{
++it;
}
}
}

View File

@@ -0,0 +1,52 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RifReaderEclipseRft.h"
#include "cvfObject.h"
class RimSummaryCaseCollection;
class RifReaderEnsembleStatisticsRft : public RifReaderRftInterface, public cvf::Object
{
public:
RifReaderEnsembleStatisticsRft( const RimSummaryCaseCollection* summaryCaseCollection );
std::set<RifEclipseRftAddress> eclipseRftAddresses() override;
void values( const RifEclipseRftAddress& rftAddress, std::vector<double>* values ) override;
std::set<QDateTime> availableTimeSteps( const QString& wellName ) override;
std::set<QDateTime> availableTimeSteps( const QString& wellName,
const RifEclipseRftAddress::RftWellLogChannelType& wellLogChannelName ) override;
std::set<QDateTime>
availableTimeSteps( const QString& wellName,
const std::set<RifEclipseRftAddress::RftWellLogChannelType>& relevantChannels ) override;
std::set<RifEclipseRftAddress::RftWellLogChannelType> availableWellLogChannels( const QString& wellName ) override;
std::set<QString> wellNames() override;
private:
void calculateStatistics( const RifEclipseRftAddress& rftAddress );
void clearData( const QString& wellName, const QDateTime& timeStep );
private:
const RimSummaryCaseCollection* m_summaryCaseCollection;
std::map<RifEclipseRftAddress, std::vector<double>> m_cachedValues;
};

View File

@@ -0,0 +1,547 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RifReaderFmuRft.h"
#include "RiaLogging.h"
#include "cafAssert.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include <limits>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderFmuRft::Observation::Observation()
: utmx( -std::numeric_limits<double>::infinity() )
, utmy( -std::numeric_limits<double>::infinity() )
, mdrkb( -std::numeric_limits<double>::infinity() )
, tvdmsl( -std::numeric_limits<double>::infinity() )
, pressure( -std::numeric_limits<double>::infinity() )
, pressureError( -std::numeric_limits<double>::infinity() )
, formation()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderFmuRft::Observation::valid() const
{
return utmx != std::numeric_limits<double>::infinity() && utmy != std::numeric_limits<double>::infinity() &&
mdrkb != std::numeric_limits<double>::infinity() && tvdmsl != std::numeric_limits<double>::infinity() &&
pressure != std::numeric_limits<double>::infinity() &&
pressureError != std::numeric_limits<double>::infinity();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderFmuRft::WellObservationSet::WellObservationSet( const QDateTime& dateTime, int measurementIndex )
: dateTime( dateTime )
, measurementIndex( measurementIndex )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderFmuRft::RifReaderFmuRft( const QString& filePath )
: m_filePath( filePath )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList RifReaderFmuRft::findSubDirectoriesWithFmuRftData( const QString& filePath )
{
QStringList subDirsContainingFmuRftData;
QFileInfo fileInfo( filePath );
if ( !( fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable() ) )
{
return subDirsContainingFmuRftData;
}
if ( directoryContainsFmuRftData( filePath ) )
{
subDirsContainingFmuRftData.push_back( filePath );
}
QDir dir( filePath );
QStringList subDirs = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable, QDir::Name );
for ( QString subDir : subDirs )
{
QString absDir = dir.absoluteFilePath( subDir );
subDirsContainingFmuRftData.append( findSubDirectoriesWithFmuRftData( absDir ) );
}
return subDirsContainingFmuRftData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderFmuRft::directoryContainsFmuRftData( const QString& filePath )
{
QFileInfo baseFileInfo( filePath );
if ( !( baseFileInfo.exists() && baseFileInfo.isDir() && baseFileInfo.isReadable() ) )
{
return false;
}
QDir dir( filePath );
if ( !dir.exists( RifReaderFmuRft::wellPathFileName() ) )
{
return false;
}
QStringList obsFiles;
obsFiles << "*.obs"
<< "*.txt";
QFileInfoList fileInfos = dir.entryInfoList( obsFiles, QDir::Files, QDir::Name );
std::map<QString, int> fileStemCounts;
for ( QFileInfo fileInfo : fileInfos )
{
// TODO:
// Uses completeBaseName() to support wells with a dot in the name.
// Not sure if this is necessary or desired
fileStemCounts[fileInfo.completeBaseName()]++;
if ( fileStemCounts[fileInfo.completeBaseName()] == 2 )
{
// At least one matching obs and txt file.
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifReaderFmuRft::wellPathFileName()
{
return "well_date_rft.txt";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<QString> RifReaderFmuRft::labels( const RifEclipseRftAddress& rftAddress )
{
std::vector<QString> formationLabels;
if ( m_allWellObservations.empty() )
{
load();
}
auto it = m_allWellObservations.find( rftAddress.wellName() );
if ( it != m_allWellObservations.end() )
{
const std::vector<Observation>& observations = it->second.observations;
for ( const Observation& observation : observations )
{
formationLabels.push_back( QString( "%1 - Pressure: %2 +/- %3" )
.arg( observation.formation )
.arg( observation.pressure )
.arg( observation.pressureError ) );
}
}
return formationLabels;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RifEclipseRftAddress> RifReaderFmuRft::eclipseRftAddresses()
{
if ( m_allWellObservations.empty() )
{
load();
}
std::set<RifEclipseRftAddress> allAddresses;
for ( const WellObservationPair& wellObservationPair : m_allWellObservations )
{
const QString& wellName = wellObservationPair.first;
const QDateTime& dateTime = wellObservationPair.second.dateTime;
const std::vector<Observation>& observations = wellObservationPair.second.observations;
for ( const Observation& observation : observations )
{
if ( observation.valid() )
{
RifEclipseRftAddress tvdAddress( wellName, dateTime, RifEclipseRftAddress::TVD );
RifEclipseRftAddress mdAddress( wellName, dateTime, RifEclipseRftAddress::MD );
RifEclipseRftAddress pressureAddress( wellName, dateTime, RifEclipseRftAddress::PRESSURE );
RifEclipseRftAddress pressureErrorAddress( wellName, dateTime, RifEclipseRftAddress::PRESSURE_ERROR );
allAddresses.insert( tvdAddress );
allAddresses.insert( mdAddress );
allAddresses.insert( pressureAddress );
allAddresses.insert( pressureErrorAddress );
}
}
}
return allAddresses;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderFmuRft::values( const RifEclipseRftAddress& rftAddress, std::vector<double>* values )
{
CAF_ASSERT( values );
if ( m_allWellObservations.empty() )
{
load();
}
auto it = m_allWellObservations.find( rftAddress.wellName() );
if ( it != m_allWellObservations.end() )
{
const std::vector<Observation>& observations = it->second.observations;
values->clear();
values->reserve( observations.size() );
for ( const Observation& observation : observations )
{
switch ( rftAddress.wellLogChannel() )
{
case RifEclipseRftAddress::TVD:
values->push_back( observation.tvdmsl );
break;
case RifEclipseRftAddress::MD:
values->push_back( observation.mdrkb );
break;
case RifEclipseRftAddress::PRESSURE:
values->push_back( observation.pressure );
break;
case RifEclipseRftAddress::PRESSURE_ERROR:
values->push_back( observation.pressureError );
break;
default:
CAF_ASSERT( false && "Wrong channel type sent to Fmu RFT reader" );
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderFmuRft::load()
{
QString errorMsg;
QFileInfo fileInfo( m_filePath );
if ( !( fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable() ) )
{
errorMsg = QString( "Directory '%1' does not exist or isn't readable" ).arg( m_filePath );
RiaLogging::error( errorMsg );
return;
}
QDir dir( m_filePath );
WellObservationMap wellObservations = loadWellDates( dir, &errorMsg );
WellObservationMap validObservations;
if ( wellObservations.empty() )
{
if ( errorMsg.isEmpty() )
{
errorMsg = QString( "'%1' contains no valid FMU RFT data" ).arg( m_filePath );
}
RiaLogging::error( errorMsg );
return;
}
for ( auto it = wellObservations.begin(); it != wellObservations.end(); ++it )
{
const QString& wellName = it->first;
WellObservationSet& wellObservationSet = it->second;
QString txtFile = QString( "%1.txt" ).arg( wellName );
QString obsFile = QString( "%1.obs" ).arg( wellName );
if ( !readTxtFile( dir.absoluteFilePath( txtFile ), &errorMsg, &wellObservationSet ) )
{
RiaLogging::warning( errorMsg );
continue;
}
if ( !readObsFile( dir.absoluteFilePath( obsFile ), &errorMsg, &wellObservationSet ) )
{
RiaLogging::warning( errorMsg );
continue;
}
validObservations.insert( *it );
}
m_allWellObservations.swap( validObservations );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime>
RifReaderFmuRft::availableTimeSteps( const QString& wellName,
const RifEclipseRftAddress::RftWellLogChannelType& wellLogChannelName )
{
if ( wellLogChannelName == RifEclipseRftAddress::TVD || wellLogChannelName == RifEclipseRftAddress::MD ||
wellLogChannelName == RifEclipseRftAddress::PRESSURE )
{
return availableTimeSteps( wellName );
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime> RifReaderFmuRft::availableTimeSteps( const QString& wellName )
{
if ( m_allWellObservations.empty() )
{
load();
}
auto it = m_allWellObservations.find( wellName );
if ( it != m_allWellObservations.end() )
{
return { it->second.dateTime };
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime>
RifReaderFmuRft::availableTimeSteps( const QString& wellName,
const std::set<RifEclipseRftAddress::RftWellLogChannelType>& relevantChannels )
{
if ( relevantChannels.count( RifEclipseRftAddress::TVD ) || relevantChannels.count( RifEclipseRftAddress::MD ) ||
relevantChannels.count( RifEclipseRftAddress::PRESSURE ) )
{
return availableTimeSteps( wellName );
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RifEclipseRftAddress::RftWellLogChannelType> RifReaderFmuRft::availableWellLogChannels( const QString& wellName )
{
if ( m_allWellObservations.empty() )
{
load();
}
if ( !m_allWellObservations.empty() )
{
return { RifEclipseRftAddress::TVD, RifEclipseRftAddress::MD, RifEclipseRftAddress::PRESSURE };
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QString> RifReaderFmuRft::wellNames()
{
if ( m_allWellObservations.empty() )
{
load();
}
std::set<QString> wellNames;
for ( auto it = m_allWellObservations.begin(); it != m_allWellObservations.end(); ++it )
{
wellNames.insert( it->first );
}
return wellNames;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderFmuRft::WellObservationMap RifReaderFmuRft::loadWellDates( QDir& dir, QString* errorMsg )
{
CAF_ASSERT( errorMsg );
WellObservationMap validObservations;
QFileInfo wellDateFileInfo( dir.absoluteFilePath( RifReaderFmuRft::wellPathFileName() ) );
if ( !( wellDateFileInfo.exists() && wellDateFileInfo.isFile() && wellDateFileInfo.isReadable() ) )
{
*errorMsg = QString( "%1 cannot be found at '%s'" ).arg( RifReaderFmuRft::wellPathFileName() ).arg( m_filePath );
return WellObservationMap();
}
{
QFile wellDateFile( wellDateFileInfo.absoluteFilePath() );
if ( !wellDateFile.open( QIODevice::Text | QIODevice::ReadOnly ) )
{
*errorMsg = QString( "Could not read '%1'" ).arg( wellDateFileInfo.absoluteFilePath() );
return WellObservationMap();
}
QTextStream fileStream( &wellDateFile );
while ( true )
{
QString line = fileStream.readLine();
if ( line.isNull() )
{
break;
}
else
{
QTextStream lineStream( &line );
QString wellName;
int day, month, year, measurementIndex;
lineStream >> wellName >> day >> month >> year >> measurementIndex;
if ( lineStream.status() != QTextStream::Ok )
{
*errorMsg = QString( "Failed to parse '%1'" ).arg( wellDateFileInfo.absoluteFilePath() );
return WellObservationMap();
}
QDateTime dateTime( QDate( year, month, day ) );
dateTime.setTimeSpec( Qt::UTC );
WellObservationSet observationSet( dateTime, measurementIndex );
validObservations.insert( std::make_pair( wellName, observationSet ) );
}
}
}
return validObservations;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderFmuRft::readTxtFile( const QString& fileName, QString* errorMsg, WellObservationSet* wellObservationSet )
{
CAF_ASSERT( wellObservationSet );
QFile file( fileName );
if ( !( file.open( QIODevice::Text | QIODevice::ReadOnly ) ) )
{
*errorMsg = QString( "Could not open '%1'" ).arg( fileName );
return false;
}
QTextStream stream( &file );
while ( true )
{
QString line = stream.readLine().trimmed();
if ( line.isNull() || line.isEmpty() )
{
break;
}
else
{
QTextStream lineStream( &line );
double utmx, utmy, mdrkb, tvdmsl;
QString formationName;
lineStream >> utmx >> utmy >> mdrkb >> tvdmsl >> formationName;
if ( lineStream.status() != QTextStream::Ok )
{
*errorMsg = QString( "Failed to parse '%1'" ).arg( fileName );
return false;
}
Observation observation;
observation.utmx = utmx;
observation.utmy = utmy;
observation.mdrkb = mdrkb;
observation.tvdmsl = tvdmsl;
observation.formation = formationName;
wellObservationSet->observations.push_back( observation );
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderFmuRft::readObsFile( const QString& fileName, QString* errorMsg, WellObservationSet* wellObservationSet )
{
QFile file( fileName );
if ( !( file.open( QIODevice::Text | QIODevice::ReadOnly ) ) )
{
*errorMsg = QString( "Could not open '%1'" ).arg( fileName );
return false;
}
size_t lineNumber = 0u;
QTextStream stream( &file );
while ( true )
{
QString line = stream.readLine().trimmed();
if ( line.isNull() || line.isEmpty() )
{
break;
}
else if ( lineNumber >= wellObservationSet->observations.size() )
{
*errorMsg = QString( "'%1' has more lines than corresponding txt file" ).arg( fileName );
return false;
}
else
{
QTextStream lineStream( &line );
double pressure, pressureError;
lineStream >> pressure >> pressureError;
if ( lineStream.status() != QTextStream::Ok )
{
*errorMsg = QString( "Failed to parse line %1 of '%2'" ).arg( lineNumber + 1 ).arg( fileName );
return false;
}
Observation& observation = wellObservationSet->observations[lineNumber];
observation.pressure = pressure;
observation.pressureError = pressureError;
}
lineNumber++;
}
if ( lineNumber != wellObservationSet->observations.size() )
{
*errorMsg = QString( "'%1' has less lines than corresponding txt file" ).arg( fileName );
return false;
}
return true;
}

View File

@@ -0,0 +1,101 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RifEclipseRftAddress.h"
#include "RifReaderRftInterface.h"
#include <map>
#include <string>
#include <vector>
#include "cvfObject.h"
#include <QDateTime>
#include <QDir>
//==================================================================================================
//
//
//==================================================================================================
class RifReaderFmuRft : public RifReaderRftInterface, public cvf::Object
{
public:
struct Observation
{
double utmx;
double utmy;
double mdrkb;
double tvdmsl;
double pressure;
double pressureError;
QString formation;
Observation();
bool valid() const;
};
struct WellObservationSet
{
QDateTime dateTime;
int measurementIndex;
std::vector<Observation> observations;
WellObservationSet( const QDateTime& dateTime, int measurementIndex );
};
public:
RifReaderFmuRft( const QString& filePath );
~RifReaderFmuRft() = default;
static QStringList findSubDirectoriesWithFmuRftData( const QString& filePath );
static bool directoryContainsFmuRftData( const QString& filePath );
static QString wellPathFileName();
std::vector<QString> labels( const RifEclipseRftAddress& rftAddress );
std::set<RifEclipseRftAddress> eclipseRftAddresses() override;
void values( const RifEclipseRftAddress& rftAddress, std::vector<double>* values ) override;
std::set<QDateTime>
availableTimeSteps( const QString& wellName,
const std::set<RifEclipseRftAddress::RftWellLogChannelType>& relevantChannels ) override;
std::set<QDateTime> availableTimeSteps( const QString& wellName ) override;
std::set<QDateTime> availableTimeSteps( const QString& wellName,
const RifEclipseRftAddress::RftWellLogChannelType& wellLogChannelName ) override;
std::set<RifEclipseRftAddress::RftWellLogChannelType> availableWellLogChannels( const QString& wellName ) override;
std::set<QString> wellNames() override;
public:
void load();
private:
typedef std::pair<const QString, WellObservationSet> WellObservationPair;
typedef std::map<QString, WellObservationSet> WellObservationMap;
WellObservationMap loadWellDates( QDir& dir, QString* errorMsg );
static bool readTxtFile( const QString& txtFileName, QString* errorMsg, WellObservationSet* wellObservationSet );
static bool readObsFile( const QString& obsFileName, QString* errorMsg, WellObservationSet* wellObservationSet );
private:
QString m_filePath;
WellObservationMap m_allWellObservations;
};

View File

@@ -0,0 +1,123 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
// Copyright (C) Ceetron Solutions AS
//
// 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 "RifReaderInterface.h"
#include "RiaPreferences.h"
#include "RifReaderSettings.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderInterface::isFaultImportEnabled()
{
return readerSettings()->importFaults;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderInterface::isImportOfCompleteMswDataEnabled()
{
return readerSettings()->importAdvancedMswData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderInterface::isNNCsEnabled()
{
return readerSettings()->importNNCs;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderInterface::includeInactiveCellsInFaultGeometry()
{
return readerSettings()->includeInactiveCellsInFaultGeometry();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const QString RifReaderInterface::faultIncludeFileAbsolutePathPrefix()
{
return readerSettings()->includeFileAbsolutePathPrefix;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderInterface::setTimeStepFilter( const std::vector<size_t>& fileTimeStepIndices )
{
m_fileTimeStepIndices = fileTimeStepIndices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RiaDefines::PhaseType> RifReaderInterface::availablePhases() const
{
return std::set<RiaDefines::PhaseType>();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderInterface::isTimeStepIncludedByFilter( size_t timeStepIndex ) const
{
if ( m_fileTimeStepIndices.empty() ) return true;
for ( auto i : m_fileTimeStepIndices )
{
if ( i == timeStepIndex )
{
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RifReaderInterface::timeStepIndexOnFile( size_t timeStepIndex ) const
{
if ( timeStepIndex < m_fileTimeStepIndices.size() )
{
return m_fileTimeStepIndices[timeStepIndex];
}
return timeStepIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RifReaderSettings* RifReaderInterface::readerSettings() const
{
RiaPreferences* prefs = RiaPreferences::current();
CVF_ASSERT( prefs->readerSettings() );
return prefs->readerSettings();
}

View File

@@ -0,0 +1,86 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RiaPorosityModel.h"
#include "cvfObject.h"
#include "cafPdmPointer.h"
#include <QString>
#include <QStringList>
#include <set>
#include <vector>
class RigEclipseCaseData;
class RifReaderSettings;
//==================================================================================================
//
// Data interface base class
//
//==================================================================================================
class RifReaderInterface : public cvf::Object
{
public:
RifReaderInterface() {}
~RifReaderInterface() override {}
bool isFaultImportEnabled();
bool isImportOfCompleteMswDataEnabled();
bool isNNCsEnabled();
bool includeInactiveCellsInFaultGeometry();
const QString faultIncludeFileAbsolutePathPrefix();
virtual bool open( const QString& fileName, RigEclipseCaseData* eclipseCase ) = 0;
virtual bool staticResult( const QString& result,
RiaDefines::PorosityModelType matrixOrFracture,
std::vector<double>* values ) = 0;
virtual bool dynamicResult( const QString& result,
RiaDefines::PorosityModelType matrixOrFracture,
size_t stepIndex,
std::vector<double>* values ) = 0;
void setFilenamesWithFaults( const std::vector<QString>& filenames ) { m_filenamesWithFaults = filenames; }
std::vector<QString> filenamesWithFaults() { return m_filenamesWithFaults; }
void setTimeStepFilter( const std::vector<size_t>& fileTimeStepIndices );
virtual std::set<RiaDefines::PhaseType> availablePhases() const;
virtual void updateFromGridCount( size_t gridCount ){};
protected:
bool isTimeStepIncludedByFilter( size_t timeStepIndex ) const;
size_t timeStepIndexOnFile( size_t timeStepIndex ) const;
private:
const RifReaderSettings* readerSettings() const;
private:
std::vector<QString> m_filenamesWithFaults;
std::vector<size_t> m_fileTimeStepIndices;
};

View File

@@ -0,0 +1,197 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RifReaderMockModel.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseResultInfo.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderMockModel::open( const QString& fileName, RigEclipseCaseData* eclipseCase )
{
m_reservoirBuilder.populateReservoir( eclipseCase );
m_reservoir = eclipseCase;
RigCaseCellResultsData* cellResults = eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
std::vector<RigEclipseTimeStepInfo> timeStepInfos;
{
std::vector<QDateTime> dates;
std::vector<double> days;
std::vector<int> repNumbers;
for ( int i = 0; i < static_cast<int>( m_reservoirBuilder.timeStepCount() ); i++ )
{
dates.push_back( QDateTime( QDate( 2012 + i, 6, 1 ) ) );
days.push_back( i );
repNumbers.push_back( i );
}
timeStepInfos = RigEclipseTimeStepInfo::createTimeStepInfos( dates, repNumbers, days );
}
for ( size_t i = 0; i < m_reservoirBuilder.resultCount(); i++ )
{
RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE,
QString( "Dynamic_Result_%1" ).arg( i ) );
cellResults->createResultEntry( resAddr, false );
cellResults->setTimeStepInfos( resAddr, timeStepInfos );
}
if ( m_reservoirBuilder.timeStepCount() == 0 ) return true;
std::vector<RigEclipseTimeStepInfo> staticResultTimeStepInfos;
staticResultTimeStepInfos.push_back( timeStepInfos[0] );
for ( int i = 0; i < static_cast<int>( m_reservoirBuilder.resultCount() ); i++ )
{
QString varEnd;
if ( i == 0 ) varEnd = "X";
if ( i == 1 ) varEnd = "Y";
int resIndex = 0;
if ( i > 1 ) resIndex = i;
RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::STATIC_NATIVE,
QString( "Static_Result_%1%2" ).arg( resIndex ).arg( varEnd ) );
cellResults->createResultEntry( resAddr, false );
cellResults->setTimeStepInfos( resAddr, staticResultTimeStepInfos );
}
#define ADD_INPUT_PROPERTY( Name ) \
{ \
QString resultName( Name ); \
RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::INPUT_PROPERTY, resultName ); \
cellResults->createResultEntry( resAddr, false ); \
cellResults->setTimeStepInfos( resAddr, staticResultTimeStepInfos ); \
cellResults->modifiableCellScalarResultTimesteps( resAddr )->resize( 1 ); \
std::vector<double>& values = cellResults->modifiableCellScalarResultTimesteps( resAddr )->at( 0 ); \
this->inputProperty( resultName, &values ); \
}
ADD_INPUT_PROPERTY( "PORO" );
ADD_INPUT_PROPERTY( "PERM" );
ADD_INPUT_PROPERTY( "MULTX" );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderMockModel::inputProperty( const QString& propertyName, std::vector<double>* values )
{
return m_reservoirBuilder.inputProperty( m_reservoir, propertyName, values );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderMockModel::staticResult( const QString& result,
RiaDefines::PorosityModelType matrixOrFracture,
std::vector<double>* values )
{
m_reservoirBuilder.staticResult( m_reservoir, result, values );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderMockModel::dynamicResult( const QString& result,
RiaDefines::PorosityModelType matrixOrFracture,
size_t stepIndex,
std::vector<double>* values )
{
m_reservoirBuilder.dynamicResult( m_reservoir, result, stepIndex, values );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderMockModel::RifReaderMockModel()
: m_reservoir( nullptr )
{
/*
m_cellResults.push_back("Dummy results");
m_cellProperties.push_back("Dummy static result");
*/
}
RifReaderMockModel::~RifReaderMockModel()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderMockModel::setWorldCoordinates( cvf::Vec3d minWorldCoordinate, cvf::Vec3d maxWorldCoordinate )
{
m_reservoirBuilder.setWorldCoordinates( minWorldCoordinate, maxWorldCoordinate );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderMockModel::setGridPointDimensions( const cvf::Vec3st& gridPointDimensions )
{
m_reservoirBuilder.setGridPointDimensions( gridPointDimensions );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderMockModel::setResultInfo( size_t resultCount, size_t timeStepCount )
{
m_reservoirBuilder.setResultInfo( resultCount, timeStepCount );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderMockModel::addLocalGridRefinement( const cvf::Vec3st& minCellPosition,
const cvf::Vec3st& maxCellPosition,
const cvf::Vec3st& singleCellRefinementFactors )
{
m_reservoirBuilder.addLocalGridRefinement( minCellPosition, maxCellPosition, singleCellRefinementFactors );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderMockModel::populateReservoir( RigEclipseCaseData* eclipseCase )
{
m_reservoirBuilder.populateReservoir( eclipseCase );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderMockModel::enableWellData( bool enableWellData )
{
m_reservoirBuilder.enableWellData( enableWellData );
}

View File

@@ -0,0 +1,57 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RifReaderInterface.h"
#include "RigReservoirBuilderMock.h"
class RifReaderMockModel : public RifReaderInterface
{
public:
RifReaderMockModel();
~RifReaderMockModel() override;
void setWorldCoordinates( cvf::Vec3d minWorldCoordinate, cvf::Vec3d maxWorldCoordinate );
void setGridPointDimensions( const cvf::Vec3st& gridPointDimensions );
void setResultInfo( size_t resultCount, size_t timeStepCount );
void enableWellData( bool enableWellData );
void addLocalGridRefinement( const cvf::Vec3st& minCellPosition,
const cvf::Vec3st& maxCellPosition,
const cvf::Vec3st& singleCellRefinementFactors );
bool open( const QString& fileName, RigEclipseCaseData* eclipseCase ) override;
bool staticResult( const QString& result,
RiaDefines::PorosityModelType matrixOrFracture,
std::vector<double>* values ) override;
bool dynamicResult( const QString& result,
RiaDefines::PorosityModelType matrixOrFracture,
size_t stepIndex,
std::vector<double>* values ) override;
private:
void populateReservoir( RigEclipseCaseData* eclipseCase );
bool inputProperty( const QString& propertyName, std::vector<double>* values );
RigReservoirBuilderMock m_reservoirBuilder;
RigEclipseCaseData* m_reservoir;
};

View File

@@ -0,0 +1,219 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifReaderObservedData.h"
#include "RifCsvUserDataParser.h"
#include "RifEclipseSummaryAddress.h"
#include "SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.h"
#include <QDateTime>
#include <QTextStream>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderObservedData::RifReaderObservedData()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderObservedData::~RifReaderObservedData()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderObservedData::open( const QString& headerFileName,
const QString& identifierName,
RifEclipseSummaryAddress::SummaryVarCategory summaryCategory )
{
AsciiDataParseOptions parseOptions;
parseOptions.dateFormat = "yyyy-MM-dd";
parseOptions.cellSeparator = "\t";
parseOptions.locale = QLocale::Norwegian;
QString data;
QTextStream out( &data );
out << "Date"
<< "\t"
<< "Oil"
<< "\t"
<< "PW"
<< "\n";
out << "1993-02-23"
<< "\t"
<< "10"
<< "\t"
<< "1"
<< "\n";
out << "1993-06-15"
<< "\t"
<< "20"
<< "\t"
<< "2"
<< "\n";
out << "1994-02-26"
<< "\t"
<< "30"
<< "\t"
<< "3"
<< "\n";
out << "1994-05-23"
<< "\t"
<< "40"
<< "\t"
<< "4"
<< "\n";
m_asciiParser = std::unique_ptr<RifCsvUserDataParser>( new RifCsvUserDataPastedTextParser( data ) );
m_timeSteps.clear();
if ( m_asciiParser->parse( parseOptions ) )
{
if ( m_asciiParser && m_asciiParser->dateTimeColumn() )
{
for ( time_t timeStep : m_asciiParser->dateTimeColumn()->dateTimeValues )
{
m_timeSteps.push_back( timeStep );
}
m_allResultAddresses.clear();
for ( auto s : m_asciiParser->tableData().columnInfos() )
{
m_allResultAddresses.insert( s.summaryAddress );
}
}
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderObservedData::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{
size_t columnIndex = m_allResultAddresses.size();
int i = 0;
for ( auto& address : m_allResultAddresses )
{
if ( address == resultAddress )
{
columnIndex = i;
}
i++;
}
if ( columnIndex != m_allResultAddresses.size() )
{
const Column* col = m_asciiParser->columnInfo( columnIndex );
if ( col && col->dataType == Column::NUMERIC )
{
for ( auto& v : col->values )
{
values->push_back( v );
}
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<time_t>& RifReaderObservedData::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{
return m_timeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddress RifReaderObservedData::address( const QString& quantity,
const QString& identifierName,
RifEclipseSummaryAddress::SummaryVarCategory summaryCategory )
{
std::string quantityName = quantity.toStdString();
int regionNumber( -1 );
int regionNumber2( -1 );
std::string wellGroupName;
std::string wellName;
int wellSegmentNumber( -1 );
std::string lgrName;
int cellI( -1 );
int cellJ( -1 );
int cellK( -1 );
int aquiferNumber( -1 );
bool isErrorResult( false );
int id( -1 );
switch ( summaryCategory )
{
case RifEclipseSummaryAddress::SUMMARY_WELL_GROUP:
wellGroupName = identifierName.toStdString();
break;
case RifEclipseSummaryAddress::SUMMARY_WELL:
wellName = identifierName.toStdString();
break;
case RifEclipseSummaryAddress::SUMMARY_WELL_LGR:
lgrName = identifierName.toStdString();
break;
default:
break;
}
return RifEclipseSummaryAddress( summaryCategory,
quantityName,
regionNumber,
regionNumber2,
wellGroupName,
wellName,
wellSegmentNumber,
lgrName,
cellI,
cellJ,
cellK,
aquiferNumber,
isErrorResult,
id );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RifReaderObservedData::unitName( const RifEclipseSummaryAddress& resultAddress ) const
{
std::string str = "";
return str;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaEclipseUnitTools::UnitSystem RifReaderObservedData::unitSystem() const
{
return RiaEclipseUnitTools::UnitSystem::UNITS_UNKNOWN;
}

View File

@@ -0,0 +1,64 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifSummaryReaderInterface.h"
#include <map>
#include <memory>
#include <string>
#include <vector>
class QString;
class RifColumnBasedAsciiParser;
class RifEclipseSummaryAddress;
class RifCsvUserDataParser;
//==================================================================================================
//
//
//==================================================================================================
class RifReaderObservedData : public RifSummaryReaderInterface
{
public:
RifReaderObservedData();
~RifReaderObservedData() override;
bool open( const QString& headerFileName,
const QString& identifierName,
RifEclipseSummaryAddress::SummaryVarCategory summaryCategory );
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;
RiaEclipseUnitTools::UnitSystem unitSystem() const override;
private:
RifEclipseSummaryAddress address( const QString& quantity,
const QString& identifierName,
RifEclipseSummaryAddress::SummaryVarCategory summaryCategory );
private:
std::unique_ptr<RifCsvUserDataParser> m_asciiParser;
std::vector<time_t> m_timeSteps;
};

View File

@@ -0,0 +1,36 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RifReaderRftInterface.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RifEclipseRftAddress> RifReaderRftInterface::eclipseRftAddresses( const QString& wellName,
const QDateTime& timeStep )
{
std::set<RifEclipseRftAddress> matchingAddresses;
std::set<RifEclipseRftAddress> allAddresses = this->eclipseRftAddresses();
for ( const RifEclipseRftAddress& address : allAddresses )
{
if ( address.wellName() == wellName && address.timeStep() == timeStep )
{
matchingAddresses.insert( address );
}
}
return matchingAddresses;
}

View File

@@ -0,0 +1,45 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- 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 "RifEclipseRftAddress.h"
#include <QDateTime>
#include <QString>
#include <set>
#include <vector>
class RifReaderRftInterface
{
public:
std::set<RifEclipseRftAddress> eclipseRftAddresses( const QString& wellName, const QDateTime& timeStep );
virtual std::set<RifEclipseRftAddress> eclipseRftAddresses() = 0;
virtual void values( const RifEclipseRftAddress& rftAddress, std::vector<double>* values ) = 0;
virtual std::set<QDateTime>
availableTimeSteps( const QString& wellName,
const std::set<RifEclipseRftAddress::RftWellLogChannelType>& relevantChannels ) = 0;
virtual std::set<QDateTime> availableTimeSteps( const QString& wellName ) = 0;
virtual std::set<QDateTime>
availableTimeSteps( const QString& wellName,
const RifEclipseRftAddress::RftWellLogChannelType& wellLogChannelName ) = 0;
virtual std::set<RifEclipseRftAddress::RftWellLogChannelType> availableWellLogChannels( const QString& wellName ) = 0;
virtual std::set<QString> wellNames() = 0;
};

View File

@@ -0,0 +1,115 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
// Copyright (C) Ceetron Solutions AS
//
// 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 "RifReaderSettings.h"
#include "cafPdmUiCheckBoxEditor.h"
CAF_PDM_SOURCE_INIT( RifReaderSettings, "RifReaderSettings" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderSettings::RifReaderSettings()
{
CAF_PDM_InitObject( "RifReaderSettings", "", "", "" );
CAF_PDM_InitField( &importFaults, "importFaults", true, "Import Faults", "", "", "" );
importFaults.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
CAF_PDM_InitField( &importNNCs, "importSimulationNNCs", true, "Import NNCs", "", "", "" );
importNNCs.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
CAF_PDM_InitField( &includeInactiveCellsInFaultGeometry,
"includeInactiveCellsInFaultGeometry",
false,
"Include Inactive Cells",
"",
"",
"" );
includeInactiveCellsInFaultGeometry.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
CAF_PDM_InitField( &importAdvancedMswData, "importAdvancedMswData", false, "Import Advanced MSW Data", "", "", "" );
importAdvancedMswData.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
CAF_PDM_InitField( &useResultIndexFile,
"useResultIndexFile",
false,
"Use Result Index File",
"",
"After import of a result file, store index data in an index file in the same folder as the "
"result file.\n"
"Import of result data if a result index file is present, will reduce file parsing "
"significantly.",
"" );
useResultIndexFile.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
CAF_PDM_InitField( &skipWellData, "skipWellData", false, "Skip Import of Simulation Well Data", "", "", "" );
skipWellData.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
CAF_PDM_InitField( &includeFileAbsolutePathPrefix,
"includeFileAbsolutePathPrefix",
QString(),
"Include File Absolute Path Prefix",
"",
"Path used to prefix absolute UNIX paths in include statements on Windows, used when searching "
"for FAULTS and EQUIL",
"" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderSettings::defineEditorAttribute( const caf::PdmFieldHandle* field,
QString uiConfigName,
caf::PdmUiEditorAttribute* attribute )
{
if ( field == &importFaults || field == &importAdvancedMswData || field == &importNNCs ||
field == &useResultIndexFile || field == &skipWellData || field == &includeInactiveCellsInFaultGeometry )
{
caf::PdmUiCheckBoxEditorAttribute* myAttr = dynamic_cast<caf::PdmUiCheckBoxEditorAttribute*>( attribute );
if ( myAttr )
{
myAttr->m_useNativeCheckBoxLabel = true;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderSettings::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &importFaults );
uiOrdering.add( &includeInactiveCellsInFaultGeometry );
#ifdef WIN32
uiOrdering.add( &includeFileAbsolutePathPrefix );
#endif
uiOrdering.add( &importNNCs );
uiOrdering.add( &importAdvancedMswData );
uiOrdering.add( &useResultIndexFile );
uiOrdering.add( &skipWellData );
bool setFaultImportSettingsReadOnly = !importFaults();
includeInactiveCellsInFaultGeometry.uiCapability()->setUiReadOnly( setFaultImportSettingsReadOnly );
includeFileAbsolutePathPrefix.uiCapability()->setUiReadOnly( setFaultImportSettingsReadOnly );
importNNCs.uiCapability()->setUiReadOnly( setFaultImportSettingsReadOnly );
}

View File

@@ -0,0 +1,52 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
// Copyright (C) Ceetron Solutions AS
//
// 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 "cafPdmField.h"
#include "cafPdmObject.h"
//==================================================================================================
///
///
//==================================================================================================
class RifReaderSettings : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
friend class RiaPreferences;
public:
RifReaderSettings();
caf::PdmField<bool> importFaults;
caf::PdmField<bool> importNNCs;
caf::PdmField<bool> includeInactiveCellsInFaultGeometry;
caf::PdmField<bool> importAdvancedMswData;
caf::PdmField<QString> includeFileAbsolutePathPrefix;
caf::PdmField<bool> useResultIndexFile;
caf::PdmField<bool> skipWellData;
private:
void defineEditorAttribute( const caf::PdmFieldHandle* field,
QString uiConfigName,
caf::PdmUiEditorAttribute* attribute ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
};

View File

@@ -0,0 +1,141 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020 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 "RifRoffReader.h"
#include <QFile>
#include <QTextStream>
const QString codeValuesString = QString( "array int codeValues" );
const QString codeNamesString = QString( "array char codeNames" );
const QString headerString = QString( "roff-asc" );
bool RifRoffReader::isCodeValuesDefinition( const QString& line )
{
return line.startsWith( codeValuesString );
}
bool RifRoffReader::isCodeNamesDefinition( const QString& line )
{
return line.startsWith( codeNamesString );
}
bool RifRoffReader::isCorrectHeader( const QString& line )
{
return line.startsWith( headerString );
}
int RifRoffReader::extractNumberAfterString( const QString& line, const QString& prefix )
{
QString copiedLine( line );
bool ok;
int num = copiedLine.remove( prefix ).toInt( &ok );
if ( !ok )
{
throw RifRoffReaderException( "Unexpected value: not an integer." );
}
return num;
}
int RifRoffReader::extractCodeValuesCount( const QString& line )
{
return extractNumberAfterString( line, codeValuesString );
}
int RifRoffReader::extractCodeNamesCount( const QString& line )
{
return extractNumberAfterString( line, codeNamesString );
}
void RifRoffReader::readCodeNames( const QString& filename, std::map<int, QString>& codeNames )
{
QFile file( filename );
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
throw RifRoffReaderException( "Unable to open roff file." );
}
bool isFirstLine = true;
int numCodeValues = -1;
int numCodeNames = -1;
std::vector<int> readCodeValues;
std::vector<QString> readCodeNames;
QTextStream in( &file );
while ( !in.atEnd() )
{
QString line = in.readLine();
// Check that the first line has the roff-asc header
if ( isFirstLine )
{
if ( !isCorrectHeader( line ) )
{
throw RifRoffReaderException( "Unexpected file type: roff-asc header missing." );
}
isFirstLine = false;
}
else if ( isCodeValuesDefinition( line ) )
{
// Expected line:
// array int codeValues 99
numCodeValues = extractCodeValuesCount( line );
for ( int i = 0; i < numCodeValues; i++ )
{
// The code values comes next, can be multiple per line.
int codeValue;
in >> codeValue;
readCodeValues.push_back( codeValue );
}
}
else if ( isCodeNamesDefinition( line ) )
{
// Expected line:
// array char codeNames 99
numCodeNames = extractCodeNamesCount( line );
for ( int i = 0; i < numCodeNames; i++ )
{
// Read code names. Assumes one name per line.
QString codeName = in.readLine();
readCodeNames.push_back( codeName.trimmed().remove( "\"" ) );
}
}
}
if ( numCodeValues == -1 )
{
throw RifRoffReaderException( "Code values not found." );
}
if ( numCodeNames == -1 )
{
throw RifRoffReaderException( "Code names not found." );
}
if ( numCodeNames != numCodeValues )
{
throw RifRoffReaderException( "Inconsistent code names and values: must be equal length." );
}
for ( int i = 0; i < numCodeNames; i++ )
{
codeNames[readCodeValues[i]] = readCodeNames[i];
}
}

View File

@@ -0,0 +1,58 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020 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 <exception>
#include <map>
#include <string>
#include <QString>
//==================================================================================================
///
//==================================================================================================
class RifRoffReaderException : public std::exception
{
public:
RifRoffReaderException( const std::string& message )
: message( message )
{
}
std::string message;
};
//==================================================================================================
///
//==================================================================================================
class RifRoffReader
{
public:
// Throws RifRoffReaderException on error
static void readCodeNames( const QString& filename, std::map<int, QString>& codeNames );
private:
static bool isCorrectHeader( const QString& line );
static bool isCodeNamesDefinition( const QString& line );
static bool isCodeValuesDefinition( const QString& line );
static int extractNumberAfterString( const QString& line, const QString& prefix );
static int extractCodeNamesCount( const QString& line );
static int extractCodeValuesCount( const QString& line );
};

View File

@@ -0,0 +1,99 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 "RifStimPlanModelAsymmetricFrkExporter.h"
#include "RimStimPlanModel.h"
#include <QFile>
#include <QTextStream>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifStimPlanModelAsymmetricFrkExporter::writeToFile( RimStimPlanModel* stimPlanModel, const QString& filepath )
{
QFile data( filepath );
if ( !data.open( QFile::WriteOnly | QFile::Truncate ) )
{
return false;
}
QTextStream stream( &data );
appendHeaderToStream( stream );
double bedDipDeg = stimPlanModel->formationDip();
bool hasBarrier = stimPlanModel->hasBarrier();
double distanceToBarrier = stimPlanModel->distanceToBarrier();
double barrierDip = stimPlanModel->barrierDip();
int wellPenetrationLayer = stimPlanModel->wellPenetrationLayer();
appendBarrierDataToStream( stream,
bedDipDeg,
hasBarrier,
RiaEclipseUnitTools::meterToFeet( distanceToBarrier ),
barrierDip,
wellPenetrationLayer );
appendFooterToStream( stream );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelAsymmetricFrkExporter::appendHeaderToStream( QTextStream& stream )
{
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl << "<asymmetric>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelAsymmetricFrkExporter::appendBarrierDataToStream( QTextStream& stream,
double bedDipDeg,
bool hasBarrier,
double distanceToBarrier,
double barrierDipDeg,
int wellPenetrationLayer )
{
stream << "<BedDipDeg>" << endl
<< bedDipDeg << endl
<< "</BedDipDeg>" << endl
<< "<Barrier>" << endl
<< static_cast<int>( hasBarrier ) << endl
<< "</Barrier>" << endl
<< "<BarrierDipDeg>" << endl
<< barrierDipDeg << endl
<< "</BarrierDipDeg>" << endl
<< "<DistanceToBarrier>" << endl
<< distanceToBarrier << endl
<< "</DistanceToBarrier>" << endl
<< "<WellPenetrationLayer>" << endl
<< wellPenetrationLayer << endl
<< "</WellPenetrationLayer>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelAsymmetricFrkExporter::appendFooterToStream( QTextStream& stream )
{
stream << "</asymmetric>" << endl;
}

View File

@@ -0,0 +1,43 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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
class RimStimPlanModel;
class QString;
class QTextStream;
//==================================================================================================
//
//==================================================================================================
class RifStimPlanModelAsymmetricFrkExporter
{
public:
static bool writeToFile( RimStimPlanModel* stimPlanModel, const QString& filepath );
private:
static void appendHeaderToStream( QTextStream& stream );
static void appendBarrierDataToStream( QTextStream& stream,
double bedDipDeg,
bool hasBarrier,
double distanceToBarrier,
double barrierDipDeg,
int wellPenetrationLayer );
static void appendFooterToStream( QTextStream& stream );
};

View File

@@ -0,0 +1,157 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 "RifStimPlanModelDeviationFrkExporter.h"
#include "RimStimPlanModel.h"
#include "RimWellPath.h"
#include "RigWellPathGeometryExporter.h"
#include <QFile>
#include <QTextStream>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifStimPlanModelDeviationFrkExporter::writeToFile( RimStimPlanModel* stimPlanModel, const QString& filepath )
{
RimWellPath* wellPath = stimPlanModel->wellPath();
if ( !wellPath )
{
return false;
}
QFile data( filepath );
if ( !data.open( QFile::WriteOnly | QFile::Truncate ) )
{
return false;
}
QTextStream stream( &data );
appendHeaderToStream( stream );
bool useMdRkb = false;
double mdStepSize = 5.0;
std::vector<double> xValues;
std::vector<double> yValues;
std::vector<double> tvdValues;
std::vector<double> mdValues;
RigWellPathGeometryExporter::exportWellPathGeometry( wellPath, mdStepSize, xValues, yValues, tvdValues, mdValues, useMdRkb );
convertFromMeterToFeet( mdValues );
convertFromMeterToFeet( tvdValues );
std::vector<double> exportTvdValues;
std::vector<double> exportMdValues;
fixupDepthValuesForExport( tvdValues, mdValues, exportTvdValues, exportMdValues );
appendToStream( stream, "mdArray", exportMdValues );
appendToStream( stream, "tvdArray", exportTvdValues );
appendFooterToStream( stream );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelDeviationFrkExporter::appendHeaderToStream( QTextStream& stream )
{
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl << "<deviation>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelDeviationFrkExporter::appendToStream( QTextStream& stream,
const QString& label,
const std::vector<double>& values )
{
stream.setRealNumberPrecision( 20 );
stream << "<cNamedSet>" << endl
<< "<name>" << endl
<< label << endl
<< "</name>" << endl
<< "<dimCount>" << endl
<< 1 << endl
<< "</dimCount>" << endl
<< "<sizes>" << endl
<< values.size() << endl
<< "</sizes>" << endl
<< "<data>" << endl;
for ( auto val : values )
{
stream << val << endl;
}
stream << "</data>" << endl << "</cNamedSet>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelDeviationFrkExporter::appendFooterToStream( QTextStream& stream )
{
stream << "</deviation>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelDeviationFrkExporter::convertFromMeterToFeet( std::vector<double>& data )
{
for ( size_t i = 0; i < data.size(); i++ )
{
data[i] = RiaEclipseUnitTools::meterToFeet( data[i] );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelDeviationFrkExporter::fixupDepthValuesForExport( const std::vector<double>& tvdValues,
const std::vector<double>& mdValues,
std::vector<double>& exportTvdValues,
std::vector<double>& exportMdValues )
{
if ( tvdValues.empty() || mdValues.empty() ) return;
exportMdValues.push_back( mdValues[0] );
exportTvdValues.push_back( tvdValues[0] );
for ( size_t i = 1; i < tvdValues.size(); i++ )
{
double changeMd = mdValues[i] - exportMdValues[i - 1];
double changeTvd = tvdValues[i] - exportTvdValues[i - 1];
// Stimplan checks that the change in MD is larger than or equal to change in TVD.
// This condition is not always satisfied due to the interpolation of TVDs.
// Move the MD value to produce a file which can be imported.
if ( changeMd < changeTvd )
{
exportMdValues.push_back( exportMdValues[i - 1] + changeTvd );
}
else
{
exportMdValues.push_back( mdValues[i] );
}
exportTvdValues.push_back( tvdValues[i] );
}
}

View File

@@ -0,0 +1,45 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 <vector>
class RimStimPlanModel;
class QString;
class QTextStream;
//==================================================================================================
//
//==================================================================================================
class RifStimPlanModelDeviationFrkExporter
{
public:
static bool writeToFile( RimStimPlanModel* stimPlanModel, const QString& filepath );
static void fixupDepthValuesForExport( const std::vector<double>& tvdValues,
const std::vector<double>& mdValues,
std::vector<double>& exportTvdValues,
std::vector<double>& exportMdValues );
private:
static void appendHeaderToStream( QTextStream& stream );
static void appendToStream( QTextStream& stream, const QString& label, const std::vector<double>& values );
static void appendFooterToStream( QTextStream& stream );
static void convertFromMeterToFeet( std::vector<double>& data );
};

View File

@@ -0,0 +1,41 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 "RifStimPlanModelExporter.h"
#include "RifStimPlanModelAsymmetricFrkExporter.h"
#include "RifStimPlanModelDeviationFrkExporter.h"
#include "RifStimPlanModelGeologicalFrkExporter.h"
#include "RifStimPlanModelPerfsFrkExporter.h"
#include "RimStimPlanModel.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifStimPlanModelExporter::writeToDirectory( RimStimPlanModel* stimPlanModel,
bool useDetailedFluidLoss,
const QString& directoryPath )
{
return RifStimPlanModelGeologicalFrkExporter::writeToFile( stimPlanModel,
useDetailedFluidLoss,
directoryPath + "/Geological.frk" ) &&
RifStimPlanModelDeviationFrkExporter::writeToFile( stimPlanModel, directoryPath + "/Deviation.frk" ) &&
RifStimPlanModelPerfsFrkExporter::writeToFile( stimPlanModel, directoryPath + "/Perfs.frk" ) &&
RifStimPlanModelAsymmetricFrkExporter::writeToFile( stimPlanModel, directoryPath + "/Asymmetric.frk" );
}

View File

@@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 <vector>
class RimStimPlanModel;
class QString;
class QTextStream;
//==================================================================================================
//
//==================================================================================================
class RifStimPlanModelExporter
{
public:
static bool writeToDirectory( RimStimPlanModel* stimPlanModel, bool useDetailedFluidLoss, const QString& directoryPath );
};

View File

@@ -0,0 +1,240 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 "RifStimPlanModelGeologicalFrkExporter.h"
#include "RiaLogging.h"
#include "RimStimPlanModel.h"
#include "RimStimPlanModelCalculator.h"
#include <QFile>
#include <QTextStream>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifStimPlanModelGeologicalFrkExporter::writeToFile( RimStimPlanModel* stimPlanModel,
bool useDetailedLoss,
const QString& filepath )
{
std::vector<QString> labels;
// TVD depth of top of zone (ft)
labels.push_back( "dpthlyr" );
// Stress at top of zone (psi)
labels.push_back( "strs" );
// Stress gradient (psi/ft)
labels.push_back( "strsg" );
// Young's modulus (MMpsi)
labels.push_back( "elyr" );
// Poisson's Ratio
labels.push_back( "poissonr" );
// K-Ic (psi*sqrt(in)
labels.push_back( "tuflyr" );
// Fluid Loss Coefficient
labels.push_back( "clyrc" );
// Spurt loss (gal/100f^2)
labels.push_back( "clyrs" );
// Proppand Embedmeent (lb/ft^2)
labels.push_back( "pembed" );
if ( useDetailedLoss )
{
// B2 Detailed Loss
// Reservoir Pressure (psi)
labels.push_back( "zoneResPres" );
// Immobile Fluid Saturation (fraction)
labels.push_back( "zoneWaterSat" );
// Porosity (fraction)
labels.push_back( "zonePorosity" );
// Horizontal Perm (md)
labels.push_back( "zoneHorizPerm" );
// Vertical Perm (md)
labels.push_back( "zoneVertPerm" );
// Temperature (F)
labels.push_back( "zoneTemp" );
// Relative permeability
labels.push_back( "zoneRelPerm" );
// Poro-Elastic constant
labels.push_back( "zonePoroElas" );
// Thermal Epansion Coefficient (1/F)
labels.push_back( "zoneThermalExp" );
}
std::vector<double> tvd = stimPlanModel->calculator()->calculateTrueVerticalDepth();
// Warn if the generated model has too many layers for StimPlan
if ( tvd.size() > MAX_STIMPLAN_LAYERS )
{
RiaLogging::warning(
QString( "Exporting model with too many layers: %1. Maximum supported number of layers is %2." )
.arg( tvd.size() )
.arg( MAX_STIMPLAN_LAYERS ) );
}
// Make sure stress gradients are in the valid interval
std::vector<double> stressGradients = stimPlanModel->calculator()->calculateStressGradient();
fixupStressGradients( stressGradients, MIN_STRESS_GRADIENT, MAX_STRESS_GRADIENT, DEFAULT_STRESS_GRADIENT );
std::map<QString, std::vector<double>> values;
values["dpthlyr"] = tvd;
values["strs"] = stimPlanModel->calculator()->calculateStress();
values["strsg"] = stressGradients;
values["elyr"] = stimPlanModel->calculator()->calculateYoungsModulus();
values["poissonr"] = stimPlanModel->calculator()->calculatePoissonsRatio();
values["tuflyr"] = stimPlanModel->calculator()->calculateKIc();
values["clyrc"] = stimPlanModel->calculator()->calculateFluidLossCoefficient();
values["clyrs"] = stimPlanModel->calculator()->calculateSpurtLoss();
values["pembed"] = stimPlanModel->calculator()->calculateProppandEmbedment();
values["zoneResPres"] = stimPlanModel->calculator()->calculateReservoirPressure();
values["zoneWaterSat"] = stimPlanModel->calculator()->calculateImmobileFluidSaturation();
values["zonePorosity"] = stimPlanModel->calculator()->calculatePorosity();
values["zoneHorizPerm"] = stimPlanModel->calculator()->calculateHorizontalPermeability();
values["zoneVertPerm"] = stimPlanModel->calculator()->calculateVerticalPermeability();
values["zoneTemp"] = stimPlanModel->calculator()->calculateTemperature();
values["zoneRelPerm"] = stimPlanModel->calculator()->calculateRelativePermeabilityFactor();
values["zonePoroElas"] = stimPlanModel->calculator()->calculatePoroElasticConstant();
values["zoneThermalExp"] = stimPlanModel->calculator()->calculateThermalExpansionCoefficient();
QFile data( filepath );
if ( !data.open( QFile::WriteOnly | QFile::Truncate ) )
{
return false;
}
QTextStream stream( &data );
appendHeaderToStream( stream );
for ( QString label : labels )
{
warnOnInvalidData( label, values[label] );
appendToStream( stream, label, values[label] );
}
appendFooterToStream( stream );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelGeologicalFrkExporter::appendHeaderToStream( QTextStream& stream )
{
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl << "<geologic>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelGeologicalFrkExporter::appendToStream( QTextStream& stream,
const QString& label,
const std::vector<double>& values )
{
stream << "<cNamedSet>" << endl
<< "<name>" << endl
<< label << endl
<< "</name>" << endl
<< "<dimCount>" << endl
<< 1 << endl
<< "</dimCount>" << endl
<< "<sizes>" << endl
<< values.size() << endl
<< "</sizes>" << endl
<< "<data>" << endl;
for ( auto val : values )
{
stream << val << endl;
}
stream << "</data>" << endl << "</cNamedSet>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelGeologicalFrkExporter::appendFooterToStream( QTextStream& stream )
{
stream << "</geologic>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelGeologicalFrkExporter::fixupStressGradients( std::vector<double>& stressGradients,
double minStressGradient,
double maxStressGradient,
double defaultStressGradient )
{
for ( size_t i = 0; i < stressGradients.size(); i++ )
{
if ( stressGradients[i] < minStressGradient || stressGradients[i] > maxStressGradient )
{
RiaLogging::warning(
QString( "Found stress gradient outside valid range [%1, %2]. Replacing %3 with default value: %4." )
.arg( minStressGradient )
.arg( maxStressGradient )
.arg( stressGradients[i] )
.arg( defaultStressGradient ) );
stressGradients[i] = defaultStressGradient;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifStimPlanModelGeologicalFrkExporter::warnOnInvalidData( const QString& label, const std::vector<double>& values )
{
bool isInvalid = hasInvalidData( values );
if ( isInvalid )
{
RiaLogging::warning( QString( "Found invalid data in Geological.FRK export of property '%1'." ).arg( label ) );
}
return isInvalid;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifStimPlanModelGeologicalFrkExporter::hasInvalidData( const std::vector<double>& values )
{
for ( auto v : values )
{
if ( std::isinf( v ) || std::isnan( v ) ) return true;
}
return false;
}

View File

@@ -0,0 +1,52 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 <vector>
class RimStimPlanModel;
class QString;
class QTextStream;
//==================================================================================================
//
//==================================================================================================
class RifStimPlanModelGeologicalFrkExporter
{
public:
static const int MAX_STIMPLAN_LAYERS = 100;
static constexpr double MIN_STRESS_GRADIENT = 0.3;
static constexpr double MAX_STRESS_GRADIENT = 0.8;
static constexpr double DEFAULT_STRESS_GRADIENT = 0.7;
static bool writeToFile( RimStimPlanModel* plot, bool useDetailedFluidLoss, const QString& filepath );
private:
static void appendHeaderToStream( QTextStream& stream );
static void appendToStream( QTextStream& stream, const QString& label, const std::vector<double>& values );
static void appendFooterToStream( QTextStream& stream );
static void fixupStressGradients( std::vector<double>& stressGradients,
double minStressGradient,
double maxStressGradient,
double defaultStressGradient );
static bool warnOnInvalidData( const QString& label, const std::vector<double>& values );
static bool hasInvalidData( const std::vector<double>& values );
};

View File

@@ -0,0 +1,159 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 "RifStimPlanModelPerfsFrkExporter.h"
#include "RiaLogging.h"
#include "RimStimPlanModel.h"
#include "RimWellPath.h"
#include "RigWellPath.h"
#include "RigWellPathGeometryTools.h"
#include <QFile>
#include <QTextStream>
#include <vector>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifStimPlanModelPerfsFrkExporter::writeToFile( RimStimPlanModel* stimPlanModel, const QString& filepath )
{
RimWellPath* wellPath = stimPlanModel->wellPath();
if ( !wellPath )
{
return false;
}
QFile data( filepath );
if ( !data.open( QFile::WriteOnly | QFile::Truncate ) )
{
return false;
}
QTextStream stream( &data );
appendHeaderToStream( stream );
bool isTransverse =
( stimPlanModel->fractureOrientation() == RimStimPlanModel::FractureOrientation::TRANSVERSE_WELL_PATH ||
stimPlanModel->fractureOrientation() == RimStimPlanModel::FractureOrientation::AZIMUTH );
appendFractureOrientationToStream( stream, isTransverse );
// Unit: meter
double perforationLength = stimPlanModel->perforationLength();
double anchorPositionMD = computeMeasuredDepthForPosition( wellPath, stimPlanModel->anchorPosition() );
double topMD = anchorPositionMD - ( perforationLength / 2.0 );
double bottomMD = anchorPositionMD + ( perforationLength / 2.0 );
appendPerforationToStream( stream,
1,
RiaEclipseUnitTools::meterToFeet( topMD ),
RiaEclipseUnitTools::meterToFeet( bottomMD ) );
appendFooterToStream( stream );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelPerfsFrkExporter::appendHeaderToStream( QTextStream& stream )
{
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl << "<perfs>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelPerfsFrkExporter::appendFractureOrientationToStream( QTextStream& stream, bool isTransverse )
{
stream << "<transverse>" << endl << static_cast<int>( isTransverse ) << endl << "</transverse>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelPerfsFrkExporter::appendPerforationToStream( QTextStream& stream, int index, double topMD, double bottomMD )
{
stream << "<perf frac=\"" << index << "\">" << endl
<< "<topMD>" << endl
<< topMD << endl
<< "</topMD>" << endl
<< "<bottomMD>" << endl
<< bottomMD << endl
<< "</bottomMD>" << endl
<< "</perf>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifStimPlanModelPerfsFrkExporter::appendFooterToStream( QTextStream& stream )
{
stream << "</perfs>" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RifStimPlanModelPerfsFrkExporter::computeMeasuredDepthForPosition( const RimWellPath* wellPath,
const cvf::Vec3d& position )
{
const RigWellPath* wellPathGeometry = wellPath->wellPathGeometry();
const std::vector<double>& mdValuesOfWellPath = wellPathGeometry->measuredDepths();
const std::vector<double>& tvdValuesOfWellPath = wellPathGeometry->trueVerticalDepths();
const double targetTvd = -position.z();
std::vector<double> tvDepthValues;
size_t index = 0;
bool isAdded = false;
for ( size_t i = 0; i < tvdValuesOfWellPath.size(); i++ )
{
double currentTvd = tvdValuesOfWellPath[i];
double prevTvd = 0.0;
if ( i > 0 ) prevTvd = tvdValuesOfWellPath[i - 1];
if ( !isAdded && targetTvd > prevTvd && targetTvd <= currentTvd )
{
// Insert the anchor position at correct order in well depths
index = i;
isAdded = true;
tvDepthValues.push_back( targetTvd );
}
tvDepthValues.push_back( currentTvd );
}
// Generate MD data by interpolation
std::vector<double> measuredDepthValues =
RigWellPathGeometryTools::interpolateMdFromTvd( mdValuesOfWellPath, tvdValuesOfWellPath, tvDepthValues );
if ( index < measuredDepthValues.size() )
return measuredDepthValues[index];
else
{
RiaLogging::error( "Unable to compute measured depth from well path data." );
return -1.0;
}
}

Some files were not shown because too many files have changed in this diff Show More