mirror of
https://github.com/OPM/ResInsight.git
synced 2026-08-27 05:37:21 -05:00
#13855 Ensure BCPROP goes first in schedule section during sector export
This commit is contained in:
committed by
Magne Sjaastad
parent
f1923333af
commit
f881899815
@@ -223,6 +223,22 @@ static std::optional<Opm::FileDeck::Index> findSectionInsertionPoint( std::uniqu
|
||||
return insertIdx;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
static std::optional<Opm::FileDeck::Index> findSectionStartPoint( std::unique_ptr<Opm::FileDeck>& fileDeck, const std::string& section )
|
||||
{
|
||||
auto sectionIdx = fileDeck->find( section );
|
||||
if ( !sectionIdx.has_value() )
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto insertIdx = sectionIdx.value();
|
||||
insertIdx++;
|
||||
return insertIdx;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -1133,6 +1149,20 @@ bool RifOpmFlowDeckFile::replaceKeyword( const std::string& section, const Opm::
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RifOpmFlowDeckFile::insertKeywordAtSectionStart( const std::string& section, const Opm::DeckKeyword& keyword )
|
||||
{
|
||||
if ( m_fileDeck.get() == nullptr ) return false;
|
||||
|
||||
auto insertPos = internal::findSectionStartPoint( m_fileDeck, section );
|
||||
if ( !insertPos.has_value() ) return false;
|
||||
|
||||
m_fileDeck->insert( insertPos.value(), keyword );
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -99,6 +99,7 @@ public:
|
||||
bool addKeyword( const std::string& section, const Opm::DeckKeyword& keyword );
|
||||
|
||||
bool replaceKeyword( const std::string& section, const Opm::DeckKeyword& keyword );
|
||||
bool insertKeywordAtSectionStart( const std::string& section, const Opm::DeckKeyword& keyword );
|
||||
bool replaceKeyword( const std::string& keyword, const std::vector<double>& data, bool dataKeyword = false );
|
||||
bool replaceKeyword( const std::string& keyword, const std::vector<int>& data, bool dataKeyword = false );
|
||||
|
||||
|
||||
@@ -480,10 +480,12 @@ std::expected<void, QString> RigSimulationInputTool::addBorderBoundaryConditions
|
||||
// Create BCPROP keyword using the factory
|
||||
Opm::DeckKeyword bcpropKw = RimKeywordFactory::bcpropKeyword( borderCellFaces, bcpropRecords );
|
||||
|
||||
// Replace BCPROP keyword in GRID section
|
||||
if ( !deckFile.replaceKeyword( Opm::ParserKeywords::SCHEDULE::keywordName, bcpropKw ) )
|
||||
// Ensure BCPROP appears at the start of the SCHEDULE section by removing any
|
||||
// existing occurrence and re-inserting it at the section start.
|
||||
deckFile.removeKeywords( bcpropKw.name() );
|
||||
if ( !deckFile.insertKeywordAtSectionStart( Opm::ParserKeywords::SCHEDULE::keywordName, bcpropKw ) )
|
||||
{
|
||||
return std::unexpected( "Failed to replace BCPROP keyword in deck file" );
|
||||
return std::unexpected( "Failed to insert BCPROP keyword at start of SCHEDULE section" );
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -461,3 +461,88 @@ TEST( RifOpmFlowDeckFileTest, BcpropKeyword )
|
||||
// Verify component
|
||||
EXPECT_TRUE( content.contains( "WATER" ) ) << "Component WATER not found";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Verify that a keyword is inserted as the first entry inside the requested section.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RifOpmFlowDeckFileTest, InsertKeywordAtSectionStart )
|
||||
{
|
||||
static const QString testDataFolder = QString( "%1/RifOpmFlowDeckFile/" ).arg( TEST_DATA_DIR );
|
||||
QString fileName = testDataFolder + "SIMPLE_NO_REGDIMS.DATA";
|
||||
|
||||
RifOpmFlowDeckFile deckFile;
|
||||
bool loadSuccess = deckFile.loadDeck( fileName.toStdString() ).has_value();
|
||||
ASSERT_TRUE( loadSuccess ) << "Failed to load test deck file";
|
||||
|
||||
Opm::DeckKeyword bcpropKw( ( Opm::ParserKeywords::BCPROP() ) );
|
||||
bool insertSuccess = deckFile.insertKeywordAtSectionStart( "SCHEDULE", bcpropKw );
|
||||
EXPECT_TRUE( insertSuccess ) << "Should successfully insert BCPROP at start of SCHEDULE section";
|
||||
|
||||
auto keywords = deckFile.keywords( false );
|
||||
auto schedIt = std::find( keywords.begin(), keywords.end(), "SCHEDULE" );
|
||||
ASSERT_NE( schedIt, keywords.end() ) << "SCHEDULE section keyword not found";
|
||||
|
||||
auto nextIt = std::next( schedIt );
|
||||
ASSERT_NE( nextIt, keywords.end() ) << "Expected a keyword after SCHEDULE";
|
||||
EXPECT_EQ( "BCPROP", *nextIt ) << "BCPROP should be the first keyword inside SCHEDULE";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Inserting into a section that does not exist should fail and leave the deck unchanged.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RifOpmFlowDeckFileTest, InsertKeywordAtSectionStartNonexistentSection )
|
||||
{
|
||||
static const QString testDataFolder = QString( "%1/RifOpmFlowDeckFile/" ).arg( TEST_DATA_DIR );
|
||||
QString fileName = testDataFolder + "SIMPLE_NO_REGDIMS.DATA";
|
||||
|
||||
RifOpmFlowDeckFile deckFile;
|
||||
bool loadSuccess = deckFile.loadDeck( fileName.toStdString() ).has_value();
|
||||
ASSERT_TRUE( loadSuccess ) << "Failed to load test deck file";
|
||||
|
||||
auto keywordsBefore = deckFile.keywords( false );
|
||||
|
||||
Opm::DeckKeyword bcpropKw( ( Opm::ParserKeywords::BCPROP() ) );
|
||||
bool insertSuccess = deckFile.insertKeywordAtSectionStart( "NONEXISTENT", bcpropKw );
|
||||
EXPECT_FALSE( insertSuccess ) << "Should fail when target section does not exist";
|
||||
|
||||
auto keywordsAfter = deckFile.keywords( false );
|
||||
EXPECT_EQ( keywordsBefore, keywordsAfter ) << "Deck should be unchanged when section is missing";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Verify the documented use case: a pre-existing keyword can be moved to the start of a
|
||||
/// section by combining removeKeywords + insertKeywordAtSectionStart.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RifOpmFlowDeckFileTest, RemoveAndInsertKeywordAtSectionStart )
|
||||
{
|
||||
static const QString testDataFolder = QString( "%1/RifOpmFlowDeckFile/" ).arg( TEST_DATA_DIR );
|
||||
QString fileName = testDataFolder + "SIMPLE_NO_REGDIMS.DATA";
|
||||
|
||||
RifOpmFlowDeckFile deckFile;
|
||||
bool loadSuccess = deckFile.loadDeck( fileName.toStdString() ).has_value();
|
||||
ASSERT_TRUE( loadSuccess ) << "Failed to load test deck file";
|
||||
|
||||
// Place BCPROP somewhere in the deck first (in GRID), so that the second insert
|
||||
// exercises the "remove existing then insert at section start" pattern.
|
||||
Opm::DeckKeyword bcpropKw( ( Opm::ParserKeywords::BCPROP() ) );
|
||||
ASSERT_TRUE( deckFile.replaceKeyword( "GRID", bcpropKw ) );
|
||||
|
||||
auto keywordsAfterFirst = deckFile.keywords( false );
|
||||
EXPECT_EQ( 1, std::count( keywordsAfterFirst.begin(), keywordsAfterFirst.end(), std::string( "BCPROP" ) ) );
|
||||
|
||||
// Remove the existing occurrence and re-insert at SCHEDULE start.
|
||||
int removed = deckFile.removeKeywords( bcpropKw.name() );
|
||||
EXPECT_EQ( 1, removed ) << "Should remove the existing BCPROP keyword";
|
||||
|
||||
bool insertSuccess = deckFile.insertKeywordAtSectionStart( "SCHEDULE", bcpropKw );
|
||||
EXPECT_TRUE( insertSuccess );
|
||||
|
||||
auto keywords = deckFile.keywords( false );
|
||||
EXPECT_EQ( 1, std::count( keywords.begin(), keywords.end(), std::string( "BCPROP" ) ) ) << "BCPROP should appear exactly once";
|
||||
|
||||
auto schedIt = std::find( keywords.begin(), keywords.end(), "SCHEDULE" );
|
||||
ASSERT_NE( schedIt, keywords.end() );
|
||||
auto nextIt = std::next( schedIt );
|
||||
ASSERT_NE( nextIt, keywords.end() );
|
||||
EXPECT_EQ( "BCPROP", *nextIt ) << "BCPROP should be the first keyword inside SCHEDULE";
|
||||
}
|
||||
|
||||
@@ -566,6 +566,15 @@ TEST( RigSimulationInputTool, ExportModel5WithBcconBcprop )
|
||||
EXPECT_TRUE( std::find( allKeywords.begin(), allKeywords.end(), "BCPROP" ) != allKeywords.end() )
|
||||
<< "BCPROP keyword missing from exported file";
|
||||
|
||||
// Verify BCPROP comes before any DATES keyword (i.e., first in SCHEDULE section)
|
||||
auto bcpropIt = std::find( allKeywords.begin(), allKeywords.end(), "BCPROP" );
|
||||
auto datesIt = std::find( allKeywords.begin(), allKeywords.end(), "DATES" );
|
||||
if ( bcpropIt != allKeywords.end() && datesIt != allKeywords.end() )
|
||||
{
|
||||
EXPECT_LT( std::distance( allKeywords.begin(), bcpropIt ), std::distance( allKeywords.begin(), datesIt ) )
|
||||
<< "BCPROP should appear before DATES in the SCHEDULE section";
|
||||
}
|
||||
|
||||
// Verify OPERNUM and OPERATER keywords do NOT exist (should only be present with OPERNUM_OPERATER)
|
||||
EXPECT_TRUE( std::find( allKeywords.begin(), allKeywords.end(), "OPERNUM" ) == allKeywords.end() )
|
||||
<< "OPERNUM keyword should not be present when using BCCON_BCPROP";
|
||||
|
||||
Reference in New Issue
Block a user