First prototype on ensemble file set summary ensembles

This commit is contained in:
Magne Sjaastad
2025-05-15 18:16:27 +02:00
committed by GitHub
parent 5e37c58d18
commit 84f9ad0dcd
29 changed files with 1396 additions and 24 deletions
+2
View File
@@ -105,12 +105,14 @@ list(
ProjectDataModel/CorrelationPlots/CMakeLists_files.cmake
ProjectDataModel/ContourMap/CMakeLists_files.cmake
ProjectDataModel/Cloud/CMakeLists_files.cmake
ProjectDataModel/EnsembleFileSet/CMakeLists_files.cmake
ProjectDataModel/Faults/CMakeLists_files.cmake
ProjectDataModel/GeoMech/CMakeLists_files.cmake
ProjectDataModel/GridCrossPlots/CMakeLists_files.cmake
ProjectDataModel/GridCrossPlots/CellFilters/CMakeLists_files.cmake
ProjectDataModel/Summary/CMakeLists_files.cmake
ProjectDataModel/Summary/Sumo/CMakeLists_files.cmake
ProjectDataModel/Summary/Ensemble/CMakeLists_files.cmake
ProjectDataModel/Flow/CMakeLists_files.cmake
ProjectDataModel/Formations/CMakeLists_files.cmake
ProjectDataModel/Annotations/CMakeLists_files.cmake
@@ -35,6 +35,7 @@ set(COMMAND_REFERENCED_CMAKE_FILES
CrossSectionCommands/CMakeLists_files.cmake
EclipseCommands/CMakeLists_files.cmake
EclipseCommands/EclipseWell/CMakeLists_files.cmake
EnsembleFileSetCommands/CMakeLists_files.cmake
ExportCommands/CMakeLists_files.cmake
FlowCommands/CMakeLists_files.cmake
GridCrossPlotCommands/CMakeLists_files.cmake
@@ -19,6 +19,7 @@
#include "RicCreateEnsembleFromFilteredCasesFeature.h"
#include "RiaLogging.h"
#include "Summary/RiaSummaryPlotTools.h"
#include "RicImportEnsembleFeature.h"
@@ -137,6 +138,8 @@ void RicCreateEnsembleFromFilteredCasesFeature::onActionTriggered( bool isChecke
if ( auto newEnsemble = RicImportEnsembleFeature::createSummaryEnsemble( casesForNewEnsemble ) )
{
RiaSummaryPlotTools::createAndAppendDefaultSummaryMultiPlot( {}, { newEnsemble } );
RiaLogging::info( "Created ensemble " + newEnsemble->name() );
}
else
@@ -0,0 +1,12 @@
set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RicImportEnsembleFileSetFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicCreateEnsembleFromFileSetFeature.h
)
set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicImportEnsembleFileSetFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCreateEnsembleFromFileSetFeature.cpp
)
list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
list(APPEND COMMAND_CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES})
@@ -0,0 +1,57 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicCreateEnsembleFromFileSetFeature.h"
#include "Summary/RiaSummaryPlotTools.h"
#include "EnsembleFileSet/RimEnsembleFileSet.h"
#include "EnsembleFileSet/RimEnsembleFileSetTools.h"
#include "cafSelectionManagerTools.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicCreateEnsembleFromFileSetFeature, "RicCreateEnsembleFromFileSetFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicCreateEnsembleFromFileSetFeature::isCommandEnabled() const
{
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateEnsembleFromFileSetFeature::onActionTriggered( bool isChecked )
{
auto ensembles = RimEnsembleFileSetTools::createSummaryEnsemblesFromFileSets( caf::selectedObjectsByType<RimEnsembleFileSet*>() );
RiaSummaryPlotTools::createAndAppendDefaultSummaryMultiPlot( {}, ensembles );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateEnsembleFromFileSetFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setIcon( QIcon( ":/Cases16x16.png" ) );
actionToSetup->setText( "Create Summary Ensemble" );
}
@@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
//==================================================================================================
///
//==================================================================================================
class RicCreateEnsembleFromFileSetFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
protected:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};
@@ -0,0 +1,57 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicImportEnsembleFileSetFeature.h"
#include "RicImportSummaryCasesFeature.h"
#include "EnsembleFileSet/RimEnsembleFileSetTools.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicImportEnsembleFileSetFeature, "RicImportEnsembleFileSetFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicImportEnsembleFileSetFeature::isCommandEnabled() const
{
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicImportEnsembleFileSetFeature::onActionTriggered( bool isChecked )
{
const QString pathCacheName = "ENSEMBLE_FILES";
auto result = RicImportSummaryCasesFeature::runRecursiveSummaryCaseFileSearchDialogWithGrouping( "Import Ensemble", pathCacheName );
if ( result.ok )
{
RimEnsembleFileSetTools::createEnsembleFileSets( result.files, result.groupingMode );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicImportEnsembleFileSetFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setIcon( QIcon( ":/Cases16x16.png" ) );
actionToSetup->setText( "Import Ensemble File Set" );
}
@@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
//==================================================================================================
///
//==================================================================================================
class RicImportEnsembleFileSetFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
protected:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};
@@ -119,6 +119,7 @@ void RicDeleteSummaryCaseCollectionFeature::onActionTriggered( bool isChecked )
for ( RimSummaryEnsemble* ensemble : ensembles )
{
summaryCaseMainCollection->removeEnsemble( ensemble );
ensemble->cleanupBeforeDelete();
delete ensemble;
}
@@ -27,10 +27,14 @@
#include "RicImportSummaryCasesFeature.h"
#include "EnsembleFileSet/RimEnsembleFileSet.h"
#include "EnsembleFileSet/RimEnsembleFileSetCollection.h"
#include "EnsembleFileSet/RimEnsembleFileSetTools.h"
#include "RimProject.h"
#include "RimSummaryCase.h"
#include "RimSummaryCaseMainCollection.h"
#include "RimSummaryEnsemble.h"
#include "Summary/Ensemble/RimSummaryFileSetEnsemble.h"
#include "RiuMainWindow.h"
#include "RiuPlotMainWindowTools.h"
@@ -62,7 +66,7 @@ RimSummaryEnsemble* RicImportEnsembleFeature::createSummaryEnsemble( std::vector
}
bool useEnsembleNameDialog = false;
return importSingleEnsemble( fileNames, useEnsembleNameDialog, groupingMode, RiaDefines::FileType::SMSPEC, name );
return importSingleEnsembleFileSet( fileNames, useEnsembleNameDialog, groupingMode, RiaDefines::FileType::SMSPEC, name );
}
//--------------------------------------------------------------------------------------------------
@@ -96,14 +100,24 @@ void RicImportEnsembleFeature::onActionTriggered( bool isChecked )
}
else
{
auto grouping = RiaEnsembleNameTools::groupFilesByEnsembleName( fileNames, ensembleGroupingMode );
std::vector<RimSummaryEnsemble*> ensembles;
auto grouping = RiaEnsembleNameTools::groupFilesByEnsembleName( fileNames, ensembleGroupingMode );
for ( const auto& [groupName, fileNames] : grouping )
{
bool useEnsembleNameDialog = false;
importSingleEnsemble( fileNames, useEnsembleNameDialog, ensembleGroupingMode, fileType, groupName );
if ( auto ensemble = importSingleEnsembleFileSet( fileNames, useEnsembleNameDialog, ensembleGroupingMode, fileType, groupName ) )
{
ensembles.push_back( ensemble );
}
}
RiaSummaryTools::updateSummaryEnsembleNames();
for ( auto ensemble : ensembles )
{
RiaSummaryPlotTools::createAndAppendDefaultSummaryMultiPlot( {}, { ensemble } );
}
RiaSummaryTools::summaryCaseMainCollection()->updateConnectedEditors();
}
}
}
@@ -152,6 +166,22 @@ RimSummaryEnsemble* RicImportEnsembleFeature::importSingleEnsemble( const QStrin
return ensemble;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryEnsemble* RicImportEnsembleFeature::importSingleEnsembleFileSet( const QStringList& fileNames,
bool useEnsembleNameDialog,
RiaDefines::EnsembleGroupingMode groupingMode,
RiaDefines::FileType fileType,
const QString& defaultEnsembleName )
{
auto fileSets = RimEnsembleFileSetTools::createEnsembleFileSets( fileNames, groupingMode );
auto ensembles = RimEnsembleFileSetTools::createSummaryEnsemblesFromFileSets( fileSets );
if ( !ensembles.empty() ) return ensembles.front();
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -51,4 +51,10 @@ private:
RiaDefines::EnsembleGroupingMode groupingMode,
RiaDefines::FileType fileType,
const QString& defaultEnsembleName = QString() );
static RimSummaryEnsemble* importSingleEnsembleFileSet( const QStringList& fileNames,
bool useEnsembleNameDialog,
RiaDefines::EnsembleGroupingMode groupingMode,
RiaDefines::FileType fileType,
const QString& defaultEnsembleName = QString() );
};
@@ -0,0 +1,14 @@
set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFileSet.h
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFileSetCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFileSetTools.h
)
set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFileSet.cpp
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFileSetCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFileSetTools.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES})
@@ -0,0 +1,366 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimEnsembleFileSet.h"
#include "Ensemble/RiaEnsembleImportTools.h"
#include "RiaEnsembleNameTools.h"
#include "RiaFilePathTools.h"
#include "RiaStdStringTools.h"
#include "RiaTextStringTools.h"
#include "RimEnsembleFileSetCollection.h"
#include "RimProject.h"
#include "cafCmdFeatureMenuBuilder.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmUiComboBoxEditor.h"
#include "cafPdmUiLineEditor.h"
CAF_PDM_SOURCE_INIT( RimEnsembleFileSet, "EnsembleFileSet" );
namespace internal
{
QString placeholderString()
{
return "*";
}
} // namespace internal
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleFileSet::RimEnsembleFileSet()
: fileSetChanged( this )
, nameChanged( this )
, m_useKey1( false )
, m_useKey2( false )
{
CAF_PDM_InitObject( "Ensemble", ":/CreateGridCaseGroup16x16.png", "", "" );
CAF_PDM_InitField( &m_pathPattern, "PathPattern", QString(), "Path Pattern", "", "", "" );
CAF_PDM_InitField( &m_realizationSubSet, "RealizationSubSet", QString(), "Realization Filter", "", "", "" );
CAF_PDM_InitFieldNoDefault( &m_groupingMode, "GroupingMode", "Grouping Mode" );
CAF_PDM_InitScriptableField( &m_autoName, "CreateAutoName", true, "Auto Name" );
QString defaultText = RiaDefines::key1VariableName() + "-" + RiaDefines::key2VariableName();
QString tooltipText = QString( "Variables in template is supported, and will be replaced to create name. Example '%1'" ).arg( defaultText );
CAF_PDM_InitField( &m_nameTemplateString, "NameTemplateString", defaultText, "Name Template", "", tooltipText );
nameField()->uiCapability()->setUiReadOnly( true );
nameField()->xmlCapability()->disableIO();
setDeletable( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList RimEnsembleFileSet::createPaths( const QString& extension ) const
{
// Append extension to the path pattern and return list of files matching the pattern
QString pathPattern = m_pathPattern();
if ( pathPattern.isEmpty() )
{
return {};
}
pathPattern += extension;
return RiaEnsembleImportTools::createPathsFromPattern( pathPattern, m_realizationSubSet(), internal::placeholderString() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::findAndSetPathPatternAndRangeString( const QStringList& filePaths )
{
QStringList normalizedPaths;
for ( const auto& path : filePaths )
{
normalizedPaths.append( RiaFilePathTools::toInternalSeparator( path ) );
}
const auto& [pattern, rangeString] = RiaEnsembleImportTools::findPathPattern( normalizedPaths, internal::placeholderString() );
// find the pattern without extension by finding . and remove rest of string
auto noExtension = pattern;
auto dotIndex = noExtension.lastIndexOf( '.' );
if ( dotIndex != -1 )
{
noExtension = noExtension.left( dotIndex );
}
m_pathPattern = noExtension;
m_realizationSubSet = rangeString;
fileSetChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::setNameTemplate( const QString& name )
{
m_nameTemplateString = name;
fileSetChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::updateName( const std::set<QString>& existingEnsembleNames )
{
const auto [key1, key2] = nameKeys();
QString templateText;
if ( m_autoName )
{
templateText = nameTemplateText();
}
else
{
templateText = m_nameTemplateString();
}
std::map<QString, QString> keyValues = {
{ RiaDefines::key1VariableName(), QString::fromStdString( key1 ) },
{ RiaDefines::key2VariableName(), QString::fromStdString( key2 ) },
};
auto candidateName = RiaTextStringTools::replaceTemplateTextWithValues( templateText, keyValues );
if ( m_autoName )
{
candidateName = candidateName.trimmed();
// When using auto name, remove leading and trailing commas that may occur if key1 or key2 is empty
if ( candidateName.startsWith( "," ) )
{
candidateName = candidateName.mid( 1 );
}
if ( candidateName.endsWith( "," ) )
{
candidateName = candidateName.left( candidateName.length() - 1 );
}
auto generateUniqueName = []( const QString& baseName, const std::set<QString>& existingNames )
{
// Avoid identical ensemble names by appending a number
QString uniqueName = baseName;
int counter = 1;
while ( existingNames.find( uniqueName ) != existingNames.end() )
{
uniqueName = QString( "%1_%2" ).arg( baseName ).arg( counter++ );
}
return uniqueName;
};
candidateName = generateUniqueName( candidateName, existingEnsembleNames );
}
if ( name() == candidateName ) return;
setName( candidateName );
nameChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::setUsePathKey1( bool useKey1 )
{
m_useKey1 = useKey1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::setUsePathKey2( bool useKey2 )
{
m_useKey2 = useKey2;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_pathPattern )
{
if ( auto lineEdAttr = dynamic_cast<caf::PdmUiLineEditorAttribute*>( attribute ) )
{
lineEdAttr->placeholderText = "Enter path pattern...";
}
}
else if ( field == &m_realizationSubSet )
{
if ( auto lineEdAttr = dynamic_cast<caf::PdmUiLineEditorAttribute*>( attribute ) )
{
lineEdAttr->placeholderText = "E.g. 0,1,4-6,10-20";
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_autoName );
if ( !m_autoName() )
{
uiOrdering.add( &m_nameTemplateString );
}
uiOrdering.add( nameField() );
uiOrdering.add( &m_pathPattern );
uiOrdering.add( &m_realizationSubSet );
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
if ( changedField == &m_nameTemplateString || changedField == &m_autoName )
{
RimProject::current()->ensembleFileSetCollection()->updateFileSetNames();
}
else
{
fileSetChanged.send();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
menuBuilder << "RicCreateEnsembleFromFileSetFeature";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::setPathPattern( const QString& pathPattern )
{
m_pathPattern = pathPattern;
fileSetChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::setRangeString( const QString& rangeString )
{
m_realizationSubSet = rangeString;
fileSetChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<std::string, std::string> RimEnsembleFileSet::nameKeys() const
{
std::string key1 = "Undefined KEY1";
std::string key2 = "Undefined KEY2";
if ( m_groupingMode() == RiaDefines::EnsembleGroupingMode::FMU_FOLDER_STRUCTURE )
{
auto pathPattern = m_pathPattern + ".SMSPEC";
auto paths = RiaEnsembleImportTools::createPathsFromPattern( pathPattern, "0", internal::placeholderString() );
if ( !paths.empty() )
{
auto fileNames = RiaEnsembleNameTools::groupFilePathsFmu( { paths.front().toStdString() } );
if ( !fileNames.empty() )
{
key1 = fileNames.begin()->first.first;
key2 = fileNames.begin()->first.second;
}
}
}
else if ( m_groupingMode() == RiaDefines::EnsembleGroupingMode::EVEREST_FOLDER_STRUCTURE )
{
auto pathPattern = m_pathPattern + ".SMSPEC";
auto paths = RiaEnsembleImportTools::createPathsFromPattern( pathPattern, "0-1", internal::placeholderString() );
if ( paths.size() > 1 )
{
auto name1 = RiaFilePathTools::toInternalSeparator( paths[0] ).toStdString();
auto name2 = RiaFilePathTools::toInternalSeparator( paths[1] ).toStdString();
auto parts1 = RiaStdStringTools::splitString( name1, '/' );
auto parts2 = RiaStdStringTools::splitString( name2, '/' );
size_t commonParts = 0;
for ( size_t i = 0; i < std::min( parts1.size(), parts2.size() ); i++ )
{
if ( parts1[i] == parts2[i] )
{
commonParts++;
}
else
{
break;
}
}
if ( commonParts == 1 )
{
key2 = parts1[commonParts - 1];
}
else if ( commonParts > 1 )
{
key1 = parts1[commonParts - 2];
key2 = parts1[commonParts - 1];
}
}
}
return { key1, key2 };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimEnsembleFileSet::nameTemplateText() const
{
QString text;
if ( m_useKey1 ) text += RiaDefines::key1VariableName();
if ( m_useKey2 )
{
if ( !text.isEmpty() ) text += ", ";
text += RiaDefines::key2VariableName();
}
return text;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSet::setGroupingMode( RiaDefines::EnsembleGroupingMode groupingMode )
{
m_groupingMode = groupingMode;
}
@@ -0,0 +1,76 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimNamedObject.h"
#include "Summary/RiaSummaryDefines.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmPointer.h"
//==================================================================================================
///
///
//==================================================================================================
class RimEnsembleFileSet : public RimNamedObject
{
CAF_PDM_HEADER_INIT;
public:
caf::Signal<> fileSetChanged;
caf::Signal<> nameChanged;
public:
RimEnsembleFileSet();
QStringList createPaths( const QString& extension ) const;
void findAndSetPathPatternAndRangeString( const QStringList& filePaths );
void setNameTemplate( const QString& name );
void updateName( const std::set<QString>& existingEnsembleNames );
void setUsePathKey1( bool useKey1 );
void setUsePathKey2( bool useKey2 );
std::pair<std::string, std::string> nameKeys() const;
QString nameTemplateText() const;
void setGroupingMode( RiaDefines::EnsembleGroupingMode groupingMode );
private:
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
void setPathPattern( const QString& pathPattern );
void setRangeString( const QString& rangeString );
private:
caf::PdmField<QString> m_pathPattern;
caf::PdmField<QString> m_realizationSubSet;
caf::PdmField<QString> m_nameTemplateString;
caf::PdmField<bool> m_autoName;
caf::PdmField<caf::AppEnum<RiaDefines::EnsembleGroupingMode>> m_groupingMode;
bool m_useKey1;
bool m_useKey2;
};
@@ -0,0 +1,142 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimEnsembleFileSetCollection.h"
#include "RimEnsembleFileSet.h"
#include "cafCmdFeatureMenuBuilder.h"
#include "cafPdmUiComboBoxEditor.h"
#include "cafPdmUiLineEditor.h"
CAF_PDM_SOURCE_INIT( RimEnsembleFileSetCollection, "EnsembleFileSetCollection" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleFileSetCollection::RimEnsembleFileSetCollection()
{
CAF_PDM_InitObject( "Disc Data", ":/CreateGridCaseGroup16x16.png", "", "" );
CAF_PDM_InitFieldNoDefault( &m_fileSets, "FileSets", "File Sets", "", "", "" );
m_fileSets.uiCapability()->setUiHidden( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSetCollection::addFileSet( RimEnsembleFileSet* fileSet )
{
if ( fileSet ) m_fileSets.push_back( fileSet );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimEnsembleFileSet*> RimEnsembleFileSetCollection::fileSets() const
{
return m_fileSets.childrenByType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSetCollection::deleteAllFileSets()
{
m_fileSets.deleteChildren();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSetCollection::deleteFileSetIfPossible( RimEnsembleFileSet* fileSet )
{
if ( fileSet )
{
// Check if the file set is connected to any objects. If not, remove it from the collection and delete it
auto connectedObjects = fileSet->objectsWithReferringPtrFields();
if ( connectedObjects.empty() )
{
m_fileSets.removeChild( fileSet );
delete fileSet;
updateConnectedEditors();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimEnsembleFileSetCollection::ensembleFileSetOptions() const
{
QList<caf::PdmOptionItemInfo> options;
for ( const auto& fileset : m_fileSets )
{
options.push_back( caf::PdmOptionItemInfo( fileset->name(), fileset, false, fileset->uiIconProvider() ) );
}
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSetCollection::updateFileSetNames()
{
std::set<std::string> key1;
std::set<std::string> key2;
for ( const auto& fileSet : fileSets() )
{
const auto keys = fileSet->nameKeys();
key1.insert( keys.first );
key2.insert( keys.second );
}
bool useKey1 = key1.size() > 1;
bool useKey2 = key2.size() > 1;
if ( !useKey1 && !useKey2 )
{
useKey2 = true;
}
std::set<QString> existingNames;
for ( auto fileSet : fileSets() )
{
fileSet->setUsePathKey1( useKey1 );
fileSet->setUsePathKey2( useKey2 );
fileSet->updateName( existingNames );
existingNames.insert( fileSet->name() );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSetCollection::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
menuBuilder << "RicImportEnsembleFileSetFeature";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleFileSetCollection::initAfterRead()
{
updateFileSetNames();
}
@@ -0,0 +1,54 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmPointer.h"
class RimEnsembleFileSet;
//==================================================================================================
///
/// Class to manage a collection of ensemble filesets
///
//==================================================================================================
class RimEnsembleFileSetCollection : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
RimEnsembleFileSetCollection();
void addFileSet( RimEnsembleFileSet* fileSet );
std::vector<RimEnsembleFileSet*> fileSets() const;
void deleteAllFileSets();
void deleteFileSetIfPossible( RimEnsembleFileSet* fileSet );
QList<caf::PdmOptionItemInfo> ensembleFileSetOptions() const;
void updateFileSetNames();
private:
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
void initAfterRead() override;
private:
caf::PdmChildArrayField<RimEnsembleFileSet*> m_fileSets;
};
@@ -0,0 +1,90 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimEnsembleFileSetTools.h"
#include "Summary/RiaSummaryPlotTools.h"
#include "Summary/RiaSummaryTools.h"
#include "Ensemble/RimSummaryFileSetEnsemble.h"
#include "EnsembleFileSet/RimEnsembleFileSet.h"
#include "EnsembleFileSet/RimEnsembleFileSetCollection.h"
#include "RiaEnsembleNameTools.h"
#include "RimProject.h"
#include "RimSummaryCaseMainCollection.h"
namespace RimEnsembleFileSetTools
{
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryEnsemble*> createSummaryEnsemblesFromFileSets( const std::vector<RimEnsembleFileSet*> fileSets )
{
std::vector<RimSummaryEnsemble*> ensembles;
for ( auto fileSet : fileSets )
{
auto ensemble = new RimSummaryFileSetEnsemble();
ensemble->setEnsembleFileSet( fileSet );
RiaSummaryTools::summaryCaseMainCollection()->addEnsemble( ensemble );
RiaSummaryTools::summaryCaseMainCollection()->updateEnsembleNames();
ensemble->loadDataAndUpdate();
ensembles.push_back( ensemble );
}
RiaSummaryTools::summaryCaseMainCollection()->updateConnectedEditors();
return ensembles;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimEnsembleFileSet*> createEnsembleFileSets( const QStringList& fileNames, RiaDefines::EnsembleGroupingMode groupingMode )
{
std::vector<RimEnsembleFileSet*> fileSets;
auto collection = RimProject::current()->ensembleFileSetCollection();
auto grouping = RiaEnsembleNameTools::groupFilesByEnsembleName( fileNames, groupingMode );
for ( const auto& [groupName, fileNames] : grouping )
{
auto ensembleFileSet = new RimEnsembleFileSet();
ensembleFileSet->setName( groupName );
ensembleFileSet->setGroupingMode( groupingMode );
ensembleFileSet->findAndSetPathPatternAndRangeString( fileNames );
collection->addFileSet( ensembleFileSet );
fileSets.push_back( ensembleFileSet );
}
collection->updateFileSetNames();
collection->updateAllRequiredEditors();
return fileSets;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> ensembleFileSetOptions()
{
return RimProject::current()->ensembleFileSetCollection()->ensembleFileSetOptions();
}
} // namespace RimEnsembleFileSetTools
@@ -0,0 +1,39 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "Summary/RiaSummaryDefines.h"
#include "cafPdmUiItem.h"
#include <QStringList>
#include <vector>
class RimSummaryEnsemble;
class RimEnsembleFileSet;
namespace RimEnsembleFileSetTools
{
std::vector<RimSummaryEnsemble*> createSummaryEnsemblesFromFileSets( const std::vector<RimEnsembleFileSet*> fileSets );
std::vector<RimEnsembleFileSet*> createEnsembleFileSets( const QStringList& fileNames, RiaDefines::EnsembleGroupingMode groupingMode );
QList<caf::PdmOptionItemInfo> ensembleFileSetOptions();
}; // namespace RimEnsembleFileSetTools
@@ -36,6 +36,7 @@
#include "Cloud/RimCloudDataSourceCollection.h"
#include "ContourMap/RimEclipseContourMapViewCollection.h"
#include "EnsembleFileSet/RimEnsembleFileSetCollection.h"
#include "Formations/RimFormationNamesCollection.h"
#include "PlotTemplates/RimPlotTemplateFolderItem.h"
#include "Polygons/RimPolygonCollection.h"
@@ -235,6 +236,9 @@ RimProject::RimProject()
CAF_PDM_InitFieldNoDefault( &m_automationSettings, "AutomationSettings", "Automation Settings" );
m_automationSettings = new RimAutomationSettings();
CAF_PDM_InitFieldNoDefault( &m_ensembleFileSetCollection, "EnsembleFileSetCollection", "Ensemble File Sets" );
m_ensembleFileSetCollection = new RimEnsembleFileSetCollection();
// For now, create a default first oilfield that contains the rest of the project
oilFields.push_back( new RimOilField );
@@ -266,6 +270,7 @@ void RimProject::close()
m_mainPlotCollection()->deleteAllContainedObjects();
}
m_ensembleFileSetCollection()->deleteAllFileSets();
oilFields.deleteChildren();
oilFields.push_back( new RimOilField );
@@ -376,6 +381,14 @@ RimAutomationSettings* RimProject::automationSettings() const
return m_automationSettings();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleFileSetCollection* RimProject::ensembleFileSetCollection() const
{
return m_ensembleFileSetCollection();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -409,6 +422,44 @@ void RimProject::setupBeforeSave()
m_projectFileVersionString = STRPRODUCTVER;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<caf::PdmFieldHandle*> RimProject::fieldsForExport() const
{
std::vector<QString> orderedKeywords;
orderedKeywords.push_back( fileNameHandle()->keyword() );
orderedKeywords.push_back( m_projectFileVersionString.keyword() );
orderedKeywords.push_back( m_globalPathList.keyword() );
orderedKeywords.push_back( m_ensembleFileSetCollection.keyword() );
std::vector<caf::PdmFieldHandle*> ordered;
auto fieldHandles = fields();
for ( const auto& kw : orderedKeywords )
{
auto it = std::find_if( fieldHandles.begin(),
fieldHandles.end(),
[&]( const caf::PdmFieldHandle* field ) { return field->keyword() == kw; } );
if ( it != fieldHandles.end() )
{
ordered.push_back( *it );
}
}
// Append the rest of the fields
for ( auto fieldHandle : fields() )
{
if ( std::find( ordered.begin(), ordered.end(), fieldHandle ) == ordered.end() )
{
ordered.push_back( fieldHandle );
}
}
return ordered;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -1463,6 +1514,7 @@ void RimProject::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, Q
}
else if ( uiConfigName == "PlotWindow.Cloud" )
{
uiTreeOrdering.add( &m_ensembleFileSetCollection );
if ( m_mainPlotCollection )
{
if ( activeOilField()->cloudDataCollection() )
@@ -73,6 +73,7 @@ class RimPlotTemplateFolderItem;
class RimGridCalculationCollection;
class RimQuickAccessCollection;
class RimAutomationSettings;
class RimEnsembleFileSetCollection;
namespace caf
{
@@ -192,12 +193,14 @@ public:
void updatesAfterProjectFileIsRead();
RimQuickAccessCollection* pinnedFieldCollection() const;
RimAutomationSettings* automationSettings() const;
RimQuickAccessCollection* pinnedFieldCollection() const;
RimAutomationSettings* automationSettings() const;
RimEnsembleFileSetCollection* ensembleFileSetCollection() const;
protected:
void initAfterRead() override;
void setupBeforeSave() override;
void initAfterRead() override;
void setupBeforeSave() override;
std::vector<caf::PdmFieldHandle*> fieldsForExport() const override;
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
@@ -207,9 +210,10 @@ private:
QString updatedFilePathFromPathId( QString filePath, RiaVariableMapper* pathListMapper = nullptr ) const;
private:
caf::PdmChildField<RimMainPlotCollection*> m_mainPlotCollection;
caf::PdmChildField<RimQuickAccessCollection*> m_pinnedFieldCollection;
caf::PdmChildField<RimAutomationSettings*> m_automationSettings;
caf::PdmChildField<RimMainPlotCollection*> m_mainPlotCollection;
caf::PdmChildField<RimQuickAccessCollection*> m_pinnedFieldCollection;
caf::PdmChildField<RimAutomationSettings*> m_automationSettings;
caf::PdmChildField<RimEnsembleFileSetCollection*> m_ensembleFileSetCollection;
caf::PdmField<QString> m_globalPathList;
caf::PdmField<QString> m_projectFileVersionString;
@@ -0,0 +1,10 @@
set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimSummaryFileSetEnsemble.h
)
set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimSummaryFileSetEnsemble.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES})
@@ -0,0 +1,221 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimSummaryFileSetEnsemble.h"
#include "Ensemble/RiaEnsembleImportTools.h"
#include "RiaFilePathTools.h"
#include "RiaLogging.h"
#include "EnsembleFileSet/RimEnsembleFileSet.h"
#include "EnsembleFileSet/RimEnsembleFileSetCollection.h"
#include "EnsembleFileSet/RimEnsembleFileSetTools.h"
#include "RimSummaryCase.h"
CAF_PDM_SOURCE_INIT( RimSummaryFileSetEnsemble, "RimSummaryFileSetEnsemble" );
namespace internal
{
const QString pathPatternPlaceholder = "*";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryFileSetEnsemble::RimSummaryFileSetEnsemble()
{
CAF_PDM_InitObject( "Path Pattern Ensemble", ":/SummaryCase.svg" );
CAF_PDM_InitFieldNoDefault( &m_ensembleFileSet, "EnsembleFileSet", "Ensemble File Set" );
m_cases.xmlCapability()->disableIO();
setAsEnsemble( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryFileSetEnsemble::setEnsembleFileSet( RimEnsembleFileSet* ensembleFileSet )
{
m_ensembleFileSet = ensembleFileSet;
connectSignals();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryFileSetEnsemble::updateName( const std::set<QString>& existingEnsembleNames )
{
QString candidateName = m_ensembleFileSet() ? m_ensembleFileSet()->name() : "Path Pattern Ensemble";
if ( m_name == candidateName ) return;
m_name = candidateName;
caseNameChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryFileSetEnsemble::cleanupBeforeDelete()
{
if ( m_ensembleFileSet() )
{
m_ensembleFileSet()->fileSetChanged.disconnect( this );
m_ensembleFileSet()->nameChanged.disconnect( this );
auto fileSet = m_ensembleFileSet();
m_ensembleFileSet = nullptr;
if ( auto coll = fileSet->firstAncestorOrThisOfType<RimEnsembleFileSetCollection>() )
{
coll->deleteFileSetIfPossible( fileSet );
}
}
RimSummaryEnsemble::cleanupBeforeDelete();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimSummaryFileSetEnsemble::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
if ( fieldNeedingOptions == &m_ensembleFileSet )
{
return RimEnsembleFileSetTools::ensembleFileSetOptions();
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryFileSetEnsemble::onFileSetChanged( const caf::SignalEmitter* emitter )
{
createSummaryCasesFromEnsembleFileSet();
buildChildNodes();
updateAllRequiredEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryFileSetEnsemble::onFileSetNameChanged( const caf::SignalEmitter* emitter )
{
updateName( {} );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryFileSetEnsemble::createSummaryCasesFromEnsembleFileSet()
{
m_cases.deleteChildrenAsync();
if ( m_ensembleFileSet() )
{
auto paths = m_ensembleFileSet()->createPaths( ".SMSPEC" );
RiaDefines::FileType fileType = RiaDefines::FileType::SMSPEC;
RiaEnsembleImportTools::CreateConfig createConfig{ .fileType = fileType, .ensembleOrGroup = false, .allowDialogs = false };
auto newCases = RiaEnsembleImportTools::createSummaryCasesFromFiles( paths, createConfig );
if ( newCases.empty() )
{
RiaLogging::warning( "No new cases are created." );
return;
}
replaceCases( newCases );
// Update name of cases and ensemble after all cases are added
for ( auto summaryCase : newCases )
{
summaryCase->setShowVectorItemsInProjectTree( false );
summaryCase->setDisplayNameOption( RimCaseDisplayNameTools::DisplayName::SHORT_CASE_NAME );
summaryCase->updateAutoShortName();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryFileSetEnsemble::initAfterRead()
{
RimSummaryEnsemble::initAfterRead();
connectSignals();
createSummaryCasesFromEnsembleFileSet();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryFileSetEnsemble::connectSignals()
{
if ( m_ensembleFileSet() )
{
m_ensembleFileSet()->fileSetChanged.connect( this, &RimSummaryFileSetEnsemble::onFileSetChanged );
m_ensembleFileSet()->nameChanged.connect( this, &RimSummaryFileSetEnsemble::onFileSetNameChanged );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryFileSetEnsemble::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
if ( m_ensembleFileSet() )
{
auto group = uiOrdering.addNewGroup( "Ensemble Definition" );
m_ensembleFileSet()->uiOrdering( uiConfigName, *group );
}
auto developersGroup = uiOrdering.addNewGroup( " -- Developers --" );
developersGroup->setCollapsedByDefault();
developersGroup->add( &m_ensembleFileSet );
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryFileSetEnsemble::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
RimSummaryEnsemble::fieldChangedByUi( changedField, oldValue, newValue );
if ( changedField == &m_ensembleFileSet )
{
connectSignals();
createSummaryCasesFromEnsembleFileSet();
caseNameChanged.send();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryFileSetEnsemble::onLoadDataAndUpdate()
{
if ( m_cases.empty() ) createSummaryCasesFromEnsembleFileSet();
RimSummaryEnsemble::onLoadDataAndUpdate();
}
@@ -0,0 +1,59 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimSummaryEnsemble.h"
#include "cafPdmPtrField.h"
class RimEnsembleFileSet;
//==================================================================================================
//
//
//
//==================================================================================================
class RimSummaryFileSetEnsemble : public RimSummaryEnsemble
{
CAF_PDM_HEADER_INIT;
public:
RimSummaryFileSetEnsemble();
void setEnsembleFileSet( RimEnsembleFileSet* ensembleFileSet );
void updateName( const std::set<QString>& existingEnsembleNames ) override;
void cleanupBeforeDelete() override;
private:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void initAfterRead() override;
void onLoadDataAndUpdate() override;
void onFileSetChanged( const caf::SignalEmitter* emitter );
void onFileSetNameChanged( const caf::SignalEmitter* emitter );
void createSummaryCasesFromEnsembleFileSet();
void connectSignals();
private:
caf::PdmPtrField<RimEnsembleFileSet*> m_ensembleFileSet;
};
@@ -1739,6 +1739,8 @@ QList<caf::PdmOptionItemInfo> RimEnsembleCurveSet::calculateValueOptions( const
//--------------------------------------------------------------------------------------------------
std::set<time_t> RimEnsembleCurveSet::allAvailableTimeSteps() const
{
if ( !summaryEnsemble() ) return {};
std::set<time_t> timeStepUnion;
for ( RimSummaryCase* sumCase : summaryEnsemble()->allSummaryCases() )
@@ -235,12 +235,6 @@ RimSummaryEnsemble* RimSummaryCaseMainCollection::addEnsemble( const std::vector
RimSummaryEnsemble* ensemble = allocator();
if ( !collectionName.isEmpty() ) ensemble->setNameTemplate( collectionName );
if ( ensemble->ensembleId() == -1 )
{
RimProject* project = RimProject::current();
project->assignIdToEnsemble( ensemble );
}
for ( RimSummaryCase* summaryCase : summaryCases )
{
auto currentSummaryCaseCollection = summaryCase->firstAncestorOrThisOfType<RimSummaryEnsemble>();
@@ -262,10 +256,7 @@ RimSummaryEnsemble* RimSummaryCaseMainCollection::addEnsemble( const std::vector
ensemble->setAsEnsemble( isEnsemble );
ensemble->caseNameChanged.connect( this, &RimSummaryCaseMainCollection::onCaseNameChanged );
m_ensembles.push_back( ensemble );
dataSourceHasChanged.send();
addEnsemble( ensemble );
return ensemble;
}
@@ -297,6 +288,8 @@ void RimSummaryCaseMainCollection::addEnsemble( RimSummaryEnsemble* ensemble )
project->assignIdToEnsemble( ensemble );
}
ensemble->caseNameChanged.connect( this, &RimSummaryCaseMainCollection::onCaseNameChanged );
dataSourceHasChanged.send();
}
@@ -550,6 +543,8 @@ void RimSummaryCaseMainCollection::onCaseNameChanged( const SignalEmitter* emitt
RimSummaryMultiPlotCollection* summaryPlotColl = RiaSummaryTools::summaryMultiPlotCollection();
summaryPlotColl->updateSummaryNameHasChanged();
updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
@@ -840,6 +840,13 @@ std::pair<double, double> RimSummaryEnsemble::minMax( const RifEclipseSummaryAdd
return m_minMaxValues[address];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryEnsemble::cleanupBeforeDelete()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -66,7 +66,7 @@ public:
QString name() const;
void setNameTemplate( const QString& name );
void updateName( const std::set<QString>& existingEnsembleNames );
virtual void updateName( const std::set<QString>& existingEnsembleNames );
void setUsePathKey1( bool useKey1 );
void setUsePathKey2( bool useKey2 );
virtual std::pair<std::string, std::string> nameKeys() const;
@@ -117,6 +117,8 @@ public:
void setMinMax( const RifEclipseSummaryAddress& address, double min, double max );
std::pair<double, double> minMax( const RifEclipseSummaryAddress& address );
virtual void cleanupBeforeDelete();
protected:
virtual void onLoadDataAndUpdate();
@@ -127,10 +129,11 @@ protected:
bool isAutoNameChecked() const;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void initAfterRead() override;
void buildChildNodes();
private:
caf::PdmFieldHandle* userDescriptionField() override;
void initAfterRead() override;
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
@@ -141,7 +144,6 @@ private:
void onCaseNameChanged( const SignalEmitter* emitter );
void buildChildNodes();
void clearChildNodes();
QString ensembleDescription() const;
@@ -189,4 +189,6 @@ void RimSummaryMultiPlotCollection::updateSummaryNameHasChanged()
multiPlot->updatePlotTitles();
}
updateConnectedEditors();
}
@@ -468,7 +468,7 @@ void RiuPlotMainWindow::refreshToolbars()
//--------------------------------------------------------------------------------------------------
void RiuPlotMainWindow::createDockPanels()
{
const std::vector<QString> treeViewTitles = { "Plots", "Data Sources", "Templates", "Scripts", "Cloud" + RiaDefines::betaFeaturePostfix() };
const std::vector<QString> treeViewTitles = { "Plots", "Data Sources", "Templates", "Scripts", "Ensemble Data" };
const std::vector<QString> treeViewConfigs = { "PlotWindow.Plots",
"PlotWindow.DataSources",
"PlotWindow.Templates",