mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Rename ApplicationCode to ApplicationLibCode
This commit is contained in:
141
ApplicationLibCode/FileInterface/CMakeLists_files.cmake
Normal file
141
ApplicationLibCode/FileInterface/CMakeLists_files.cmake
Normal 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 )
|
||||
139
ApplicationLibCode/FileInterface/RifActiveCellsReader.cpp
Normal file
139
ApplicationLibCode/FileInterface/RifActiveCellsReader.cpp
Normal 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 );
|
||||
}
|
||||
}
|
||||
39
ApplicationLibCode/FileInterface/RifActiveCellsReader.h
Normal file
39
ApplicationLibCode/FileInterface/RifActiveCellsReader.h
Normal 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 );
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 );
|
||||
};
|
||||
264
ApplicationLibCode/FileInterface/RifColorLegendData.cpp
Normal file
264
ApplicationLibCode/FileInterface/RifColorLegendData.cpp
Normal 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;
|
||||
}
|
||||
45
ApplicationLibCode/FileInterface/RifColorLegendData.h
Normal file
45
ApplicationLibCode/FileInterface/RifColorLegendData.h
Normal 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 );
|
||||
};
|
||||
281
ApplicationLibCode/FileInterface/RifColumnBasedUserData.cpp
Normal file
281
ApplicationLibCode/FileInterface/RifColumnBasedUserData.cpp
Normal 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;
|
||||
}
|
||||
62
ApplicationLibCode/FileInterface/RifColumnBasedUserData.h
Normal file
62
ApplicationLibCode/FileInterface/RifColumnBasedUserData.h
Normal 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;
|
||||
};
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
138
ApplicationLibCode/FileInterface/RifCsvDataTableFormatter.cpp
Normal file
138
ApplicationLibCode/FileInterface/RifCsvDataTableFormatter.cpp
Normal 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();
|
||||
}
|
||||
50
ApplicationLibCode/FileInterface/RifCsvDataTableFormatter.h
Normal file
50
ApplicationLibCode/FileInterface/RifCsvDataTableFormatter.h
Normal 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;
|
||||
};
|
||||
168
ApplicationLibCode/FileInterface/RifCsvUserData.cpp
Normal file
168
ApplicationLibCode/FileInterface/RifCsvUserData.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
62
ApplicationLibCode/FileInterface/RifCsvUserData.h
Normal file
62
ApplicationLibCode/FileInterface/RifCsvUserData.h
Normal 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;
|
||||
};
|
||||
864
ApplicationLibCode/FileInterface/RifCsvUserDataParser.cpp
Normal file
864
ApplicationLibCode/FileInterface/RifCsvUserDataParser.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
129
ApplicationLibCode/FileInterface/RifCsvUserDataParser.h
Normal file
129
ApplicationLibCode/FileInterface/RifCsvUserDataParser.h
Normal 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;
|
||||
};
|
||||
296
ApplicationLibCode/FileInterface/RifDataSourceForRftPlt.cpp
Normal file
296
ApplicationLibCode/FileInterface/RifDataSourceForRftPlt.cpp
Normal 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
|
||||
89
ApplicationLibCode/FileInterface/RifDataSourceForRftPlt.h
Normal file
89
ApplicationLibCode/FileInterface/RifDataSourceForRftPlt.h
Normal 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 );
|
||||
@@ -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 );
|
||||
104
ApplicationLibCode/FileInterface/RifDerivedEnsembleReader.cpp
Normal file
104
ApplicationLibCode/FileInterface/RifDerivedEnsembleReader.cpp
Normal 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;
|
||||
}
|
||||
44
ApplicationLibCode/FileInterface/RifDerivedEnsembleReader.h
Normal file
44
ApplicationLibCode/FileInterface/RifDerivedEnsembleReader.h
Normal 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;
|
||||
};
|
||||
1870
ApplicationLibCode/FileInterface/RifEclipseInputFileTools.cpp
Normal file
1870
ApplicationLibCode/FileInterface/RifEclipseInputFileTools.cpp
Normal file
File diff suppressed because it is too large
Load Diff
179
ApplicationLibCode/FileInterface/RifEclipseInputFileTools.h
Normal file
179
ApplicationLibCode/FileInterface/RifEclipseInputFileTools.h
Normal 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();
|
||||
};
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
};
|
||||
710
ApplicationLibCode/FileInterface/RifEclipseOutputFileTools.cpp
Normal file
710
ApplicationLibCode/FileInterface/RifEclipseOutputFileTools.cpp
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
99
ApplicationLibCode/FileInterface/RifEclipseOutputFileTools.h
Normal file
99
ApplicationLibCode/FileInterface/RifEclipseOutputFileTools.h
Normal 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 );
|
||||
};
|
||||
102
ApplicationLibCode/FileInterface/RifEclipseRestartDataAccess.cpp
Normal file
102
ApplicationLibCode/FileInterface/RifEclipseRestartDataAccess.cpp
Normal 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;
|
||||
}
|
||||
115
ApplicationLibCode/FileInterface/RifEclipseRestartDataAccess.h
Normal file
115
ApplicationLibCode/FileInterface/RifEclipseRestartDataAccess.h
Normal 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 ){};
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
54
ApplicationLibCode/FileInterface/RifEclipseRftAddress.cpp
Normal file
54
ApplicationLibCode/FileInterface/RifEclipseRftAddress.cpp
Normal 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;
|
||||
}
|
||||
83
ApplicationLibCode/FileInterface/RifEclipseRftAddress.h
Normal file
83
ApplicationLibCode/FileInterface/RifEclipseRftAddress.h
Normal 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 );
|
||||
1154
ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.cpp
Normal file
1154
ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.cpp
Normal file
File diff suppressed because it is too large
Load Diff
240
ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.h
Normal file
240
ApplicationLibCode/FileInterface/RifEclipseSummaryAddress.h
Normal 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 );
|
||||
@@ -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 );
|
||||
195
ApplicationLibCode/FileInterface/RifEclipseSummaryTools.cpp
Normal file
195
ApplicationLibCode/FileInterface/RifEclipseSummaryTools.cpp
Normal 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 );
|
||||
}
|
||||
50
ApplicationLibCode/FileInterface/RifEclipseSummaryTools.h
Normal file
50
ApplicationLibCode/FileInterface/RifEclipseSummaryTools.h
Normal 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 );
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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] );
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
164
ApplicationLibCode/FileInterface/RifEclipseUserDataParserTools.h
Normal file
164
ApplicationLibCode/FileInterface/RifEclipseUserDataParserTools.h
Normal 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 );
|
||||
};
|
||||
188
ApplicationLibCode/FileInterface/RifElasticPropertiesReader.cpp
Normal file
188
ApplicationLibCode/FileInterface/RifElasticPropertiesReader.cpp
Normal 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 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
};
|
||||
239
ApplicationLibCode/FileInterface/RifElementPropertyReader.cpp
Normal file
239
ApplicationLibCode/FileInterface/RifElementPropertyReader.cpp
Normal 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 );
|
||||
}
|
||||
58
ApplicationLibCode/FileInterface/RifElementPropertyReader.h
Normal file
58
ApplicationLibCode/FileInterface/RifElementPropertyReader.h
Normal 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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
118
ApplicationLibCode/FileInterface/RifEnsembleStatisticsReader.cpp
Normal file
118
ApplicationLibCode/FileInterface/RifEnsembleStatisticsReader.cpp
Normal 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();
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
46
ApplicationLibCode/FileInterface/RifFileParseTools.cpp
Normal file
46
ApplicationLibCode/FileInterface/RifFileParseTools.cpp
Normal 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;
|
||||
}
|
||||
46
ApplicationLibCode/FileInterface/RifFileParseTools.h
Normal file
46
ApplicationLibCode/FileInterface/RifFileParseTools.h
Normal 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;
|
||||
};
|
||||
414
ApplicationLibCode/FileInterface/RifHdf5Reader.cpp
Normal file
414
ApplicationLibCode/FileInterface/RifHdf5Reader.cpp
Normal 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 );
|
||||
}
|
||||
60
ApplicationLibCode/FileInterface/RifHdf5Reader.h
Normal file
60
ApplicationLibCode/FileInterface/RifHdf5Reader.h
Normal 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
|
||||
};
|
||||
19
ApplicationLibCode/FileInterface/RifHdf5ReaderInterface.cpp
Normal file
19
ApplicationLibCode/FileInterface/RifHdf5ReaderInterface.cpp
Normal 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"
|
||||
40
ApplicationLibCode/FileInterface/RifHdf5ReaderInterface.h
Normal file
40
ApplicationLibCode/FileInterface/RifHdf5ReaderInterface.h
Normal 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;
|
||||
};
|
||||
151
ApplicationLibCode/FileInterface/RifJsonEncodeDecode.cpp
Normal file
151
ApplicationLibCode/FileInterface/RifJsonEncodeDecode.cpp
Normal 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
|
||||
65
ApplicationLibCode/FileInterface/RifJsonEncodeDecode.h
Normal file
65
ApplicationLibCode/FileInterface/RifJsonEncodeDecode.h
Normal 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
|
||||
101
ApplicationLibCode/FileInterface/RifKeywordVectorParser.cpp
Normal file
101
ApplicationLibCode/FileInterface/RifKeywordVectorParser.cpp
Normal 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() );
|
||||
}
|
||||
47
ApplicationLibCode/FileInterface/RifKeywordVectorParser.h
Normal file
47
ApplicationLibCode/FileInterface/RifKeywordVectorParser.h
Normal 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;
|
||||
};
|
||||
282
ApplicationLibCode/FileInterface/RifKeywordVectorUserData.cpp
Normal file
282
ApplicationLibCode/FileInterface/RifKeywordVectorUserData.cpp
Normal 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 "";
|
||||
}
|
||||
65
ApplicationLibCode/FileInterface/RifKeywordVectorUserData.h
Normal file
65
ApplicationLibCode/FileInterface/RifKeywordVectorUserData.h
Normal 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;
|
||||
};
|
||||
@@ -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() );
|
||||
}
|
||||
@@ -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 );
|
||||
};
|
||||
87
ApplicationLibCode/FileInterface/RifReaderEclipseInput.cpp
Normal file
87
ApplicationLibCode/FileInterface/RifReaderEclipseInput.cpp
Normal 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;
|
||||
}
|
||||
48
ApplicationLibCode/FileInterface/RifReaderEclipseInput.h
Normal file
48
ApplicationLibCode/FileInterface/RifReaderEclipseInput.h
Normal 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;
|
||||
}
|
||||
};
|
||||
2515
ApplicationLibCode/FileInterface/RifReaderEclipseOutput.cpp
Normal file
2515
ApplicationLibCode/FileInterface/RifReaderEclipseOutput.cpp
Normal file
File diff suppressed because it is too large
Load Diff
148
ApplicationLibCode/FileInterface/RifReaderEclipseOutput.h
Normal file
148
ApplicationLibCode/FileInterface/RifReaderEclipseOutput.h
Normal 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;
|
||||
};
|
||||
441
ApplicationLibCode/FileInterface/RifReaderEclipseRft.cpp
Normal file
441
ApplicationLibCode/FileInterface/RifReaderEclipseRft.cpp
Normal 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;
|
||||
}
|
||||
74
ApplicationLibCode/FileInterface/RifReaderEclipseRft.h
Normal file
74
ApplicationLibCode/FileInterface/RifReaderEclipseRft.h
Normal 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;
|
||||
};
|
||||
679
ApplicationLibCode/FileInterface/RifReaderEclipseSummary.cpp
Normal file
679
ApplicationLibCode/FileInterface/RifReaderEclipseSummary.cpp
Normal 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;
|
||||
}
|
||||
126
ApplicationLibCode/FileInterface/RifReaderEclipseSummary.h
Normal file
126
ApplicationLibCode/FileInterface/RifReaderEclipseSummary.h
Normal 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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
547
ApplicationLibCode/FileInterface/RifReaderFmuRft.cpp
Normal file
547
ApplicationLibCode/FileInterface/RifReaderFmuRft.cpp
Normal 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;
|
||||
}
|
||||
101
ApplicationLibCode/FileInterface/RifReaderFmuRft.h
Normal file
101
ApplicationLibCode/FileInterface/RifReaderFmuRft.h
Normal 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;
|
||||
};
|
||||
123
ApplicationLibCode/FileInterface/RifReaderInterface.cpp
Normal file
123
ApplicationLibCode/FileInterface/RifReaderInterface.cpp
Normal 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();
|
||||
}
|
||||
86
ApplicationLibCode/FileInterface/RifReaderInterface.h
Normal file
86
ApplicationLibCode/FileInterface/RifReaderInterface.h
Normal 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;
|
||||
};
|
||||
197
ApplicationLibCode/FileInterface/RifReaderMockModel.cpp
Normal file
197
ApplicationLibCode/FileInterface/RifReaderMockModel.cpp
Normal 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 );
|
||||
}
|
||||
57
ApplicationLibCode/FileInterface/RifReaderMockModel.h
Normal file
57
ApplicationLibCode/FileInterface/RifReaderMockModel.h
Normal 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;
|
||||
};
|
||||
219
ApplicationLibCode/FileInterface/RifReaderObservedData.cpp
Normal file
219
ApplicationLibCode/FileInterface/RifReaderObservedData.cpp
Normal 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;
|
||||
}
|
||||
64
ApplicationLibCode/FileInterface/RifReaderObservedData.h
Normal file
64
ApplicationLibCode/FileInterface/RifReaderObservedData.h
Normal 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;
|
||||
};
|
||||
36
ApplicationLibCode/FileInterface/RifReaderRftInterface.cpp
Normal file
36
ApplicationLibCode/FileInterface/RifReaderRftInterface.cpp
Normal 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;
|
||||
}
|
||||
45
ApplicationLibCode/FileInterface/RifReaderRftInterface.h
Normal file
45
ApplicationLibCode/FileInterface/RifReaderRftInterface.h
Normal 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;
|
||||
};
|
||||
115
ApplicationLibCode/FileInterface/RifReaderSettings.cpp
Normal file
115
ApplicationLibCode/FileInterface/RifReaderSettings.cpp
Normal 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 );
|
||||
}
|
||||
52
ApplicationLibCode/FileInterface/RifReaderSettings.h
Normal file
52
ApplicationLibCode/FileInterface/RifReaderSettings.h
Normal 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;
|
||||
};
|
||||
141
ApplicationLibCode/FileInterface/RifRoffReader.cpp
Normal file
141
ApplicationLibCode/FileInterface/RifRoffReader.cpp
Normal 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];
|
||||
}
|
||||
}
|
||||
58
ApplicationLibCode/FileInterface/RifRoffReader.h
Normal file
58
ApplicationLibCode/FileInterface/RifRoffReader.h
Normal 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 );
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 );
|
||||
};
|
||||
@@ -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] );
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
};
|
||||
@@ -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" );
|
||||
}
|
||||
34
ApplicationLibCode/FileInterface/RifStimPlanModelExporter.h
Normal file
34
ApplicationLibCode/FileInterface/RifStimPlanModelExporter.h
Normal 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 );
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 );
|
||||
};
|
||||
@@ -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
Reference in New Issue
Block a user