mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-25 22:50:25 -05:00
#13411 Sector Model Export: unify BOX/ENDBOX processing into single pass
Replace 7 separate deck iterations (cropDataKeywordsInsideBoxContext, expandBoxContextInDeckFile, and 5 replace*KeywordIndices wrappers) with a single transformKeywordsInDeckFile function that tracks BOX/ENDBOX state once and handles all keyword types as they are encountered.
This commit is contained in:
1 parent
fce37b8fdb
commit
539eec6cc5
3 files changed
+196
-250
No files matched your search
@@ -101,8 +101,6 @@ std::expected<void, QString> RigSimulationInputTool::exportSimulationInput( RimE
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
cropDataKeywordsInsideBoxContext( deckFile, settings.min(), settings.max(), settings.refinement() );
|
|
||||||
|
|
||||||
auto croppedKeywords = cropDataKeywordsInDeckFile( &eclipseCase, settings, deckFile );
|
auto croppedKeywords = cropDataKeywordsInDeckFile( &eclipseCase, settings, deckFile );
|
||||||
|
|
||||||
if ( auto result = replaceKeywordValuesInDeckFile( &eclipseCase, settings, deckFile, croppedKeywords ); !result )
|
if ( auto result = replaceKeywordValuesInDeckFile( &eclipseCase, settings, deckFile, croppedKeywords ); !result )
|
||||||
@@ -110,31 +108,9 @@ std::expected<void, QString> RigSimulationInputTool::exportSimulationInput( RimE
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pre-process BOX/ENDBOX context: inject BOX indices into EQUALS/COPY/ADD/MULTIPLY records
|
// Single-pass BOX/ENDBOX processing: crop data keywords, inject+transform EQUALS/COPY/ADD/MULTIPLY,
|
||||||
// that don't have explicit box indices, so they get properly transformed by subsequent steps.
|
// and transform BOX coordinates, all while tracking BOX/ENDBOX state.
|
||||||
expandBoxContextInDeckFile( deckFile );
|
if ( auto result = transformKeywordsInDeckFile( &eclipseCase, settings, deckFile ); !result )
|
||||||
|
|
||||||
if ( auto result = replaceEqualsKeywordIndices( &eclipseCase, settings, deckFile ); !result )
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( auto result = replaceCopyKeywordIndices( &eclipseCase, settings, deckFile ); !result )
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( auto result = replaceMultiplyKeywordIndices( &eclipseCase, settings, deckFile ); !result )
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( auto result = replaceAddKeywordIndices( &eclipseCase, settings, deckFile ); !result )
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( auto result = replaceBoxKeywordIndices( &eclipseCase, settings, deckFile ); !result )
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -602,19 +578,47 @@ static std::array<int, 6> extractBoxIndicesFromRecord( const Opm::DeckRecord& re
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
/// Pre-processing step: expand BOX context into EQUALS/COPY/ADD/MULTIPLY records.
|
/// Single-pass BOX/ENDBOX processing: tracks BOX/ENDBOX state and handles all keyword types
|
||||||
/// For keywords inside a BOX/ENDBOX block, records without explicit box indices
|
/// in one iteration. Crops data keywords to sector/box intersection, injects BOX indices into
|
||||||
/// get the active BOX indices injected. This ensures all records have explicit
|
/// EQUALS/COPY/ADD/MULTIPLY records and transforms their coordinates, and transforms BOX
|
||||||
/// indices before the individual keyword processing transforms them.
|
/// coordinates. Replaces the previous multi-pass approach (expandBoxContextInDeckFile +
|
||||||
|
/// cropDataKeywordsInsideBoxContext + replace*KeywordIndices).
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
void RigSimulationInputTool::expandBoxContextInDeckFile( RifOpmFlowDeckFile& deckFile )
|
std::expected<void, QString> RigSimulationInputTool::transformKeywordsInDeckFile( RimEclipseCase* eclipseCase,
|
||||||
|
const RigSimulationInputSettings& settings,
|
||||||
|
RifOpmFlowDeckFile& deckFile )
|
||||||
{
|
{
|
||||||
Opm::FileDeck* fd = deckFile.fileDeck();
|
Opm::FileDeck* fd = deckFile.fileDeck();
|
||||||
if ( !fd ) return {};
|
if ( !fd ) return {};
|
||||||
|
|
||||||
bool insideBox = false;
|
const auto sectorMin = settings.min();
|
||||||
std::array<int, 6> activeBoxIndices{};
|
const auto sectorMax = settings.max();
|
||||||
const std::set<std::string> affectedKeywords = { "EQUALS", "COPY", "ADD", "MULTIPLY" };
|
const auto refinement = settings.refinement();
|
||||||
|
|
||||||
|
// Map keyword names to their record processor functions
|
||||||
|
const std::map<std::string, RecordProcessorFunc> recordProcessors = {
|
||||||
|
{ "EQUALS", processEqualsRecord },
|
||||||
|
{ "COPY", processCopyRecord },
|
||||||
|
{ "ADD", processAddRecord },
|
||||||
|
{ "MULTIPLY", processMultiplyRecord },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Modification
|
||||||
|
{
|
||||||
|
Opm::FileDeck::Index index;
|
||||||
|
enum Action
|
||||||
|
{
|
||||||
|
Replace,
|
||||||
|
Remove
|
||||||
|
} action;
|
||||||
|
Opm::DeckKeyword replacement;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool insideBox = false;
|
||||||
|
std::array<int, 6> activeBoxIndices{};
|
||||||
|
caf::VecIjk0 boxMin( 0, 0, 0 );
|
||||||
|
caf::VecIjk0 boxMax( 0, 0, 0 );
|
||||||
|
std::vector<Modification> modifications;
|
||||||
|
|
||||||
for ( auto it = fd->start(); it != fd->stop(); it++ )
|
for ( auto it = fd->start(); it != fd->stop(); it++ )
|
||||||
{
|
{
|
||||||
@@ -628,6 +632,7 @@ void RigSimulationInputTool::expandBoxContextInDeckFile( RifOpmFlowDeckFile& dec
|
|||||||
RiaLogging::warning( "BOX keyword found while already inside a BOX context. Previous BOX will be overridden." );
|
RiaLogging::warning( "BOX keyword found while already inside a BOX context. Previous BOX will be overridden." );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insideBox = true;
|
||||||
if ( kw.size() > 0 )
|
if ( kw.size() > 0 )
|
||||||
{
|
{
|
||||||
const auto& rec = kw.getRecord( 0 );
|
const auto& rec = kw.getRecord( 0 );
|
||||||
@@ -639,9 +644,36 @@ void RigSimulationInputTool::expandBoxContextInDeckFile( RifOpmFlowDeckFile& dec
|
|||||||
rec.getItem( 3 ).get<int>( 0 ),
|
rec.getItem( 3 ).get<int>( 0 ),
|
||||||
rec.getItem( 4 ).get<int>( 0 ),
|
rec.getItem( 4 ).get<int>( 0 ),
|
||||||
rec.getItem( 5 ).get<int>( 0 ) };
|
rec.getItem( 5 ).get<int>( 0 ) };
|
||||||
insideBox = true;
|
|
||||||
|
// BOX items: I1, I2, J1, J2, K1, K2 (1-based) -> 0-based for data keyword cropping
|
||||||
|
boxMin = caf::VecIjk0( activeBoxIndices[0] - 1, activeBoxIndices[2] - 1, activeBoxIndices[4] - 1 );
|
||||||
|
boxMax = caf::VecIjk0( activeBoxIndices[1] - 1, activeBoxIndices[3] - 1, activeBoxIndices[5] - 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transform BOX coordinates via processBoxRecord
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if ( kw.size() > 0 )
|
||||||
|
{
|
||||||
|
auto result = processBoxRecord( kw.getRecord( 0 ), sectorMin, sectorMax, refinement );
|
||||||
|
if ( result )
|
||||||
|
{
|
||||||
|
Opm::DeckKeyword transformedKw( kw.location(), kw.name() );
|
||||||
|
transformedKw.addRecord( std::move( result.value() ) );
|
||||||
|
modifications.push_back( { it, Modification::Replace, std::move( transformedKw ) } );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
modifications.push_back( { it, Modification::Remove, Opm::DeckKeyword{} } );
|
||||||
|
RiaLogging::warning( QString( "Failed to process BOX record: %1" ).arg( result.error() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( std::exception& e )
|
||||||
|
{
|
||||||
|
return std::unexpected( QString( "Exception processing BOX keyword: %1" ).arg( e.what() ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ( name == "ENDBOX" )
|
else if ( name == "ENDBOX" )
|
||||||
{
|
{
|
||||||
@@ -651,110 +683,9 @@ void RigSimulationInputTool::expandBoxContextInDeckFile( RifOpmFlowDeckFile& dec
|
|||||||
}
|
}
|
||||||
insideBox = false;
|
insideBox = false;
|
||||||
}
|
}
|
||||||
else if ( insideBox && affectedKeywords.count( name ) )
|
|
||||||
{
|
|
||||||
// Check if any record in this keyword needs expansion
|
|
||||||
bool needsExpansion = false;
|
|
||||||
for ( size_t r = 0; r < kw.size(); ++r )
|
|
||||||
{
|
|
||||||
if ( !recordHasExplicitBoxIndices( kw.getRecord( r ) ) )
|
|
||||||
{
|
|
||||||
needsExpansion = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( needsExpansion )
|
|
||||||
{
|
|
||||||
Opm::DeckKeyword expandedKw( kw.location(), kw.name() );
|
|
||||||
|
|
||||||
// Track "current operation box" - starts with active BOX indices
|
|
||||||
std::array<int, 6> currentOpBox = activeBoxIndices;
|
|
||||||
|
|
||||||
for ( size_t r = 0; r < kw.size(); ++r )
|
|
||||||
{
|
|
||||||
const auto& rec = kw.getRecord( r );
|
|
||||||
if ( recordHasExplicitBoxIndices( rec ) )
|
|
||||||
{
|
|
||||||
// Update current operation box from this record's explicit indices
|
|
||||||
currentOpBox = extractBoxIndicesFromRecord( rec );
|
|
||||||
Opm::DeckRecord copy( rec );
|
|
||||||
expandedKw.addRecord( std::move( copy ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Inject current operation box indices into this record
|
|
||||||
expandedKw.addRecord( injectBoxIndicesIntoRecord( rec, currentOpBox ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deckFile.replaceKeywordAtIndex( it, expandedKw );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( insideBox )
|
|
||||||
{
|
|
||||||
RiaLogging::warning( "BOX keyword found without a matching ENDBOX at end of deck." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
/// Crop data keywords (PORO, EQLNUM, PERMX, etc.) inside BOX/ENDBOX blocks to the intersection
|
|
||||||
/// of the BOX region with the sector. If the box does not intersect the sector, the data keyword
|
|
||||||
/// is removed. This preserves the BOX/ENDBOX structure in the output while ensuring data sizes
|
|
||||||
/// match the transformed box dimensions.
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
void RigSimulationInputTool::cropDataKeywordsInsideBoxContext( RifOpmFlowDeckFile& deckFile,
|
|
||||||
const caf::VecIjk0& sectorMin,
|
|
||||||
const caf::VecIjk0& sectorMax,
|
|
||||||
const cvf::Vec3st& refinement )
|
|
||||||
{
|
|
||||||
Opm::FileDeck* fd = deckFile.fileDeck();
|
|
||||||
if ( !fd ) return;
|
|
||||||
|
|
||||||
struct Modification
|
|
||||||
{
|
|
||||||
Opm::FileDeck::Index index;
|
|
||||||
bool remove = false;
|
|
||||||
Opm::DeckKeyword replacement;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool insideBox = false;
|
|
||||||
caf::VecIjk0 boxMin( 0, 0, 0 );
|
|
||||||
caf::VecIjk0 boxMax( 0, 0, 0 );
|
|
||||||
std::vector<Modification> modifications;
|
|
||||||
|
|
||||||
for ( auto it = fd->start(); it != fd->stop(); it++ )
|
|
||||||
{
|
|
||||||
const auto& kw = ( *fd )[it];
|
|
||||||
const std::string& name = kw.name();
|
|
||||||
|
|
||||||
if ( name == "BOX" )
|
|
||||||
{
|
|
||||||
insideBox = true;
|
|
||||||
if ( kw.size() > 0 )
|
|
||||||
{
|
|
||||||
const auto& rec = kw.getRecord( 0 );
|
|
||||||
if ( rec.size() >= 6 )
|
|
||||||
{
|
|
||||||
// BOX items: I1, I2, J1, J2, K1, K2 (1-based)
|
|
||||||
boxMin = caf::VecIjk0( rec.getItem( 0 ).get<int>( 0 ) - 1,
|
|
||||||
rec.getItem( 2 ).get<int>( 0 ) - 1,
|
|
||||||
rec.getItem( 4 ).get<int>( 0 ) - 1 );
|
|
||||||
boxMax = caf::VecIjk0( rec.getItem( 1 ).get<int>( 0 ) - 1,
|
|
||||||
rec.getItem( 3 ).get<int>( 0 ) - 1,
|
|
||||||
rec.getItem( 5 ).get<int>( 0 ) - 1 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( name == "ENDBOX" )
|
|
||||||
{
|
|
||||||
insideBox = false;
|
|
||||||
}
|
|
||||||
else if ( insideBox && kw.isDataKeyword() )
|
else if ( insideBox && kw.isDataKeyword() )
|
||||||
{
|
{
|
||||||
// Compute intersection of box with sector (0-based, inclusive)
|
// Crop data keyword to sector/box intersection
|
||||||
caf::VecIjk0 intMin( std::max( boxMin.x(), sectorMin.x() ),
|
caf::VecIjk0 intMin( std::max( boxMin.x(), sectorMin.x() ),
|
||||||
std::max( boxMin.y(), sectorMin.y() ),
|
std::max( boxMin.y(), sectorMin.y() ),
|
||||||
std::max( boxMin.z(), sectorMin.z() ) );
|
std::max( boxMin.z(), sectorMin.z() ) );
|
||||||
@@ -764,8 +695,7 @@ void RigSimulationInputTool::cropDataKeywordsInsideBoxContext( RifOpmFlowDeckFil
|
|||||||
|
|
||||||
if ( intMin.x() > intMax.x() || intMin.y() > intMax.y() || intMin.z() > intMax.z() )
|
if ( intMin.x() > intMax.x() || intMin.y() > intMax.y() || intMin.z() > intMax.z() )
|
||||||
{
|
{
|
||||||
// No intersection - remove the data keyword
|
modifications.push_back( { it, Modification::Remove, Opm::DeckKeyword{} } );
|
||||||
modifications.push_back( { it, true, Opm::DeckKeyword{} } );
|
|
||||||
RiaLogging::info( QString( "Removing data keyword '%1' inside BOX/ENDBOX: box does not intersect sector" )
|
RiaLogging::info( QString( "Removing data keyword '%1' inside BOX/ENDBOX: box does not intersect sector" )
|
||||||
.arg( QString::fromStdString( name ) ) );
|
.arg( QString::fromStdString( name ) ) );
|
||||||
continue;
|
continue;
|
||||||
@@ -775,7 +705,6 @@ void RigSimulationInputTool::cropDataKeywordsInsideBoxContext( RifOpmFlowDeckFil
|
|||||||
|
|
||||||
const auto& item = kw.getRecord( 0 ).getItem( 0 );
|
const auto& item = kw.getRecord( 0 ).getItem( 0 );
|
||||||
|
|
||||||
// Box dimensions (source grid for the data)
|
|
||||||
const size_t boxNi = boxMax.x() - boxMin.x() + 1;
|
const size_t boxNi = boxMax.x() - boxMin.x() + 1;
|
||||||
const size_t boxNj = boxMax.y() - boxMin.y() + 1;
|
const size_t boxNj = boxMax.y() - boxMin.y() + 1;
|
||||||
|
|
||||||
@@ -783,7 +712,6 @@ void RigSimulationInputTool::cropDataKeywordsInsideBoxContext( RifOpmFlowDeckFil
|
|||||||
{
|
{
|
||||||
std::vector<T> croppedData;
|
std::vector<T> croppedData;
|
||||||
|
|
||||||
// Iterate over refined intersection cells
|
|
||||||
for ( size_t k = intMin.z(); k <= static_cast<size_t>( intMax.z() ); ++k )
|
for ( size_t k = intMin.z(); k <= static_cast<size_t>( intMax.z() ); ++k )
|
||||||
{
|
{
|
||||||
for ( size_t rk = 0; rk < refinement.z(); ++rk )
|
for ( size_t rk = 0; rk < refinement.z(); ++rk )
|
||||||
@@ -794,11 +722,10 @@ void RigSimulationInputTool::cropDataKeywordsInsideBoxContext( RifOpmFlowDeckFil
|
|||||||
{
|
{
|
||||||
for ( size_t i = intMin.x(); i <= static_cast<size_t>( intMax.x() ); ++i )
|
for ( size_t i = intMin.x(); i <= static_cast<size_t>( intMax.x() ); ++i )
|
||||||
{
|
{
|
||||||
// Box-relative indices
|
size_t boxRelI = i - boxMin.x();
|
||||||
size_t boxRelI = i - boxMin.x();
|
size_t boxRelJ = j - boxMin.y();
|
||||||
size_t boxRelJ = j - boxMin.y();
|
size_t boxRelK = k - boxMin.z();
|
||||||
size_t boxRelK = k - boxMin.z();
|
size_t srcIdx = boxRelI + boxRelJ * boxNi + boxRelK * boxNi * boxNj;
|
||||||
size_t srcIdx = boxRelI + boxRelJ * boxNi + boxRelK * boxNi * boxNj;
|
|
||||||
|
|
||||||
for ( size_t ri = 0; ri < refinement.x(); ++ri )
|
for ( size_t ri = 0; ri < refinement.x(); ++ri )
|
||||||
{
|
{
|
||||||
@@ -810,7 +737,6 @@ void RigSimulationInputTool::cropDataKeywordsInsideBoxContext( RifOpmFlowDeckFil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build replacement keyword
|
|
||||||
Opm::DeckKeyword newKw = kw.emptyStructuralCopy();
|
Opm::DeckKeyword newKw = kw.emptyStructuralCopy();
|
||||||
Opm::DeckRecord record;
|
Opm::DeckRecord record;
|
||||||
|
|
||||||
@@ -832,7 +758,7 @@ void RigSimulationInputTool::cropDataKeywordsInsideBoxContext( RifOpmFlowDeckFil
|
|||||||
}
|
}
|
||||||
|
|
||||||
newKw.addRecord( std::move( record ) );
|
newKw.addRecord( std::move( record ) );
|
||||||
modifications.push_back( { it, false, std::move( newKw ) } );
|
modifications.push_back( { it, Modification::Replace, std::move( newKw ) } );
|
||||||
|
|
||||||
RiaLogging::info( QString( "Cropped data keyword '%1' inside BOX/ENDBOX (%2 -> %3 values)" )
|
RiaLogging::info( QString( "Cropped data keyword '%1' inside BOX/ENDBOX (%2 -> %3 values)" )
|
||||||
.arg( QString::fromStdString( name ) )
|
.arg( QString::fromStdString( name ) )
|
||||||
@@ -849,18 +775,82 @@ void RigSimulationInputTool::cropDataKeywordsInsideBoxContext( RifOpmFlowDeckFil
|
|||||||
cropBoxData( kw.getRawDoubleData() );
|
cropBoxData( kw.getRawDoubleData() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ( auto procIt = recordProcessors.find( name ); procIt != recordProcessors.end() )
|
||||||
|
{
|
||||||
|
// EQUALS, COPY, ADD, MULTIPLY keyword
|
||||||
|
const auto& processorFunc = procIt->second;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Opm::DeckKeyword transformedKw( kw.location(), kw.name() );
|
||||||
|
|
||||||
|
// Track "current operation box" for records inside BOX context
|
||||||
|
std::array<int, 6> currentOpBox = activeBoxIndices;
|
||||||
|
|
||||||
|
for ( size_t r = 0; r < kw.size(); ++r )
|
||||||
|
{
|
||||||
|
const auto& rec = kw.getRecord( r );
|
||||||
|
|
||||||
|
Opm::DeckRecord recordToProcess = rec;
|
||||||
|
|
||||||
|
if ( insideBox )
|
||||||
|
{
|
||||||
|
// Inside BOX: inject box indices into records without explicit coords
|
||||||
|
if ( recordHasExplicitBoxIndices( rec ) )
|
||||||
|
{
|
||||||
|
currentOpBox = extractBoxIndicesFromRecord( rec );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
recordToProcess = injectBoxIndicesIntoRecord( rec, currentOpBox );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform the record
|
||||||
|
auto result = processorFunc( recordToProcess, sectorMin, sectorMax, refinement );
|
||||||
|
if ( result )
|
||||||
|
{
|
||||||
|
transformedKw.addRecord( std::move( result.value() ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RiaLogging::warning(
|
||||||
|
QString( "Failed to process %1 record: %2" ).arg( QString::fromStdString( name ) ).arg( result.error() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( transformedKw.size() > 0 )
|
||||||
|
{
|
||||||
|
modifications.push_back( { it, Modification::Replace, std::move( transformedKw ) } );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// All records failed - replace with SKIP
|
||||||
|
modifications.push_back( { it, Modification::Replace, Opm::DeckKeyword( kw.location(), "SKIP" ) } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( std::exception& e )
|
||||||
|
{
|
||||||
|
return std::unexpected( QString( "Exception processing %1 keyword: %2" ).arg( QString::fromStdString( name ) ).arg( e.what() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( insideBox )
|
||||||
|
{
|
||||||
|
RiaLogging::warning( "BOX keyword found without a matching ENDBOX at end of deck." );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply modifications in reverse order to maintain valid indices
|
// Apply modifications in reverse order to maintain valid indices
|
||||||
for ( auto it = modifications.rbegin(); it != modifications.rend(); ++it )
|
for ( auto modIt = modifications.rbegin(); modIt != modifications.rend(); ++modIt )
|
||||||
{
|
{
|
||||||
if ( it->remove )
|
if ( modIt->action == Modification::Remove )
|
||||||
{
|
{
|
||||||
deckFile.removeKeywordAtIndex( it->index );
|
deckFile.removeKeywordAtIndex( modIt->index );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
deckFile.replaceKeywordAtIndex( it->index, it->replacement );
|
deckFile.replaceKeywordAtIndex( modIt->index, modIt->replacement );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -929,46 +919,6 @@ std::expected<void, QString> RigSimulationInputTool::replaceKeywordWithBoxIndice
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
///
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
std::expected<void, QString> RigSimulationInputTool::replaceEqualsKeywordIndices( RimEclipseCase* eclipseCase,
|
|
||||||
const RigSimulationInputSettings& settings,
|
|
||||||
RifOpmFlowDeckFile& deckFile )
|
|
||||||
{
|
|
||||||
return replaceKeywordWithBoxIndices( "EQUALS", eclipseCase, settings, deckFile, processEqualsRecord );
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
///
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
std::expected<void, QString> RigSimulationInputTool::replaceMultiplyKeywordIndices( RimEclipseCase* eclipseCase,
|
|
||||||
const RigSimulationInputSettings& settings,
|
|
||||||
RifOpmFlowDeckFile& deckFile )
|
|
||||||
{
|
|
||||||
return replaceKeywordWithBoxIndices( "MULTIPLY", eclipseCase, settings, deckFile, processMultiplyRecord );
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
///
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
std::expected<void, QString> RigSimulationInputTool::replaceCopyKeywordIndices( RimEclipseCase* eclipseCase,
|
|
||||||
const RigSimulationInputSettings& settings,
|
|
||||||
RifOpmFlowDeckFile& deckFile )
|
|
||||||
{
|
|
||||||
return replaceKeywordWithBoxIndices( "COPY", eclipseCase, settings, deckFile, processCopyRecord );
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
///
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
std::expected<void, QString> RigSimulationInputTool::replaceAddKeywordIndices( RimEclipseCase* eclipseCase,
|
|
||||||
const RigSimulationInputSettings& settings,
|
|
||||||
RifOpmFlowDeckFile& deckFile )
|
|
||||||
{
|
|
||||||
return replaceKeywordWithBoxIndices( "ADD", eclipseCase, settings, deckFile, processAddRecord );
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -999,16 +949,6 @@ std::expected<void, QString> RigSimulationInputTool::replaceAqunumKeywordIndices
|
|||||||
return replaceKeywordWithBoxIndices( "AQUNUM", eclipseCase, settings, deckFile, processAqunumRecord );
|
return replaceKeywordWithBoxIndices( "AQUNUM", eclipseCase, settings, deckFile, processAqunumRecord );
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
///
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
std::expected<void, QString> RigSimulationInputTool::replaceBoxKeywordIndices( RimEclipseCase* eclipseCase,
|
|
||||||
const RigSimulationInputSettings& settings,
|
|
||||||
RifOpmFlowDeckFile& deckFile )
|
|
||||||
{
|
|
||||||
return replaceKeywordWithBoxIndices( "BOX", eclipseCase, settings, deckFile, processBoxRecord );
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <expected>
|
#include <expected>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -102,11 +103,8 @@ public:
|
|||||||
|
|
||||||
static std::vector<int> createRefinedVisibility( const RigGridExportAdapter& gridAdapter );
|
static std::vector<int> createRefinedVisibility( const RigGridExportAdapter& gridAdapter );
|
||||||
|
|
||||||
static void expandBoxContextInDeckFile( RifOpmFlowDeckFile& deckFile );
|
static std::expected<void, QString>
|
||||||
static void cropDataKeywordsInsideBoxContext( RifOpmFlowDeckFile& deckFile,
|
transformKeywordsInDeckFile( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings, RifOpmFlowDeckFile& deckFile );
|
||||||
const caf::VecIjk0& sectorMin,
|
|
||||||
const caf::VecIjk0& sectorMax,
|
|
||||||
const cvf::Vec3st& refinement );
|
|
||||||
|
|
||||||
// Public EDITNNC methods for testing
|
// Public EDITNNC methods for testing
|
||||||
static std::vector<NNCConnection> extractDeckEditNncConnections( RifOpmFlowDeckFile& deckFile, const RigMainGrid& mainGrid );
|
static std::vector<NNCConnection> extractDeckEditNncConnections( RifOpmFlowDeckFile& deckFile, const RigMainGrid& mainGrid );
|
||||||
@@ -144,21 +142,6 @@ private:
|
|||||||
cvf::ref<cvf::UByteArray> visibility,
|
cvf::ref<cvf::UByteArray> visibility,
|
||||||
RifOpmFlowDeckFile& deckFile );
|
RifOpmFlowDeckFile& deckFile );
|
||||||
|
|
||||||
static std::expected<void, QString>
|
|
||||||
replaceEqualsKeywordIndices( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings, RifOpmFlowDeckFile& deckFile );
|
|
||||||
|
|
||||||
static std::expected<void, QString>
|
|
||||||
replaceMultiplyKeywordIndices( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings, RifOpmFlowDeckFile& deckFile );
|
|
||||||
|
|
||||||
static std::expected<void, QString>
|
|
||||||
replaceBoxKeywordIndices( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings, RifOpmFlowDeckFile& deckFile );
|
|
||||||
|
|
||||||
static std::expected<void, QString>
|
|
||||||
replaceCopyKeywordIndices( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings, RifOpmFlowDeckFile& deckFile );
|
|
||||||
|
|
||||||
static std::expected<void, QString>
|
|
||||||
replaceAddKeywordIndices( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings, RifOpmFlowDeckFile& deckFile );
|
|
||||||
|
|
||||||
static std::expected<void, QString>
|
static std::expected<void, QString>
|
||||||
replaceAquconKeywordIndices( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings, RifOpmFlowDeckFile& deckFile );
|
replaceAquconKeywordIndices( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings, RifOpmFlowDeckFile& deckFile );
|
||||||
|
|
||||||
|
|||||||
@@ -1822,11 +1822,12 @@ TEST( RigSimulationInputTool, ProcessMultiplyRecord_WithBoxIndices )
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
/// Test expandBoxContextInDeckFile: EQUALS inside BOX/ENDBOX with no explicit indices
|
/// Test transformKeywordsInDeckFile: EQUALS inside BOX/ENDBOX with no explicit indices
|
||||||
|
/// gets BOX indices injected and then transformed to sector-relative coordinates.
|
||||||
|
/// Using sector covering the whole grid so transformed coords = original coords.
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
TEST( RigSimulationInputTool, ExpandBoxContext_EqualsInheritsBoxIndices )
|
TEST( RigSimulationInputTool, ExpandBoxContext_EqualsInheritsBoxIndices )
|
||||||
{
|
{
|
||||||
// Create a minimal DATA file with BOX/ENDBOX containing EQUALS without indices
|
|
||||||
QTemporaryDir tempDir;
|
QTemporaryDir tempDir;
|
||||||
ASSERT_TRUE( tempDir.isValid() );
|
ASSERT_TRUE( tempDir.isValid() );
|
||||||
|
|
||||||
@@ -1847,20 +1848,24 @@ TEST( RigSimulationInputTool, ExpandBoxContext_EqualsInheritsBoxIndices )
|
|||||||
auto loadResult = deckFile.loadDeck( dataFilePath.toStdString() );
|
auto loadResult = deckFile.loadDeck( dataFilePath.toStdString() );
|
||||||
ASSERT_TRUE( loadResult.has_value() ) << loadResult.error();
|
ASSERT_TRUE( loadResult.has_value() ) << loadResult.error();
|
||||||
|
|
||||||
// Verify EQUALS has no explicit box indices before expansion
|
// Verify EQUALS has no explicit box indices before transformation
|
||||||
auto equalsBeforeVec = deckFile.findAllKeywordsWithIndices( "EQUALS" );
|
auto equalsBeforeVec = deckFile.findAllKeywordsWithIndices( "EQUALS" );
|
||||||
ASSERT_EQ( 1u, equalsBeforeVec.size() );
|
ASSERT_EQ( 1u, equalsBeforeVec.size() );
|
||||||
ASSERT_EQ( 1u, equalsBeforeVec[0].second.size() );
|
ASSERT_EQ( 1u, equalsBeforeVec[0].second.size() );
|
||||||
// The record should have fewer than 8 items or items without values
|
const auto& recBefore = equalsBeforeVec[0].second.getRecord( 0 );
|
||||||
const auto& recBefore = equalsBeforeVec[0].second.getRecord( 0 );
|
bool hadExplicitBefore = recBefore.size() >= 8 && recBefore.getItem( 2 ).hasValue( 0 ) && recBefore.getItem( 3 ).hasValue( 0 ) &&
|
||||||
bool hadExplicitBefore =
|
recBefore.getItem( 4 ).hasValue( 0 ) && recBefore.getItem( 5 ).hasValue( 0 ) &&
|
||||||
recBefore.size() >= 8 && recBefore.getItem( 2 ).hasValue( 0 ) && recBefore.getItem( 3 ).hasValue( 0 ) &&
|
recBefore.getItem( 6 ).hasValue( 0 ) && recBefore.getItem( 7 ).hasValue( 0 );
|
||||||
recBefore.getItem( 4 ).hasValue( 0 ) && recBefore.getItem( 5 ).hasValue( 0 ) && recBefore.getItem( 6 ).hasValue( 0 ) &&
|
EXPECT_FALSE( hadExplicitBefore ) << "Record should not have explicit box indices before transformation";
|
||||||
recBefore.getItem( 7 ).hasValue( 0 );
|
|
||||||
EXPECT_FALSE( hadExplicitBefore ) << "Record should not have explicit box indices before expansion";
|
|
||||||
|
|
||||||
// Run expansion
|
// Sector covers entire grid: sectorMin=(0,0,0), sectorMax=(9,9,4), refinement=(1,1,1)
|
||||||
RigSimulationInputTool::expandBoxContextInDeckFile( deckFile );
|
// This makes coordinate transformation an identity operation
|
||||||
|
RigSimulationInputSettings settings;
|
||||||
|
settings.setMin( caf::VecIjk0( 0, 0, 0 ) );
|
||||||
|
settings.setMax( caf::VecIjk0( 9, 9, 4 ) );
|
||||||
|
settings.setRefinement( cvf::Vec3st( 1, 1, 1 ) );
|
||||||
|
|
||||||
|
RigSimulationInputTool::transformKeywordsInDeckFile( nullptr, settings, deckFile );
|
||||||
|
|
||||||
// Verify EQUALS now has explicit box indices matching the BOX keyword
|
// Verify EQUALS now has explicit box indices matching the BOX keyword
|
||||||
auto equalsAfterVec = deckFile.findAllKeywordsWithIndices( "EQUALS" );
|
auto equalsAfterVec = deckFile.findAllKeywordsWithIndices( "EQUALS" );
|
||||||
@@ -1879,7 +1884,8 @@ TEST( RigSimulationInputTool, ExpandBoxContext_EqualsInheritsBoxIndices )
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
/// Test expandBoxContextInDeckFile: records with explicit indices keep their own indices
|
/// Test transformKeywordsInDeckFile: records with explicit indices keep their own indices
|
||||||
|
/// (not overridden by BOX indices) and are transformed to sector-relative coordinates.
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
TEST( RigSimulationInputTool, ExpandBoxContext_ExplicitIndicesPreserved )
|
TEST( RigSimulationInputTool, ExpandBoxContext_ExplicitIndicesPreserved )
|
||||||
{
|
{
|
||||||
@@ -1903,7 +1909,13 @@ TEST( RigSimulationInputTool, ExpandBoxContext_ExplicitIndicesPreserved )
|
|||||||
auto loadResult = deckFile.loadDeck( dataFilePath.toStdString() );
|
auto loadResult = deckFile.loadDeck( dataFilePath.toStdString() );
|
||||||
ASSERT_TRUE( loadResult.has_value() ) << loadResult.error();
|
ASSERT_TRUE( loadResult.has_value() ) << loadResult.error();
|
||||||
|
|
||||||
RigSimulationInputTool::expandBoxContextInDeckFile( deckFile );
|
// Sector covers entire grid
|
||||||
|
RigSimulationInputSettings settings;
|
||||||
|
settings.setMin( caf::VecIjk0( 0, 0, 0 ) );
|
||||||
|
settings.setMax( caf::VecIjk0( 9, 9, 4 ) );
|
||||||
|
settings.setRefinement( cvf::Vec3st( 1, 1, 1 ) );
|
||||||
|
|
||||||
|
RigSimulationInputTool::transformKeywordsInDeckFile( nullptr, settings, deckFile );
|
||||||
|
|
||||||
auto equalsVec = deckFile.findAllKeywordsWithIndices( "EQUALS" );
|
auto equalsVec = deckFile.findAllKeywordsWithIndices( "EQUALS" );
|
||||||
ASSERT_EQ( 1u, equalsVec.size() );
|
ASSERT_EQ( 1u, equalsVec.size() );
|
||||||
@@ -1921,7 +1933,8 @@ TEST( RigSimulationInputTool, ExpandBoxContext_ExplicitIndicesPreserved )
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
/// Test expandBoxContextInDeckFile: keywords outside BOX context are not modified
|
/// Test transformKeywordsInDeckFile: EQUALS outside BOX context without explicit indices
|
||||||
|
/// passes through unchanged (no box indices injected).
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
TEST( RigSimulationInputTool, ExpandBoxContext_OutsideBoxNotModified )
|
TEST( RigSimulationInputTool, ExpandBoxContext_OutsideBoxNotModified )
|
||||||
{
|
{
|
||||||
@@ -1943,7 +1956,13 @@ TEST( RigSimulationInputTool, ExpandBoxContext_OutsideBoxNotModified )
|
|||||||
auto loadResult = deckFile.loadDeck( dataFilePath.toStdString() );
|
auto loadResult = deckFile.loadDeck( dataFilePath.toStdString() );
|
||||||
ASSERT_TRUE( loadResult.has_value() ) << loadResult.error();
|
ASSERT_TRUE( loadResult.has_value() ) << loadResult.error();
|
||||||
|
|
||||||
RigSimulationInputTool::expandBoxContextInDeckFile( deckFile );
|
// Sector covers entire grid
|
||||||
|
RigSimulationInputSettings settings;
|
||||||
|
settings.setMin( caf::VecIjk0( 0, 0, 0 ) );
|
||||||
|
settings.setMax( caf::VecIjk0( 9, 9, 4 ) );
|
||||||
|
settings.setRefinement( cvf::Vec3st( 1, 1, 1 ) );
|
||||||
|
|
||||||
|
RigSimulationInputTool::transformKeywordsInDeckFile( nullptr, settings, deckFile );
|
||||||
|
|
||||||
auto equalsVec = deckFile.findAllKeywordsWithIndices( "EQUALS" );
|
auto equalsVec = deckFile.findAllKeywordsWithIndices( "EQUALS" );
|
||||||
ASSERT_EQ( 1u, equalsVec.size() );
|
ASSERT_EQ( 1u, equalsVec.size() );
|
||||||
@@ -1957,7 +1976,7 @@ TEST( RigSimulationInputTool, ExpandBoxContext_OutsideBoxNotModified )
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
/// Test cropDataKeywordsInsideBoxContext: data keywords inside BOX/ENDBOX are cropped
|
/// Test transformKeywordsInDeckFile: data keywords inside BOX/ENDBOX are cropped
|
||||||
/// to the intersection of the box with the sector
|
/// to the intersection of the box with the sector
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
TEST( RigSimulationInputTool, CropDataKeywordsInsideBoxContext )
|
TEST( RigSimulationInputTool, CropDataKeywordsInsideBoxContext )
|
||||||
@@ -1993,11 +2012,13 @@ TEST( RigSimulationInputTool, CropDataKeywordsInsideBoxContext )
|
|||||||
auto eqlnumBefore = deckFile.findAllKeywordsWithIndices( "EQLNUM" );
|
auto eqlnumBefore = deckFile.findAllKeywordsWithIndices( "EQLNUM" );
|
||||||
EXPECT_EQ( 2u, eqlnumBefore.size() );
|
EXPECT_EQ( 2u, eqlnumBefore.size() );
|
||||||
|
|
||||||
// Run cropping with sector (2,2,1)-(7,7,4), no refinement
|
// Run transformation with sector (2,2,1)-(7,7,4), no refinement
|
||||||
caf::VecIjk0 sectorMin( 2, 2, 1 );
|
RigSimulationInputSettings settings;
|
||||||
caf::VecIjk0 sectorMax( 7, 7, 4 );
|
settings.setMin( caf::VecIjk0( 2, 2, 1 ) );
|
||||||
cvf::Vec3st refinement( 1, 1, 1 );
|
settings.setMax( caf::VecIjk0( 7, 7, 4 ) );
|
||||||
RigSimulationInputTool::cropDataKeywordsInsideBoxContext( deckFile, sectorMin, sectorMax, refinement );
|
settings.setRefinement( cvf::Vec3st( 1, 1, 1 ) );
|
||||||
|
|
||||||
|
RigSimulationInputTool::transformKeywordsInDeckFile( nullptr, settings, deckFile );
|
||||||
|
|
||||||
// After cropping: should still find two EQLNUM keywords
|
// After cropping: should still find two EQLNUM keywords
|
||||||
auto eqlnumAfter = deckFile.findAllKeywordsWithIndices( "EQLNUM" );
|
auto eqlnumAfter = deckFile.findAllKeywordsWithIndices( "EQLNUM" );
|
||||||
@@ -2024,7 +2045,7 @@ TEST( RigSimulationInputTool, CropDataKeywordsInsideBoxContext )
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
/// Test cropDataKeywordsInsideBoxContext: box that doesn't intersect sector removes keyword
|
/// Test transformKeywordsInDeckFile: box that doesn't intersect sector removes data keyword
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
TEST( RigSimulationInputTool, CropDataKeywordsInsideBoxContext_NoIntersection )
|
TEST( RigSimulationInputTool, CropDataKeywordsInsideBoxContext_NoIntersection )
|
||||||
{
|
{
|
||||||
@@ -2053,10 +2074,12 @@ TEST( RigSimulationInputTool, CropDataKeywordsInsideBoxContext_NoIntersection )
|
|||||||
ASSERT_TRUE( loadResult.has_value() ) << loadResult.error();
|
ASSERT_TRUE( loadResult.has_value() ) << loadResult.error();
|
||||||
|
|
||||||
// Sector does not include K=4
|
// Sector does not include K=4
|
||||||
caf::VecIjk0 sectorMin( 2, 2, 0 );
|
RigSimulationInputSettings settings;
|
||||||
caf::VecIjk0 sectorMax( 7, 7, 2 );
|
settings.setMin( caf::VecIjk0( 2, 2, 0 ) );
|
||||||
cvf::Vec3st refinement( 1, 1, 1 );
|
settings.setMax( caf::VecIjk0( 7, 7, 2 ) );
|
||||||
RigSimulationInputTool::cropDataKeywordsInsideBoxContext( deckFile, sectorMin, sectorMax, refinement );
|
settings.setRefinement( cvf::Vec3st( 1, 1, 1 ) );
|
||||||
|
|
||||||
|
RigSimulationInputTool::transformKeywordsInDeckFile( nullptr, settings, deckFile );
|
||||||
|
|
||||||
// Boxed EQLNUM should be removed since box doesn't intersect sector
|
// Boxed EQLNUM should be removed since box doesn't intersect sector
|
||||||
auto eqlnumAfter = deckFile.findAllKeywordsWithIndices( "EQLNUM" );
|
auto eqlnumAfter = deckFile.findAllKeywordsWithIndices( "EQLNUM" );
|
||||||
|
|||||||
Reference in new issue
Block a user