From 06fb3e1241c37d3472f6e347072f67b1ee1cebeb Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 18 Nov 2024 17:01:26 +0100 Subject: [PATCH] #11895 Always show Oil Saturation as available If no SOIL is found on file, compute based on available SWAT and SGAS. --- .../FileInterface/RifReaderOpmRft.cpp | 91 +++++++++++++++++-- .../FileInterface/RifReaderOpmRft.h | 1 + .../RigSoilResultCalculator.cpp | 1 + 3 files changed, 84 insertions(+), 9 deletions(-) diff --git a/ApplicationLibCode/FileInterface/RifReaderOpmRft.cpp b/ApplicationLibCode/FileInterface/RifReaderOpmRft.cpp index 49bd7042ef..a2154ce229 100644 --- a/ApplicationLibCode/FileInterface/RifReaderOpmRft.cpp +++ b/ApplicationLibCode/FileInterface/RifReaderOpmRft.cpp @@ -20,6 +20,7 @@ #include "RiaLogging.h" #include "RiaQDateTimeTools.h" +#include "RiaResultNames.h" #include "RiaRftDefines.h" #include "RiaStdStringTools.h" @@ -138,7 +139,43 @@ void RifReaderOpmRft::values( const RifEclipseRftAddress& rftAddress, std::vecto try { - std::vector data = resultAsFloat( resultName, wellName, y, m, d ); + std::vector data; + + if ( rftAddress.wellLogChannel() == RifEclipseRftAddress::RftWellLogChannelType::SOIL && + !isNativeResultAvailable( RiaResultNames::soil().toStdString(), wellName, y, m, d ) ) + { + // Compute SOIL from SWAT and SGAS + // There is a similar function in RigSoilResultCalculator, but they are too different to be merged + auto computeSoil = [&]( const std::string& wellName, int y, int m, int d ) -> std::vector + { + auto swat = resultAsFloat( RiaResultNames::swat().toStdString(), wellName, y, m, d ); + auto sgas = resultAsFloat( RiaResultNames::sgas().toStdString(), wellName, y, m, d ); + + auto maxItems = std::max( swat.size(), sgas.size() ); + std::vector data( maxItems, 1.0f ); + + for ( size_t i = 0; i < maxItems; ++i ) + { + if ( i < swat.size() ) + { + data[i] -= swat[i]; + } + if ( i < sgas.size() ) + { + data[i] -= sgas[i]; + } + data[i] = std::clamp( data[i], 0.0f, 1.0f ); + } + + return data; + }; + + data = computeSoil( wellName, y, m, d ); + } + else + { + data = resultAsFloat( resultName, wellName, y, m, d ); + } if ( !data.empty() ) { @@ -241,6 +278,17 @@ std::set RifReaderOpmRft::availableTimeSteps( const QString& timeSteps.insert( address.timeStep() ); } } + + if ( timeSteps.empty() && wellLogChannelName == RifEclipseRftAddress::RftWellLogChannelType::SOIL ) + { + auto sgasTimeSteps = availableTimeSteps( wellName, RifEclipseRftAddress::RftWellLogChannelType::SGAS ); + auto swatTimeSteps = availableTimeSteps( wellName, RifEclipseRftAddress::RftWellLogChannelType::SWAT ); + + // Combine time steps from SGAS and SWAT + timeSteps.insert( sgasTimeSteps.begin(), sgasTimeSteps.end() ); + timeSteps.insert( swatTimeSteps.begin(), swatTimeSteps.end() ); + } + return timeSteps; } @@ -281,6 +329,13 @@ std::set RifReaderOpmRft::available } } + if ( types.contains( RifEclipseRftAddress::RftWellLogChannelType::SWAT ) || + types.contains( RifEclipseRftAddress::RftWellLogChannelType::SGAS ) ) + { + // Add SOIL if SGAS or SWAT are available, SOIL can be computed from these + types.insert( RifEclipseRftAddress::RftWellLogChannelType::SOIL ); + } + return types; } @@ -473,8 +528,8 @@ std::vector { if ( !isFirstSegment && std::fabs( startMD[i] - endMD[i - 1] ) > 0.1 ) { - // Insert a segment representing the connection between the segments. Assign infinity as value to this segment - // to allow discontinuous plotting. + // Insert a segment representing the connection between the segments. Assign infinity as value to this + // segment to allow discontinuous plotting. startEndValues.emplace_back( endMD[i - 1], startMD[i], false ); } startEndValues.emplace_back( startMD[i], endMD[i], true ); @@ -1081,13 +1136,14 @@ RifEclipseRftAddress::RftWellLogChannelType RifReaderOpmRft::identifyChannelType { if ( resultName == "DEPTH" ) return RifEclipseRftAddress::RftWellLogChannelType::TVD; if ( resultName == "PRESSURE" ) return RifEclipseRftAddress::RftWellLogChannelType::PRESSURE; - if ( resultName == "SWAT" ) return RifEclipseRftAddress::RftWellLogChannelType::SWAT; - if ( resultName == "SOIL" ) return RifEclipseRftAddress::RftWellLogChannelType::SOIL; - if ( resultName == "SGAS" ) return RifEclipseRftAddress::RftWellLogChannelType::SGAS; if ( resultName == "WRAT" ) return RifEclipseRftAddress::RftWellLogChannelType::WRAT; if ( resultName == "ORAT" ) return RifEclipseRftAddress::RftWellLogChannelType::ORAT; if ( resultName == "GRAT" ) return RifEclipseRftAddress::RftWellLogChannelType::GRAT; + if ( resultName == RiaResultNames::swat().toStdString() ) return RifEclipseRftAddress::RftWellLogChannelType::SWAT; + if ( resultName == RiaResultNames::soil().toStdString() ) return RifEclipseRftAddress::RftWellLogChannelType::SOIL; + if ( resultName == RiaResultNames::sgas().toStdString() ) return RifEclipseRftAddress::RftWellLogChannelType::SGAS; + return RifEclipseRftAddress::RftWellLogChannelType::NONE; } @@ -1098,13 +1154,14 @@ std::string RifReaderOpmRft::resultNameFromChannelType( RifEclipseRftAddress::Rf { if ( channelType == RifEclipseRftAddress::RftWellLogChannelType::TVD ) return "DEPTH"; if ( channelType == RifEclipseRftAddress::RftWellLogChannelType::PRESSURE ) return "PRESSURE"; - if ( channelType == RifEclipseRftAddress::RftWellLogChannelType::SWAT ) return "SWAT"; - if ( channelType == RifEclipseRftAddress::RftWellLogChannelType::SOIL ) return "SOIL"; - if ( channelType == RifEclipseRftAddress::RftWellLogChannelType::SGAS ) return "SGAS"; if ( channelType == RifEclipseRftAddress::RftWellLogChannelType::WRAT ) return "WRAT"; if ( channelType == RifEclipseRftAddress::RftWellLogChannelType::ORAT ) return "ORAT"; if ( channelType == RifEclipseRftAddress::RftWellLogChannelType::GRAT ) return "GRAT"; + if ( channelType == RifEclipseRftAddress::RftWellLogChannelType::SWAT ) return RiaResultNames::swat().toStdString(); + if ( channelType == RifEclipseRftAddress::RftWellLogChannelType::SOIL ) return RiaResultNames::soil().toStdString(); + if ( channelType == RifEclipseRftAddress::RftWellLogChannelType::SGAS ) return RiaResultNames::sgas().toStdString(); + return {}; } @@ -1145,6 +1202,22 @@ std::vector RifReaderOpmRft::resultAsFloat( const std::string& resultName return {}; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifReaderOpmRft::isNativeResultAvailable( const std::string& resultName, const std::string& wellName, int year, int month, int day ) const +{ + if ( !m_opm_rft ) return false; + + auto results = m_opm_rft->listOfRftArrays( wellName, year, month, day ); + for ( const auto& [name, arrayType, size] : results ) + { + if ( resultName == name ) return true; + } + + return false; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/FileInterface/RifReaderOpmRft.h b/ApplicationLibCode/FileInterface/RifReaderOpmRft.h index 97b40172df..28b51bfcd8 100644 --- a/ApplicationLibCode/FileInterface/RifReaderOpmRft.h +++ b/ApplicationLibCode/FileInterface/RifReaderOpmRft.h @@ -87,6 +87,7 @@ private: static std::string resultNameFromChannelType( RifEclipseRftAddress::RftWellLogChannelType channelType ); std::vector resultAsFloat( const std::string& resultName, const std::string& wellName, int year, int month, int day ) const; + bool isNativeResultAvailable( const std::string& resultName, const std::string& wellName, int year, int month, int day ) const; bool openFiles(); diff --git a/ApplicationLibCode/ReservoirDataModel/ResultCalculators/RigSoilResultCalculator.cpp b/ApplicationLibCode/ReservoirDataModel/ResultCalculators/RigSoilResultCalculator.cpp index ef7dde6064..e0497d68e8 100644 --- a/ApplicationLibCode/ReservoirDataModel/ResultCalculators/RigSoilResultCalculator.cpp +++ b/ApplicationLibCode/ReservoirDataModel/ResultCalculators/RigSoilResultCalculator.cpp @@ -50,6 +50,7 @@ bool RigSoilResultCalculator::isMatching( const RigEclipseResultAddress& resVarA //-------------------------------------------------------------------------------------------------- void RigSoilResultCalculator::calculate( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex ) { + // See similar function in RifReaderOpmRft::values, but the current implementation is not suitable for merging // Compute SGAS based on SWAT if the simulation contains no oil m_resultsData->testAndComputeSgasForTimeStep( timeStepIndex );