From 11942e377fb6fc29fc8d04bdcb10d69bcebd4012 Mon Sep 17 00:00:00 2001 From: JJ <69144954+jonjenssen@users.noreply.github.com> Date: Tue, 7 Oct 2025 18:21:15 +0200 Subject: [PATCH] Opm Flow: Support for adding more dates to data file (#12991) * Add support for appending dates keyword at end of file * Make sure well group from job is used * Increase well groups in welldims in case a new group is made * GUI cleanup --- .../FileInterface/RifOpmFlowDeckFile.cpp | 226 ++++++++++-------- .../FileInterface/RifOpmFlowDeckFile.h | 1 + .../RimWellPathCompletionSettings.cpp | 8 + .../RimWellPathCompletionSettings.h | 1 + .../ProjectDataModel/Jobs/RimOpmFlowJob.cpp | 187 +++++++++++---- .../ProjectDataModel/Jobs/RimOpmFlowJob.h | 15 ++ 6 files changed, 299 insertions(+), 139 deletions(-) diff --git a/ApplicationLibCode/FileInterface/RifOpmFlowDeckFile.cpp b/ApplicationLibCode/FileInterface/RifOpmFlowDeckFile.cpp index 87abff83b3..6261a3b41e 100644 --- a/ApplicationLibCode/FileInterface/RifOpmFlowDeckFile.cpp +++ b/ApplicationLibCode/FileInterface/RifOpmFlowDeckFile.cpp @@ -70,13 +70,13 @@ static std::optional locateTimeStep( std::unique_ptr locateKeywordAtTimeStep( std::unique_ptr& fileDeck, int timeStep, std::string keyword ) { - auto startPos = internal::locateTimeStep( fileDeck, timeStep ); - if ( startPos.has_value() ) + auto startIdx = internal::locateTimeStep( fileDeck, timeStep ); + if ( startIdx.has_value() ) { - auto startIdx = startPos.value(); - startIdx--; + auto idx = startIdx.value(); + idx--; // locate keyword for the selected step, break if another date is found - for ( auto it = startIdx; it != fileDeck->start(); it-- ) + for ( auto it = idx; it != fileDeck->start(); it-- ) { auto& kw = fileDeck->operator[]( it ); if ( kw.name() == Opm::ParserKeywords::DATES::keywordName ) @@ -154,13 +154,13 @@ static Opm::ParseContext defaultParseContext() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -static bool insertDataAtPosition( std::unique_ptr& fileDeck, Opm::DeckKeyword& keyword, Opm::FileDeck::Index insertPos ) +static bool insertKeywordAtIndex( std::unique_ptr& fileDeck, Opm::DeckKeyword& keyword, Opm::FileDeck::Index insertIdx ) { Opm::ErrorGuard errors{}; try { - fileDeck->insert( insertPos, keyword ); + fileDeck->insert( insertIdx, keyword ); } catch ( ... ) { @@ -176,17 +176,17 @@ static bool insertDataAtPosition( std::unique_ptr& fileDeck, Opm: static std::optional findSectionInsertionPoint( std::unique_ptr& fileDeck, const std::string& section ) { // Find the specified section - auto sectionPos = fileDeck->find( section ); - if ( !sectionPos.has_value() ) + auto sectionIdx = fileDeck->find( section ); + if ( !sectionIdx.has_value() ) { return std::nullopt; // Section not found } - auto insertPos = sectionPos.value(); - insertPos++; // Start after the section keyword + auto insertIdx = sectionIdx.value(); + insertIdx++; // Start after the section keyword // Find a good insertion point within the section - for ( auto it = insertPos; it != fileDeck->stop(); it++ ) + for ( auto it = insertIdx; it != fileDeck->stop(); it++ ) { auto& kw = fileDeck->operator[]( it ); @@ -196,16 +196,16 @@ static std::optional findSectionInsertionPoint( std::uniqu kw.name() == Opm::ParserKeywords::SOLUTION::keywordName || kw.name() == Opm::ParserKeywords::SUMMARY::keywordName || kw.name() == Opm::ParserKeywords::SCHEDULE::keywordName ) { - insertPos = it; + insertIdx = it; break; } // Keep moving forward in the current section - insertPos = it; - insertPos++; + insertIdx = it; + insertIdx++; } - return insertPos; + return insertIdx; } } // namespace internal @@ -278,7 +278,7 @@ void RifOpmFlowDeckFile::splitDatesIfNecessary() } std::reverse( newKeywords.begin(), newKeywords.end() ); - // erase old kw and insert the new ones at the same position + // erase old kw and insert the new ones at the same index m_fileDeck->erase( it ); for ( auto& newKw : newKeywords ) { @@ -372,7 +372,7 @@ bool RifOpmFlowDeckFile::mergeWellDeckAtTimeStep( int timeStep, std::string file } // increase wells and connections in welldims to make sure they are big enough - return setWelldims( (int)welldims[0] + 1, (int)( welldims[1] + additionalConnections ), (int)welldims[2], (int)welldims[3] ); + return setWelldims( (int)welldims[0] + 1, (int)( welldims[1] + additionalConnections ), (int)welldims[2] + 1, (int)welldims[3] + 1 ); } return false; @@ -409,14 +409,14 @@ int RifOpmFlowDeckFile::mergeWellDeckAtPosition( int position, std::string filen const auto foundWelspecs = m_fileDeck->find( Opm::ParserKeywords::WELSPECS::keywordName ); if ( foundWelspecs.has_value() ) { - auto& existing_pos = foundWelspecs.value(); - auto& welspecs_kw = m_fileDeck->operator[]( existing_pos ); + auto& existing_idx = foundWelspecs.value(); + auto& welspecs_kw = m_fileDeck->operator[]( existing_idx ); Opm::DeckKeyword newWelspecsKw( welspecs_kw ); newWelspecsKw.addRecord( std::move( newWelspecRecToAdd ) ); - m_fileDeck->erase( existing_pos ); - m_fileDeck->insert( existing_pos, newWelspecsKw ); + m_fileDeck->erase( existing_idx ); + m_fileDeck->insert( existing_idx, newWelspecsKw ); } else { @@ -431,8 +431,8 @@ int RifOpmFlowDeckFile::mergeWellDeckAtPosition( int position, std::string filen const auto foundCompdat = m_fileDeck->find( Opm::ParserKeywords::COMPDAT::keywordName ); if ( foundCompdat.has_value() ) { - auto& existing_pos = foundCompdat.value(); - auto& compdat_kw = m_fileDeck->operator[]( existing_pos ); + auto& existing_idx = foundCompdat.value(); + auto& compdat_kw = m_fileDeck->operator[]( existing_idx ); Opm::DeckKeyword newCompdatKw( compdat_kw ); @@ -442,8 +442,8 @@ int RifOpmFlowDeckFile::mergeWellDeckAtPosition( int position, std::string filen newCompdatKw.addRecord( std::move( newRecToAdd ) ); } - m_fileDeck->erase( existing_pos ); - m_fileDeck->insert( existing_pos, newCompdatKw ); + m_fileDeck->erase( existing_idx ); + m_fileDeck->insert( existing_idx, newCompdatKw ); } else { @@ -453,7 +453,7 @@ int RifOpmFlowDeckFile::mergeWellDeckAtPosition( int position, std::string filen } // increase wells and connections in welldims to make sure they are big enough - if ( setWelldims( (int)welldims[0] + 1, (int)( welldims[1] + additionalConnections ), (int)welldims[2], (int)welldims[3] ) ) + if ( setWelldims( (int)welldims[0] + 1, (int)( welldims[1] + additionalConnections ), (int)welldims[2] + 1, (int)welldims[3] + 1 ) ) { return position; } @@ -465,12 +465,12 @@ int RifOpmFlowDeckFile::mergeWellDeckAtPosition( int position, std::string filen //-------------------------------------------------------------------------------------------------- bool RifOpmFlowDeckFile::openWellAtTimeStep( int timeStep, Opm::DeckKeyword& openKeyword ) { - auto datePos = internal::locateTimeStep( m_fileDeck, timeStep + 1 ); - if ( datePos.has_value() ) + auto dateIndex = internal::locateTimeStep( m_fileDeck, timeStep + 1 ); + if ( dateIndex.has_value() ) { - auto insertPos = datePos.value(); - insertPos--; - return internal::insertDataAtPosition( m_fileDeck, openKeyword, insertPos ); + auto insertIdx = dateIndex.value(); + insertIdx--; + return internal::insertKeywordAtIndex( m_fileDeck, openKeyword, insertIdx ); } return false; } @@ -483,7 +483,7 @@ bool RifOpmFlowDeckFile::openWellAtDeckPosition( int deckPosition, Opm::DeckKeyw auto index = internal::positionToIndex( deckPosition, m_fileDeck ); if ( index.has_value() ) { - return internal::insertDataAtPosition( m_fileDeck, openKeyword, index.value() ); + return internal::insertKeywordAtIndex( m_fileDeck, openKeyword, index.value() ); } return false; } @@ -519,8 +519,8 @@ std::vector RifOpmFlowDeckFile::keywords() bool RifOpmFlowDeckFile::hasDatesKeyword() { if ( m_fileDeck.get() == nullptr ) return false; - auto pos = m_fileDeck->find( Opm::ParserKeywords::DATES::keywordName ); - return pos.has_value(); + auto idx = m_fileDeck->find( Opm::ParserKeywords::DATES::keywordName ); + return idx.has_value(); } //-------------------------------------------------------------------------------------------------- @@ -529,8 +529,8 @@ bool RifOpmFlowDeckFile::hasDatesKeyword() bool RifOpmFlowDeckFile::isRestartFile() { if ( m_fileDeck.get() == nullptr ) return false; - auto pos = m_fileDeck->find( Opm::ParserKeywords::RESTART::keywordName ); - return pos.has_value(); + auto idx = m_fileDeck->find( Opm::ParserKeywords::RESTART::keywordName ); + return idx.has_value(); } //-------------------------------------------------------------------------------------------------- @@ -598,6 +598,48 @@ std::vector RifOpmFlowDeckFile::dates() return values; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifOpmFlowDeckFile::appendDateKeywords( const std::vector& dates ) +{ + if ( m_fileDeck.get() == nullptr ) return false; + + auto kws = keywords(); + if ( kws.size() < 1 ) return false; + + auto lastIdx = internal::positionToIndex( (int)kws.size() - 1, m_fileDeck ); + if ( !lastIdx.has_value() ) return false; + + auto lastKw = m_fileDeck->operator[]( lastIdx.value() ); + m_fileDeck->erase( lastIdx.value() ); + + std::vector revDates; + std::reverse_copy( dates.begin(), dates.end(), std::back_inserter( revDates ) ); + + for ( auto dt : revDates ) + { + Opm::DeckKeyword newKw( ( Opm::ParserKeywords::DATES() ) ); + Opm::DeckRecord newRec; + + std::tm* lt = localtime( &dt ); + + std::string month = Opm::TimeService::eclipseMonthNames().at( lt->tm_mon + 1 ); + + newRec.addItem( RifOpmDeckTools::item( Opm::ParserKeywords::DATES::DAY::itemName, lt->tm_mday ) ); + newRec.addItem( RifOpmDeckTools::item( Opm::ParserKeywords::DATES::MONTH::itemName, month ) ); + newRec.addItem( RifOpmDeckTools::item( Opm::ParserKeywords::DATES::YEAR::itemName, lt->tm_year + 1900 ) ); + + newKw.addRecord( std::move( newRec ) ); + + m_fileDeck->insert( lastIdx.value(), newKw ); + } + + m_fileDeck->insert( lastIdx.value(), lastKw ); + + return true; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -605,12 +647,12 @@ std::vector RifOpmFlowDeckFile::welldims() { using W = Opm::ParserKeywords::WELLDIMS; if ( m_fileDeck.get() == nullptr ) return {}; - auto pos = m_fileDeck->find( W::keywordName ); - if ( pos.has_value() ) + auto idx = m_fileDeck->find( W::keywordName ); + if ( idx.has_value() ) { std::vector dims; - auto& kw = m_fileDeck->operator[]( pos.value() ); + auto& kw = m_fileDeck->operator[]( idx.value() ); const auto& rec = kw.getRecord( 0 ); dims.push_back( rec.getItem().get( 0 ) ); dims.push_back( rec.getItem().get( 0 ) ); @@ -629,12 +671,10 @@ bool RifOpmFlowDeckFile::setWelldims( int maxWells, int maxConnections, int maxG { using W = Opm::ParserKeywords::WELLDIMS; if ( m_fileDeck.get() == nullptr ) return false; - auto pos = m_fileDeck->find( W::keywordName ); - if ( pos.has_value() ) + auto idx = m_fileDeck->find( W::keywordName ); + if ( idx.has_value() ) { - std::vector dims; - - auto& oldkw = m_fileDeck->operator[]( pos.value() ); + auto& oldkw = m_fileDeck->operator[]( idx.value() ); Opm::DeckKeyword newKw( Opm::ParserKeyword( oldkw.name() ) ); @@ -643,8 +683,8 @@ bool RifOpmFlowDeckFile::setWelldims( int maxWells, int maxConnections, int maxG RifOpmDeckTools::item( W::MAXGROUPS::itemName, maxGroups ), RifOpmDeckTools::item( W::MAX_GROUPSIZE::itemName, maxWellsInGroup ) } } ); - m_fileDeck->erase( pos.value() ); - m_fileDeck->insert( pos.value(), newKw ); + m_fileDeck->erase( idx.value() ); + m_fileDeck->insert( idx.value(), newKw ); return true; } return false; @@ -657,12 +697,12 @@ std::vector RifOpmFlowDeckFile::regdims() { using R = Opm::ParserKeywords::REGDIMS; if ( m_fileDeck.get() == nullptr ) return {}; - auto pos = m_fileDeck->find( R::keywordName ); - if ( pos.has_value() ) + auto idx = m_fileDeck->find( R::keywordName ); + if ( idx.has_value() ) { std::vector dims; - auto& kw = m_fileDeck->operator[]( pos.value() ); + auto& kw = m_fileDeck->operator[]( idx.value() ); const auto& rec = kw.getRecord( 0 ); dims.push_back( rec.getItem( R::NTFIP::itemName ).get( 0 ) ); dims.push_back( rec.getItem( R::NMFIPR::itemName ).get( 0 ) ); @@ -681,10 +721,10 @@ bool RifOpmFlowDeckFile::setRegdims( int maxRegions, int maxRegionDefinitions, i { using R = Opm::ParserKeywords::REGDIMS; if ( m_fileDeck.get() == nullptr ) return false; - auto pos = m_fileDeck->find( R::keywordName ); - if ( pos.has_value() ) + auto idx = m_fileDeck->find( R::keywordName ); + if ( idx.has_value() ) { - auto& oldkw = m_fileDeck->operator[]( pos.value() ); + auto& oldkw = m_fileDeck->operator[]( idx.value() ); Opm::DeckKeyword newKw( Opm::ParserKeyword( oldkw.name() ) ); newKw.addRecord( Opm::DeckRecord{ { RifOpmDeckTools::item( R::NTFIP::itemName, maxRegions ), @@ -692,8 +732,8 @@ bool RifOpmFlowDeckFile::setRegdims( int maxRegions, int maxRegionDefinitions, i RifOpmDeckTools::item( R::NRFREG::itemName, maxRegionFlowConnections ), RifOpmDeckTools::item( R::NTFREG::itemName, maxFIPRegions ) } } ); - m_fileDeck->erase( pos.value() ); - m_fileDeck->insert( pos.value(), newKw ); + m_fileDeck->erase( idx.value() ); + m_fileDeck->insert( idx.value(), newKw ); return true; } return false; @@ -708,31 +748,28 @@ bool RifOpmFlowDeckFile::ensureRegdimsKeyword() if ( m_fileDeck.get() == nullptr ) return false; // Check if REGDIMS already exists - auto pos = m_fileDeck->find( R::keywordName ); - if ( pos.has_value() ) + auto idx = m_fileDeck->find( R::keywordName ); + if ( idx.has_value() ) { return true; // Already exists } // Find RUNSPEC section to add REGDIMS - auto runspecPos = m_fileDeck->find( Opm::ParserKeywords::RUNSPEC::keywordName ); - if ( !runspecPos.has_value() ) - { - return false; // Cannot add REGDIMS without RUNSPEC section - } + auto runspecIdx = m_fileDeck->find( Opm::ParserKeywords::RUNSPEC::keywordName ); + if ( !runspecIdx.has_value() ) return false; // Cannot add REGDIMS without RUNSPEC section // Look for a good insertion point after RUNSPEC and before GRID section - auto insertPos = runspecPos.value(); - insertPos++; // Start after RUNSPEC keyword + auto insertIdx = runspecIdx.value(); + insertIdx++; // Start after RUNSPEC keyword // Try to find GRID or other sections that should come after REGDIMS - for ( auto it = insertPos; it != m_fileDeck->stop(); it++ ) + for ( auto it = insertIdx; it != m_fileDeck->stop(); it++ ) { auto& kw = m_fileDeck->operator[]( it ); if ( kw.name() == Opm::ParserKeywords::GRID::keywordName || kw.name() == Opm::ParserKeywords::SOLUTION::keywordName || kw.name() == Opm::ParserKeywords::SCHEDULE::keywordName ) { - insertPos = it; + insertIdx = it; break; } } @@ -744,7 +781,7 @@ bool RifOpmFlowDeckFile::ensureRegdimsKeyword() RifOpmDeckTools::item( R::NRFREG::itemName, 1 ), RifOpmDeckTools::item( R::NTFREG::itemName, 1 ) } } ); - m_fileDeck->insert( insertPos, regdimsKw ); + m_fileDeck->insert( insertIdx, regdimsKw ); return true; } @@ -756,17 +793,14 @@ bool RifOpmFlowDeckFile::addIncludeKeyword( std::string section, std::string key if ( m_fileDeck.get() == nullptr ) return false; // Find insertion point within the section - auto insertPos = internal::findSectionInsertionPoint( m_fileDeck, section ); - if ( !insertPos.has_value() ) - { - return false; // Section not found - } + auto insertIdx = internal::findSectionInsertionPoint( m_fileDeck, section ); + if ( !insertIdx.has_value() ) return false; // Section not found // Create the INCLUDE keyword Opm::DeckKeyword includeKw( ( Opm::ParserKeywords::INCLUDE() ) ); includeKw.addRecord( Opm::DeckRecord{ { RifOpmDeckTools::item( Opm::ParserKeywords::INCLUDE::IncludeFile::itemName, filePath ) } } ); - m_fileDeck->insert( insertPos.value(), includeKw ); + m_fileDeck->insert( insertIdx.value(), includeKw ); return true; } @@ -784,11 +818,8 @@ bool RifOpmFlowDeckFile::addOperaterKeyword( std::string section, if ( m_fileDeck.get() == nullptr ) return false; // Find insertion point within the section - auto insertPos = internal::findSectionInsertionPoint( m_fileDeck, section ); - if ( !insertPos.has_value() ) - { - return false; // Section not found - } + auto insertIdx = internal::findSectionInsertionPoint( m_fileDeck, section ); + if ( !insertIdx.has_value() ) return false; // Section not found using O = Opm::ParserKeywords::OPERATER; @@ -826,7 +857,7 @@ bool RifOpmFlowDeckFile::addOperaterKeyword( std::string section, operaterKw.addRecord( Opm::DeckRecord{ std::move( recordItems ) } ); - m_fileDeck->insert( insertPos.value(), operaterKw ); + m_fileDeck->insert( insertIdx.value(), operaterKw ); return true; } @@ -847,7 +878,7 @@ bool RifOpmFlowDeckFile::mergeMswData( std::vector& mswFileData ) auto& kw = m_fileDeck->operator[]( it ); if ( kw.name() != Opm::ParserKeywords::DATES::keywordName ) continue; - Opm::FileDeck::Index insertPos( it ); + Opm::FileDeck::Index insertIdx( it ); if ( mswFileData[curTimeStep] != prevFileData ) { @@ -862,21 +893,21 @@ bool RifOpmFlowDeckFile::mergeMswData( std::vector& mswFileData ) const auto found = m_fileDeck->find( Opm::ParserKeywords::WELSPECS::keywordName ); if ( !found.has_value() ) { - m_fileDeck->insert( insertPos, newKw ); - insertPos++; + m_fileDeck->insert( insertIdx, newKw ); + insertIdx++; } else { Opm::DeckRecord newRecToAdd( newKw.getRecord( 0 ) ); - auto& existing_pos = found.value(); - auto& welspecs_kw = m_fileDeck->operator[]( existing_pos ); + auto& existing_idx = found.value(); + auto& welspecs_kw = m_fileDeck->operator[]( existing_idx ); Opm::DeckKeyword newWelspecsKw( welspecs_kw ); newWelspecsKw.addRecord( std::move( newRecToAdd ) ); - m_fileDeck->erase( existing_pos ); - m_fileDeck->insert( existing_pos, newWelspecsKw ); + m_fileDeck->erase( existing_idx ); + m_fileDeck->insert( existing_idx, newWelspecsKw ); } } else if ( ( newKw.name() == Opm::ParserKeywords::COMPDAT::keywordName ) && ( curTimeStep == 0 ) ) @@ -884,13 +915,13 @@ bool RifOpmFlowDeckFile::mergeMswData( std::vector& mswFileData ) const auto found = m_fileDeck->find( Opm::ParserKeywords::COMPDAT::keywordName ); if ( !found.has_value() ) { - m_fileDeck->insert( insertPos, newKw ); - insertPos++; + m_fileDeck->insert( insertIdx, newKw ); + insertIdx++; } else { - auto& existing_pos = found.value(); - auto& compdat_kw = m_fileDeck->operator[]( existing_pos ); + auto& existing_idx = found.value(); + auto& compdat_kw = m_fileDeck->operator[]( existing_idx ); Opm::DeckKeyword newCompdatKw( compdat_kw ); @@ -900,14 +931,14 @@ bool RifOpmFlowDeckFile::mergeMswData( std::vector& mswFileData ) newCompdatKw.addRecord( std::move( newRecToAdd ) ); } - m_fileDeck->erase( existing_pos ); - m_fileDeck->insert( existing_pos, newCompdatKw ); + m_fileDeck->erase( existing_idx ); + m_fileDeck->insert( existing_idx, newCompdatKw ); } } else { - m_fileDeck->insert( insertPos, newKw ); - insertPos++; + m_fileDeck->insert( insertIdx, newKw ); + insertIdx++; } } @@ -940,12 +971,11 @@ bool RifOpmFlowDeckFile::stopAtTimeStep( int timeStep ) { if ( !m_fileDeck ) return false; - auto datePos = internal::locateTimeStep( m_fileDeck, timeStep ); - if ( datePos.has_value() ) + auto dateIdx = internal::locateTimeStep( m_fileDeck, timeStep ); + if ( dateIdx.has_value() ) { Opm::DeckKeyword newKw( ( Opm::ParserKeywords::END() ) ); - m_fileDeck->insert( datePos.value(), newKw ); + m_fileDeck->insert( dateIdx.value(), newKw ); } - return true; } diff --git a/ApplicationLibCode/FileInterface/RifOpmFlowDeckFile.h b/ApplicationLibCode/FileInterface/RifOpmFlowDeckFile.h index a525bfb915..29630a5f49 100644 --- a/ApplicationLibCode/FileInterface/RifOpmFlowDeckFile.h +++ b/ApplicationLibCode/FileInterface/RifOpmFlowDeckFile.h @@ -61,6 +61,7 @@ public: bool isRestartFile(); std::vector dateStrings(); std::vector dates(); + bool appendDateKeywords( const std::vector& dates ); std::set wellGroupsInFile(); diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp index 6cfa2da84f..75514bd94a 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp @@ -247,6 +247,14 @@ QString RimWellPathCompletionSettings::groupName() const return m_groupName(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathCompletionSettings::setGroupName( const QString& name ) +{ + m_groupName = name; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.h b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.h index de15a27d47..44d42f9ada 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.h +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.h @@ -73,6 +73,7 @@ public: QString groupName() const; QString wellName() const; + void setGroupName( const QString& name ); void setWellNameForExport( const QString& name ); void updateWellPathNameHasChanged( const QString& newWellPathName, const QString& previousWellPathName ); diff --git a/ApplicationLibCode/ProjectDataModel/Jobs/RimOpmFlowJob.cpp b/ApplicationLibCode/ProjectDataModel/Jobs/RimOpmFlowJob.cpp index 67451c0db6..8a1dc5efde 100644 --- a/ApplicationLibCode/ProjectDataModel/Jobs/RimOpmFlowJob.cpp +++ b/ApplicationLibCode/ProjectDataModel/Jobs/RimOpmFlowJob.cpp @@ -77,6 +77,16 @@ void caf::AppEnum::setUp() setDefault( RimOpmFlowJob::WellOpenType::OPEN_AT_DATE ); } + +template <> +void caf::AppEnum::setUp() +{ + addItem( RimOpmFlowJob::DateAppendType::ADD_DAYS, "AppendDays", "Day(s)" ); + addItem( RimOpmFlowJob::DateAppendType::ADD_MONTHS, "AppendMonths", "Month(s)" ); + + setDefault( RimOpmFlowJob::DateAppendType::ADD_MONTHS ); +} + } // namespace caf //-------------------------------------------------------------------------------------------------- @@ -125,6 +135,11 @@ RimOpmFlowJob::RimOpmFlowJob() CAF_PDM_InitField( &m_endTimeStep, "EndTimeStep", 0, " " ); CAF_PDM_InitField( &m_endTimeStepEnabled, "EndTimeStepEnabled", false, "Stop Simulation at Date" ); + CAF_PDM_InitField( &m_appendNewDates, "AppendNewDates", false, "Append Extra Dates" ); + CAF_PDM_InitField( &m_newDatesInterval, "NewDatesInterval", 1, "Interval" ); + CAF_PDM_InitField( &m_numberOfNewDates, "NumberOfNewDates", 12, "Number of Dates to Append" ); + CAF_PDM_InitField( &m_dateAppendType, "DateAppendType", caf::AppEnum( DateAppendType::ADD_MONTHS ), " " ); + CAF_PDM_InitField( &m_runButton, "runButton", false, "" ); caf::PdmUiPushButtonEditor::configureEditorLabelHidden( &m_runButton ); m_runButton.xmlCapability()->disableIO(); @@ -143,6 +158,7 @@ RimOpmFlowJob::RimOpmFlowJob() caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_includeMSWData ); caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_addNewWell ); caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_endTimeStepEnabled ); + caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_appendNewDates ); setDeletable( true ); } @@ -220,62 +236,81 @@ void RimOpmFlowJob::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& genGrp->add( nameField() ); genGrp->add( &m_deckFileName ); genGrp->add( &m_workDir ); + genGrp->add( &m_eclipseCase ); + if ( m_eclipseCase() == nullptr ) { m_addNewWell = false; } else - { - genGrp->add( &m_addNewWell ); - } - - if ( m_addNewWell() ) { auto wellGrp = uiOrdering.addNewGroup( "New Well Settings" ); + wellGrp->add( &m_addNewWell ); - wellGrp->add( &m_wellPath ); - wellGrp->add( &m_wellGroupName ); - wellGrp->add( &m_wellOpenKeyword ); - if ( m_wellOpenKeyword() == "WCONPROD" ) + if ( m_addNewWell() ) { - auto wconGrp = wellGrp->addNewGroup( "WCONPROD Settings" ); - m_wconprodKeyword->uiOrdering( wconGrp ); - } - else - { - auto wconGrp = wellGrp->addNewGroup( "WCONINJE Settings" ); - m_wconinjeKeyword->uiOrdering( wconGrp ); - } - - wellGrp->add( &m_wellOpenType ); - - if ( m_fileDeckHasDates ) - { - if ( m_wellOpenType() == WellOpenType::OPEN_AT_DATE ) + wellGrp->add( &m_wellPath ); + wellGrp->add( &m_wellGroupName ); + wellGrp->add( &m_wellOpenKeyword ); + if ( m_wellOpenKeyword() == "WCONPROD" ) { - wellGrp->add( &m_openTimeStep ); - if ( !m_fileDeckIsRestart ) - { - wellGrp->add( &m_useRestart ); - } - else - { - m_useRestart = false; - } - if ( m_eclipseCase() ) wellGrp->add( &m_includeMSWData ); + auto wconGrp = wellGrp->addNewGroup( "WCONPROD Settings" ); + m_wconprodKeyword->uiOrdering( wconGrp ); + wconGrp->setCollapsedByDefault(); } - else if ( m_wellOpenType == WellOpenType::OPEN_BY_POSITION ) + else + { + auto wconGrp = wellGrp->addNewGroup( "WCONINJE Settings" ); + m_wconinjeKeyword->uiOrdering( wconGrp ); + wconGrp->setCollapsedByDefault(); + } + + wellGrp->add( &m_wellOpenType ); + + if ( m_fileDeckHasDates ) + { + if ( m_wellOpenType() == WellOpenType::OPEN_AT_DATE ) + { + wellGrp->add( &m_openTimeStep ); + if ( !m_fileDeckIsRestart ) + { + wellGrp->add( &m_useRestart ); + } + else + { + m_useRestart = false; + } + if ( m_eclipseCase() ) wellGrp->add( &m_includeMSWData ); + } + else if ( m_wellOpenType == WellOpenType::OPEN_BY_POSITION ) + { + wellGrp->add( &m_openSelectButton ); + } + m_wellOpenType.uiCapability()->setUiReadOnly( false ); + } + else { wellGrp->add( &m_openSelectButton ); + m_wellOpenType = WellOpenType::OPEN_BY_POSITION; + m_wellOpenType.uiCapability()->setUiReadOnly( true ); } } - else - { - wellGrp->add( &m_openSelectButton ); - } } - auto opmGrp = uiOrdering.addNewGroup( "Opm Flow" ); + if ( m_fileDeckHasDates ) + { + auto dateGrp = uiOrdering.addNewGroup( "Date Settings" ); + dateGrp->setCollapsedByDefault(); + dateGrp->add( &m_appendNewDates ); + if ( m_appendNewDates() ) + { + dateGrp->add( &m_numberOfNewDates ); + dateGrp->add( &m_newDatesInterval ); + dateGrp->appendToRow( &m_dateAppendType ); + } + } + + auto opmGrp = uiOrdering.addNewGroup( "OPM Flow" ); opmGrp->add( &m_runButton ); opmGrp->add( &m_pauseBeforeRun ); if ( m_fileDeckHasDates ) @@ -313,10 +348,10 @@ QList RimOpmFlowJob::calculateValueOptions( const caf::P openDeckFile(); if ( m_deckFile != nullptr ) { - auto timeStepNames = m_deckFile->dateStrings(); + auto timeStepNames = dateStrings(); for ( int i = 0; i < static_cast( timeStepNames.size() - 1 ); ++i ) { - options.push_back( caf::PdmOptionItemInfo( QString::fromStdString( timeStepNames[i] ), QVariant::fromValue( i ) ) ); + options.push_back( caf::PdmOptionItemInfo( timeStepNames[i], QVariant::fromValue( i ) ) ); } } } @@ -332,10 +367,68 @@ QList RimOpmFlowJob::calculateValueOptions( const caf::P options.push_back( caf::PdmOptionItemInfo( grp, QVariant::fromValue( grp ) ) ); } } + else if ( fieldNeedingOptions == &m_eclipseCase ) + { + RimTools::eclipseCaseOptionItems( &options ); + } return options; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimOpmFlowJob::dateStrings() +{ + std::vector dateStrs; + + for ( auto& dt : dateTimes() ) + { + dateStrs.push_back( dt.toString( "dd-MMM-yyyy (HH:mm)" ) ); + } + + return dateStrs; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimOpmFlowJob::dateTimes() +{ + auto dates = datesInFileDeck(); + auto newDates = addedDateTimes(); + dates.insert( dates.end(), newDates.begin(), newDates.end() ); + + return dates; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimOpmFlowJob::addedDateTimes() +{ + if ( !m_appendNewDates() || !m_fileDeckHasDates ) return {}; + + auto existingDates = datesInFileDeck(); + auto& startDate = existingDates.back(); + + std::vector newDates; + for ( auto dt = startDate; newDates.size() < static_cast( m_numberOfNewDates() ); ) + { + if ( m_dateAppendType() == DateAppendType::ADD_DAYS ) + { + dt = dt.addDays( m_newDatesInterval() ); + } + else if ( m_dateAppendType() == DateAppendType::ADD_MONTHS ) + { + dt = dt.addMonths( m_newDatesInterval() ); + } + newDates.push_back( dt ); + } + + return newDates; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -623,6 +716,17 @@ bool RimOpmFlowJob::onPrepare() return false; } + // add extra date keywords + if ( m_appendNewDates() && m_fileDeckHasDates ) + { + std::vector newDates; + for ( auto& dt : addedDateTimes() ) + { + newDates.push_back( dt.toSecsSinceEpoch() ); + } + m_deckFile->appendDateKeywords( newDates ); + } + // add a new well? if ( m_addNewWell() ) { @@ -650,6 +754,7 @@ bool RimOpmFlowJob::onPrepare() RiaLogging::error( "Please set the well group name." ); return false; } + m_wellPath->completionSettings()->setGroupName( m_wellGroupName() ); int mergePosition = m_openWellDeckPosition(); diff --git a/ApplicationLibCode/ProjectDataModel/Jobs/RimOpmFlowJob.h b/ApplicationLibCode/ProjectDataModel/Jobs/RimOpmFlowJob.h index d5fb358a2f..27f05ccb8a 100644 --- a/ApplicationLibCode/ProjectDataModel/Jobs/RimOpmFlowJob.h +++ b/ApplicationLibCode/ProjectDataModel/Jobs/RimOpmFlowJob.h @@ -47,6 +47,12 @@ public: OPEN_AT_DATE }; + enum class DateAppendType + { + ADD_DAYS, + ADD_MONTHS + }; + public: RimOpmFlowJob(); ~RimOpmFlowJob() override; @@ -85,6 +91,10 @@ private: std::vector datesInFileDeck(); std::vector wellgroupsInFileDeck(); + std::vector dateStrings(); + std::vector dateTimes(); + std::vector addedDateTimes(); + static QString readFileContent( QString filename ); void exportBasicWellSettings(); @@ -116,6 +126,11 @@ private: caf::PdmField m_includeMSWData; caf::PdmField m_wellGroupName; + caf::PdmField m_appendNewDates; + caf::PdmField m_newDatesInterval; + caf::PdmField m_numberOfNewDates; + caf::PdmField> m_dateAppendType; + caf::PdmChildField m_wconprodKeyword; caf::PdmChildField m_wconinjeKeyword;