diff --git a/ApplicationCode/Commands/RicConvertGroupToEnsembleFeature.cpp b/ApplicationCode/Commands/RicConvertGroupToEnsembleFeature.cpp index 628f42bdd4..3f1e64d3eb 100644 --- a/ApplicationCode/Commands/RicConvertGroupToEnsembleFeature.cpp +++ b/ApplicationCode/Commands/RicConvertGroupToEnsembleFeature.cpp @@ -76,7 +76,6 @@ void RicConvertGroupToEnsembleFeature::onActionTriggered(bool isChecked) { if (group->isEnsemble()) continue; - RicImportEnsembleFeature::validateEnsembleCases(group->allSummaryCases()); group->setAsEnsemble(true); } } diff --git a/ApplicationCode/Commands/RicImportEnsembleFeature.cpp b/ApplicationCode/Commands/RicImportEnsembleFeature.cpp index 4e8b1fb767..ea8e82a40d 100644 --- a/ApplicationCode/Commands/RicImportEnsembleFeature.cpp +++ b/ApplicationCode/Commands/RicImportEnsembleFeature.cpp @@ -49,66 +49,6 @@ CAF_CMD_SOURCE_INIT(RicImportEnsembleFeature, "RicImportEnsembleFeature"); -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicImportEnsembleFeature::validateEnsembleCases(std::vector cases) -{ - // Validate ensemble parameters - try - { - QString errors; - std::hash paramsHasher; - size_t paramsHash = 0; - - for (RimSummaryCase* rimCase : cases) - { - if (rimCase->caseRealizationParameters() == nullptr || rimCase->caseRealizationParameters()->parameters().empty()) - { - errors.append(QString("The case %1 has no ensemble parameters\n").arg(QFileInfo(rimCase->summaryHeaderFilename()).fileName())); - } - else - { - QString paramNames; - for (std::pair paramPair : rimCase->caseRealizationParameters()->parameters()) - { - paramNames.append(paramPair.first); - } - - size_t currHash = paramsHasher(paramNames.toStdString()); - if (paramsHash == 0) - { - paramsHash = currHash; - } - else if (paramsHash != currHash) - { - throw QString("Ensemble parameters differ between cases"); - } - } - } - - - if (!errors.isEmpty()) - { - errors.append("\n"); - errors.append("No parameters file (parameters.txt or runspecification.xml) was found in \n"); - errors.append("the searched folders. ResInsight searches the home folder of the summary \n"); - errors.append("case file and the three folder levels above that.\n"); - - throw errors; - } - return true; - } - catch (QString errorMessage) - { - QMessageBox mbox; - mbox.setIcon(QMessageBox::Icon::Warning); - mbox.setInformativeText(errorMessage); - mbox.exec(); - return false; - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -133,8 +73,6 @@ void RicImportEnsembleFeature::onActionTriggered(bool isChecked) std::vector cases; RicImportSummaryCasesFeature::createSummaryCasesFromFiles(fileNames, &cases, true); - validateEnsembleCases(cases); - RicImportSummaryCasesFeature::addSummaryCases(cases); auto newGroup = RicCreateSummaryCaseCollectionFeature::groupSummaryCases(cases, ensembleName, true); diff --git a/ApplicationCode/Commands/RicImportEnsembleFeature.h b/ApplicationCode/Commands/RicImportEnsembleFeature.h index 62a7a80366..dfb0883d45 100644 --- a/ApplicationCode/Commands/RicImportEnsembleFeature.h +++ b/ApplicationCode/Commands/RicImportEnsembleFeature.h @@ -35,9 +35,6 @@ class RicImportEnsembleFeature : public caf::CmdFeature { CAF_CMD_HEADER_INIT; -public: - static bool validateEnsembleCases(std::vector cases); - protected: // Overrides virtual bool isCommandEnabled() override; diff --git a/ApplicationCode/ProjectDataModel/Summary/RimDerivedEnsembleCaseCollection.cpp b/ApplicationCode/ProjectDataModel/Summary/RimDerivedEnsembleCaseCollection.cpp index e096f24021..a843746c76 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimDerivedEnsembleCaseCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimDerivedEnsembleCaseCollection.cpp @@ -231,6 +231,9 @@ void RimDerivedEnsembleCaseCollection::defineUiOrdering(QString uiConfigName, ca uiOrdering.add(&m_swapEnsemblesButton); uiOrdering.skipRemainingFields(true); + + updateAutoName(); + if (!isValid()) m_caseCount = ""; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp index a48d0b291e..c891f074a2 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp @@ -26,7 +26,11 @@ #include "RifSummaryReaderInterface.h" +#include +#include + #include +#include CAF_PDM_SOURCE_INIT(RimSummaryCaseCollection, "SummaryCaseSubCollection"); @@ -65,8 +69,15 @@ RimSummaryCaseCollection::~RimSummaryCaseCollection() //-------------------------------------------------------------------------------------------------- void RimSummaryCaseCollection::removeCase(RimSummaryCase* summaryCase) { + size_t caseCountBeforeRemove = m_cases.size(); m_cases.removeChildObject(summaryCase); updateReferringCurveSets(); + + if (m_isEnsemble && m_cases.size() != caseCountBeforeRemove) + { + if(dynamic_cast(summaryCase) == nullptr) + calculateEnsembleParametersIntersectionHash(); + } } //-------------------------------------------------------------------------------------------------- @@ -96,6 +107,12 @@ void RimSummaryCaseCollection::addCase(RimSummaryCase* summaryCase, bool updateC if (updateCurveSets) derEnsemble->updateReferringCurveSets(); } + if (m_isEnsemble) + { + validateEnsembleCases({ summaryCase }); + calculateEnsembleParametersIntersectionHash(); + } + if(updateCurveSets) updateReferringCurveSets(); } @@ -136,8 +153,17 @@ bool RimSummaryCaseCollection::isEnsemble() const //-------------------------------------------------------------------------------------------------- void RimSummaryCaseCollection::setAsEnsemble(bool isEnsemble) { - m_isEnsemble = isEnsemble; - updateIcon(); + if (isEnsemble != m_isEnsemble) + { + m_isEnsemble = isEnsemble; + updateIcon(); + + if (m_isEnsemble && dynamic_cast(this) == nullptr) + { + validateEnsembleCases(allSummaryCases()); + calculateEnsembleParametersIntersectionHash(); + } + } } //-------------------------------------------------------------------------------------------------- @@ -254,6 +280,55 @@ EnsembleParameter RimSummaryCaseCollection::ensembleParameter(const QString& par return eParam; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryCaseCollection::calculateEnsembleParametersIntersectionHash() +{ + clearEnsembleParametersHashes(); + + // Find ensemble parameters intersection + std::set paramNames; + auto sumCases = allSummaryCases(); + + for (int i = 0; i < sumCases.size(); i++) + { + auto crp = sumCases[i]->caseRealizationParameters(); + if (!crp) continue; + + auto caseParamNames = crp->parameterNames(); + + if (i == 0) paramNames = caseParamNames; + else + { + std::set newIntersection; + std::set_intersection(paramNames.begin(), paramNames.end(), + caseParamNames.begin(), caseParamNames.end(), + std::inserter(newIntersection, newIntersection.end())); + + if(paramNames.size() != newIntersection.size()) paramNames = newIntersection; + } + } + + for (auto sumCase : sumCases) + { + auto crp = sumCase->caseRealizationParameters(); + if(crp) crp->calculateParametersHash(paramNames); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryCaseCollection::clearEnsembleParametersHashes() +{ + for (auto sumCase : allSummaryCases()) + { + auto crp = sumCase->caseRealizationParameters(); + if (crp) crp->clearParametersHash(); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -262,6 +337,66 @@ void RimSummaryCaseCollection::loadDataAndUpdate() onLoadDataAndUpdate(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimSummaryCaseCollection::validateEnsembleCases(const std::vector cases) +{ + // Validate ensemble parameters + try + { + QString errors; + std::hash paramsHasher; + size_t paramsHash = 0; + + for (RimSummaryCase* rimCase : cases) + { + if (rimCase->caseRealizationParameters() == nullptr || rimCase->caseRealizationParameters()->parameters().empty()) + { + errors.append(QString("The case %1 has no ensemble parameters\n").arg(QFileInfo(rimCase->summaryHeaderFilename()).fileName())); + } + else + { + QString paramNames; + for (std::pair paramPair : rimCase->caseRealizationParameters()->parameters()) + { + paramNames.append(paramPair.first); + } + + size_t currHash = paramsHasher(paramNames.toStdString()); + if (paramsHash == 0) + { + paramsHash = currHash; + } + else if (paramsHash != currHash) + { + throw QString("Ensemble parameters differ between cases"); + } + } + } + + + if (!errors.isEmpty()) + { + errors.append("\n"); + errors.append("No parameters file (parameters.txt or runspecification.xml) was found in \n"); + errors.append("the searched folders. ResInsight searches the home folder of the summary \n"); + errors.append("case file and the three folder levels above that.\n"); + + throw errors; + } + return true; + } + catch (QString errorMessage) + { + QMessageBox mbox; + mbox.setIcon(QMessageBox::Icon::Warning); + mbox.setInformativeText(errorMessage); + mbox.exec(); + return false; + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -275,7 +410,7 @@ caf::PdmFieldHandle* RimSummaryCaseCollection::userDescriptionField() //-------------------------------------------------------------------------------------------------- void RimSummaryCaseCollection::onLoadDataAndUpdate() { - // NOP + if (m_isEnsemble) calculateEnsembleParametersIntersectionHash(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h index eaf3bd1a13..e83302dd91 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h @@ -74,9 +74,13 @@ public: void setAsEnsemble(bool isEnsemble); virtual std::set calculateUnionOfSummaryAddresses() const; EnsembleParameter ensembleParameter(const QString& paramName) const; + void calculateEnsembleParametersIntersectionHash(); + void clearEnsembleParametersHashes(); void loadDataAndUpdate(); + static bool validateEnsembleCases(const std::vector cases); + private: caf::PdmFieldHandle* userDescriptionField() override; QString nameAndItemCount() const; diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp index 16fa6d3275..c7f0899220 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp @@ -242,7 +242,6 @@ RimSummaryCaseCollection* RimSummaryCaseMainCollection::addCaseCollection(std::v { RimSummaryCaseCollection* summaryCaseCollection = allocator(); if(!collectionName.isEmpty()) summaryCaseCollection->setName(collectionName); - summaryCaseCollection->setAsEnsemble(isEnsemble); for (RimSummaryCase* summaryCase : summaryCases) { @@ -261,6 +260,8 @@ RimSummaryCaseCollection* RimSummaryCaseMainCollection::addCaseCollection(std::v summaryCaseCollection->addCase(summaryCase); } + summaryCaseCollection->setAsEnsemble(isEnsemble); + m_caseCollections.push_back(summaryCaseCollection); return summaryCaseCollection; diff --git a/ApplicationCode/ReservoirDataModel/RigCaseRealizationParameters.cpp b/ApplicationCode/ReservoirDataModel/RigCaseRealizationParameters.cpp index bedab5973d..6e3433cda8 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseRealizationParameters.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseRealizationParameters.cpp @@ -115,6 +115,16 @@ std::map RigCaseRealizationParamet return m_parameters; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RigCaseRealizationParameters::parameterNames() const +{ + std::set names; + for (auto& par : parameters()) names.insert(par.first); + return names; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -143,16 +153,41 @@ size_t RigCaseRealizationParameters::parameterHash(const QString& name) const //-------------------------------------------------------------------------------------------------- size_t RigCaseRealizationParameters::parametersHash() { - if (m_parametersHash == 0) + if (m_parametersHash == 0) calculateParametersHash(); + return m_parametersHash; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigCaseRealizationParameters::clearParametersHash() +{ + m_parametersHash = 0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigCaseRealizationParameters::calculateParametersHash(const std::set& paramNames /*= std::set()*/) +{ + QStringList hashes; + + if (paramNames.empty()) { - QStringList hashes; for (auto param : m_parameters) { hashes.push_back(QString::number(parameterHash(param.first))); } - - std::hash stringHasher; - m_parametersHash = stringHasher(hashes.join("").toStdString()); } - return m_parametersHash; + else + { + for (auto paramName : paramNames) + { + if (m_parameters.find(paramName) == m_parameters.end()) return; + hashes.push_back(QString::number(parameterHash(paramName))); + } + } + + std::hash stringHasher; + m_parametersHash = stringHasher(hashes.join("").toStdString()); } diff --git a/ApplicationCode/ReservoirDataModel/RigCaseRealizationParameters.h b/ApplicationCode/ReservoirDataModel/RigCaseRealizationParameters.h index 2bd5e7db78..b4cc1bc0ad 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseRealizationParameters.h +++ b/ApplicationCode/ReservoirDataModel/RigCaseRealizationParameters.h @@ -24,6 +24,7 @@ #include #include +#include #include //================================================================================================== @@ -66,10 +67,14 @@ public: Value parameterValue(const QString& name); std::map parameters() const; + std::set parameterNames() const; size_t parameterHash(const QString& name) const; size_t parametersHash(); + void clearParametersHash(); + void calculateParametersHash(const std::set& paramNames = std::set()); + private: std::map m_parameters; size_t m_parametersHash;