mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 23:20:29 -05:00
#14063 Well Event: Group records of same keyword across wells
The schedule generator previously concatenated full keyword blocks (`KEYWORD ... /\n/\n`) — one per well — producing verbose output where each WELSPECS / COMPDAT / WCONHIST / WELSEGS / COMPSEGS / etc. block appeared once per contributing well. Eclipse keywords are designed to hold multiple records under a single header; the per-well repetition is syntactically valid but bloats the file and obscures intent. Switch `RicScheduleDataGenerator` to accumulate `std::map<QString, Opm::DeckKeyword>` instead of raw concatenated text. Each per-well helper now returns an `Opm::DeckKeyword`, and a new `mergeKeyword` primitive appends its records into the accumulator entry, creating the entry from the helper's keyword on first encounter. At emission time each accumulated keyword is serialised once. To support this, `RifEventKeywordFormatter` is split: each `format*` QString function now wraps a corresponding `build*` function that returns `std::optional<Opm::DeckKeyword>`. `RimWellEventKeyword` and `RimKeywordEvent` expose a parallel `generateDeckKeyword` accessor. The text-scraping `extractKeywordName` helper becomes dead code and is removed.
This commit is contained in:
1 parent
d2e7bed6b8
commit
6ef024cee9
9 files changed
+249
-177
No files matched your search
+86
-120
@@ -33,6 +33,7 @@
|
||||
#include "RimWellPathCompletionSettings.h"
|
||||
|
||||
#include "opm/input/eclipse/Deck/DeckKeyword.hpp"
|
||||
#include "opm/input/eclipse/Deck/DeckRecord.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
@@ -88,6 +89,26 @@ std::vector<QDateTime> RicScheduleDataGenerator::collectAllDates( const RimWellE
|
||||
return std::vector<QDateTime>( uniqueDates.begin(), uniqueDates.end() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Append the records of `kw` into the entry for `name`, creating that entry from a copy of `kw`
|
||||
/// on first encounter so the accumulated DeckKeyword is bound to the right ParserKeyword.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicScheduleDataGenerator::mergeKeyword( std::map<QString, Opm::DeckKeyword>& acc, const QString& name, Opm::DeckKeyword kw )
|
||||
{
|
||||
if ( kw.size() == 0 && !kw.isDataKeyword() ) return;
|
||||
|
||||
auto it = acc.find( name );
|
||||
if ( it == acc.end() )
|
||||
{
|
||||
acc.emplace( name, std::move( kw ) );
|
||||
return;
|
||||
}
|
||||
for ( const auto& rec : kw )
|
||||
{
|
||||
it->second.addRecord( Opm::DeckRecord( rec ) );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -120,66 +141,64 @@ QString RicScheduleDataGenerator::generateDateSection( const RimWellEventTimelin
|
||||
// Generate DATES keyword
|
||||
result += RimKeywordFactory::deckKeywordToString( RimKeywordFactory::datesKeyword( date ) ) + "\n";
|
||||
|
||||
// Collect all keyword output into a map keyed by keyword name
|
||||
std::map<QString, QString> keywordBlocks;
|
||||
// Records for each keyword name are accumulated across wells, then serialised once below.
|
||||
std::map<QString, Opm::DeckKeyword> keywordBlocks;
|
||||
|
||||
for ( auto* well : wellPaths )
|
||||
{
|
||||
if ( !well ) continue;
|
||||
|
||||
QString welspecsKw = generateWelspecsForWell( timeline, eclipseCase, *well, date );
|
||||
if ( !welspecsKw.isEmpty() )
|
||||
if ( auto welspecs = generateWelspecsForWell( timeline, eclipseCase, *well, date ) )
|
||||
{
|
||||
keywordBlocks["WELSPECS"] += welspecsKw;
|
||||
mergeKeyword( keywordBlocks, "WELSPECS", std::move( *welspecs ) );
|
||||
}
|
||||
|
||||
QString wellCompdat = generateCompdatForWell( timeline, eclipseCase, *well, date );
|
||||
if ( !wellCompdat.isEmpty() )
|
||||
if ( auto compdat = generateCompdatForWell( timeline, eclipseCase, *well, date ) )
|
||||
{
|
||||
keywordBlocks["COMPDAT"] += wellCompdat;
|
||||
mergeKeyword( keywordBlocks, "COMPDAT", std::move( *compdat ) );
|
||||
}
|
||||
|
||||
generateMswForWell( timeline, eclipseCase, *well, date, keywordBlocks );
|
||||
generateWellControlForWell( timeline, *well, date, keywordBlocks );
|
||||
}
|
||||
|
||||
// Process schedule-level keyword events (not tied to a specific well)
|
||||
// Schedule-level keyword events (not tied to a specific well)
|
||||
auto events = timeline.getEventsAtDate( date );
|
||||
for ( auto* event : events )
|
||||
{
|
||||
if ( event->eventType() == RimWellEvent::EventType::SCHEDULE_KEYWORD )
|
||||
if ( event->eventType() != RimWellEvent::EventType::SCHEDULE_KEYWORD ) continue;
|
||||
auto* keywordEvent = dynamic_cast<RimKeywordEvent*>( event );
|
||||
if ( !keywordEvent ) continue;
|
||||
if ( auto kw = keywordEvent->generateDeckKeyword( "" ) )
|
||||
{
|
||||
auto* keywordEvent = dynamic_cast<RimKeywordEvent*>( event );
|
||||
if ( keywordEvent )
|
||||
{
|
||||
QString keywordStr = keywordEvent->generateScheduleKeyword( "" );
|
||||
if ( !keywordStr.isEmpty() )
|
||||
{
|
||||
keywordBlocks[keywordEvent->keywordName().toUpper()] += keywordStr + "\n";
|
||||
}
|
||||
}
|
||||
mergeKeyword( keywordBlocks, keywordEvent->keywordName().toUpper(), std::move( *kw ) );
|
||||
}
|
||||
}
|
||||
|
||||
auto appendKeywordText = [&]( const Opm::DeckKeyword& kw )
|
||||
{
|
||||
if ( kw.size() == 0 && !kw.isDataKeyword() ) return;
|
||||
result += RimKeywordFactory::deckKeywordToString( kw );
|
||||
result += "\n";
|
||||
};
|
||||
|
||||
// Output keywords in priority order
|
||||
std::set<QString> emitted;
|
||||
for ( const auto& kw : keywordOrder )
|
||||
{
|
||||
auto it = keywordBlocks.find( kw );
|
||||
if ( it != keywordBlocks.end() && !it->second.isEmpty() )
|
||||
if ( it != keywordBlocks.end() )
|
||||
{
|
||||
result += it->second;
|
||||
appendKeywordText( it->second );
|
||||
emitted.insert( kw );
|
||||
}
|
||||
}
|
||||
|
||||
// Output remaining keywords not in priority list
|
||||
for ( const auto& [kw, data] : keywordBlocks )
|
||||
// Output remaining keywords not in the priority list
|
||||
for ( const auto& [kw, deckKw] : keywordBlocks )
|
||||
{
|
||||
if ( emitted.find( kw ) == emitted.end() && !data.isEmpty() )
|
||||
{
|
||||
result += data;
|
||||
}
|
||||
if ( emitted.contains( kw ) ) continue;
|
||||
appendKeywordText( deckKw );
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -188,12 +207,11 @@ QString RicScheduleDataGenerator::generateDateSection( const RimWellEventTimelin
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RicScheduleDataGenerator::generateWelspecsForWell( const RimWellEventTimeline& timeline,
|
||||
RimEclipseCase& eclipseCase,
|
||||
RimWellPath& well,
|
||||
const QDateTime& date )
|
||||
std::optional<Opm::DeckKeyword> RicScheduleDataGenerator::generateWelspecsForWell( const RimWellEventTimeline& timeline,
|
||||
RimEclipseCase& eclipseCase,
|
||||
RimWellPath& well,
|
||||
const QDateTime& date )
|
||||
{
|
||||
// Get perforation events at this exact date for this well
|
||||
auto events = timeline.getEventsAtDate( date );
|
||||
|
||||
bool hasEvents = false;
|
||||
@@ -208,27 +226,22 @@ QString RicScheduleDataGenerator::generateWelspecsForWell( const RimWellEventTim
|
||||
}
|
||||
}
|
||||
|
||||
if ( !hasEvents ) return QString();
|
||||
if ( !hasEvents ) return std::nullopt;
|
||||
|
||||
std::string wellGroupName = well.completionSettings()->groupNameForExport().toStdString();
|
||||
auto welspecsKw = RimKeywordFactory::welspecsKeyword( wellGroupName, &eclipseCase, &well );
|
||||
|
||||
QString result;
|
||||
result += RimKeywordFactory::deckKeywordToString( welspecsKw );
|
||||
result += "\n";
|
||||
|
||||
return result;
|
||||
if ( welspecsKw.name().empty() ) return std::nullopt;
|
||||
return welspecsKw;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RicScheduleDataGenerator::generateCompdatForWell( const RimWellEventTimeline& timeline,
|
||||
RimEclipseCase& eclipseCase,
|
||||
RimWellPath& well,
|
||||
const QDateTime& date )
|
||||
std::optional<Opm::DeckKeyword> RicScheduleDataGenerator::generateCompdatForWell( const RimWellEventTimeline& timeline,
|
||||
RimEclipseCase& eclipseCase,
|
||||
RimWellPath& well,
|
||||
const QDateTime& date )
|
||||
{
|
||||
// Get perforation events at this exact date for this well
|
||||
auto events = timeline.getEventsAtDate( date );
|
||||
|
||||
bool hasPerfEvents = false;
|
||||
@@ -241,38 +254,32 @@ QString RicScheduleDataGenerator::generateCompdatForWell( const RimWellEventTime
|
||||
}
|
||||
}
|
||||
|
||||
if ( !hasPerfEvents ) return QString();
|
||||
if ( !hasPerfEvents ) return std::nullopt;
|
||||
|
||||
auto compdata = RicWellPathExportCompletionDataFeatureImpl::completionDataForWellPath( &well, &eclipseCase, date );
|
||||
auto wellName = well.completionSettings()->wellNameForExport().toStdString();
|
||||
|
||||
auto compdatKw = RimKeywordFactory::compdatKeyword( compdata, wellName );
|
||||
QString result;
|
||||
result += RimKeywordFactory::deckKeywordToString( compdatKw );
|
||||
result += "\n";
|
||||
|
||||
return result;
|
||||
auto compdatKw = RimKeywordFactory::compdatKeyword( compdata, wellName );
|
||||
if ( compdatKw.name().empty() ) return std::nullopt;
|
||||
return compdatKw;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicScheduleDataGenerator::generateMswForWell( const RimWellEventTimeline& timeline,
|
||||
RimEclipseCase& eclipseCase,
|
||||
RimWellPath& wellPath,
|
||||
const QDateTime& date,
|
||||
std::map<QString, QString>& keywordBlocks )
|
||||
void RicScheduleDataGenerator::generateMswForWell( const RimWellEventTimeline& timeline,
|
||||
RimEclipseCase& eclipseCase,
|
||||
RimWellPath& wellPath,
|
||||
const QDateTime& date,
|
||||
std::map<QString, Opm::DeckKeyword>& keywordBlocks )
|
||||
{
|
||||
// Check if the well has MSW configured (from any previous tubing events applied via set_timestamp)
|
||||
// If MSW is enabled, we should generate WELSEGS/COMPSEGS instead of COMPDAT
|
||||
auto* mswParams = wellPath.mswCompletionParameters();
|
||||
if ( !mswParams )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Also check if there are valve or tubing events at this specific date for this well
|
||||
// (these trigger updates to the MSW configuration)
|
||||
// MSW is generated only when there are valve/tubing/perforation events at this exact date.
|
||||
auto events = timeline.getEventsAtDate( date );
|
||||
bool hasMswEvents = false;
|
||||
bool hasPerfEvents = false;
|
||||
@@ -290,15 +297,11 @@ void RicScheduleDataGenerator::generateMswForWell( const RimWellEventTimeline& t
|
||||
}
|
||||
}
|
||||
|
||||
// Only generate MSW output if there are events at this specific date for this well
|
||||
// This ensures wells only appear in schedule sections at their event dates
|
||||
if ( !hasMswEvents && !hasPerfEvents )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract MSW data using the existing infrastructure
|
||||
// Pass the export date to filter valve/perforation output based on their creation dates
|
||||
bool exportAfterMainBore = true;
|
||||
auto mswDataResult = RicWellPathExportMswTableData::extractSingleWellMswData( &eclipseCase,
|
||||
&wellPath,
|
||||
@@ -310,77 +313,40 @@ void RicScheduleDataGenerator::generateMswForWell( const RimWellEventTimeline& t
|
||||
|
||||
const auto& mswData = mswDataResult.value();
|
||||
|
||||
// Generate WELSEGS keyword
|
||||
int maxSegments = 0;
|
||||
int maxBranches = 0;
|
||||
Opm::DeckKeyword welsegsKw = RimKeywordFactory::welsegsKeyword( mswData, maxSegments, maxBranches );
|
||||
if ( welsegsKw.isDataKeyword() || welsegsKw.size() > 0 )
|
||||
{
|
||||
keywordBlocks["WELSEGS"] += RimKeywordFactory::deckKeywordToString( welsegsKw ) + "\n";
|
||||
}
|
||||
int maxSegments = 0;
|
||||
int maxBranches = 0;
|
||||
auto welsegsKw = RimKeywordFactory::welsegsKeyword( mswData, maxSegments, maxBranches );
|
||||
mergeKeyword( keywordBlocks, "WELSEGS", std::move( welsegsKw ) );
|
||||
|
||||
// Generate COMPSEGS keyword
|
||||
Opm::DeckKeyword compsegsKw = RimKeywordFactory::compsegsKeyword( mswData );
|
||||
if ( compsegsKw.isDataKeyword() || compsegsKw.size() > 0 )
|
||||
{
|
||||
keywordBlocks["COMPSEGS"] += RimKeywordFactory::deckKeywordToString( compsegsKw ) + "\n";
|
||||
}
|
||||
auto compsegsKw = RimKeywordFactory::compsegsKeyword( mswData );
|
||||
mergeKeyword( keywordBlocks, "COMPSEGS", std::move( compsegsKw ) );
|
||||
|
||||
// Generate WSEGVALV keyword (for valve events)
|
||||
Opm::DeckKeyword wsegvalvKw = RimKeywordFactory::wsegvalvKeyword( mswData );
|
||||
if ( wsegvalvKw.isDataKeyword() || wsegvalvKw.size() > 0 )
|
||||
{
|
||||
keywordBlocks["WSEGVALV"] += RimKeywordFactory::deckKeywordToString( wsegvalvKw ) + "\n";
|
||||
}
|
||||
auto wsegvalvKw = RimKeywordFactory::wsegvalvKeyword( mswData );
|
||||
mergeKeyword( keywordBlocks, "WSEGVALV", std::move( wsegvalvKw ) );
|
||||
|
||||
// Generate WSEGAICD keyword (if AICD data present)
|
||||
Opm::DeckKeyword wsegaicdKw = RimKeywordFactory::wsegaicdKeyword( mswData );
|
||||
if ( wsegaicdKw.isDataKeyword() || wsegaicdKw.size() > 0 )
|
||||
{
|
||||
keywordBlocks["WSEGAICD"] += RimKeywordFactory::deckKeywordToString( wsegaicdKw ) + "\n";
|
||||
}
|
||||
auto wsegaicdKw = RimKeywordFactory::wsegaicdKeyword( mswData );
|
||||
mergeKeyword( keywordBlocks, "WSEGAICD", std::move( wsegaicdKw ) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicScheduleDataGenerator::generateWellControlForWell( const RimWellEventTimeline& timeline,
|
||||
const RimWellPath& well,
|
||||
const QDateTime& date,
|
||||
std::map<QString, QString>& keywordBlocks )
|
||||
void RicScheduleDataGenerator::generateWellControlForWell( const RimWellEventTimeline& timeline,
|
||||
const RimWellPath& well,
|
||||
const QDateTime& date,
|
||||
std::map<QString, Opm::DeckKeyword>& keywordBlocks )
|
||||
{
|
||||
// Get state and control events at this exact date for this well
|
||||
auto events = timeline.getEventsAtDate( date );
|
||||
|
||||
for ( auto* event : events )
|
||||
{
|
||||
if ( event->wellName() != well.name() ) continue;
|
||||
|
||||
QString keywordStr = RifEventKeywordFormatter::formatWellEvent( event, well.name() );
|
||||
if ( !keywordStr.isEmpty() )
|
||||
{
|
||||
QString kwName = extractKeywordName( keywordStr );
|
||||
if ( !kwName.isEmpty() )
|
||||
{
|
||||
keywordBlocks[kwName] += keywordStr + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
auto kw = RifEventKeywordFormatter::buildWellEvent( event, well.name() );
|
||||
if ( !kw ) continue;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RicScheduleDataGenerator::extractKeywordName( const QString& block )
|
||||
{
|
||||
const auto lines = block.split( '\n' );
|
||||
for ( const auto& line : lines )
|
||||
{
|
||||
QString trimmed = line.trimmed();
|
||||
if ( !trimmed.isEmpty() && !trimmed.startsWith( "--" ) )
|
||||
{
|
||||
return trimmed;
|
||||
}
|
||||
const QString name = QString::fromStdString( kw->name() );
|
||||
if ( name.isEmpty() ) continue;
|
||||
mergeKeyword( keywordBlocks, name, std::move( *kw ) );
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <QString>
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
class RimEclipseCase;
|
||||
@@ -29,6 +30,11 @@ class RimWellPath;
|
||||
class RimWellEvent;
|
||||
class RimWellEventTimeline;
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
class DeckKeyword;
|
||||
} // namespace Opm
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
/// Generator for Eclipse schedule data based on well events
|
||||
@@ -53,26 +59,26 @@ private:
|
||||
const std::vector<RimWellPath*>& wellPaths,
|
||||
const QDateTime& date );
|
||||
|
||||
static QString
|
||||
static std::optional<Opm::DeckKeyword>
|
||||
generateWelspecsForWell( const RimWellEventTimeline& timeline, RimEclipseCase& eclipseCase, RimWellPath& well, const QDateTime& date );
|
||||
|
||||
// Generate COMPDAT for a well at a specific date based on events
|
||||
static QString
|
||||
static std::optional<Opm::DeckKeyword>
|
||||
generateCompdatForWell( const RimWellEventTimeline& timeline, RimEclipseCase& eclipseCase, RimWellPath& well, const QDateTime& date );
|
||||
|
||||
// Generate WELSEGS and COMPSEGS for a well at a specific date, populating keyword blocks map
|
||||
static void generateMswForWell( const RimWellEventTimeline& timeline,
|
||||
RimEclipseCase& eclipseCase,
|
||||
RimWellPath& well,
|
||||
const QDateTime& date,
|
||||
std::map<QString, QString>& keywordBlocks );
|
||||
// Generate WELSEGS / COMPSEGS / WSEGVALV / WSEGAICD for a well at a specific date, merging into the accumulator
|
||||
static void generateMswForWell( const RimWellEventTimeline& timeline,
|
||||
RimEclipseCase& eclipseCase,
|
||||
RimWellPath& well,
|
||||
const QDateTime& date,
|
||||
std::map<QString, Opm::DeckKeyword>& keywordBlocks );
|
||||
|
||||
// Generate well control keywords (WCONPROD, WCONINJE, WELOPEN) for a well at a specific date, populating keyword blocks map
|
||||
static void generateWellControlForWell( const RimWellEventTimeline& timeline,
|
||||
const RimWellPath& well,
|
||||
const QDateTime& date,
|
||||
std::map<QString, QString>& keywordBlocks );
|
||||
// Generate well control / well keyword event keywords for a well at a specific date, merging into the accumulator
|
||||
static void generateWellControlForWell( const RimWellEventTimeline& timeline,
|
||||
const RimWellPath& well,
|
||||
const QDateTime& date,
|
||||
std::map<QString, Opm::DeckKeyword>& keywordBlocks );
|
||||
|
||||
// Extract keyword name from the first non-comment line of a keyword block
|
||||
static QString extractKeywordName( const QString& block );
|
||||
// Append records of `kw` into the entry for `name`, creating it from `kw` if absent
|
||||
static void mergeKeyword( std::map<QString, Opm::DeckKeyword>& acc, const QString& name, Opm::DeckKeyword kw );
|
||||
};
|
||||
@@ -43,10 +43,23 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace
|
||||
{
|
||||
QString keywordToString( const Opm::DeckKeyword& kw )
|
||||
{
|
||||
if ( kw.name().empty() ) return {};
|
||||
std::ostringstream oss;
|
||||
Opm::DeckOutput out( oss, 10 );
|
||||
kw.write( out );
|
||||
return QString::fromStdString( oss.str() );
|
||||
}
|
||||
} // namespace
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RifEventKeywordFormatter::formatKeyword( const QString& keywordName, const std::vector<RimWellEventKeywordItem*>& items )
|
||||
std::optional<Opm::DeckKeyword> RifEventKeywordFormatter::buildKeyword( const QString& keywordName,
|
||||
const std::vector<RimWellEventKeywordItem*>& items )
|
||||
{
|
||||
QString keyword = keywordName.toUpper();
|
||||
std::string kwName = keyword.toStdString();
|
||||
@@ -185,29 +198,20 @@ QString RifEventKeywordFormatter::formatKeyword( const QString& keywordName, con
|
||||
}
|
||||
}
|
||||
|
||||
// Return empty string if keyword creation failed
|
||||
if ( kw.name().empty() )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// Format with OPM DeckOutput
|
||||
std::ostringstream oss;
|
||||
Opm::DeckOutput out( oss, 10 );
|
||||
kw.write( out );
|
||||
return QString::fromStdString( oss.str() );
|
||||
if ( kw.name().empty() ) return std::nullopt;
|
||||
return kw;
|
||||
}
|
||||
catch ( const std::exception& e )
|
||||
{
|
||||
RiaLogging::error( std::format( "Failed to create keyword '{}': {}", keyword, e.what() ) );
|
||||
return "";
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RifEventKeywordFormatter::formatWconprod( const RimWellEventControl* controlEvent, const QString& wellName )
|
||||
std::optional<Opm::DeckKeyword> RifEventKeywordFormatter::buildWconprod( const RimWellEventControl* controlEvent, const QString& wellName )
|
||||
{
|
||||
using W = Opm::ParserKeywords::WCONPROD;
|
||||
|
||||
@@ -243,17 +247,13 @@ QString RifEventKeywordFormatter::formatWconprod( const RimWellEventControl* con
|
||||
|
||||
Opm::DeckKeyword kw{ W() };
|
||||
kw.addRecord( Opm::DeckRecord{ std::move( items ) } );
|
||||
|
||||
std::ostringstream oss;
|
||||
Opm::DeckOutput out( oss, 10 );
|
||||
kw.write( out );
|
||||
return QString::fromStdString( oss.str() );
|
||||
return kw;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RifEventKeywordFormatter::formatWconinje( const RimWellEventControl* controlEvent, const QString& wellName )
|
||||
std::optional<Opm::DeckKeyword> RifEventKeywordFormatter::buildWconinje( const RimWellEventControl* controlEvent, const QString& wellName )
|
||||
{
|
||||
using W = Opm::ParserKeywords::WCONINJE;
|
||||
|
||||
@@ -281,41 +281,57 @@ QString RifEventKeywordFormatter::formatWconinje( const RimWellEventControl* con
|
||||
|
||||
Opm::DeckKeyword kw{ W() };
|
||||
kw.addRecord( Opm::DeckRecord{ std::move( items ) } );
|
||||
|
||||
std::ostringstream oss;
|
||||
Opm::DeckOutput out( oss, 10 );
|
||||
kw.write( out );
|
||||
return QString::fromStdString( oss.str() );
|
||||
return kw;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RifEventKeywordFormatter::formatWellEvent( const RimWellEvent* event, const QString& wellName )
|
||||
std::optional<Opm::DeckKeyword> RifEventKeywordFormatter::buildWellEvent( const RimWellEvent* event, const QString& wellName )
|
||||
{
|
||||
if ( event->eventType() == RimWellEvent::EventType::WCONTROL )
|
||||
{
|
||||
auto* controlEvent = dynamic_cast<const RimWellEventControl*>( event );
|
||||
const auto* controlEvent = dynamic_cast<const RimWellEventControl*>( event );
|
||||
if ( controlEvent )
|
||||
{
|
||||
if ( controlEvent->isProducer() )
|
||||
{
|
||||
return formatWconprod( controlEvent, wellName );
|
||||
}
|
||||
else
|
||||
{
|
||||
return formatWconinje( controlEvent, wellName );
|
||||
}
|
||||
return controlEvent->isProducer() ? buildWconprod( controlEvent, wellName ) : buildWconinje( controlEvent, wellName );
|
||||
}
|
||||
}
|
||||
else if ( event->eventType() == RimWellEvent::EventType::KEYWORD )
|
||||
{
|
||||
auto* keywordEvent = dynamic_cast<const RimWellEventKeyword*>( event );
|
||||
const auto* keywordEvent = dynamic_cast<const RimWellEventKeyword*>( event );
|
||||
if ( keywordEvent )
|
||||
{
|
||||
return formatKeyword( keywordEvent->keywordName(), keywordEvent->items() );
|
||||
return buildKeyword( keywordEvent->keywordName(), keywordEvent->items() );
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// QString-returning wrappers: build the keyword and serialize once.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RifEventKeywordFormatter::formatKeyword( const QString& keywordName, const std::vector<RimWellEventKeywordItem*>& items )
|
||||
{
|
||||
auto kw = buildKeyword( keywordName, items );
|
||||
return kw ? keywordToString( *kw ) : QString();
|
||||
}
|
||||
|
||||
QString RifEventKeywordFormatter::formatWconprod( const RimWellEventControl* controlEvent, const QString& wellName )
|
||||
{
|
||||
auto kw = buildWconprod( controlEvent, wellName );
|
||||
return kw ? keywordToString( *kw ) : QString();
|
||||
}
|
||||
|
||||
QString RifEventKeywordFormatter::formatWconinje( const RimWellEventControl* controlEvent, const QString& wellName )
|
||||
{
|
||||
auto kw = buildWconinje( controlEvent, wellName );
|
||||
return kw ? keywordToString( *kw ) : QString();
|
||||
}
|
||||
|
||||
QString RifEventKeywordFormatter::formatWellEvent( const RimWellEvent* event, const QString& wellName )
|
||||
{
|
||||
auto kw = buildWellEvent( event, wellName );
|
||||
return kw ? keywordToString( *kw ) : QString();
|
||||
}
|
||||
@@ -19,14 +19,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
class DeckKeyword;
|
||||
} // namespace Opm
|
||||
|
||||
class RimWellEventControl;
|
||||
class RimWellEvent;
|
||||
class RimWellEventKeywordItem;
|
||||
|
||||
namespace RifEventKeywordFormatter
|
||||
{
|
||||
// build*: produce a structured Opm::DeckKeyword (used by callers that merge records across wells).
|
||||
std::optional<Opm::DeckKeyword> buildKeyword( const QString& keywordName, const std::vector<RimWellEventKeywordItem*>& items );
|
||||
std::optional<Opm::DeckKeyword> buildWconprod( const RimWellEventControl* controlEvent, const QString& wellName );
|
||||
std::optional<Opm::DeckKeyword> buildWconinje( const RimWellEventControl* controlEvent, const QString& wellName );
|
||||
std::optional<Opm::DeckKeyword> buildWellEvent( const RimWellEvent* event, const QString& wellName );
|
||||
|
||||
// format*: serialize the build* result to text. Convenience for single-keyword stringification.
|
||||
QString formatKeyword( const QString& keywordName, const std::vector<RimWellEventKeywordItem*>& items );
|
||||
QString formatWconprod( const RimWellEventControl* controlEvent, const QString& wellName );
|
||||
QString formatWconinje( const RimWellEventControl* controlEvent, const QString& wellName );
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#include "FileInterface/RifEventKeywordFormatter.h"
|
||||
|
||||
#include "opm/input/eclipse/Deck/DeckKeyword.hpp"
|
||||
|
||||
#include "cafPdmFieldScriptingCapability.h"
|
||||
#include "cafPdmObjectScriptingCapability.h"
|
||||
#include "cafPdmUiOrdering.h"
|
||||
@@ -133,6 +135,14 @@ QString RimKeywordEvent::generateScheduleKeyword( const QString& wellName ) cons
|
||||
return RifEventKeywordFormatter::formatKeyword( m_keywordName(), items() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::optional<Opm::DeckKeyword> RimKeywordEvent::generateDeckKeyword( const QString& wellName ) const
|
||||
{
|
||||
return RifEventKeywordFormatter::buildKeyword( m_keywordName(), items() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -22,8 +22,14 @@
|
||||
|
||||
#include "cafPdmField.h"
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
class DeckKeyword;
|
||||
} // namespace Opm
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
/// Schedule-level keyword event - represents a schedule keyword with arbitrary keyword items
|
||||
@@ -51,8 +57,9 @@ public:
|
||||
std::vector<class RimWellEventKeywordItem*> items() const;
|
||||
|
||||
// Override from RimWellEvent
|
||||
EventType eventType() const override { return EventType::SCHEDULE_KEYWORD; }
|
||||
QString generateScheduleKeyword( const QString& wellName ) const override;
|
||||
EventType eventType() const override { return EventType::SCHEDULE_KEYWORD; }
|
||||
QString generateScheduleKeyword( const QString& wellName ) const override;
|
||||
std::optional<Opm::DeckKeyword> generateDeckKeyword( const QString& wellName ) const;
|
||||
|
||||
protected:
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#include "FileInterface/RifEventKeywordFormatter.h"
|
||||
|
||||
#include "opm/input/eclipse/Deck/DeckKeyword.hpp"
|
||||
|
||||
#include "cafPdmFieldScriptingCapability.h"
|
||||
#include "cafPdmObjectScriptingCapability.h"
|
||||
#include "cafPdmUiOrdering.h"
|
||||
@@ -133,6 +135,14 @@ QString RimWellEventKeyword::generateScheduleKeyword( const QString& wellName )
|
||||
return RifEventKeywordFormatter::formatKeyword( m_keywordName(), items() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::optional<Opm::DeckKeyword> RimWellEventKeyword::generateDeckKeyword( const QString& wellName ) const
|
||||
{
|
||||
return RifEventKeywordFormatter::buildKeyword( m_keywordName(), items() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -22,8 +22,14 @@
|
||||
|
||||
#include "cafPdmField.h"
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
class DeckKeyword;
|
||||
} // namespace Opm
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
/// Well keyword event - represents a schedule keyword with arbitrary keyword items
|
||||
@@ -50,8 +56,9 @@ public:
|
||||
std::vector<class RimWellEventKeywordItem*> items() const;
|
||||
|
||||
// Override from RimWellEvent
|
||||
EventType eventType() const override { return EventType::KEYWORD; }
|
||||
QString generateScheduleKeyword( const QString& wellName ) const override;
|
||||
EventType eventType() const override { return EventType::KEYWORD; }
|
||||
QString generateScheduleKeyword( const QString& wellName ) const override;
|
||||
std::optional<Opm::DeckKeyword> generateDeckKeyword( const QString& wellName ) const;
|
||||
|
||||
protected:
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
|
||||
Reference in new issue
Block a user