Sector Export: add OPERNUM result.

This commit is contained in:
Kristian Bendiksen committed 2025-09-26 15:28:29 +02:00
1 parent b07e49258e
commit fdbb07b8cd
4 files changed
+281

No files matched your search

@@ -151,6 +151,9 @@ void RicExportEclipseSectorModelFeature::executeCommand( RimEclipseView*
if ( !bordnumVisibility.isNull() ) if ( !bordnumVisibility.isNull() )
{ {
RigEclipseResultTools::generateBorderResult( view->eclipseCase(), bordnumVisibility, "BORDNUM" ); RigEclipseResultTools::generateBorderResult( view->eclipseCase(), bordnumVisibility, "BORDNUM" );
// Generate OPERNUM result based on BORDNUM (border cells get max existing OPERNUM + 1)
RigEclipseResultTools::generateOperNumResult( view->eclipseCase() );
} }
if ( exportSettings.exportParameters() != RicExportEclipseSectorModelUi::EXPORT_NO_RESULTS ) if ( exportSettings.exportParameters() != RicExportEclipseSectorModelUi::EXPORT_NO_RESULTS )
@@ -164,6 +167,12 @@ void RicExportEclipseSectorModelFeature::executeCommand( RimEclipseView*
keywords.push_back( "BORDNUM" ); keywords.push_back( "BORDNUM" );
} }
// Automatically add OPERNUM to the keywords list if not already present
if ( std::find( keywords.begin(), keywords.end(), "OPERNUM" ) == keywords.end() )
{
keywords.push_back( "OPERNUM" );
}
if ( exportSettings.exportParameters == RicExportEclipseSectorModelUi::EXPORT_TO_SEPARATE_FILE_PER_RESULT ) if ( exportSettings.exportParameters == RicExportEclipseSectorModelUi::EXPORT_TO_SEPARATE_FILE_PER_RESULT )
{ {
QFileInfo info( exportSettings.exportGridFilename() ); QFileInfo info( exportSettings.exportGridFilename() );
@@ -102,4 +102,126 @@ void generateBorderResult( RimEclipseCase* eclipseCase, cvf::ref<cvf::UByteArray
eclipseCase->updateConnectedEditors(); eclipseCase->updateConnectedEditors();
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void generateOperNumResult( RimEclipseCase* eclipseCase, int borderCellValue )
{
if ( eclipseCase == nullptr ) return;
// Auto-determine border cell value if not specified
if ( borderCellValue == -1 )
{
int maxOperNum = findMaxOperNumValue( eclipseCase );
borderCellValue = maxOperNum + 1;
}
auto activeReservoirCellIdxs =
eclipseCase->eclipseCaseData()->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL )->activeReservoirCellIndices();
int numActiveCells = static_cast<int>( activeReservoirCellIdxs.size() );
std::vector<int> result;
result.resize( numActiveCells, 0 );
// Check if OPERNUM already exists - if so, keep existing values.
RigEclipseResultAddress operNumAddrNative( RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::ResultDataType::INTEGER, "OPERNUM" );
RigEclipseResultAddress operNumAddrGenerated( RiaDefines::ResultCatType::GENERATED, RiaDefines::ResultDataType::INTEGER, "OPERNUM" );
auto resultsData = eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
RigEclipseResultAddress operNumAddr;
bool hasExistingOperNum = false;
if ( resultsData->hasResultEntry( operNumAddrNative ) )
{
operNumAddr = operNumAddrNative;
hasExistingOperNum = true;
}
else if ( resultsData->hasResultEntry( operNumAddrGenerated ) )
{
operNumAddr = operNumAddrGenerated;
hasExistingOperNum = true;
}
if ( hasExistingOperNum )
{
resultsData->ensureKnownResultLoaded( operNumAddr );
auto existingValues = resultsData->cellScalarResults( operNumAddr );
if ( !existingValues.empty() )
{
for ( int i = 0; i < numActiveCells; i++ )
{
result[i] = static_cast<int>( existingValues[0][i] );
}
}
}
// Check if BORDNUM exists to modify border cells
RigEclipseResultAddress bordNumAddr( RiaDefines::ResultCatType::GENERATED, RiaDefines::ResultDataType::INTEGER, "BORDNUM" );
if ( resultsData->hasResultEntry( bordNumAddr ) )
{
resultsData->ensureKnownResultLoaded( bordNumAddr );
auto bordNumValues = resultsData->cellScalarResults( bordNumAddr );
if ( !bordNumValues.empty() )
{
for ( int i = 0; i < numActiveCells; i++ )
{
// If BORDNUM = 1 (BORDER_CELL), assign the border cell value
if ( static_cast<int>( bordNumValues[0][i] ) == BorderType::BORDER_CELL )
{
result[i] = borderCellValue;
}
}
}
}
RigEclipseResultTools::createResultVector( *eclipseCase, "OPERNUM", result );
eclipseCase->updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int findMaxOperNumValue( RimEclipseCase* eclipseCase )
{
if ( eclipseCase == nullptr ) return 0;
auto resultsData = eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
if ( !resultsData ) return 0;
// Try to find OPERNUM in both STATIC_NATIVE (from file) and GENERATED (created by us) categories
RigEclipseResultAddress operNumAddrNative( RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::ResultDataType::INTEGER, "OPERNUM" );
RigEclipseResultAddress operNumAddrGenerated( RiaDefines::ResultCatType::GENERATED, RiaDefines::ResultDataType::INTEGER, "OPERNUM" );
RigEclipseResultAddress operNumAddr;
bool hasOperNum = false;
if ( resultsData->hasResultEntry( operNumAddrNative ) )
{
operNumAddr = operNumAddrNative;
hasOperNum = true;
}
else if ( resultsData->hasResultEntry( operNumAddrGenerated ) )
{
operNumAddr = operNumAddrGenerated;
hasOperNum = true;
}
if ( !hasOperNum ) return 0;
resultsData->ensureKnownResultLoaded( operNumAddr );
auto operNumValues = resultsData->cellScalarResults( operNumAddr );
if ( operNumValues.empty() ) return 0;
// Find maximum value
int maxValue = 0;
for ( double value : operNumValues[0] )
{
int intValue = static_cast<int>( value );
maxValue = std::max( maxValue, intValue );
}
return maxValue;
}
} // namespace RigEclipseResultTools } // namespace RigEclipseResultTools
@@ -39,4 +39,8 @@ void createResultVector( RimEclipseCase& eclipseCase, const QString& resultName,
void generateBorderResult( RimEclipseCase* eclipseCase, cvf::ref<cvf::UByteArray> customVisibility, const QString& resultName = "BORDER" ); void generateBorderResult( RimEclipseCase* eclipseCase, cvf::ref<cvf::UByteArray> customVisibility, const QString& resultName = "BORDER" );
void generateOperNumResult( RimEclipseCase* eclipseCase, int borderCellValue = -1 );
int findMaxOperNumValue( RimEclipseCase* eclipseCase );
} // namespace RigEclipseResultTools } // namespace RigEclipseResultTools
@@ -25,6 +25,7 @@
#include "RimEclipseResultCase.h" #include "RimEclipseResultCase.h"
#include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h" #include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h" #include "RigEclipseCaseData.h"
#include "RigEclipseCaseDataTools.h" #include "RigEclipseCaseDataTools.h"
@@ -496,3 +497,148 @@ TEST( RigEclipseCaseDataToolsTest, GenerateBorderResultFromIjkBounds )
int totalCells = invisibleCells + borderCells + interiorCells; int totalCells = invisibleCells + borderCells + interiorCells;
ASSERT_EQ( totalCells, static_cast<int>( resultVector.size() ) ) << "Total should match result vector size"; ASSERT_EQ( totalCells, static_cast<int>( resultVector.size() ) ) << "Total should match result vector size";
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RigEclipseCaseDataToolsTest, GenerateOperNumResultFromBorderResult )
{
// Load the BRUGGE test model using RifReaderEclipseOutput
QDir baseFolder( TEST_MODEL_DIR );
bool subFolderExists = baseFolder.cd( "Case_with_10_timesteps/Real0" );
ASSERT_TRUE( subFolderExists ) << "Could not find test model directory";
QString filename( "BRUGGE_0000.EGRID" );
QString filePath = baseFolder.absoluteFilePath( filename );
ASSERT_TRUE( QFile::exists( filePath ) ) << "BRUGGE test model file does not exist: " << filePath.toStdString();
std::unique_ptr<RimEclipseResultCase> resultCase( new RimEclipseResultCase );
cvf::ref<RigEclipseCaseData> eclipseCase = new RigEclipseCaseData( resultCase.get() );
cvf::ref<RifReaderEclipseOutput> readerInterfaceEcl = new RifReaderEclipseOutput;
bool success = readerInterfaceEcl->open( filePath, eclipseCase.p() );
ASSERT_TRUE( success ) << "Could not load BRUGGE test model";
resultCase->setReservoirData( eclipseCase.p() );
// Define IJK bounds for testing
cvf::Vec3st minIjk( 20, 20, 5 );
cvf::Vec3st maxIjk( 30, 30, 8 );
// Create visibility from IJK bounds
auto visibility = RigEclipseCaseDataTools::createVisibilityFromIjkBounds( eclipseCase.p(), minIjk, maxIjk );
ASSERT_FALSE( visibility.isNull() ) << "Visibility should be created successfully";
// Generate border result first (required for OPERNUM generation)
RigEclipseResultTools::generateBorderResult( resultCase.get(), visibility, "BORDNUM" );
// Verify BORDNUM was created
auto resultsData = resultCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
ASSERT_NE( resultsData, nullptr ) << "Results data should not be null";
RigEclipseResultAddress bordnumAddress( RiaDefines::ResultCatType::GENERATED, RiaDefines::ResultDataType::INTEGER, "BORDNUM" );
ASSERT_TRUE( resultsData->hasResultEntry( bordnumAddress ) ) << "BORDNUM result should exist";
// Test case 1: Generate OPERNUM with automatic border cell value (no existing OPERNUM, should get 1)
RigEclipseResultTools::generateOperNumResult( resultCase.get() );
// Verify OPERNUM was created
RigEclipseResultAddress opernumAddress( RiaDefines::ResultCatType::GENERATED, RiaDefines::ResultDataType::INTEGER, "OPERNUM" );
ASSERT_TRUE( resultsData->hasResultEntry( opernumAddress ) ) << "OPERNUM result should exist";
// Get the result data
const std::vector<double>& bordnumVector = resultsData->cellScalarResults( bordnumAddress, 0 );
const std::vector<double>& opernumVector = resultsData->cellScalarResults( opernumAddress, 0 );
ASSERT_EQ( bordnumVector.size(), opernumVector.size() ) << "BORDNUM and OPERNUM should have same size";
ASSERT_GT( opernumVector.size(), 0 ) << "OPERNUM vector should not be empty";
// Count cells with different values and verify the logic
int borderCellsWithOperValue = 0; // BORDNUM=1 cells that should get OPERNUM=1 (max 0 + 1)
int defaultOperCells = 0; // BORDNUM!=1 cells that should get OPERNUM=0
int borderCellsTotal = 0; // Total BORDNUM=1 cells
for ( size_t i = 0; i < bordnumVector.size(); ++i )
{
int bordnumValue = static_cast<int>( bordnumVector[i] );
int opernumValue = static_cast<int>( opernumVector[i] );
if ( bordnumValue == RigEclipseResultTools::BorderType::BORDER_CELL )
{
borderCellsTotal++;
ASSERT_EQ( opernumValue, 1 ) << "Border cells (BORDNUM=1) should have OPERNUM=1 at index " << i;
borderCellsWithOperValue++;
}
else
{
ASSERT_EQ( opernumValue, 0 ) << "Non-border cells should have OPERNUM=0 at index " << i;
defaultOperCells++;
}
}
// Verify we have the expected distribution
ASSERT_GT( borderCellsTotal, 0 ) << "Should have border cells (BORDNUM=1)";
ASSERT_EQ( borderCellsWithOperValue, borderCellsTotal ) << "All border cells should get OPERNUM=1";
ASSERT_GT( defaultOperCells, 0 ) << "Should have non-border cells with OPERNUM=0";
// Test case 2: Test automatic max value detection with existing OPERNUM
// First create a custom OPERNUM result with some predefined values
auto activeReservoirCellIdxs = eclipseCase->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL )->activeReservoirCellIndices();
int numActiveCells = static_cast<int>( activeReservoirCellIdxs.size() );
std::vector<int> customOperValues;
customOperValues.resize( numActiveCells, 5 ); // Set all to 5 initially
// Add some higher values to test max detection
if ( numActiveCells > 10 )
{
customOperValues[5] = 15; // Maximum will be 15
customOperValues[8] = 12;
}
// Create the OPERNUM result directly
RigEclipseResultTools::createResultVector( *resultCase, "OPERNUM", customOperValues );
// Test case 3: Test the utility function directly (before regeneration)
int maxOperValue = RigEclipseResultTools::findMaxOperNumValue( resultCase.get() );
ASSERT_EQ( maxOperValue, 15 ) << "Max OPERNUM value should be 15";
// Now generate OPERNUM again - should use max value + 1 = 16 for border cells
RigEclipseResultTools::generateOperNumResult( resultCase.get() );
// Get updated result
const std::vector<double>& updatedOpernumVector = resultsData->cellScalarResults( opernumAddress, 0 );
// Verify the behavior
int preservedValues = 0;
int modifiedValues = 0;
for ( size_t i = 0; i < bordnumVector.size(); ++i )
{
int bordnumValue = static_cast<int>( bordnumVector[i] );
int opernumValue = static_cast<int>( updatedOpernumVector[i] );
if ( bordnumValue == RigEclipseResultTools::BorderType::BORDER_CELL )
{
ASSERT_EQ( opernumValue, 16 ) << "Border cells should be updated to OPERNUM=16 (max 15 + 1) at index " << i;
modifiedValues++;
}
else
{
// Non-border cells should preserve their original values
if ( numActiveCells > 10 && i == 5 )
ASSERT_EQ( opernumValue, 15 ) << "Non-border cells should preserve original max value at index " << i;
else if ( numActiveCells > 10 && i == 8 )
ASSERT_EQ( opernumValue, 12 ) << "Non-border cells should preserve original value at index " << i;
else
ASSERT_EQ( opernumValue, 5 ) << "Non-border cells should preserve original value at index " << i;
preservedValues++;
}
}
ASSERT_GT( modifiedValues, 0 ) << "Should have modified some border cells";
ASSERT_GT( preservedValues, 0 ) << "Should have preserved some non-border cells";
// Total should match vector size
int totalChecked = modifiedValues + preservedValues;
ASSERT_EQ( totalChecked, static_cast<int>( updatedOpernumVector.size() ) ) << "Should check all cells";
}