mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-11 16:06:04 -06:00
#5829 Add reader for ROFF files to extract category names and values from file
This commit is contained in:
parent
423b6c2887
commit
3f4778509d
@ -51,6 +51,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RifActiveCellsReader.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifCsvDataTableFormatter.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifEclipseInputPropertyLoader.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifSurfaceReader.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifRoffReader.h
|
||||
|
||||
# HDF5 file reader is directly included in ResInsight main CmakeList.txt
|
||||
#${CMAKE_CURRENT_LIST_DIR}/RifHdf5Reader.h
|
||||
@ -106,7 +107,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RifCsvDataTableFormatter.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifReaderEnsembleStatisticsRft.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifEclipseInputPropertyLoader.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifSurfaceReader.cpp
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifRoffReader.cpp
|
||||
|
||||
# HDF5 file reader is directly included in ResInsight main CmakeList.txt
|
||||
#${CMAKE_CURRENT_LIST_DIR}/RifHdf5Reader.cpp
|
||||
|
141
ApplicationCode/FileInterface/RifRoffReader.cpp
Normal file
141
ApplicationCode/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
ApplicationCode/FileInterface/RifRoffReader.h
Normal file
58
ApplicationCode/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 );
|
||||
};
|
@ -66,6 +66,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RifWellMeasurementReader-Test.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaDateStringParser-Test.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigHexGradientTools-Test.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifSurfaceReader-Test.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifRoffReader-Test.cpp
|
||||
)
|
||||
|
||||
if (RESINSIGHT_ENABLE_GRPC)
|
||||
|
87
ApplicationCode/UnitTests/RifRoffReader-Test.cpp
Normal file
87
ApplicationCode/UnitTests/RifRoffReader-Test.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "RifRoffReader.h"
|
||||
|
||||
#include "RiaTestDataDirectory.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
|
||||
TEST( RifRoffReader, ReadValidFile )
|
||||
{
|
||||
QDir baseFolder( TEST_DATA_DIR );
|
||||
|
||||
QString filename( "RifRoffReader/facies_info.roff" );
|
||||
QString filePath = baseFolder.absoluteFilePath( filename );
|
||||
EXPECT_TRUE( QFile::exists( filePath ) );
|
||||
|
||||
std::map<int, QString> codeNames;
|
||||
RifRoffReader::readCodeNames( filePath, codeNames );
|
||||
|
||||
ASSERT_EQ( 6u, codeNames.size() );
|
||||
for ( int i = 0; i < 6; i++ )
|
||||
{
|
||||
ASSERT_TRUE( codeNames.find( i ) != codeNames.end() );
|
||||
ASSERT_EQ( codeNames.find( i )->second.toStdString(), QString( "code name %1" ).arg( i + 1 ).toStdString() );
|
||||
}
|
||||
}
|
||||
|
||||
std::string readIncorrectFile( const QString filename )
|
||||
{
|
||||
QDir baseFolder( TEST_DATA_DIR );
|
||||
|
||||
QString filePath = baseFolder.absoluteFilePath( filename );
|
||||
|
||||
std::map<int, QString> codeNames;
|
||||
try
|
||||
{
|
||||
RifRoffReader::readCodeNames( filePath, codeNames );
|
||||
return "";
|
||||
}
|
||||
catch ( RifRoffReaderException& ex )
|
||||
{
|
||||
return ex.message;
|
||||
}
|
||||
}
|
||||
|
||||
TEST( RifRoffReader, ReadWrongFileType )
|
||||
{
|
||||
// Read a surface file: no expected to work
|
||||
QString filename( "RifSurfaceReader/test.ptl" );
|
||||
ASSERT_EQ( readIncorrectFile( filename ), std::string( "Unexpected file type: roff-asc header missing." ) );
|
||||
}
|
||||
|
||||
TEST( RifRoffReader, ReadNonExistingFileType )
|
||||
{
|
||||
// Read a non-existing file
|
||||
QString filename( "RifRoffReader/this_file_does_not_exist.roff" );
|
||||
ASSERT_EQ( readIncorrectFile( filename ), std::string( "Unable to open roff file." ) );
|
||||
}
|
||||
|
||||
TEST( RifRoffReader, ReadFileWithIncorrectInteger )
|
||||
{
|
||||
// Read a file with incorrect integer for code values
|
||||
QString filename( "RifRoffReader/code_values_integer_wrong.roff" );
|
||||
ASSERT_EQ( readIncorrectFile( filename ), std::string( "Unexpected value: not an integer." ) );
|
||||
}
|
||||
|
||||
TEST( RifRoffReader, ReadFileCodeNamesMissing )
|
||||
{
|
||||
// Read a file without code names
|
||||
QString filename( "RifRoffReader/code_names_missing.roff" );
|
||||
ASSERT_EQ( readIncorrectFile( filename ), std::string( "Code names not found." ) );
|
||||
}
|
||||
|
||||
TEST( RifRoffReader, ReadFileCodeValuesMissing )
|
||||
{
|
||||
// Read a file without code values
|
||||
QString filename( "RifRoffReader/code_values_missing.roff" );
|
||||
ASSERT_EQ( readIncorrectFile( filename ), std::string( "Code values not found." ) );
|
||||
}
|
||||
|
||||
TEST( RifRoffReader, ReadFileCodeNamesAndValuesMismatch )
|
||||
{
|
||||
// Read a file without code values
|
||||
QString filename( "RifRoffReader/code_names_and_values_mismatch.roff" );
|
||||
ASSERT_EQ( readIncorrectFile( filename ), std::string( "Inconsistent code names and values: must be equal length." ) );
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
roff-asc
|
||||
#ROFF file#
|
||||
#Creator: RMS - Reservoir Modeling System, version 11.1.0#
|
||||
tag filedata
|
||||
int byteswaptest 1
|
||||
char filetype "parameter"
|
||||
char creationDate "06/03/2020 14:25:36"
|
||||
endtag
|
||||
tag version
|
||||
int major 2
|
||||
int minor 0
|
||||
endtag
|
||||
tag dimensions
|
||||
int nX 46
|
||||
int nY 112
|
||||
int nZ 242
|
||||
endtag
|
||||
tag parameter
|
||||
char name "composite"
|
||||
array char codeNames 4
|
||||
"only"
|
||||
"four"
|
||||
"code"
|
||||
"names"
|
||||
array int codeValues 6
|
||||
0 1 2 3 4 5
|
||||
array int data 4
|
||||
-999 -999 -999 -999
|
||||
endtag
|
||||
tag eof
|
||||
endtag
|
26
ApplicationCode/UnitTests/TestData/RifRoffReader/code_names_missing.roff
Executable file
26
ApplicationCode/UnitTests/TestData/RifRoffReader/code_names_missing.roff
Executable file
@ -0,0 +1,26 @@
|
||||
roff-asc
|
||||
#ROFF file#
|
||||
#Creator: RMS - Reservoir Modeling System, version 11.1.0#
|
||||
tag filedata
|
||||
int byteswaptest 1
|
||||
char filetype "parameter"
|
||||
char creationDate "06/03/2020 14:25:36"
|
||||
endtag
|
||||
tag version
|
||||
int major 2
|
||||
int minor 0
|
||||
endtag
|
||||
tag dimensions
|
||||
int nX 46
|
||||
int nY 112
|
||||
int nZ 242
|
||||
endtag
|
||||
tag parameter
|
||||
char name "composite"
|
||||
array int codeValues 6
|
||||
0 1 2 3 4 5
|
||||
array int data 4
|
||||
-999 -999 -999 -999
|
||||
endtag
|
||||
tag eof
|
||||
endtag
|
@ -0,0 +1,29 @@
|
||||
roff-asc
|
||||
#ROFF file#
|
||||
#Creator: RMS - Reservoir Modeling System, version 11.1.0#
|
||||
tag filedata
|
||||
int byteswaptest 1
|
||||
char filetype "parameter"
|
||||
char creationDate "06/03/2020 14:25:36"
|
||||
endtag
|
||||
tag version
|
||||
int major 2
|
||||
int minor 0
|
||||
endtag
|
||||
tag dimensions
|
||||
int nX 46
|
||||
int nY 112
|
||||
int nZ 242
|
||||
endtag
|
||||
tag parameter
|
||||
char name "composite"
|
||||
array char codeNames 2
|
||||
"cn1"
|
||||
"cn2"
|
||||
array int codeValues this_is_not_a_number
|
||||
0 1 2 3 4 5
|
||||
array int data 4
|
||||
-999 -999 -999 -999
|
||||
endtag
|
||||
tag eof
|
||||
endtag
|
26
ApplicationCode/UnitTests/TestData/RifRoffReader/code_values_missing.roff
Executable file
26
ApplicationCode/UnitTests/TestData/RifRoffReader/code_values_missing.roff
Executable file
@ -0,0 +1,26 @@
|
||||
roff-asc
|
||||
#ROFF file#
|
||||
#Creator: RMS - Reservoir Modeling System, version 11.1.0#
|
||||
tag filedata
|
||||
int byteswaptest 1
|
||||
char filetype "parameter"
|
||||
char creationDate "06/03/2020 14:25:36"
|
||||
endtag
|
||||
tag version
|
||||
int major 2
|
||||
int minor 0
|
||||
endtag
|
||||
tag dimensions
|
||||
int nX 46
|
||||
int nY 112
|
||||
int nZ 242
|
||||
endtag
|
||||
tag parameter
|
||||
char name "composite"
|
||||
array char codeNames 1
|
||||
"a name"
|
||||
array int data 4
|
||||
-999 -999 -999 -999
|
||||
endtag
|
||||
tag eof
|
||||
endtag
|
33
ApplicationCode/UnitTests/TestData/RifRoffReader/facies_info.roff
Executable file
33
ApplicationCode/UnitTests/TestData/RifRoffReader/facies_info.roff
Executable file
@ -0,0 +1,33 @@
|
||||
roff-asc
|
||||
#ROFF file#
|
||||
#Creator: RMS - Reservoir Modeling System, version 11.1.0#
|
||||
tag filedata
|
||||
int byteswaptest 1
|
||||
char filetype "parameter"
|
||||
char creationDate "06/03/2020 14:25:36"
|
||||
endtag
|
||||
tag version
|
||||
int major 2
|
||||
int minor 0
|
||||
endtag
|
||||
tag dimensions
|
||||
int nX 46
|
||||
int nY 112
|
||||
int nZ 242
|
||||
endtag
|
||||
tag parameter
|
||||
char name "composite"
|
||||
array char codeNames 6
|
||||
"code name 1"
|
||||
"code name 2"
|
||||
"code name 3"
|
||||
"code name 4"
|
||||
"code name 5"
|
||||
"code name 6"
|
||||
array int codeValues 6
|
||||
0 1 2 3 4 5
|
||||
array int data 4
|
||||
-999 -999 -999 -999
|
||||
endtag
|
||||
tag eof
|
||||
endtag
|
Loading…
Reference in New Issue
Block a user