From 3150d5df169d2336149302d72284a3018ac99161 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Fri, 12 Sep 2025 16:51:24 +0200 Subject: [PATCH] #12900 Add method for padding ijk bounding box. --- .../RigEclipseCaseDataTools.cpp | 25 +++++ .../RigEclipseCaseDataTools.h | 9 +- .../RigEclipseCaseDataTools-Test.cpp | 93 +++++++++++++++++++ 3 files changed, 124 insertions(+), 3 deletions(-) diff --git a/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseDataTools.cpp b/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseDataTools.cpp index 0d43b6f4b9..8a9e3db426 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseDataTools.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseDataTools.cpp @@ -174,3 +174,28 @@ std::pair RigEclipseCaseDataTools::wellsBoundingBoxIjk return { globalMin, globalMax }; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RigEclipseCaseDataTools::expandBoundingBoxIjk( RigEclipseCaseData* eclipseCaseData, + const cvf::Vec3st& minIjk, + const cvf::Vec3st& maxIjk, + size_t numPadding ) +{ + if ( !eclipseCaseData || minIjk.isUndefined() || maxIjk.isUndefined() ) return { cvf::Vec3st::UNDEFINED, cvf::Vec3st::UNDEFINED }; + + auto mainGrid = eclipseCaseData->mainGrid(); + if ( !mainGrid ) return { cvf::Vec3st::UNDEFINED, cvf::Vec3st::UNDEFINED }; + + // Calculate expanded bounds with padding, ensuring we stay within grid bounds + size_t expandedMinI = ( minIjk.x() >= numPadding ) ? ( minIjk.x() - numPadding ) : 0; + size_t expandedMinJ = ( minIjk.y() >= numPadding ) ? ( minIjk.y() - numPadding ) : 0; + size_t expandedMinK = ( minIjk.z() >= numPadding ) ? ( minIjk.z() - numPadding ) : 0; + + size_t expandedMaxI = std::min( maxIjk.x() + numPadding, mainGrid->cellCountI() - 1 ); + size_t expandedMaxJ = std::min( maxIjk.y() + numPadding, mainGrid->cellCountJ() - 1 ); + size_t expandedMaxK = std::min( maxIjk.z() + numPadding, mainGrid->cellCountK() - 1 ); + + return { cvf::Vec3st( expandedMinI, expandedMinJ, expandedMinK ), cvf::Vec3st( expandedMaxI, expandedMaxJ, expandedMaxK ) }; +} diff --git a/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseDataTools.h b/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseDataTools.h index 616ea97f25..93441d2261 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseDataTools.h +++ b/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseDataTools.h @@ -50,7 +50,10 @@ public: static std::pair wellsBoundingBoxIjk( RigEclipseCaseData* eclipseCaseData, const std::vector& simWells, - int timeStepIndex, - bool isAutoDetectingBranches, - bool isUsingCellCenterForPipe ); + int timeStepIndex, + bool isAutoDetectingBranches, + bool isUsingCellCenterForPipe ); + + static std::pair + expandBoundingBoxIjk( RigEclipseCaseData* eclipseCaseData, const cvf::Vec3st& minIjk, const cvf::Vec3st& maxIjk, size_t numPadding ); }; diff --git a/ApplicationLibCode/UnitTests/RigEclipseCaseDataTools-Test.cpp b/ApplicationLibCode/UnitTests/RigEclipseCaseDataTools-Test.cpp index c46fb63bfb..aa955689f9 100644 --- a/ApplicationLibCode/UnitTests/RigEclipseCaseDataTools-Test.cpp +++ b/ApplicationLibCode/UnitTests/RigEclipseCaseDataTools-Test.cpp @@ -197,3 +197,96 @@ TEST( RigEclipseCaseDataToolsTest, MultipleWellsBoundingBoxWithBruggeModel ) ASSERT_LE( minIjk.y(), maxIjk.y() ) << "Min J should be <= Max J"; ASSERT_LE( minIjk.z(), maxIjk.z() ) << "Min K should be <= Max K"; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( RigEclipseCaseDataToolsTest, ExpandBoundingBoxIjkWithPadding ) +{ + // 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 resultCase( new RimEclipseResultCase ); + cvf::ref eclipseCase = new RigEclipseCaseData( resultCase.get() ); + + cvf::ref readerInterfaceEcl = new RifReaderEclipseOutput; + bool success = readerInterfaceEcl->open( filePath, eclipseCase.p() ); + ASSERT_TRUE( success ) << "Could not load BRUGGE test model"; + + eclipseCase->mainGrid()->computeCachedData(); + + // Get grid dimensions for boundary testing + auto mainGrid = eclipseCase->mainGrid(); + size_t gridCellCountI = mainGrid->cellCountI(); + size_t gridCellCountJ = mainGrid->cellCountJ(); + size_t gridCellCountK = mainGrid->cellCountK(); + + // Test case 1: Normal expansion with padding (using safe values that won't hit grid boundaries) + cvf::Vec3st originalMin( 20, 20, 3 ); + cvf::Vec3st originalMax( 22, 22, 4 ); + size_t padding = 3; + + auto [expandedMin1, expandedMax1] = RigEclipseCaseDataTools::expandBoundingBoxIjk( eclipseCase.p(), originalMin, originalMax, padding ); + + ASSERT_NE( expandedMin1, cvf::Vec3st::UNDEFINED ) << "Expanded min should be valid"; + ASSERT_NE( expandedMax1, cvf::Vec3st::UNDEFINED ) << "Expanded max should be valid"; + + // Check expansion worked correctly (these values should not hit grid boundaries) + ASSERT_EQ( expandedMin1.x(), originalMin.x() - padding ) << "Min I should be reduced by padding"; + ASSERT_EQ( expandedMin1.y(), originalMin.y() - padding ) << "Min J should be reduced by padding"; + ASSERT_EQ( expandedMin1.z(), originalMin.z() - padding ) << "Min K should be reduced by padding"; + + ASSERT_EQ( expandedMax1.x(), originalMax.x() + padding ) << "Max I should be increased by padding"; + ASSERT_EQ( expandedMax1.y(), originalMax.y() + padding ) << "Max J should be increased by padding"; + ASSERT_EQ( expandedMax1.z(), originalMax.z() + padding ) << "Max K should be increased by padding"; + + // Test case 2: Expansion at grid boundary - ensure min never goes below 0 + cvf::Vec3st boundaryMin( 1, 1, 1 ); + cvf::Vec3st boundaryMax( 3, 3, 3 ); + size_t largePadding = 5; + + auto [expandedMin2, expandedMax2] = + RigEclipseCaseDataTools::expandBoundingBoxIjk( eclipseCase.p(), boundaryMin, boundaryMax, largePadding ); + + ASSERT_NE( expandedMin2, cvf::Vec3st::UNDEFINED ) << "Boundary expanded min should be valid"; + ASSERT_NE( expandedMax2, cvf::Vec3st::UNDEFINED ) << "Boundary expanded max should be valid"; + + // Ensure min coordinates never go negative (should be clamped to 0) + ASSERT_EQ( expandedMin2.x(), 0 ) << "Min I should be clamped to 0"; + ASSERT_EQ( expandedMin2.y(), 0 ) << "Min J should be clamped to 0"; + ASSERT_EQ( expandedMin2.z(), 0 ) << "Min K should be clamped to 0"; + + // Test case 3: Expansion at grid upper boundary - ensure max never exceeds grid dimensions + cvf::Vec3st upperBoundaryMin( gridCellCountI - 3, gridCellCountJ - 3, gridCellCountK - 3 ); + cvf::Vec3st upperBoundaryMax( gridCellCountI - 1, gridCellCountJ - 1, gridCellCountK - 1 ); + + auto [expandedMin3, expandedMax3] = + RigEclipseCaseDataTools::expandBoundingBoxIjk( eclipseCase.p(), upperBoundaryMin, upperBoundaryMax, largePadding ); + + ASSERT_NE( expandedMin3, cvf::Vec3st::UNDEFINED ) << "Upper boundary expanded min should be valid"; + ASSERT_NE( expandedMax3, cvf::Vec3st::UNDEFINED ) << "Upper boundary expanded max should be valid"; + + // Ensure max coordinates never exceed grid dimensions (should be clamped to grid size - 1) + ASSERT_EQ( expandedMax3.x(), gridCellCountI - 1 ) << "Max I should be clamped to grid size - 1"; + ASSERT_EQ( expandedMax3.y(), gridCellCountJ - 1 ) << "Max J should be clamped to grid size - 1"; + ASSERT_EQ( expandedMax3.z(), gridCellCountK - 1 ) << "Max K should be clamped to grid size - 1"; + + // General sanity checks for all test cases + ASSERT_LE( expandedMin1.x(), expandedMax1.x() ) << "Expanded Min I should be <= Max I"; + ASSERT_LE( expandedMin1.y(), expandedMax1.y() ) << "Expanded Min J should be <= Max J"; + ASSERT_LE( expandedMin1.z(), expandedMax1.z() ) << "Expanded Min K should be <= Max K"; + + ASSERT_LE( expandedMin2.x(), expandedMax2.x() ) << "Boundary expanded Min I should be <= Max I"; + ASSERT_LE( expandedMin2.y(), expandedMax2.y() ) << "Boundary expanded Min J should be <= Max J"; + ASSERT_LE( expandedMin2.z(), expandedMax2.z() ) << "Boundary expanded Min K should be <= Max K"; + + ASSERT_LE( expandedMin3.x(), expandedMax3.x() ) << "Upper boundary expanded Min I should be <= Max I"; + ASSERT_LE( expandedMin3.y(), expandedMax3.y() ) << "Upper boundary expanded Min J should be <= Max J"; + ASSERT_LE( expandedMin3.z(), expandedMax3.z() ) << "Upper boundary expanded Min K should be <= Max K"; +}