diff --git a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake index 8a488e718e..0501684119 100644 --- a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake +++ b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake @@ -75,6 +75,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RifProjectSummaryDataWriter.h ${CMAKE_CURRENT_LIST_DIR}/RifReaderOpmRft.h ${CMAKE_CURRENT_LIST_DIR}/RifRftSegment.h + ${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -151,6 +152,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RifProjectSummaryDataWriter.cpp ${CMAKE_CURRENT_LIST_DIR}/RifReaderOpmRft.cpp ${CMAKE_CURRENT_LIST_DIR}/RifRftSegment.cpp + ${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader.cpp ) list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) diff --git a/ApplicationLibCode/FileInterface/RifPressureDepthTextFileReader.cpp b/ApplicationLibCode/FileInterface/RifPressureDepthTextFileReader.cpp new file mode 100644 index 0000000000..b1ac1c2d48 --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifPressureDepthTextFileReader.cpp @@ -0,0 +1,137 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 - Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RifPressureDepthTextFileReader.h" + +#include "RiaDefines.h" + +#include "RigPressureDepthData.h" + +#include "RifFileParseTools.h" + +#include "cafAssert.h" + +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair, QString> RifPressureDepthTextFileReader::readFile( const QString& filePath ) +{ + std::vector items; + + QFile file( filePath ); + if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + return std::make_pair( items, QString( "Unable to open file: %1" ).arg( filePath ) ); + } + + QString separator = " "; + + QTextStream in( &file ); + while ( !in.atEnd() ) + { + QString line = in.readLine(); + if ( isHeaderLine( line ) ) + { + QStringList headerValues = RifFileParseTools::splitLineAndTrim( line, separator ); + RigPressureDepthData data; + data.setWellName( headerValues[1] ); + items.push_back( data ); + } + else if ( isDateLine( line ) ) + { + // TODO: parse date + } + else if ( isPropertiesLine( line ) || isUnitsLine( line ) || isCommentLine( line ) ) + { + // Ignored. + } + else if ( std::optional> p = parseDataLine( line ) ) + { + auto [pressure, depth] = p.value(); + items.back().addPressureAtDepth( pressure, depth ); + } + } + + return std::make_pair( items, "" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifPressureDepthTextFileReader::isHeaderLine( const QString& line ) +{ + return line.startsWith( "WELLNAME" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifPressureDepthTextFileReader::isCommentLine( const QString& line ) +{ + return line.startsWith( "--" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifPressureDepthTextFileReader::isDateLine( const QString& line ) +{ + return line.startsWith( "DATE" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifPressureDepthTextFileReader::isPropertiesLine( const QString& line ) +{ + // TODO: this might be to strict.. + return line.startsWith( "PRESSURE DEPTH" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifPressureDepthTextFileReader::isUnitsLine( const QString& line ) +{ + // TODO: this might be to strict.. + return line.startsWith( "BARSA METRES" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::optional> RifPressureDepthTextFileReader::parseDataLine( const QString& line ) +{ + // Expect two data values separated by one space + QStringList values = RifFileParseTools::splitLineAndTrim( line, " " ); + if ( values.size() != 2 ) return {}; + + // First value is pressure + bool isOk = false; + double pressure = values[0].toDouble( &isOk ); + if ( !isOk ) return {}; + + // Second value is depth + double depth = values[1].toDouble( &isOk ); + if ( !isOk ) return {}; + + return std::make_pair( pressure, depth ); +} diff --git a/ApplicationLibCode/FileInterface/RifPressureDepthTextFileReader.h b/ApplicationLibCode/FileInterface/RifPressureDepthTextFileReader.h new file mode 100644 index 0000000000..2173ec6911 --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifPressureDepthTextFileReader.h @@ -0,0 +1,45 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 - Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +#include +#include +#include + +class RigPressureDepthData; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RifPressureDepthTextFileReader +{ +public: + static std::pair, QString> readFile( const QString& fileName ); + +private: + static bool isHeaderLine( const QString& line ); + static bool isCommentLine( const QString& line ); + static bool isDateLine( const QString& line ); + static bool isPropertiesLine( const QString& line ); + static bool isUnitsLine( const QString& line ); + + static std::optional> parseDataLine( const QString& line ); +}; diff --git a/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake index 6094b83499..64a9c69ae9 100644 --- a/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake @@ -95,6 +95,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RigSurfaceResampler.h ${CMAKE_CURRENT_LIST_DIR}/RigSurfaceStatisticsCalculator.h ${CMAKE_CURRENT_LIST_DIR}/RigWellLogIndexDepthOffset.h + ${CMAKE_CURRENT_LIST_DIR}/RigPressureDepthData.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -187,6 +188,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RigSurfaceResampler.cpp ${CMAKE_CURRENT_LIST_DIR}/RigSurfaceStatisticsCalculator.cpp ${CMAKE_CURRENT_LIST_DIR}/RigWellLogIndexDepthOffset.cpp + ${CMAKE_CURRENT_LIST_DIR}/RigPressureDepthData.cpp ) list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) diff --git a/ApplicationLibCode/ReservoirDataModel/RigPressureDepthData.cpp b/ApplicationLibCode/ReservoirDataModel/RigPressureDepthData.cpp new file mode 100644 index 0000000000..2e742246d1 --- /dev/null +++ b/ApplicationLibCode/ReservoirDataModel/RigPressureDepthData.cpp @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 - Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RigPressureDepthData.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigPressureDepthData::RigPressureDepthData() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigPressureDepthData::~RigPressureDepthData() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigPressureDepthData::setWellName( const QString& wellName ) +{ + m_wellName = wellName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RigPressureDepthData::wellName() const +{ + return m_wellName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigPressureDepthData::addPressureAtDepth( double pressure, double depth ) +{ + m_values.push_back( std::make_pair( pressure, depth ) ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RigPressureDepthData::getPressureDepthValues() const +{ + return m_values; +} diff --git a/ApplicationLibCode/ReservoirDataModel/RigPressureDepthData.h b/ApplicationLibCode/ReservoirDataModel/RigPressureDepthData.h new file mode 100644 index 0000000000..9916ccc063 --- /dev/null +++ b/ApplicationLibCode/ReservoirDataModel/RigPressureDepthData.h @@ -0,0 +1,45 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 - Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaDefines.h" + +#include + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RigPressureDepthData +{ +public: + RigPressureDepthData(); + ~RigPressureDepthData(); + + void setWellName( const QString& name ); + QString wellName() const; + + void addPressureAtDepth( double pressure, double depth ); + std::vector> getPressureDepthValues() const; + +private: + QString m_wellName; + std::vector> m_values; +}; diff --git a/ApplicationLibCode/UnitTests/CMakeLists_files.cmake b/ApplicationLibCode/UnitTests/CMakeLists_files.cmake index aeacdb0461..9ee459a01c 100644 --- a/ApplicationLibCode/UnitTests/CMakeLists_files.cmake +++ b/ApplicationLibCode/UnitTests/CMakeLists_files.cmake @@ -85,6 +85,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RifEclipseTextFileReader-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaSummaryStringTools-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaVariableMapper-Test.cpp + ${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader-Test.cpp ) if(RESINSIGHT_ENABLE_GRPC) diff --git a/ApplicationLibCode/UnitTests/RifPressureDepthTextFileReader-Test.cpp b/ApplicationLibCode/UnitTests/RifPressureDepthTextFileReader-Test.cpp new file mode 100644 index 0000000000..5787d74b62 --- /dev/null +++ b/ApplicationLibCode/UnitTests/RifPressureDepthTextFileReader-Test.cpp @@ -0,0 +1,62 @@ +#include "gtest/gtest.h" + +#include "RiaTestDataDirectory.h" + +#include "RifPressureDepthTextFileReader.h" +#include "RigPressureDepthData.h" + +#include +#include + +static const QString CASE_REAL_TEST_DATA_DIRECTORY_04 = + QString( "%1/RifPressureDepthTextFileReader/" ).arg( TEST_DATA_DIR ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( RifPressureDepthTextFileReaderTest, LoadFile ) +{ + QString fileName = CASE_REAL_TEST_DATA_DIRECTORY_04 + "example_file.txt"; + + auto [items, errorMessage] = RifPressureDepthTextFileReader::readFile( fileName ); + + EXPECT_TRUE( errorMessage.isEmpty() ); + ASSERT_EQ( 3u, items.size() ); + + EXPECT_EQ( "'G-14'", items[0].wellName().toStdString() ); + std::vector> values0 = items[0].getPressureDepthValues(); + EXPECT_EQ( 4u, values0.size() ); + double delta = 0.001; + EXPECT_NEAR( 418.88, values0[0].first, delta ); + EXPECT_NEAR( 2726.91, values0[0].second, delta ); + + EXPECT_EQ( "'G-14'", items[1].wellName().toStdString() ); + EXPECT_EQ( 28, items[1].timeStep().date().day() ); + EXPECT_EQ( 12, items[1].timeStep().date().month() ); + EXPECT_EQ( 1996, items[1].timeStep().date().year() ); + std::vector> values1 = items[1].getPressureDepthValues(); + EXPECT_NEAR( 418.88, values1[0].first, delta ); + EXPECT_NEAR( 2726.91, values1[0].second, delta ); + + EXPECT_EQ( "'F-56'", items[2].wellName().toStdString() ); + EXPECT_EQ( 15, items[2].timeStep().date().day() ); + EXPECT_EQ( 1, items[2].timeStep().date().month() ); + EXPECT_EQ( 2012, items[2].timeStep().date().year() ); + std::vector> values2 = items[2].getPressureDepthValues(); + EXPECT_EQ( 7u, values2.size() ); + EXPECT_NEAR( 413.32, values2[6].first, delta ); + EXPECT_NEAR( 2896.555, values2[6].second, delta ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( RifPressureDepthTextFileReaderTest, LoadFileNonExistingFiles ) +{ + QString fileName = CASE_REAL_TEST_DATA_DIRECTORY_04 + "this_file_does_not_exist.csv"; + + auto [items, errorMessage] = RifPressureDepthTextFileReader::readFile( fileName ); + + EXPECT_FALSE( errorMessage.isEmpty() ); + EXPECT_EQ( 0u, items.size() ); +} diff --git a/ApplicationLibCode/UnitTests/TestData/RifPressureDepthTextFileReader/example_file.txt b/ApplicationLibCode/UnitTests/TestData/RifPressureDepthTextFileReader/example_file.txt new file mode 100644 index 0000000000..57ed746a62 --- /dev/null +++ b/ApplicationLibCode/UnitTests/TestData/RifPressureDepthTextFileReader/example_file.txt @@ -0,0 +1,32 @@ +--TVDMSL +RFT +-- +WELLNAME 'G-14' +DATE 28-DEC-1995 +PRESSURE DEPTH +BARSA METRES +418.88 2726.91 +419.02 2729.36 +419.11 2733.29 +419.17 2735.26 +-- +WELLNAME 'G-14' +DATE 28-DEC-1996 +PRESSURE DEPTH +BARSA METRES +418.88 2726.91 +419.02 2729.36 +419.11 2733.29 +419.17 2735.26 +-- +WELLNAME 'F-56' +DATE 15-jan-12 +PRESSURE DEPTH +BARSA METRES +414.40 2911.029 +415.92 2929.496 +417.23 2935.801 +415.76 2934.981 +414.75 2919.446 +413.53 2903.147 +413.32 2896.555