mirror of
https://github.com/OPM/ResInsight.git
synced 2026-09-03 20:53:13 -05:00
committed by
Magne Sjaastad
parent
d226e10e89
commit
ebf0ef0cc0
@@ -45,6 +45,14 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace
|
||||
{
|
||||
bool shouldEmitKeyword( const Opm::DeckKeyword& keyword )
|
||||
{
|
||||
return keyword.size() > 0 || keyword.isDataKeyword() || RifEventKeywordFormatter::isRecordlessKeyword( keyword );
|
||||
}
|
||||
} // namespace
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -146,7 +154,7 @@ std::vector<QDateTime> RicScheduleDataGenerator::collectAllDates( const RimWellE
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicScheduleDataGenerator::mergeKeyword( std::map<QString, Opm::DeckKeyword>& acc, const QString& name, Opm::DeckKeyword kw )
|
||||
{
|
||||
if ( kw.size() == 0 && !kw.isDataKeyword() ) return;
|
||||
if ( !shouldEmitKeyword( kw ) ) return;
|
||||
|
||||
auto it = acc.find( name );
|
||||
if ( it == acc.end() )
|
||||
@@ -172,7 +180,8 @@ std::expected<QString, QString> RicScheduleDataGenerator::generateDateSection( c
|
||||
bool alignColumns )
|
||||
{
|
||||
// Keyword priority order for output
|
||||
static const std::vector<QString> keywordOrder = { "WELSPECS",
|
||||
static const std::vector<QString> keywordOrder = { "END",
|
||||
"WELSPECS",
|
||||
"COMPORD",
|
||||
"GRUPTREE",
|
||||
"COMPDAT",
|
||||
@@ -333,7 +342,7 @@ std::expected<QString, QString> RicScheduleDataGenerator::generateDateSection( c
|
||||
|
||||
auto appendKeywordText = [&]( const Opm::DeckKeyword& kw )
|
||||
{
|
||||
if ( kw.size() == 0 && !kw.isDataKeyword() ) return;
|
||||
if ( !shouldEmitKeyword( kw ) ) return;
|
||||
appendEventComments( QString::fromStdString( kw.name() ) );
|
||||
result += serializeKeyword( kw );
|
||||
result += "\n";
|
||||
|
||||
@@ -56,6 +56,23 @@ QString keywordToString( const Opm::DeckKeyword& kw )
|
||||
}
|
||||
} // namespace
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RifEventKeywordFormatter::isRecordlessKeyword( const Opm::DeckKeyword& keyword )
|
||||
{
|
||||
try
|
||||
{
|
||||
static const Opm::Parser parser;
|
||||
const auto& parserKeyword = parser.getKeyword( keyword.name() );
|
||||
return parserKeyword.begin() == parserKeyword.end();
|
||||
}
|
||||
catch ( const std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -71,7 +88,17 @@ std::optional<Opm::DeckKeyword> RifEventKeywordFormatter::buildKeyword( const QS
|
||||
const Opm::ParserKeyword& parserKw = parser.getKeyword( kwName );
|
||||
Opm::DeckKeyword kw( parserKw );
|
||||
|
||||
const size_t numRecords = static_cast<size_t>( std::distance( parserKw.begin(), parserKw.end() ) );
|
||||
const size_t numRecords = static_cast<size_t>( std::distance( parserKw.begin(), parserKw.end() ) );
|
||||
if ( numRecords == 0 )
|
||||
{
|
||||
if ( !items.empty() )
|
||||
{
|
||||
RiaLogging::error( std::format( "Recordless keyword '{}' does not accept items.", keyword ) );
|
||||
return std::nullopt;
|
||||
}
|
||||
return kw;
|
||||
}
|
||||
|
||||
const Opm::ParserRecord& parserRecord = parserKw.getRecord( 0 );
|
||||
|
||||
auto stringValue = []( const RimWellEventKeywordItem* item ) -> std::string
|
||||
|
||||
@@ -33,6 +33,8 @@ class RimWellEventKeywordItem;
|
||||
|
||||
namespace RifEventKeywordFormatter
|
||||
{
|
||||
bool isRecordlessKeyword( const Opm::DeckKeyword& keyword );
|
||||
|
||||
// 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 );
|
||||
|
||||
@@ -2169,6 +2169,26 @@ class TestOrionEventsIntegration:
|
||||
assert "1 'FEB' 2024" in schedule
|
||||
assert "1 'JUN' 2024" in schedule
|
||||
|
||||
def test_end_is_first_keyword_after_date(self, project_with_case_and_wells):
|
||||
project, case, timeline = project_with_case_and_wells
|
||||
document = parse_orion_events(
|
||||
"ORIONEVENTS 2.0\nSCHEDULE\n"
|
||||
"2024-01-01 RPTRST BASIC=2 FREQ=1\n"
|
||||
"2024-01-01 END\n"
|
||||
)
|
||||
|
||||
report = apply_orion_document(document, timeline, project)
|
||||
assert report.errors == []
|
||||
schedule = timeline.generate_schedule_text(
|
||||
eclipse_case=case,
|
||||
first_date_as_comment=False,
|
||||
)
|
||||
|
||||
date_position = schedule.index("1 'JAN' 2024")
|
||||
end_position = schedule.index("\nEND\n", date_position)
|
||||
rptrst_position = schedule.index("\nRPTRST\n", date_position)
|
||||
assert date_position < end_position < rptrst_position
|
||||
|
||||
def test_apply_creates_perforations_and_schedule(self, project_with_case_and_wells):
|
||||
"""End-to-end: parse -> apply -> set_timestamp -> generate schedule."""
|
||||
project, case, timeline = project_with_case_and_wells
|
||||
|
||||
Reference in New Issue
Block a user