diff --git a/ApplicationLibCode/Application/Tools/CMakeLists_files.cmake b/ApplicationLibCode/Application/Tools/CMakeLists_files.cmake index cf7d37a4c4..8907e2e8b0 100644 --- a/ApplicationLibCode/Application/Tools/CMakeLists_files.cmake +++ b/ApplicationLibCode/Application/Tools/CMakeLists_files.cmake @@ -53,6 +53,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RiaFileLogger.h ${CMAKE_CURRENT_LIST_DIR}/RiaProjectBackupTools.h ${CMAKE_CURRENT_LIST_DIR}/RiaQuantityInfoTools.h + ${CMAKE_CURRENT_LIST_DIR}/RiaHashTools.h ) set(SOURCE_GROUP_SOURCE_FILES diff --git a/ApplicationLibCode/Application/Tools/RiaHashTools.h b/ApplicationLibCode/Application/Tools/RiaHashTools.h new file mode 100644 index 0000000000..8a50f80ed3 --- /dev/null +++ b/ApplicationLibCode/Application/Tools/RiaHashTools.h @@ -0,0 +1,90 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include +#include + +//================================================================================================== +// +// +// +//================================================================================================== +namespace RiaHashTools +{ +//-------------------------------------------------------------------------------------------------- +/// Variadic template function to combine multiple parameters into a single hash +//-------------------------------------------------------------------------------------------------- +template +void combineHash( size_t& seed, const T& value ) +{ + // Based on https://www.boost.org/doc/libs/1_84_0/libs/container_hash/doc/html/hash.html#notes_hash_combine + seed ^= std::hash()( value ) + 0x9e3779b9 + ( seed << 6 ) + ( seed >> 2 ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +void combineHash( size_t& seed, const T& value, const Rest&... rest ) +{ + combineHash( seed, value ); + ( combineHash( seed, rest ), ... ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +void combineHash( size_t& seed, const Range& range, const Rest&... rest ) +{ + for ( const auto& elem : range ) + { + combineHash( seed, elem ); + } + ( combineHash( seed, rest ), ... ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template +size_t hash( const Args&... args ) +{ + size_t seed = 0; + combineHash( seed, args... ); + return seed; +} + +//-------------------------------------------------------------------------------------------------- +/// Generic hash function for any range +//-------------------------------------------------------------------------------------------------- +template +size_t hash( const Range& range ) +{ + size_t seed = 0; + for ( const auto& elem : range ) + { + combineHash( seed, elem ); + } + return seed; +} + +}; // namespace RiaHashTools diff --git a/ApplicationLibCode/FileInterface/RifSummaryReaderInterface.cpp b/ApplicationLibCode/FileInterface/RifSummaryReaderInterface.cpp index 01ee289adb..51c9be4541 100644 --- a/ApplicationLibCode/FileInterface/RifSummaryReaderInterface.cpp +++ b/ApplicationLibCode/FileInterface/RifSummaryReaderInterface.cpp @@ -22,6 +22,8 @@ #include +int RifSummaryReaderInterface::m_nextSerialNumber = 0; + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -56,6 +58,23 @@ void RifSummaryReaderInterface::buildMetaData() { } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RifSummaryReaderInterface::serialNumber() const +{ + return m_serialNumber; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RifSummaryReaderInterface::RifSummaryReaderInterface() +{ +#pragma omp critical + m_serialNumber = m_nextSerialNumber++; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/FileInterface/RifSummaryReaderInterface.h b/ApplicationLibCode/FileInterface/RifSummaryReaderInterface.h index efdd2973c6..2f86ae86af 100644 --- a/ApplicationLibCode/FileInterface/RifSummaryReaderInterface.h +++ b/ApplicationLibCode/FileInterface/RifSummaryReaderInterface.h @@ -37,6 +37,8 @@ class QDateTime; class RifSummaryReaderInterface : public cvf::Object { public: + RifSummaryReaderInterface(); + bool hasAddress( const RifEclipseSummaryAddress& resultAddress ) const; const std::set& allResultAddresses() const; @@ -53,7 +55,13 @@ public: virtual void buildMetaData(); + int serialNumber() const; + protected: std::set m_allResultAddresses; // Result and error addresses std::set m_allErrorAddresses; // Error addresses + +private: + static int m_nextSerialNumber; + int m_serialNumber; }; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp index 711e598bda..bec4c2309e 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp @@ -20,6 +20,7 @@ #include "RiaColorTools.h" #include "RiaGuiApplication.h" +#include "RiaHashTools.h" #include "RiaPreferences.h" #include "RiaQDateTimeTools.h" #include "RiaResultNames.h" @@ -116,6 +117,7 @@ CAF_PDM_SOURCE_INIT( RimEnsembleCurveSet, "RimEnsembleCurveSet" ); //-------------------------------------------------------------------------------------------------- RimEnsembleCurveSet::RimEnsembleCurveSet() : filterChanged( this ) + , m_hash( 0 ) { CAF_PDM_InitObject( "Ensemble Curve Set", ":/EnsembleCurveSet16x16.png" ); @@ -1664,26 +1666,38 @@ void RimEnsembleCurveSet::appendOptionItemsForSummaryAddresses( QList addrSet; - for ( RimSummaryCase* summaryCase : summaryCaseGroup->allSummaryCases() ) + auto allSummaryCases = summaryCaseGroup->allSummaryCases(); + auto hash = RiaHashTools::hash( allSummaryCases ); + if ( hash != m_hash ) { - RifSummaryReaderInterface* reader = summaryCase->summaryReader(); - const std::set& addrs = reader ? reader->allResultAddresses() : std::set(); + m_hash = hash; - for ( auto& addr : addrs ) + std::set addressesForEnsemble; + for ( RimSummaryCase* summaryCase : allSummaryCases ) { - addrSet.insert( addr ); + if ( !summaryCase ) continue; + + if ( auto reader = summaryCase->summaryReader() ) + { + const auto& addrs = reader->allResultAddresses(); + addressesForEnsemble.insert( addrs.begin(), addrs.end() ); + } } + + m_cachedAddressOptions.clear(); + + for ( const auto& addr : addressesForEnsemble ) + { + std::string name = addr.uiText(); + QString s = QString::fromStdString( name ); + m_cachedAddressOptions.push_back( caf::PdmOptionItemInfo( s, QVariant::fromValue( addr ) ) ); + } + + m_cachedAddressOptions.push_front( + caf::PdmOptionItemInfo( RiaResultNames::undefinedResultName(), QVariant::fromValue( RifEclipseSummaryAddress() ) ) ); } - for ( auto& addr : addrSet ) - { - std::string name = addr.uiText(); - QString s = QString::fromStdString( name ); - options->push_back( caf::PdmOptionItemInfo( s, QVariant::fromValue( addr ) ) ); - } - - options->push_front( caf::PdmOptionItemInfo( RiaResultNames::undefinedResultName(), QVariant::fromValue( RifEclipseSummaryAddress() ) ) ); + options->append( m_cachedAddressOptions ); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h index a5b63c8b46..755b838686 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h @@ -180,7 +180,7 @@ public: void appendColorGroup( caf::PdmUiOrdering& uiOrdering ); - static void appendOptionItemsForSummaryAddresses( QList* options, RimSummaryEnsemble* summaryCaseGroup ); + void appendOptionItemsForSummaryAddresses( QList* options, RimSummaryEnsemble* summaryCaseGroup ); const RimEnsembleCurveFilterCollection* curveFilters() const; @@ -317,4 +317,7 @@ private: bool m_disableStatisticCurves; bool m_isCurveSetFiltered; + + QList m_cachedAddressOptions; + size_t m_hash; }; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleStatisticsCase.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleStatisticsCase.cpp index c24ccc446c..ed7e53a7ad 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleStatisticsCase.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleStatisticsCase.cpp @@ -19,6 +19,7 @@ #include "RimEnsembleStatisticsCase.h" #include "RiaCurveMerger.h" +#include "RiaHashTools.h" #include "RiaTimeHistoryCurveResampler.h" #include "Summary/RiaSummaryTools.h" @@ -129,6 +130,11 @@ void RimEnsembleStatisticsCase::calculate( const std::vector& s const RifEclipseSummaryAddress& inputAddress, bool includeIncompleteCurves ) { + auto hash = RiaHashTools::hash( summaryCases, inputAddress.toEclipseTextAddress(), includeIncompleteCurves ); + if ( hash == m_hash ) return; + + m_hash = hash; + clearData(); if ( !inputAddress.isValid() ) return; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleStatisticsCase.h b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleStatisticsCase.h index 9b3fcc518f..ba819986cb 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleStatisticsCase.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleStatisticsCase.h @@ -64,4 +64,5 @@ private: std::vector m_meanData; caf::PdmPointer m_firstSummaryCase; + size_t m_hash = 0; }; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.cpp index 053da9e37d..4551c80df3 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.cpp @@ -225,6 +225,15 @@ void RimSummaryCase::buildChildNodes() m_dataVectorFolders->updateFolderStructure( addresses, m_caseId ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSummaryCase::serialNumber() +{ + auto reader = summaryReader(); + return reader ? reader->serialNumber() : -1; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.h index a3e5a1f5de..4ee7c6c1e0 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.h @@ -18,6 +18,9 @@ #pragma once #include "RiaDefines.h" + +#include "RiaHashTools.h" + #include "RigCaseRealizationParameters.h" #include "RimCaseDisplayNameTools.h" @@ -105,6 +108,7 @@ protected: private: void buildChildNodes(); + int serialNumber(); protected: caf::PdmField m_displayName; @@ -123,4 +127,25 @@ protected: caf::PdmField m_useAutoShortName_OBSOLETE; static const QString DEFAULT_DISPLAY_NAME; + + friend struct std::hash; +}; + +// Custom specialization of std::hash injected in namespace std +// NB! Note that this is a specialization of std::hash for a pointer type +template <> +struct std::hash +{ + std::size_t operator()( RimSummaryCase* s ) const noexcept + { + if ( !s ) return 0; + + auto serialNumber = s->serialNumber(); + if ( serialNumber != -1 ) + { + return RiaHashTools::hash( serialNumber ); + } + + return RiaHashTools::hash( s->summaryHeaderFilename().toStdString() ); + } };