Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions ApplicationLibCode/FileInterface/RifOpmDeckTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,26 @@ Opm::DeckItem optionalItem( std::string name, std::optional<float> value )
return defaultItem( name );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Opm::DeckItem item( std::string name, std::set<std::string> values )
{
Opm::DeckItem item1( name, "" );
for ( const auto& value : values )
item1.push_back( value );
return item1;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Opm::DeckItem item( std::string name, std::vector<std::string> values )
{
Opm::DeckItem item1( name, "" );
for ( const auto& value : values )
item1.push_back( value );
return item1;
}

} // namespace RifOpmDeckTools
4 changes: 4 additions & 0 deletions ApplicationLibCode/FileInterface/RifOpmDeckTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
#pragma once

#include <optional>
#include <set>
#include <string>
#include <vector>

namespace Opm
{
Expand All @@ -38,5 +40,7 @@ Opm::DeckItem item( std::string name, double value );
Opm::DeckItem optionalItem( std::string name, std::optional<float> value );
Opm::DeckItem optionalItem( std::string name, std::optional<double> value );
Opm::DeckItem defaultItem( std::string name );
Opm::DeckItem item( std::string name, std::set<std::string> values );
Opm::DeckItem item( std::string name, std::vector<std::string> values );

} // namespace RifOpmDeckTools
13 changes: 13 additions & 0 deletions ApplicationLibCode/FileInterface/RifOpmFlowDeckFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,19 @@ bool RifOpmFlowDeckFile::replaceKeywordAtIndex( const Opm::FileDeck::Index& inde
return true;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifOpmFlowDeckFile::removeKeywordAtIndex( const Opm::FileDeck::Index& index )
{
if ( m_fileDeck.get() == nullptr ) return false;

// Erase the keyword at the given index and insert the new one
m_fileDeck->erase( index );

return true;
}

//--------------------------------------------------------------------------------------------------
/// Returns number of removed keywords
//--------------------------------------------------------------------------------------------------
Expand Down
3 changes: 2 additions & 1 deletion ApplicationLibCode/FileInterface/RifOpmFlowDeckFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ class RifOpmFlowDeckFile
bool replaceAllKeywords( const std::string& keywordName, const std::vector<Opm::DeckKeyword>& keywords );
bool replaceKeywordAtIndex( const Opm::FileDeck::Index& index, const Opm::DeckKeyword& keyword );

int removeKeywords( const std::string& keywordName );
int removeKeywords( const std::string& keywordName );
bool removeKeywordAtIndex( const Opm::FileDeck::Index& index );

private:
void splitDatesIfNecessary();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "RiaLogging.h"
#include "RiaNncDefines.h"
#include "RiaStdStringTools.h"

#include "RigModelPaddingSettings.h"
#include "RigPadModel.h"
Expand Down Expand Up @@ -145,7 +146,14 @@ std::expected<void, QString> RigSimulationInputTool::exportSimulationInput( RimE
return result;
}

if ( auto result = filterAndUpdateWellKeywords( &eclipseCase, settings, deckFile ); !result )
auto validWellNames = wellNamesToInclude( &eclipseCase, settings );

if ( auto result = filterAndUpdateWellKeywords( validWellNames, settings, deckFile ); !result )
{
return result;
}

if ( auto result = updateWellListKeywords( validWellNames, settings, deckFile ); !result )
{
return result;
}
Expand Down Expand Up @@ -1269,9 +1277,7 @@ std::expected<Opm::DeckRecord, QString> RigSimulationInputTool::processBoxRecord
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<void, QString> RigSimulationInputTool::filterAndUpdateWellKeywords( RimEclipseCase* eclipseCase,
const RigSimulationInputSettings& settings,
RifOpmFlowDeckFile& deckFile )
std::set<std::string> RigSimulationInputTool::wellNamesToInclude( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings )
{
// Find wells that intersect with the sector
auto intersectingWells = findIntersectingWells( eclipseCase, settings.min(), settings.max() );
Expand Down Expand Up @@ -1306,6 +1312,126 @@ std::expected<void, QString> RigSimulationInputTool::filterAndUpdateWellKeywords
return names;
}() ) ) );

return validWellNames;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<void, QString> RigSimulationInputTool::updateWellListKeywords( std::set<std::string>& validWellNames,
const RigSimulationInputSettings& settings,
RifOpmFlowDeckFile& deckFile )
{
using W = Opm::ParserKeywords::WLIST;

int replacedCount = 0;
int removedCount = 0;

// gather existing lists

auto keywordsWithIndices = deckFile.findAllKeywordsWithIndices( W::keywordName );
if ( keywordsWithIndices.empty() ) return {};

std::set<std::string> existingLists;

// for each WLIST keyword
for ( auto [index, kw] : keywordsWithIndices )
{
std::map<std::string, std::set<std::string>> wellLists;
std::map<std::string, std::set<std::string>> deleteLists;

// for each list operation in this keyword
for ( size_t recordIdx = 0; recordIdx < kw.size(); recordIdx++ )
{
const auto& record = kw.getRecord( recordIdx );
if ( record.size() < 3 ) continue;

// the list name
const auto& listNameItem = record.getItem( 0 );
if ( !listNameItem.hasValue( 0 ) || listNameItem.getType() != Opm::type_tag::string ) continue;
std::string listName = listNameItem.get<std::string>( 0 );

// the list operation
const auto& operationItem = record.getItem( 1 );
if ( !operationItem.hasValue( 0 ) || operationItem.getType() != Opm::type_tag::string ) continue;
std::string operationName = operationItem.get<std::string>( 0 );
operationName = RiaStdStringTools::toUpper( operationName );

bool delOperation = operationName == "DEL";
if ( operationName != "ADD" && operationName != "NEW" && !delOperation )
{
RiaLogging::warning( QString( "Unsupported %1 operation '%2' in list '%3', skipping" )
.arg( W::keywordName.c_str() )
.arg( operationName.c_str() )
.arg( listName.c_str() ) );
continue;
}

// the list of wells to do something with, only include the ones in our valid list
const auto& wellsItem = record.getItem( 2 );
for ( size_t i = 0; i < wellsItem.data_size(); i++ )
{
std::string wellName = wellsItem.get<std::string>( i );
if ( validWellNames.contains( wellName ) )
{
if ( delOperation )
deleteLists[listName].insert( wellName );
else
wellLists[listName].insert( wellName );
}
}
}
Opm::DeckKeyword newKw( kw.location(), kw.name() );

for ( const auto& [listName, wells] : wellLists )
{
if ( wells.empty() ) continue;
std::vector<Opm::DeckItem> items;
items.push_back( RifOpmDeckTools::item( "NAME", listName ) );
const std::string action = existingLists.contains( listName ) ? "ADD" : "NEW";
items.push_back( RifOpmDeckTools::item( "ACTION", action ) );
items.push_back( RifOpmDeckTools::item( "WELLS", wells ) );
newKw.addRecord( Opm::DeckRecord{ std::move( items ) } );
existingLists.insert( listName );
}

for ( const auto& [listName, wells] : deleteLists )
{
if ( wells.empty() ) continue;
std::vector<Opm::DeckItem> items;
items.push_back( RifOpmDeckTools::item( "NAME", listName ) );
items.push_back( RifOpmDeckTools::item( "ACTION", "DEL" ) );
items.push_back( RifOpmDeckTools::item( "WELLS", wells ) );
newKw.addRecord( Opm::DeckRecord{ std::move( items ) } );
}

if ( newKw.size() > 0 )
{
// replace the first wlist kw with the new one, remove remaining kws
deckFile.replaceKeywordAtIndex( index, std::move( newKw ) );
replacedCount++;
}
else
{
// replace with SKIP kw to remove later
deckFile.replaceKeywordAtIndex( index, Opm::DeckKeyword( kw.location(), "SKIP" ) );
removedCount++;
}
}

RiaLogging::info(
QString( "Processed keyword '%1': %2 updated, %3 removed" ).arg( W::keywordName.c_str() ).arg( replacedCount ).arg( removedCount ) );

return {};
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<void, QString> RigSimulationInputTool::filterAndUpdateWellKeywords( std::set<std::string>& validWellNames,
const RigSimulationInputSettings& settings,
RifOpmFlowDeckFile& deckFile )
{
// List of well-related keywords to filter (keywords that reference well names)
std::vector<std::string> wellKeywords = { "COMPDAT", "COMPLUMP", "COMPORD", "COMPSEGS", "WCONHIST", "WCONINJE", "WCONINJH",
"WCONPROD", "WCYCLE", "WDFAC", "WDFACCOR", "WEFAC", "WELCNTL", "WELOPEN",
Expand Down Expand Up @@ -1361,7 +1487,7 @@ std::expected<void, QString> RigSimulationInputTool::filterAndUpdateWellKeywords
if ( keywordName == "COMPSEGS" || keywordName == "WELSEGS" )
{
currentSegmentWell = wellName;
keepSegmentRecords = ( validWellNames.find( wellName ) != validWellNames.end() );
keepSegmentRecords = ( validWellNames.contains( wellName ) );
}
}
else if ( keywordName == "COMPSEGS" || keywordName == "WELSEGS" )
Expand All @@ -1371,7 +1497,7 @@ std::expected<void, QString> RigSimulationInputTool::filterAndUpdateWellKeywords
}

// Check if this well is in our valid set
if ( ( isWellNameRecord && validWellNames.find( wellName ) != validWellNames.end() ) ||
if ( ( isWellNameRecord && validWellNames.contains( wellName ) ) ||
( !isWellNameRecord && ( keywordName == "COMPSEGS" || keywordName == "WELSEGS" ) && keepSegmentRecords ) )
{
// For keywords with IJK coordinates, we need to transform them
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <expected>
#include <functional>
#include <set>
#include <string>
#include <vector>

Expand Down Expand Up @@ -148,8 +149,15 @@ class RigSimulationInputTool
static std::expected<void, QString>
addFaultsToDeckFile( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings, RifOpmFlowDeckFile& deckFile );

static std::expected<void, QString>
filterAndUpdateWellKeywords( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings, RifOpmFlowDeckFile& deckFile );
static std::expected<void, QString> filterAndUpdateWellKeywords( std::set<std::string>& validWellNames,
const RigSimulationInputSettings& settings,
RifOpmFlowDeckFile& deckFile );

static std::expected<void, QString> updateWellListKeywords( std::set<std::string>& validWellNames,
const RigSimulationInputSettings& settings,
RifOpmFlowDeckFile& deckFile );

static std::set<std::string> wellNamesToInclude( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings );

static std::expected<void, QString>
exportEditNncKeyword( RimEclipseCase* eclipseCase, const RigSimulationInputSettings& settings, RifOpmFlowDeckFile& deckFile );
Expand Down