From 038dabc77ba00b4035597ec01030e909f70a4b14 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 14 Oct 2026 15:22:20 +0200 Subject: [PATCH] #8370: Create summary addresses and handle unknown vectors when setting summary values --- .../RifSummaryReaderAggregator.cpp | 6 +++ .../Summary/RimFileSummaryCase.cpp | 53 +++++++++++++++++-- .../Summary/RimFileSummaryCase.h | 3 ++ .../RimcSummaryCase.cpp | 6 +++ 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/ApplicationLibCode/FileInterface/RifSummaryReaderAggregator.cpp b/ApplicationLibCode/FileInterface/RifSummaryReaderAggregator.cpp index 70d4809cf7..962fac1127 100644 --- a/ApplicationLibCode/FileInterface/RifSummaryReaderAggregator.cpp +++ b/ApplicationLibCode/FileInterface/RifSummaryReaderAggregator.cpp @@ -47,10 +47,13 @@ std::vector RifSummaryReaderAggregator::timeSteps( const RifEclipseSumma std::pair> RifSummaryReaderAggregator::values( const RifEclipseSummaryAddress& resultAddress ) const { std::vector values; + bool anyReaderHasValues = false; for ( const auto& reader : m_summaryReaders ) { auto [isOk, readerValues] = reader->values( resultAddress ); + if ( !readerValues.empty() ) anyReaderHasValues = true; + if ( readerValues.empty() ) { // When a well is introduced, no data is present before the time step the well is introduced @@ -70,6 +73,9 @@ std::pair> RifSummaryReaderAggregator::values( const R values.insert( values.end(), readerValues.begin(), readerValues.end() ); } + // The address is unknown to all readers. Do not return zeros, as this hides vectors in other readers, like additional summary files + if ( !anyReaderHasValues ) return { false, {} }; + CAF_ASSERT( m_aggregatedTimeSteps.size() == values.size() ); return { true, values }; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.cpp index bdc680a1c1..f39dfc8e3c 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.cpp @@ -303,6 +303,10 @@ void RimFileSummaryCase::openAndAttachAdditionalReader() auto isValid = opmCommonReader->open( additionalSummaryFilePath, includeRestartFiles, nullptr ); if ( isValid ) { + // The additional file is small, and the addresses are required to read values also when the addresses of the case are not + // created (e.g. realizations in an ensemble) + opmCommonReader->createAddressesIfRequired(); + m_additionalSummaryReaderId = opmCommonReader->serialNumber(); m_multiSummaryReader->addReader( std::move( opmCommonReader ) ); } @@ -361,6 +365,11 @@ std::expected auto address = RifEclipseSummaryAddress::fromEclipseTextAddressParseErrorTokens( keyword ); auto fileReader = m_multiSummaryReader->findReader( m_fileSummaryReaderId ); + if ( fileReader ) + { + // Addresses are created lazily, and can be missing for realizations in an ensemble + fileReader->createAddressesIfRequired(); + } if ( fileReader && fileReader->hasAddress( address ) ) { QString errorMsg = QString( "Cannot set summary values for '%1' because the vector comes from the source summary file. " @@ -433,31 +442,67 @@ std::expected return {}; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimFileSummaryCase::additionalSummaryFilePath() const +{ + return m_additionalSummaryFilePath().path(); +} + +//-------------------------------------------------------------------------------------------------- +/// Attach an existing file with user-defined summary vectors. Used when the case is recreated, e.g. when +/// an ensemble is defined by a file set and the cases are not stored in the project file. +//-------------------------------------------------------------------------------------------------- +void RimFileSummaryCase::setAdditionalSummaryFilePath( const QString& filePath ) +{ + if ( filePath.isEmpty() || !QFile::exists( filePath ) ) return; + + m_additionalSummaryFilePath = filePath; + + if ( m_multiSummaryReader ) + { + m_multiSummaryReader->removeReader( m_additionalSummaryReaderId ); + openAndAttachAdditionalReader(); + + // Addresses are created lazily for realizations in an ensemble, only refresh if already created + if ( !m_multiSummaryReader->allResultAddresses().empty() ) + { + m_multiSummaryReader->createAndSetAddresses(); + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFileSummaryCase::onProjectBeingSaved() { - // If additional data is stored in temp folder, copy to project folder and remove file in temp folder + // If additional data is stored in temp folder, copy to project folder and remove file in temp folder. The project file is not written + // yet, so additionalSummaryDataFilePath() would still point to the temp folder on the first save. + const QString projectFileName = RimProject::current() ? RimProject::current()->fileName() : QString(); + if ( projectFileName.isEmpty() ) return; auto existingFilePath = m_additionalSummaryFilePath().path(); if ( QFile::exists( existingFilePath ) ) { - auto currentFilePath = additionalSummaryDataFilePath(); + auto currentFilePath = QFileInfo( projectFileName ).dir().absoluteFilePath( QFileInfo( existingFilePath ).fileName() ); if ( existingFilePath != currentFilePath ) { + if ( m_multiSummaryReader ) m_multiSummaryReader->removeReader( m_additionalSummaryReaderId ); + if ( QFile::copy( existingFilePath, currentFilePath ) ) { QFile::remove( existingFilePath ); m_additionalSummaryFilePath = currentFilePath; - - openAndAttachAdditionalReader(); } else { QString txt = "Error when copying temporary file to " + currentFilePath; RiaLogging::error( txt.toStdString() ); } + + if ( m_multiSummaryReader ) openAndAttachAdditionalReader(); } } } diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.h b/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.h index c35e4d05ec..14c24d9781 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimFileSummaryCase.h @@ -63,6 +63,9 @@ public: std::expected setSummaryData( const std::string& keyword, const std::string& unit, const std::vector& values ); void onProjectBeingSaved(); + QString additionalSummaryFilePath() const; + void setAdditionalSummaryFilePath( const QString& filePath ); + static std::unique_ptr findRelatedFilesAndCreateReader( const QString& headerFileName, bool lookForRestartFiles, RifEnsembleImportConfig ensembleImportState, diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcSummaryCase.cpp b/ApplicationLibCode/ProjectDataModelCommands/RimcSummaryCase.cpp index d7af37bb05..652bc9dc8a 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcSummaryCase.cpp +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcSummaryCase.cpp @@ -24,6 +24,7 @@ #include "RimFileSummaryCase.h" #include "RimSummaryCase.h" +#include "RimSummaryEnsemble.h" #include "RimcDataContainerDouble.h" #include "RimcDataContainerString.h" @@ -276,6 +277,11 @@ std::expected RimSummaryCase_setSummaryVectorVal { fileSummaryCase->buildTreeNodesIfRequired(); fileSummaryCase->updateConnectedEditors(); + + if ( auto* ensemble = fileSummaryCase->firstAncestorOrThisOfType() ) + { + ensemble->onSummaryVectorsChanged(); + } } return nullptr;