Refactor: move opm-flow deck keyword generation to factory.

This commit is contained in:
Kristian Bendiksen committed 2025-10-24 19:33:35 +02:00
1 parent 04dfa4ecba
commit 4e736a8cc0
7 files changed
+216 -227

No files matched your search

@@ -471,10 +471,13 @@ std::expected<void, QString> RicExportEclipseSectorModelFeature::addBorderBounda
if ( !borderCellFaces.empty() ) if ( !borderCellFaces.empty() )
{ {
// Add BCCON keyword // Create BCCON keyword using the factory
if ( !deckFile.addBcconKeyword( "GRID", borderCellFaces ) ) Opm::DeckKeyword bcconKw = RimKeywordFactory::bcconKeyword( borderCellFaces );
// Replace BCCON keyword in GRID section
if ( !deckFile.replaceKeyword( "GRID", bcconKw ) )
{ {
return std::unexpected( "Failed to add BCCON keyword to deck file" ); return std::unexpected( "Failed to replace BCCON keyword in deck file" );
} }
// Build BCPROP records from the UI configuration // Build BCPROP records from the UI configuration
@@ -489,10 +492,13 @@ std::expected<void, QString> RicExportEclipseSectorModelFeature::addBorderBounda
} }
} }
// Add BCPROP keyword // Create BCPROP keyword using the factory
if ( !deckFile.addBcpropKeyword( "GRID", borderCellFaces, bcpropRecords ) ) Opm::DeckKeyword bcpropKw = RimKeywordFactory::bcpropKeyword( borderCellFaces, bcpropRecords );
// Replace BCPROP keyword in GRID section
if ( !deckFile.replaceKeyword( "GRID", bcpropKw ) )
{ {
return std::unexpected( "Failed to add BCPROP keyword to deck file" ); return std::unexpected( "Failed to replace BCPROP keyword in deck file" );
} }
} }
else else
@@ -20,8 +20,6 @@
#include "RifOpmDeckTools.h" #include "RifOpmDeckTools.h"
#include "RigEclipseResultTools.h"
#include "opm/common/utility/TimeService.hpp" #include "opm/common/utility/TimeService.hpp"
#include "opm/input/eclipse/Deck/Deck.hpp" #include "opm/input/eclipse/Deck/Deck.hpp"
#include "opm/input/eclipse/Deck/FileDeck.hpp" #include "opm/input/eclipse/Deck/FileDeck.hpp"
@@ -29,19 +27,16 @@
#include "opm/input/eclipse/Parser/InputErrorAction.hpp" #include "opm/input/eclipse/Parser/InputErrorAction.hpp"
#include "opm/input/eclipse/Parser/ParseContext.hpp" #include "opm/input/eclipse/Parser/ParseContext.hpp"
#include "opm/input/eclipse/Parser/Parser.hpp" #include "opm/input/eclipse/Parser/Parser.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/B.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/C.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/C.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/D.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/D.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/E.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/E.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/G.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/G.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/I.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/I.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/O.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/R.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/R.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/S.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/S.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/W.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/W.hpp"
#include "cvfStructGrid.h" #include <cmath>
#include <format> #include <format>
#include <memory> #include <memory>
#include <optional> #include <optional>
@@ -752,189 +747,6 @@ bool RifOpmFlowDeckFile::addIncludeKeyword( std::string section, std::string key
return true; return true;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifOpmFlowDeckFile::addOperaterKeyword( std::string section,
std::string targetProperty,
int regionId,
std::string equation,
std::string inputProperty,
std::optional<float> alpha,
std::optional<float> beta )
{
if ( m_fileDeck.get() == nullptr ) return false;
// Find insertion point within the section
auto insertIdx = internal::findSectionInsertionPoint( m_fileDeck, section );
if ( !insertIdx.has_value() ) return false; // Section not found
using O = Opm::ParserKeywords::OPERATER;
// Create the OPERATER keyword
Opm::DeckKeyword operaterKw( ( Opm::ParserKeywords::OPERATER() ) );
std::vector<Opm::DeckItem> recordItems;
recordItems.push_back( RifOpmDeckTools::item( O::TARGET_ARRAY::itemName, targetProperty ) );
recordItems.push_back( RifOpmDeckTools::item( O::REGION_NUMBER::itemName, regionId ) );
recordItems.push_back( RifOpmDeckTools::item( O::OPERATION::itemName, equation ) );
recordItems.push_back( RifOpmDeckTools::item( O::ARRAY_PARAMETER::itemName, inputProperty ) );
// Add alpha parameter
if ( alpha.has_value() )
{
recordItems.push_back( RifOpmDeckTools::item( O::PARAM1::itemName, std::to_string( alpha.value() ) ) );
}
else
{
recordItems.push_back( RifOpmDeckTools::defaultItem( O::PARAM1::itemName ) );
}
// Add beta parameter
if ( beta.has_value() )
{
recordItems.push_back( RifOpmDeckTools::item( O::PARAM2::itemName, std::to_string( beta.value() ) ) );
}
else
{
recordItems.push_back( RifOpmDeckTools::defaultItem( O::PARAM2::itemName ) );
}
// Add final default item
recordItems.push_back( RifOpmDeckTools::defaultItem( O::REGION_NAME::itemName ) ); // 1* for the last field
operaterKw.addRecord( Opm::DeckRecord{ std::move( recordItems ) } );
m_fileDeck->insert( insertIdx.value(), operaterKw );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifOpmFlowDeckFile::addBcconKeyword( std::string section, const std::vector<RigEclipseResultTools::BorderCellFace>& borderCellFaces )
{
if ( m_fileDeck.get() == nullptr ) return false;
if ( borderCellFaces.empty() ) return true; // Nothing to add
// Find insertion point within the section
auto insertPos = internal::findSectionInsertionPoint( m_fileDeck, section );
if ( !insertPos.has_value() )
{
return false; // Section not found
}
// Helper lambda to convert FaceType to string
auto faceTypeToString = []( cvf::StructGridInterface::FaceType faceType ) -> std::string
{
switch ( faceType )
{
case cvf::StructGridInterface::POS_I:
return "X";
case cvf::StructGridInterface::NEG_I:
return "X-";
case cvf::StructGridInterface::POS_J:
return "Y";
case cvf::StructGridInterface::NEG_J:
return "Y-";
case cvf::StructGridInterface::POS_K:
return "Z";
case cvf::StructGridInterface::NEG_K:
return "Z-";
default:
return "";
}
};
// Create the BCCON keyword using OPM's BCCON parser keyword
using B = Opm::ParserKeywords::BCCON;
Opm::DeckKeyword bcconKw( ( Opm::ParserKeywords::BCCON() ) );
for ( const auto& borderFace : borderCellFaces )
{
// Convert from 0-based to 1-based Eclipse indexing
int i1 = static_cast<int>( borderFace.ijk[0] ) + 1;
int j1 = static_cast<int>( borderFace.ijk[1] ) + 1;
int k1 = static_cast<int>( borderFace.ijk[2] ) + 1;
std::string faceStr = faceTypeToString( borderFace.faceType );
// Create items for the record using proper BCCON item names
std::vector<Opm::DeckItem> recordItems;
recordItems.push_back( RifOpmDeckTools::item( B::INDEX::itemName, borderFace.boundaryCondition ) );
recordItems.push_back( RifOpmDeckTools::item( B::I1::itemName, i1 ) );
recordItems.push_back( RifOpmDeckTools::item( B::I2::itemName, i1 ) ); // Same as i1 for single cell
recordItems.push_back( RifOpmDeckTools::item( B::J1::itemName, j1 ) );
recordItems.push_back( RifOpmDeckTools::item( B::J2::itemName, j1 ) ); // Same as j1 for single cell
recordItems.push_back( RifOpmDeckTools::item( B::K1::itemName, k1 ) );
recordItems.push_back( RifOpmDeckTools::item( B::K2::itemName, k1 ) ); // Same as k1 for single cell
recordItems.push_back( RifOpmDeckTools::item( B::DIRECTION::itemName, faceStr ) );
bcconKw.addRecord( Opm::DeckRecord{ std::move( recordItems ) } );
}
m_fileDeck->insert( insertPos.value(), bcconKw );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifOpmFlowDeckFile::addBcpropKeyword( std::string section,
const std::vector<RigEclipseResultTools::BorderCellFace>& boundaryConditions,
const std::vector<Opm::DeckRecord>& boundaryConditionProperties )
{
if ( m_fileDeck.get() == nullptr ) return false;
if ( boundaryConditions.empty() ) return true; // Nothing to add
// Find insertion point within the section
auto insertPos = internal::findSectionInsertionPoint( m_fileDeck, section );
if ( !insertPos.has_value() )
{
return false; // Section not found
}
// Create the BCPROP keyword using OPM's BCPROP parser keyword
using B = Opm::ParserKeywords::BCPROP;
Opm::DeckKeyword bcpropKw( ( Opm::ParserKeywords::BCPROP() ) );
// Add one entry per boundary condition
for ( const auto& bc : boundaryConditions )
{
if ( bc.boundaryCondition <= 0 ) continue; // Skip entries without a valid boundary condition
// Find the corresponding property record
// The properties vector should be indexed by boundaryCondition - 1
size_t propIndex = static_cast<size_t>( bc.boundaryCondition - 1 );
if ( propIndex < boundaryConditionProperties.size() )
{
const auto& propRecord = boundaryConditionProperties[propIndex];
// Create a new record with the boundary condition INDEX
std::vector<Opm::DeckItem> recordItems;
// Add INDEX field
recordItems.push_back( RifOpmDeckTools::item( B::INDEX::itemName, bc.boundaryCondition ) );
// Copy all items from the property record (which doesn't include INDEX)
for ( size_t i = 0; i < propRecord.size(); ++i )
{
recordItems.push_back( propRecord.getItem( i ) );
}
bcpropKw.addRecord( Opm::DeckRecord{ std::move( recordItems ) } );
}
}
m_fileDeck->insert( insertPos.value(), bcpropKw );
return true;
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -942,6 +754,13 @@ bool RifOpmFlowDeckFile::replaceKeyword( const std::string& section, const Opm::
{ {
if ( m_fileDeck.get() == nullptr ) return false; if ( m_fileDeck.get() == nullptr ) return false;
// Add keyword to specified section if it doesn't exist
auto insertPos = internal::findSectionInsertionPoint( m_fileDeck, section );
if ( !insertPos.has_value() )
{
return false; // Section not found
}
// Find and replace keyword in deck // Find and replace keyword in deck
auto keywordIdx = m_fileDeck->find( keyword.name() ); auto keywordIdx = m_fileDeck->find( keyword.name() );
if ( keywordIdx.has_value() ) if ( keywordIdx.has_value() )
@@ -952,12 +771,6 @@ bool RifOpmFlowDeckFile::replaceKeyword( const std::string& section, const Opm::
} }
else else
{ {
// Add keyword to specified section if it doesn't exist
auto insertPos = internal::findSectionInsertionPoint( m_fileDeck, section );
if ( !insertPos.has_value() )
{
return false; // Section not found
}
m_fileDeck->insert( insertPos.value(), keyword ); m_fileDeck->insert( insertPos.value(), keyword );
} }
@@ -34,11 +34,6 @@ class DeckRecord;
class ParseContext; class ParseContext;
} // namespace Opm } // namespace Opm
namespace RigEclipseResultTools
{
struct BorderCellFace;
}
//================================================================================================== //==================================================================================================
/// ///
/// ///
@@ -81,18 +76,6 @@ public:
bool ensureRegdimsKeyword(); bool ensureRegdimsKeyword();
bool addIncludeKeyword( std::string section, std::string keyword, std::string filePath ); bool addIncludeKeyword( std::string section, std::string keyword, std::string filePath );
bool addOperaterKeyword( std::string section,
std::string targetProperty,
int regionId,
std::string equation,
std::string inputProperty,
std::optional<float> alpha,
std::optional<float> beta );
bool addBcconKeyword( std::string section, const std::vector<RigEclipseResultTools::BorderCellFace>& borderCellFaces );
bool addBcpropKeyword( std::string section,
const std::vector<RigEclipseResultTools::BorderCellFace>& boundaryConditions,
const std::vector<Opm::DeckRecord>& boundaryConditionProperties );
bool replaceKeywordData( const std::string& keyword, const std::vector<double>& data ); bool replaceKeywordData( const std::string& keyword, const std::vector<double>& data );
bool replaceKeywordData( const std::string& keyword, const std::vector<int>& data ); bool replaceKeywordData( const std::string& keyword, const std::vector<int>& data );
@@ -25,6 +25,7 @@
#include "RifEclipseInputFileTools.h" #include "RifEclipseInputFileTools.h"
#include "RifOpmDeckTools.h" #include "RifOpmDeckTools.h"
#include "RigEclipseResultTools.h"
#include "RigFault.h" #include "RigFault.h"
#include "RigMainGrid.h" #include "RigMainGrid.h"
@@ -38,8 +39,10 @@
#include "opm/input/eclipse/Deck/DeckKeyword.hpp" #include "opm/input/eclipse/Deck/DeckKeyword.hpp"
#include "opm/input/eclipse/Deck/DeckRecord.hpp" #include "opm/input/eclipse/Deck/DeckRecord.hpp"
#include "opm/input/eclipse/Parser/ParserKeyword.hpp" #include "opm/input/eclipse/Parser/ParserKeyword.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/B.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/C.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/C.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/F.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/F.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/O.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/W.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/W.hpp"
//================================================================================================== //==================================================================================================
@@ -289,4 +292,161 @@ Opm::DeckKeyword faultsKeyword( const RigMainGrid* mainGrid, const cvf::Vec3st&
return kw; return kw;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Opm::DeckKeyword bcconKeyword( const std::vector<RigEclipseResultTools::BorderCellFace>& borderCellFaces )
{
if ( borderCellFaces.empty() )
{
return Opm::DeckKeyword();
}
// Helper lambda to convert FaceType to Eclipse face string
auto faceTypeToString = []( cvf::StructGridInterface::FaceType faceType ) -> std::string
{
switch ( faceType )
{
case cvf::StructGridInterface::POS_I:
return "X";
case cvf::StructGridInterface::NEG_I:
return "X-";
case cvf::StructGridInterface::POS_J:
return "Y";
case cvf::StructGridInterface::NEG_J:
return "Y-";
case cvf::StructGridInterface::POS_K:
return "Z";
case cvf::StructGridInterface::NEG_K:
return "Z-";
default:
return "";
}
};
using B = Opm::ParserKeywords::BCCON;
Opm::DeckKeyword kw{ Opm::ParserKeywords::BCCON() };
for ( const auto& borderFace : borderCellFaces )
{
// Convert from 0-based to 1-based Eclipse indexing
int i1 = static_cast<int>( borderFace.ijk[0] ) + 1;
int j1 = static_cast<int>( borderFace.ijk[1] ) + 1;
int k1 = static_cast<int>( borderFace.ijk[2] ) + 1;
std::string faceStr = faceTypeToString( borderFace.faceType );
// Create items for the record
std::vector<Opm::DeckItem> items;
items.push_back( RifOpmDeckTools::item( B::INDEX::itemName, borderFace.boundaryCondition ) );
items.push_back( RifOpmDeckTools::item( B::I1::itemName, i1 ) );
items.push_back( RifOpmDeckTools::item( B::I2::itemName, i1 ) );
items.push_back( RifOpmDeckTools::item( B::J1::itemName, j1 ) );
items.push_back( RifOpmDeckTools::item( B::J2::itemName, j1 ) );
items.push_back( RifOpmDeckTools::item( B::K1::itemName, k1 ) );
items.push_back( RifOpmDeckTools::item( B::K2::itemName, k1 ) );
items.push_back( RifOpmDeckTools::item( B::DIRECTION::itemName, faceStr ) );
kw.addRecord( Opm::DeckRecord{ std::move( items ) } );
}
return kw;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Opm::DeckKeyword bcpropKeyword( const std::vector<RigEclipseResultTools::BorderCellFace>& boundaryConditions,
const std::vector<Opm::DeckRecord>& boundaryConditionProperties )
{
if ( boundaryConditions.empty() )
{
return Opm::DeckKeyword();
}
using B = Opm::ParserKeywords::BCPROP;
Opm::DeckKeyword kw{ Opm::ParserKeywords::BCPROP() };
// Add one entry per boundary condition
for ( const auto& bc : boundaryConditions )
{
if ( bc.boundaryCondition <= 0 ) continue; // Skip entries without a valid boundary condition
// Find the corresponding property record
// The properties vector should be indexed by boundaryCondition - 1
size_t propIndex = static_cast<size_t>( bc.boundaryCondition - 1 );
if ( propIndex < boundaryConditionProperties.size() )
{
const auto& propRecord = boundaryConditionProperties[propIndex];
// Create a new record with the boundary condition INDEX
std::vector<Opm::DeckItem> items;
// Add INDEX field
items.push_back( RifOpmDeckTools::item( B::INDEX::itemName, bc.boundaryCondition ) );
// Copy all items from the property record (which doesn't include INDEX)
for ( size_t i = 0; i < propRecord.size(); ++i )
{
items.push_back( propRecord.getItem( i ) );
}
kw.addRecord( Opm::DeckRecord{ std::move( items ) } );
}
}
return kw;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Opm::DeckKeyword operaterKeyword( std::string targetProperty,
int regionId,
std::string equation,
std::string inputProperty,
std::optional<float> alpha,
std::optional<float> beta )
{
using O = Opm::ParserKeywords::OPERATER;
// Create the OPERATER keyword
Opm::DeckKeyword operaterKw( ( Opm::ParserKeywords::OPERATER() ) );
std::vector<Opm::DeckItem> recordItems;
recordItems.push_back( RifOpmDeckTools::item( O::TARGET_ARRAY::itemName, targetProperty ) );
recordItems.push_back( RifOpmDeckTools::item( O::REGION_NUMBER::itemName, regionId ) );
recordItems.push_back( RifOpmDeckTools::item( O::OPERATION::itemName, equation ) );
recordItems.push_back( RifOpmDeckTools::item( O::ARRAY_PARAMETER::itemName, inputProperty ) );
// Add alpha parameter
if ( alpha.has_value() )
{
recordItems.push_back( RifOpmDeckTools::item( O::PARAM1::itemName, std::to_string( alpha.value() ) ) );
}
else
{
recordItems.push_back( RifOpmDeckTools::defaultItem( O::PARAM1::itemName ) );
}
// Add beta parameter
if ( beta.has_value() )
{
recordItems.push_back( RifOpmDeckTools::item( O::PARAM2::itemName, std::to_string( beta.value() ) ) );
}
else
{
recordItems.push_back( RifOpmDeckTools::defaultItem( O::PARAM2::itemName ) );
}
// Add final default item
recordItems.push_back( RifOpmDeckTools::defaultItem( O::REGION_NAME::itemName ) ); // 1* for the last field
operaterKw.addRecord( Opm::DeckRecord{ std::move( recordItems ) } );
return operaterKw;
}
} // namespace RimKeywordFactory } // namespace RimKeywordFactory
@@ -20,7 +20,9 @@
#include "cvfVector3.h" #include "cvfVector3.h"
#include <optional>
#include <string> #include <string>
#include <vector>
class RigMainGrid; class RigMainGrid;
class RimEclipseCase; class RimEclipseCase;
@@ -29,12 +31,18 @@ class RimWellPath;
namespace Opm namespace Opm
{ {
class DeckKeyword; class DeckKeyword;
class DeckRecord;
} // namespace Opm } // namespace Opm
//================================================================================================== //==================================================================================================
/// ///
/// ///
//================================================================================================== //==================================================================================================
namespace RigEclipseResultTools
{
struct BorderCellFace;
}
namespace RimKeywordFactory namespace RimKeywordFactory
{ {
@@ -44,5 +52,14 @@ Opm::DeckKeyword faultsKeyword( const RigMainGrid* mainGrid,
const cvf::Vec3st& min = cvf::Vec3st::ZERO, const cvf::Vec3st& min = cvf::Vec3st::ZERO,
const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED, const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED,
const cvf::Vec3st& refinement = cvf::Vec3st( 1, 1, 1 ) ); const cvf::Vec3st& refinement = cvf::Vec3st( 1, 1, 1 ) );
Opm::DeckKeyword bcconKeyword( const std::vector<RigEclipseResultTools::BorderCellFace>& borderCellFaces );
Opm::DeckKeyword bcpropKeyword( const std::vector<RigEclipseResultTools::BorderCellFace>& boundaryConditions,
const std::vector<Opm::DeckRecord>& boundaryConditionProperties );
Opm::DeckKeyword operaterKeyword( std::string targetProperty,
int regionId,
std::string equation,
std::string inputProperty,
std::optional<float> alpha = std::nullopt,
std::optional<float> beta = std::nullopt );
} // namespace RimKeywordFactory } // namespace RimKeywordFactory
@@ -7,9 +7,12 @@
#include "RigEclipseResultTools.h" #include "RigEclipseResultTools.h"
#include "ProjectDataModel/Jobs/RimKeywordFactory.h"
#include "cvfStructGrid.h" #include "cvfStructGrid.h"
#include "opm/input/eclipse/Deck/DeckItem.hpp" #include "opm/input/eclipse/Deck/DeckItem.hpp"
#include "opm/input/eclipse/Deck/DeckKeyword.hpp"
#include "opm/input/eclipse/Deck/DeckRecord.hpp" #include "opm/input/eclipse/Deck/DeckRecord.hpp"
#include "opm/input/eclipse/Parser/ParserKeywords/B.hpp" #include "opm/input/eclipse/Parser/ParserKeywords/B.hpp"
@@ -268,11 +271,12 @@ TEST( RifOpmFlowDeckFileTest, AddOperaterKeyword )
ASSERT_TRUE( loadSuccess ) << "Failed to load test deck file"; ASSERT_TRUE( loadSuccess ) << "Failed to load test deck file";
// Add OPERATER statement to GRID section: PORV 9 MULTX PORV 1.0e6 1* 1* // Add OPERATER statement to GRID section: PORV 9 MULTX PORV 1.0e6 1* 1*
bool addSuccess = deckFile.addOperaterKeyword( "GRID", "PORV", 9, "MULTX", "PORV", 1.0e6f, std::nullopt ); bool addSuccess = deckFile.replaceKeyword( "GRID", RimKeywordFactory::operaterKeyword( "PORV", 9, "MULTX", "PORV", 1.0e6f, std::nullopt ) );
EXPECT_TRUE( addSuccess ) << "Should successfully add OPERATER statement in GRID section"; EXPECT_TRUE( addSuccess ) << "Should successfully add OPERATER statement in GRID section";
// Test adding to non-existent section // Test adding to non-existent section
bool addFailure = deckFile.addOperaterKeyword( "NONEXISTENT", "PORV", 1, "MULTX", "PORV", std::nullopt, std::nullopt ); bool addFailure = deckFile.replaceKeyword( "NONEXISTENT",
RimKeywordFactory::operaterKeyword( "PORV", 1, "MULTX", "PORV", std::nullopt, std::nullopt ) );
EXPECT_FALSE( addFailure ) << "Should fail when adding to non-existent section"; EXPECT_FALSE( addFailure ) << "Should fail when adding to non-existent section";
// Verify the keywords list contains our OPERATER statement // Verify the keywords list contains our OPERATER statement
@@ -304,7 +308,7 @@ TEST( RifOpmFlowDeckFileTest, AddOperaterSaveAndReload )
ASSERT_TRUE( loadSuccess ) << "Failed to load test deck file"; ASSERT_TRUE( loadSuccess ) << "Failed to load test deck file";
// Add OPERATER statement: PORV 9 MULTX PORV 1.0e6 1* 1* // Add OPERATER statement: PORV 9 MULTX PORV 1.0e6 1* 1*
bool addSuccess = deckFile.addOperaterKeyword( "GRID", "PORV", 9, "MULTX", "PORV", 1.0e6f, std::nullopt ); bool addSuccess = deckFile.replaceKeyword( "GRID", RimKeywordFactory::operaterKeyword( "PORV", 9, "MULTX", "PORV", 1.0e6f, std::nullopt ) );
EXPECT_TRUE( addSuccess ) << "Should successfully add OPERATER statement"; EXPECT_TRUE( addSuccess ) << "Should successfully add OPERATER statement";
// Save the deck to a temporary location // Save the deck to a temporary location
@@ -406,9 +410,10 @@ TEST( RifOpmFlowDeckFileTest, BcpropKeyword )
bcProperties.push_back( Opm::DeckRecord{ std::move( items ) } ); bcProperties.push_back( Opm::DeckRecord{ std::move( items ) } );
} }
// Add BCPROP keyword // Create BCPROP keyword using factory and replace in deck
bool bcpropAdded = deckFile.addBcpropKeyword( "GRID", boundaryConditions, bcProperties ); Opm::DeckKeyword bcpropKw = RimKeywordFactory::bcpropKeyword( boundaryConditions, bcProperties );
ASSERT_TRUE( bcpropAdded ) << "Failed to add BCPROP keyword"; bool bcpropAdded = deckFile.replaceKeyword( "GRID", bcpropKw );
ASSERT_TRUE( bcpropAdded ) << "Failed to replace BCPROP keyword";
// Save deck and verify format // Save deck and verify format
QString outputDeckPath = tempDir.filePath( "output_bcprop.DATA" ); QString outputDeckPath = tempDir.filePath( "output_bcprop.DATA" );
@@ -25,6 +25,8 @@
#include "RifReaderEclipseOutput.h" #include "RifReaderEclipseOutput.h"
#include "RigEclipseResultTools.h" #include "RigEclipseResultTools.h"
#include "ProjectDataModel/Jobs/RimKeywordFactory.h"
#include "RigActiveCellInfo.h" #include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h" #include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h" #include "RigEclipseCaseData.h"
@@ -32,6 +34,8 @@
#include "RigMainGrid.h" #include "RigMainGrid.h"
#include "RimEclipseResultCase.h" #include "RimEclipseResultCase.h"
#include "opm/input/eclipse/Deck/DeckKeyword.hpp"
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QTemporaryDir> #include <QTemporaryDir>
@@ -175,9 +179,10 @@ TEST( RigEclipseResultToolsTest, BorderCellBcconGeneration )
bool deckLoaded = deckFile.loadDeck( deckFilePath.toStdString() ); bool deckLoaded = deckFile.loadDeck( deckFilePath.toStdString() );
ASSERT_TRUE( deckLoaded ) << "Failed to load deck file"; ASSERT_TRUE( deckLoaded ) << "Failed to load deck file";
// Add BCCON keyword // Create BCCON keyword using factory and replace in deck
bool bcconAdded = deckFile.addBcconKeyword( "GRID", borderCellFaces ); Opm::DeckKeyword bcconKw = RimKeywordFactory::bcconKeyword( borderCellFaces );
ASSERT_TRUE( bcconAdded ) << "Failed to add BCCON keyword"; bool bcconAdded = deckFile.replaceKeyword( "GRID", bcconKw );
ASSERT_TRUE( bcconAdded ) << "Failed to replace BCCON keyword";
// Step 7: Save deck and verify format // Step 7: Save deck and verify format
QString outputDeckPath = tempDir.filePath( "output_bccon.DATA" ); QString outputDeckPath = tempDir.filePath( "output_bccon.DATA" );