#14683 Avoid building an Opm::Parser per keyword in schedule generation

Constructing an Opm::Parser populates the complete keyword database (2774
keywords, measured at 2.4 ms per construction) and this was done once per
keyword event in RifEventKeywordFormatter::buildKeyword, and twice more per
keyword in the column-aligned serialisation in RimKeywordFactory. Schedule
generation was therefore completely dominated by parser construction and grew
directly with the number of events on the timeline. Use a single shared parser
instance instead, since the parser is stateless once constructed.

Also compute the events for a date once in generateDateSection and pass them to
the per-well helpers, instead of calling RimWellEventTimeline::getEventsAtDate
four times per well and date, which scaled as dates x wells x events.

Generating a schedule for a production data set with 1737 events over 490 dates
goes from 4.2 s to 0.1 s, and 21000 events over 14 wells now complete in 0.5 s.
This commit is contained in:
Kristian Bendiksen committed 2026-09-07 18:58:05 +02:00
1 parent 51a4fa74bf
commit 30254df9e9
4 files changed
+56 -43

No files matched your search

@@ -64,6 +64,18 @@
///
///
//==================================================================================================
namespace
{
// A single shared parser instance is used for all keyword schema lookups. Constructing an
// Opm::Parser populates the complete keyword database and costs milliseconds, which is far too
// expensive to repeat for every keyword being serialised.
const Opm::Parser& sharedParser()
{
static const Opm::Parser parser;
return parser;
}
} // namespace
namespace RimKeywordFactory
{
@@ -932,8 +944,7 @@ QString deckKeywordToAlignedString( const Opm::DeckKeyword& keyword )
std::vector<std::string> canonicalItemOrder;
try
{
Opm::Parser parser;
const Opm::ParserKeyword& parserKeyword = parser.getKeyword( keyword.name() );
const Opm::ParserKeyword& parserKeyword = sharedParser().getKeyword( keyword.name() );
if ( std::distance( parserKeyword.begin(), parserKeyword.end() ) == 1 )
{
const Opm::ParserRecord& parserRecord = parserKeyword.getRecord( 0 );
@@ -1078,8 +1089,7 @@ QString deckKeywordToAlignedString( const Opm::DeckKeyword& keyword )
bool slashTerminated = true;
try
{
Opm::Parser parser;
slashTerminated = !parser.getKeyword( keyword.name() ).hasFixedSize();
slashTerminated = !sharedParser().getKeyword( keyword.name() ).hasFixedSize();
}
catch ( ... )
{