From 31d653bce75c2706748b671f56bcb4a11aeba350 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 5 Jul 2024 09:06:16 +0200 Subject: [PATCH] Add Sumo summary ensemble and summary case Add feature to create ensemble from a sumo data source --- ApplicationLibCode/CMakeLists.txt | 2 + .../RicSumoDataFeature.cpp | 2 +- ApplicationLibCode/Commands/CMakeLists.txt | 1 + .../RicShowDataSourcesForRealization.cpp | 6 +- .../Commands/Sumo/CMakeLists_files.cmake | 10 + .../Sumo/RicCreateSumoEnsembleFeature.cpp | 62 +++ .../Sumo/RicCreateSumoEnsembleFeature.h | 33 ++ .../Cloud/CMakeLists_files.cmake | 11 + .../Cloud/RimCloudDataSourceCollection.cpp | 233 ++++++++++ .../Cloud/RimCloudDataSourceCollection.h | 65 +++ .../ProjectDataModel/RimOilField.cpp | 4 + .../ProjectDataModel/RimOilField.h | 2 + .../ProjectDataModel/RimProject.cpp | 6 + .../RimSummaryCalculationCollection.cpp | 2 +- .../RimDerivedEnsembleCaseCollection.cpp | 4 + .../Summary/RimSummaryCase.cpp | 4 +- .../ProjectDataModel/Summary/RimSummaryCase.h | 4 +- .../Summary/RimSummaryCaseCollection.cpp | 2 +- .../Summary/RimSummaryCaseCollection.h | 3 +- .../Summary/RimSummaryCaseMainCollection.cpp | 18 + .../Summary/RimSummaryCaseMainCollection.h | 1 + .../Summary/Sumo/CMakeLists_files.cmake | 14 + .../Summary/Sumo/RimSummaryCaseSumo.cpp | 179 ++++++++ .../Summary/Sumo/RimSummaryCaseSumo.h | 67 +++ .../Summary/Sumo/RimSummaryEnsembleSumo.cpp | 421 ++++++++++++++++++ .../Summary/Sumo/RimSummaryEnsembleSumo.h | 92 ++++ .../Summary/Sumo/RimSummarySumoDataSource.cpp | 207 +++++++++ .../Summary/Sumo/RimSummarySumoDataSource.h | 73 +++ 28 files changed, 1517 insertions(+), 11 deletions(-) create mode 100644 ApplicationLibCode/Commands/Sumo/CMakeLists_files.cmake create mode 100644 ApplicationLibCode/Commands/Sumo/RicCreateSumoEnsembleFeature.cpp create mode 100644 ApplicationLibCode/Commands/Sumo/RicCreateSumoEnsembleFeature.h create mode 100644 ApplicationLibCode/ProjectDataModel/Cloud/CMakeLists_files.cmake create mode 100644 ApplicationLibCode/ProjectDataModel/Cloud/RimCloudDataSourceCollection.cpp create mode 100644 ApplicationLibCode/ProjectDataModel/Cloud/RimCloudDataSourceCollection.h create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/Sumo/CMakeLists_files.cmake create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryCaseSumo.cpp create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryCaseSumo.h create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryEnsembleSumo.cpp create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryEnsembleSumo.h create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummarySumoDataSource.cpp create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummarySumoDataSource.h diff --git a/ApplicationLibCode/CMakeLists.txt b/ApplicationLibCode/CMakeLists.txt index dfdf6c6127..da5036c463 100644 --- a/ApplicationLibCode/CMakeLists.txt +++ b/ApplicationLibCode/CMakeLists.txt @@ -103,11 +103,13 @@ list( ProjectDataModel/CMakeLists_files.cmake ProjectDataModel/AnalysisPlots/CMakeLists_files.cmake ProjectDataModel/CorrelationPlots/CMakeLists_files.cmake + ProjectDataModel/Cloud/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/Flow/CMakeLists_files.cmake ProjectDataModel/Annotations/CMakeLists_files.cmake ProjectDataModel/Completions/CMakeLists_files.cmake diff --git a/ApplicationLibCode/Commands/ApplicationCommands/RicSumoDataFeature.cpp b/ApplicationLibCode/Commands/ApplicationCommands/RicSumoDataFeature.cpp index e1c8e67203..c877ba196f 100644 --- a/ApplicationLibCode/Commands/ApplicationCommands/RicSumoDataFeature.cpp +++ b/ApplicationLibCode/Commands/ApplicationCommands/RicSumoDataFeature.cpp @@ -124,7 +124,7 @@ void SimpleDialog::onAssetsClicked() { if ( !isTokenValid() ) return; - m_sumoConnector->requestAssets(); + m_sumoConnector->requestAssetsBlocking(); m_sumoConnector->assets(); label->setText( "Requesting fields (see log for response" ); diff --git a/ApplicationLibCode/Commands/CMakeLists.txt b/ApplicationLibCode/Commands/CMakeLists.txt index f3cd9401e4..34d7e65b88 100644 --- a/ApplicationLibCode/Commands/CMakeLists.txt +++ b/ApplicationLibCode/Commands/CMakeLists.txt @@ -42,6 +42,7 @@ set(COMMAND_REFERENCED_CMAKE_FILES FractureCommands/CMakeLists_files.cmake PlotBuilderCommands/CMakeLists_files.cmake PolygonCommands/CMakeLists_files.cmake + Sumo/CMakeLists_files.cmake ) # Include source file lists from *.cmake files diff --git a/ApplicationLibCode/Commands/RicShowDataSourcesForRealization.cpp b/ApplicationLibCode/Commands/RicShowDataSourcesForRealization.cpp index c1f9b92e80..f444d933e1 100644 --- a/ApplicationLibCode/Commands/RicShowDataSourcesForRealization.cpp +++ b/ApplicationLibCode/Commands/RicShowDataSourcesForRealization.cpp @@ -46,7 +46,7 @@ bool RicShowDataSourcesForRealization::isCommandChecked() const if ( !selection.empty() ) { - return selection.front()->showRealizationDataSources(); + return selection.front()->showVectorItemsInProjectTree(); } return false; @@ -80,10 +80,10 @@ void RicShowDataSourcesForRealization::onActionTriggered( bool isChecked ) if ( selection.empty() ) return; - bool enableDataSources = !selection.front()->showRealizationDataSources(); + bool enableDataSources = !selection.front()->showVectorItemsInProjectTree(); for ( auto summaryCase : selection ) { - summaryCase->setShowRealizationDataSource( enableDataSources ); + summaryCase->setShowVectorItemsInProjectTree( enableDataSources ); } } diff --git a/ApplicationLibCode/Commands/Sumo/CMakeLists_files.cmake b/ApplicationLibCode/Commands/Sumo/CMakeLists_files.cmake new file mode 100644 index 0000000000..8424c2cd60 --- /dev/null +++ b/ApplicationLibCode/Commands/Sumo/CMakeLists_files.cmake @@ -0,0 +1,10 @@ +set(SOURCE_GROUP_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/RicCreateSumoEnsembleFeature.h +) + +set(SOURCE_GROUP_SOURCE_FILES + ${CMAKE_CURRENT_LIST_DIR}/RicCreateSumoEnsembleFeature.cpp +) + +list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) +list(APPEND COMMAND_CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES}) diff --git a/ApplicationLibCode/Commands/Sumo/RicCreateSumoEnsembleFeature.cpp b/ApplicationLibCode/Commands/Sumo/RicCreateSumoEnsembleFeature.cpp new file mode 100644 index 0000000000..957cda5e7e --- /dev/null +++ b/ApplicationLibCode/Commands/Sumo/RicCreateSumoEnsembleFeature.cpp @@ -0,0 +1,62 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicCreateSumoEnsembleFeature.h" + +#include "RiaSummaryTools.h" + +#include "PlotBuilderCommands/RicSummaryPlotBuilder.h" + +#include "RimSummaryCaseMainCollection.h" +#include "Sumo/RimSummaryEnsembleSumo.h" +#include "Sumo/RimSummarySumoDataSource.h" + +#include "cafSelectionManagerTools.h" + +#include + +CAF_CMD_SOURCE_INIT( RicCreateSumoEnsembleFeature, "RicCreateSumoEnsembleFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateSumoEnsembleFeature::onActionTriggered( bool isChecked ) +{ + auto dataSources = caf::selectedObjectsByType(); + for ( auto dataSource : dataSources ) + { + RimSummaryEnsembleSumo* ensemble = new RimSummaryEnsembleSumo(); + ensemble->setSumoDataSource( dataSource ); + ensemble->updateName(); + RiaSummaryTools::summaryCaseMainCollection()->addEnsemble( ensemble ); + ensemble->loadDataAndUpdate(); + + RicSummaryPlotBuilder::createAndAppendDefaultSummaryMultiPlot( {}, { ensemble } ); + } + + RiaSummaryTools::summaryCaseMainCollection()->updateAllRequiredEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateSumoEnsembleFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setText( "Create Sumo Ensemble" ); + actionToSetup->setIcon( QIcon( ":/SummaryEnsemble.svg" ) ); +} diff --git a/ApplicationLibCode/Commands/Sumo/RicCreateSumoEnsembleFeature.h b/ApplicationLibCode/Commands/Sumo/RicCreateSumoEnsembleFeature.h new file mode 100644 index 0000000000..e9b7674926 --- /dev/null +++ b/ApplicationLibCode/Commands/Sumo/RicCreateSumoEnsembleFeature.h @@ -0,0 +1,33 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicCreateSumoEnsembleFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationLibCode/ProjectDataModel/Cloud/CMakeLists_files.cmake b/ApplicationLibCode/ProjectDataModel/Cloud/CMakeLists_files.cmake new file mode 100644 index 0000000000..382da6d6a8 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Cloud/CMakeLists_files.cmake @@ -0,0 +1,11 @@ +set(SOURCE_GROUP_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/RimCloudDataSourceCollection.h +) + +set(SOURCE_GROUP_SOURCE_FILES + ${CMAKE_CURRENT_LIST_DIR}/RimCloudDataSourceCollection.cpp +) + +list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) + +list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES}) diff --git a/ApplicationLibCode/ProjectDataModel/Cloud/RimCloudDataSourceCollection.cpp b/ApplicationLibCode/ProjectDataModel/Cloud/RimCloudDataSourceCollection.cpp new file mode 100644 index 0000000000..e8adeaa172 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Cloud/RimCloudDataSourceCollection.cpp @@ -0,0 +1,233 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimCloudDataSourceCollection.h" + +#include "RiaApplication.h" + +#include "RimOilField.h" +#include "RimProject.h" +#include "Sumo/RimSummarySumoDataSource.h" + +#include "RiuPlotMainWindowTools.h" + +#include "cafPdmUiPushButtonEditor.h" +#include "cafPdmUiTreeSelectionEditor.h" + +CAF_PDM_SOURCE_INIT( RimCloudDataSourceCollection, "RimCloudDataSourceCollection" ); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCloudDataSourceCollection::RimCloudDataSourceCollection() +{ + CAF_PDM_InitObject( "Cloud Data", ":/cloud-and-server.svg" ); + + CAF_PDM_InitFieldNoDefault( &m_sumoFieldName, "SumoFieldId", "Field Id" ); + CAF_PDM_InitFieldNoDefault( &m_sumoCaseId, "SumoCaseId", "Case Id" ); + m_sumoCaseId.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); + + CAF_PDM_InitFieldNoDefault( &m_sumoEnsembleNames, "SumoEnsembleNames", "Ensembles" ); + m_sumoEnsembleNames.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); + + CAF_PDM_InitFieldNoDefault( &m_addEnsembles, "AddEnsembles", "" ); + caf::PdmUiPushButtonEditor::configureEditorLabelLeft( &m_addEnsembles ); + + CAF_PDM_InitFieldNoDefault( &m_sumoDataSources, "SumoDataSources", "Sumo Data Sources" ); + + m_sumoConnector = RiaApplication::instance()->makeSumoConnector(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCloudDataSourceCollection* RimCloudDataSourceCollection::instance() +{ + return RimProject::current()->activeOilField()->cloudDataCollection(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimCloudDataSourceCollection::sumoDataSources() const +{ + return m_sumoDataSources.childrenByType(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCloudDataSourceCollection::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) +{ + if ( changedField == &m_sumoFieldName ) + { + m_sumoCaseId = ""; + m_sumoEnsembleNames.v().clear(); + + m_sumoConnector->requestCasesForFieldBlocking( m_sumoFieldName ); + } + else if ( changedField == &m_sumoCaseId ) + { + m_sumoEnsembleNames.v().clear(); + } + if ( changedField == &m_addEnsembles ) + { + addEnsemble(); + + m_addEnsembles = false; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimCloudDataSourceCollection::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) +{ + QList options; + if ( fieldNeedingOptions == &m_sumoFieldName ) + { + if ( m_sumoConnector->assets().empty() ) + { + m_sumoConnector->requestAssetsBlocking(); + } + + for ( const auto& asset : m_sumoConnector->assets() ) + { + if ( m_sumoFieldName().isEmpty() ) + { + m_sumoFieldName = asset.name; + } + + options.push_back( { asset.name, asset.name } ); + } + } + else if ( fieldNeedingOptions == &m_sumoCaseId && !m_sumoFieldName().isEmpty() ) + { + if ( m_sumoConnector->cases().empty() ) + { + m_sumoConnector->requestCasesForFieldBlocking( m_sumoFieldName ); + } + + for ( const auto& sumoCase : m_sumoConnector->cases() ) + { + options.push_back( { sumoCase.name, sumoCase.caseId.get() } ); + } + } + else if ( fieldNeedingOptions == &m_sumoEnsembleNames && !m_sumoCaseId().isEmpty() ) + { + if ( m_sumoConnector->ensembleNamesForCase( SumoCaseId( m_sumoCaseId ) ).empty() ) + { + m_sumoConnector->requestEnsembleByCasesIdBlocking( SumoCaseId( m_sumoCaseId ) ); + } + + for ( const auto& name : m_sumoConnector->ensembleNamesForCase( SumoCaseId( m_sumoCaseId ) ) ) + { + options.push_back( { name, name } ); + } + } + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCloudDataSourceCollection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + uiOrdering.add( &m_sumoFieldName ); + uiOrdering.add( &m_sumoCaseId ); + uiOrdering.add( &m_sumoEnsembleNames ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCloudDataSourceCollection::defineEditorAttribute( const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute ) +{ + if ( field == &m_addEnsembles ) + { + if ( auto attrib = dynamic_cast( attribute ) ) + { + attrib->m_buttonText = "Add Ensemble(s)"; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCloudDataSourceCollection::addEnsemble() +{ + RimSummarySumoDataSource* objectToSelect = nullptr; + auto sumoCaseId = SumoCaseId( m_sumoCaseId ); + + for ( const auto& ensembleName : m_sumoEnsembleNames() ) + { + bool createNewDataSource = true; + for ( const auto dataSource : sumoDataSources() ) + { + if ( dataSource->caseId() == sumoCaseId && dataSource->ensembleName() == ensembleName ) + { + createNewDataSource = false; + break; + } + } + + if ( !createNewDataSource ) + { + continue; + } + + QString caseName; + for ( const auto& sumoCase : m_sumoConnector->cases() ) + { + if ( sumoCase.caseId == sumoCaseId ) + { + caseName = sumoCase.name; + break; + } + } + + m_sumoConnector->requestRealizationIdsForEnsembleBlocking( sumoCaseId, ensembleName ); + m_sumoConnector->requestVectorNamesForEnsembleBlocking( sumoCaseId, ensembleName ); + + auto realizationIds = m_sumoConnector->realizationIds(); + auto vectorNames = m_sumoConnector->vectorNames(); + + auto dataSource = new RimSummarySumoDataSource(); + dataSource->setCaseId( sumoCaseId ); + dataSource->setCaseName( caseName ); + dataSource->setEnsembleName( ensembleName ); + dataSource->setRealizationIds( realizationIds ); + dataSource->setVectorNames( vectorNames ); + dataSource->updateName(); + + objectToSelect = dataSource; + + m_sumoDataSources.push_back( dataSource ); + } + + uiCapability()->updateAllRequiredEditors(); + + if ( objectToSelect ) + { + RiuPlotMainWindowTools::setExpanded( objectToSelect ); + RiuPlotMainWindowTools::selectAsCurrentItem( objectToSelect ); + } +} diff --git a/ApplicationLibCode/ProjectDataModel/Cloud/RimCloudDataSourceCollection.h b/ApplicationLibCode/ProjectDataModel/Cloud/RimCloudDataSourceCollection.h new file mode 100644 index 0000000000..20f699e26d --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Cloud/RimCloudDataSourceCollection.h @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include "Cloud/RiaSumoConnector.h" + +#include +#include + +class RimSummarySumoDataSource; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimCloudDataSourceCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimCloudDataSourceCollection(); + + static RimCloudDataSourceCollection* instance(); + + std::vector sumoDataSources() const; + +private: + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + + QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override; + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; + + void addEnsemble(); + +private: + caf::PdmField m_sumoFieldName; + caf::PdmField m_sumoCaseId; + caf::PdmField> m_sumoEnsembleNames; + + caf::PdmField m_addEnsembles; + caf::PdmChildArrayField m_sumoDataSources; + + QPointer m_sumoConnector; +}; diff --git a/ApplicationLibCode/ProjectDataModel/RimOilField.cpp b/ApplicationLibCode/ProjectDataModel/RimOilField.cpp index 58355cdd4c..97cb58c00d 100644 --- a/ApplicationLibCode/ProjectDataModel/RimOilField.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimOilField.cpp @@ -37,6 +37,7 @@ #include "RimSurfaceCollection.h" #include "RimWellPathCollection.h" +#include "Cloud/RimCloudDataSourceCollection.h" #include "Polygons/RimPolygonCollection.h" #include "VerticalFlowPerformance/RimVfpDataCollection.h" @@ -97,6 +98,9 @@ RimOilField::RimOilField() CAF_PDM_InitFieldNoDefault( &vfpDataCollection, "VfpDataCollection", "VFP Data" ); vfpDataCollection = new RimVfpDataCollection(); + CAF_PDM_InitFieldNoDefault( &cloudDataCollection, "CloudDataCollection", "Cloud Data" ); + cloudDataCollection = new RimCloudDataSourceCollection(); + m_fractureTemplateCollection_OBSOLETE = new RimFractureTemplateCollection; m_fractureTemplateCollection_OBSOLETE.xmlCapability()->setIOWritable( false ); } diff --git a/ApplicationLibCode/ProjectDataModel/RimOilField.h b/ApplicationLibCode/ProjectDataModel/RimOilField.h index 2974ea42c7..42cac85898 100644 --- a/ApplicationLibCode/ProjectDataModel/RimOilField.h +++ b/ApplicationLibCode/ProjectDataModel/RimOilField.h @@ -45,6 +45,7 @@ class RimPolygonCollection; class RimEclipseViewCollection; class RimEclipseContourMapViewCollection; class RimVfpDataCollection; +class RimCloudDataSourceCollection; //================================================================================================== /// @@ -81,6 +82,7 @@ public: caf::PdmChildField polygonCollection; caf::PdmChildField eclipseContourMapCollection; caf::PdmChildField vfpDataCollection; + caf::PdmChildField cloudDataCollection; protected: void initAfterRead() override; diff --git a/ApplicationLibCode/ProjectDataModel/RimProject.cpp b/ApplicationLibCode/ProjectDataModel/RimProject.cpp index bac06037db..5377b8079f 100644 --- a/ApplicationLibCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimProject.cpp @@ -34,6 +34,7 @@ #include "RigEclipseCaseData.h" #include "RigGridBase.h" +#include "Cloud/RimCloudDataSourceCollection.h" #include "PlotTemplates/RimPlotTemplateFolderItem.h" #include "Polygons/RimPolygonCollection.h" #include "RimAdvancedSnapshotExportDefinition.h" @@ -1364,6 +1365,11 @@ void RimProject::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, Q { if ( m_mainPlotCollection ) { + if ( activeOilField()->cloudDataCollection() ) + { + uiTreeOrdering.add( activeOilField()->cloudDataCollection() ); + } + if ( m_mainPlotCollection->summaryMultiPlotCollection() ) { uiTreeOrdering.add( m_mainPlotCollection->summaryMultiPlotCollection() ); diff --git a/ApplicationLibCode/ProjectDataModel/RimSummaryCalculationCollection.cpp b/ApplicationLibCode/ProjectDataModel/RimSummaryCalculationCollection.cpp index 9e97481b73..7a6f338660 100644 --- a/ApplicationLibCode/ProjectDataModel/RimSummaryCalculationCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimSummaryCalculationCollection.cpp @@ -62,7 +62,7 @@ void RimSummaryCalculationCollection::updateDataDependingOnCalculations() { reader->buildMetaData(); - if ( summaryCase->showRealizationDataSources() ) + if ( summaryCase->showVectorItemsInProjectTree() ) { summaryCase->onCalculationUpdated(); } diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimDerivedEnsembleCaseCollection.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimDerivedEnsembleCaseCollection.cpp index 3d09020a86..f882e17a23 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimDerivedEnsembleCaseCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimDerivedEnsembleCaseCollection.cpp @@ -429,6 +429,10 @@ RimDerivedSummaryCase* RimDerivedEnsembleCaseCollection::firstCaseNotInUse() // If no active case was found, add a new case to the collection auto newCase = new RimDerivedSummaryCase(); + + // Show realization data source for the first case. If we create for all, the performance will be bad + newCase->setShowVectorItemsInProjectTree( m_cases.empty() ); + m_cases.push_back( newCase ); return newCase; } diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.cpp index c4a9deab55..006ecc9548 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.cpp @@ -104,7 +104,7 @@ bool RimSummaryCase::isObservedData() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimSummaryCase::showRealizationDataSources() const +bool RimSummaryCase::showVectorItemsInProjectTree() const { return m_showSubNodesInTree(); } @@ -112,7 +112,7 @@ bool RimSummaryCase::showRealizationDataSources() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimSummaryCase::setShowRealizationDataSource( bool enable ) +void RimSummaryCase::setShowVectorItemsInProjectTree( bool enable ) { m_showSubNodesInTree = enable; updateConnectedEditors(); diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.h index 7c6f36a3c3..81352cc701 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCase.h @@ -79,8 +79,8 @@ public: bool isObservedData() const; - bool showRealizationDataSources() const; - void setShowRealizationDataSource( bool enable ); + bool showVectorItemsInProjectTree() const; + void setShowVectorItemsInProjectTree( bool enable ); void setCaseRealizationParameters( const std::shared_ptr& crlParameters ); std::shared_ptr caseRealizationParameters() const; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp index e53fa8085f..0124a43da3 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp @@ -121,7 +121,7 @@ void RimSummaryCaseCollection::addCase( RimSummaryCase* summaryCase ) { summaryCase->nameChanged.connect( this, &RimSummaryCaseCollection::onCaseNameChanged ); - summaryCase->setShowRealizationDataSource( m_cases.empty() ); + summaryCase->setShowVectorItemsInProjectTree( m_cases.empty() ); m_cases.push_back( summaryCase ); m_cachedSortedEnsembleParameters.clear(); diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h index 02ce930e10..d52a28c69f 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h @@ -115,7 +115,6 @@ private: void onCaseNameChanged( const SignalEmitter* emitter ); - void buildMetaData(); void buildChildNodes(); void clearChildNodes(); @@ -124,6 +123,8 @@ protected: void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override; + void buildMetaData(); + caf::PdmChildArrayField m_cases; private: diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp index d38616948d..3d4588cd4f 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp @@ -258,6 +258,24 @@ void RimSummaryCaseMainCollection::removeCaseCollection( RimSummaryCaseCollectio dataSourceHasChanged.send(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryCaseMainCollection::addEnsemble( RimSummaryCaseCollection* ensemble ) +{ + CVF_ASSERT( ensemble ); + + m_caseCollections.push_back( ensemble ); + + if ( ensemble->ensembleId() == -1 ) + { + RimProject* project = RimProject::current(); + project->assignIdToEnsemble( ensemble ); + } + + dataSourceHasChanged.send(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.h index 2d1e6fe22b..a02f3e666e 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.h @@ -66,6 +66,7 @@ public: bool isEnsemble, std::function allocator = defaultAllocator ); void removeCaseCollection( RimSummaryCaseCollection* caseCollection ); + void addEnsemble( RimSummaryCaseCollection* ensemble ); void loadAllSummaryCaseData(); diff --git a/ApplicationLibCode/ProjectDataModel/Summary/Sumo/CMakeLists_files.cmake b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/CMakeLists_files.cmake new file mode 100644 index 0000000000..16d2577a8f --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/CMakeLists_files.cmake @@ -0,0 +1,14 @@ +set(SOURCE_GROUP_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/RimSummaryEnsembleSumo.h + ${CMAKE_CURRENT_LIST_DIR}/RimSummaryCaseSumo.h + ${CMAKE_CURRENT_LIST_DIR}/RimSummarySumoDataSource.h +) + +set(SOURCE_GROUP_SOURCE_FILES + ${CMAKE_CURRENT_LIST_DIR}/RimSummaryEnsembleSumo.cpp + ${CMAKE_CURRENT_LIST_DIR}/RimSummaryCaseSumo.cpp + ${CMAKE_CURRENT_LIST_DIR}/RimSummarySumoDataSource.cpp +) + +list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) +list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES}) diff --git a/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryCaseSumo.cpp b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryCaseSumo.cpp new file mode 100644 index 0000000000..9676dbacb0 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryCaseSumo.cpp @@ -0,0 +1,179 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimSummaryCaseSumo.h" + +#include "RimSummaryEnsembleSumo.h" + +#include "cafPdmObjectScriptingCapability.h" + +CAF_PDM_SOURCE_INIT( RimSummaryCaseSumo, "RimSummaryCaseSumo" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryCaseSumo::RimSummaryCaseSumo() + : m_realizationNumber( -1 ) +{ + CAF_PDM_InitScriptableObject( "Sumo Realization", ":/SummaryCase.svg" ); + + m_ensemble = nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryCaseSumo::createSummaryReaderInterface() +{ + // Nothing to do here +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RifSummaryReaderInterface* RimSummaryCaseSumo::summaryReader() +{ + return this; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSummaryCaseSumo::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const +{ + return m_timeSteps; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair> RimSummaryCaseSumo::values( const RifEclipseSummaryAddress& resultAddress ) const +{ + auto it = m_values.find( resultAddress ); + if ( it == m_values.end() && m_ensemble ) + { + // We can be asked for a result that is not available in the cache. In this case we need to load the data from the ensemble. + + m_ensemble->loadSummaryData( resultAddress ); + it = m_values.find( resultAddress ); + } + + if ( it != m_values.end() ) + { + std::vector doubleValues; + doubleValues.reserve( it->second.size() ); + for ( auto value : it->second ) + { + doubleValues.push_back( value ); + } + return { true, doubleValues }; + } + + return {}; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::string RimSummaryCaseSumo::unitName( const RifEclipseSummaryAddress& resultAddress ) const +{ + if ( m_ensemble ) return m_ensemble->unitName( resultAddress ); + + return {}; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaDefines::EclipseUnitSystem RimSummaryCaseSumo::unitSystem() const +{ + if ( m_ensemble ) return m_ensemble->unitSystem(); + + return RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryCaseSumo::setEnsemble( RimSummaryEnsembleSumo* ensemble ) +{ + m_ensemble = ensemble; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryCaseSumo::setValues( const std::vector& timeSteps, + const RifEclipseSummaryAddress& resultAddress, + const std::vector& values ) +{ + m_timeSteps = timeSteps; + m_values[resultAddress] = values; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int32_t RimSummaryCaseSumo::realizationNumber() const +{ + return m_realizationNumber; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryCaseSumo::setRealizationNumber( int32_t realizationNumber ) +{ + m_realizationNumber = realizationNumber; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummaryCaseSumo::realizationName() const +{ + return m_realizationName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryCaseSumo::setRealizationName( const QString& realizationName ) +{ + m_realizationName = realizationName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummaryCaseSumo::caseName() const +{ + return realizationName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryCaseSumo::buildMetaData() +{ + if ( m_ensemble ) + { + auto addresses = m_ensemble->allResultAddresses(); + m_allResultAddresses = addresses; + } +} diff --git a/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryCaseSumo.h b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryCaseSumo.h new file mode 100644 index 0000000000..54ffb0f3fe --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryCaseSumo.h @@ -0,0 +1,67 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RifSummaryReaderInterface.h" + +#include "RimSummaryCase.h" + +#include "cafPdmPointer.h" + +class RimSummaryEnsembleSumo; + +//================================================================================================== +// +// +// +//================================================================================================== +class RimSummaryCaseSumo : public RimSummaryCase, public RifSummaryReaderInterface +{ + CAF_PDM_HEADER_INIT; + +public: + RimSummaryCaseSumo(); + + void setEnsemble( RimSummaryEnsembleSumo* ensemble ); + void setValues( const std::vector& timeSteps, const RifEclipseSummaryAddress& resultAddress, const std::vector& values ); + + int32_t realizationNumber() const; + void setRealizationNumber( int32_t realizationNumber ); + + QString realizationName() const; + void setRealizationName( const QString& realizationName ); + + void createSummaryReaderInterface() override; + RifSummaryReaderInterface* summaryReader() override; + + std::vector timeSteps( const RifEclipseSummaryAddress& resultAddress ) const override; + std::pair> values( const RifEclipseSummaryAddress& resultAddress ) const override; + std::string unitName( const RifEclipseSummaryAddress& resultAddress ) const override; + RiaDefines::EclipseUnitSystem unitSystem() const override; + +protected: + QString caseName() const override; + void buildMetaData() override; + +private: + caf::PdmPointer m_ensemble; + QString m_realizationName; + int32_t m_realizationNumber; + std::vector m_timeSteps; + std::map> m_values; +}; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryEnsembleSumo.cpp b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryEnsembleSumo.cpp new file mode 100644 index 0000000000..7f5d8d30d1 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryEnsembleSumo.cpp @@ -0,0 +1,421 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimSummaryEnsembleSumo.h" + +#include "RiaApplication.h" +#include "RiaLogging.h" +#include "RiaSummaryDefines.h" +#include "RiaSummaryTools.h" +#include "RiaTimeTTools.h" + +#include "RifArrowTools.h" +#include "RifByteArrayArrowRandomAccessFile.h" +#include "RifEclipseSummaryAddress.h" + +#include "Cloud/RimCloudDataSourceCollection.h" +#include "RimSummaryCaseSumo.h" +#include "RimSummarySumoDataSource.h" + +CAF_PDM_SOURCE_INIT( RimSummaryEnsembleSumo, "RimSummaryEnsembleSumo" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryEnsembleSumo::RimSummaryEnsembleSumo() +{ + CAF_PDM_InitObject( "Sumo Ensemble", ":/SummaryCase.svg", "", "The Base Class for all Summary Cases" ); + + CAF_PDM_InitFieldNoDefault( &m_sumoDataSource, "SumoDataSource", "Sumo Data Source" ); + + // Disable IO for cases, as the reconstruction is done by loading data from Sumo + // Will also reduce the amount of data stored in the project file + m_cases.xmlCapability()->disableIO(); + + setAsEnsemble( true ); + + m_sumoConnector = RiaApplication::instance()->makeSumoConnector(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryEnsembleSumo::setSumoDataSource( RimSummarySumoDataSource* sumoDataSource ) +{ + m_sumoDataSource = sumoDataSource; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryEnsembleSumo::updateName() +{ + if ( m_sumoDataSource() ) + { + setName( m_sumoDataSource()->name() ); + } + else + { + setName( "No Sumo Data Source" ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::string RimSummaryEnsembleSumo::unitName( const RifEclipseSummaryAddress& resultAddress ) +{ + // TODO: Not implemented yet. Need to get the unit name from the Sumo data source + return {}; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaDefines::EclipseUnitSystem RimSummaryEnsembleSumo::unitSystem() const +{ + // TODO: Not implemented yet. Need to get the unit name from the Sumo data source + return RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RimSummaryEnsembleSumo::allResultAddresses() const +{ + return m_resultAddresses; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryEnsembleSumo::loadSummaryData( const RifEclipseSummaryAddress& resultAddress ) +{ + if ( resultAddress.category() == SummaryCategory::SUMMARY_ENSEMBLE_STATISTICS ) return; + + if ( !m_sumoDataSource() ) return; + + auto resultText = QString::fromStdString( resultAddress.toEclipseTextAddress() ); + + auto sumoCaseId = m_sumoDataSource->caseId(); + auto sumoEnsembleName = m_sumoDataSource->ensembleName(); + + auto key = ParquetKey{ sumoCaseId, sumoEnsembleName, resultText }; + + if ( m_parquetTable.find( key ) == m_parquetTable.end() ) + { + auto contents = loadParquetData( key ); + + arrow::MemoryPool* pool = arrow::default_memory_pool(); + + std::shared_ptr input = std::make_shared( contents ); + + std::shared_ptr table; + std::unique_ptr arrow_reader; + if ( parquet::arrow::OpenFile( input, pool, &arrow_reader ).ok() ) + { + if ( arrow_reader->ReadTable( &table ).ok() ) + { + RiaLogging::info( "Parquet: Read table" ); + } + else + { + RiaLogging::warning( "Parquet: Error detected during parsing of table" ); + } + } + else + { + RiaLogging::warning( "Parquet: Not able to open data stream" ); + } + + m_parquetTable[key] = table; + + distributeDataToRealizations( resultAddress, table ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QByteArray RimSummaryEnsembleSumo::loadParquetData( const ParquetKey& parquetKey ) +{ + if ( !m_sumoConnector ) return {}; + + return m_sumoConnector->requestParquetDataBlocking( SumoCaseId( parquetKey.caseId ), parquetKey.ensembleId, parquetKey.vectorName ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryEnsembleSumo::distributeDataToRealizations( const RifEclipseSummaryAddress& resultAddress, std::shared_ptr table ) +{ + if ( !table ) + { + RiaLogging::warning( "Failed to load table" ); + return; + } + + { + // print header information + QString txt = "Column Names: "; + + for ( std::string columnName : table->ColumnNames() ) + { + txt += QString::fromStdString( columnName ) + " "; + } + + RiaLogging::info( txt ); + } + + std::vector timeSteps; + std::vector realizations; + std::vector values; + + { + const std::string columnName = "DATE"; + std::shared_ptr column = table->GetColumnByName( columnName ); + if ( column && column->type()->id() == arrow::Type::TIMESTAMP ) + { + auto timeColumn = RifArrowTools::chunkedArrayToVector( column ); + timeSteps = std::vector( timeColumn.size() ); + + for ( size_t i = 0; i < timeColumn.size(); ++i ) + { + timeSteps[i] = RiaTimeTTools::fromDouble( timeColumn[i] ); + } + } + else + { + RiaLogging::warning( "Failed to find DATE column" ); + return; + } + } + + { + const std::string columnName = "REAL"; + std::shared_ptr column = table->GetColumnByName( columnName ); + if ( column && column->type()->id() == arrow::Type::INT16 ) + { + realizations = RifArrowTools::chunkedArrayToVector( column ); + } + else + { + RiaLogging::warning( "Failed to find realization column" ); + return; + } + } + + { + const std::string columnName = resultAddress.toEclipseTextAddress(); + std::shared_ptr column = table->GetColumnByName( columnName ); + if ( column && column->type()->id() == arrow::Type::FLOAT ) + { + values = RifArrowTools::chunkedArrayToVector( column ); + } + else + { + RiaLogging::warning( "Failed to find values column" ); + return; + } + } + + // find unique realizations + std::set uniqueRealizations; + for ( auto realizationNumber : realizations ) + { + uniqueRealizations.insert( realizationNumber ); + } + + // find start and end index for a given realization number + std::map> realizationIndex; + for ( size_t i = 0; i < realizations.size(); ++i ) + { + auto realizationNumber = realizations[i]; + uniqueRealizations.insert( realizationNumber ); + + if ( realizationIndex.find( realizationNumber ) == realizationIndex.end() ) + { + realizationIndex[realizationNumber] = { i, i }; + } + else + { + realizationIndex[realizationNumber].second = i; + } + } + + auto findSummaryCase = [this]( int16_t realizationNumber ) -> RimSummaryCaseSumo* + { + for ( auto sumCase : allSummaryCases() ) + { + auto sumCaseSumo = dynamic_cast( sumCase ); + if ( sumCaseSumo->realizationNumber() == realizationNumber ) return sumCaseSumo; + } + + return nullptr; + }; + + for ( auto realizationNumber : uniqueRealizations ) + { + auto summaryCase = findSummaryCase( realizationNumber ); + if ( !summaryCase ) continue; + + auto start = realizationIndex[realizationNumber].first; + auto end = realizationIndex[realizationNumber].second; + + std::vector realizationTimeSteps( timeSteps.begin() + start, timeSteps.begin() + end ); + std::vector realizationValues( values.begin() + start, values.begin() + end ); + + summaryCase->setValues( realizationTimeSteps, resultAddress, realizationValues ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryEnsembleSumo::buildMetaData() +{ + for ( auto summaryCase : allSummaryCases() ) + { + summaryCase->summaryReader()->buildMetaData(); + } + + RimSummaryCaseCollection::buildMetaData(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryEnsembleSumo::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + uiOrdering.add( &m_sumoDataSource ); + + auto group = uiOrdering.addNewGroup( "General" ); + RimSummaryCaseCollection::defineUiOrdering( uiConfigName, *group ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimSummaryEnsembleSumo::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) +{ + QList options; + if ( fieldNeedingOptions == &m_sumoDataSource ) + { + for ( const auto& sumoDataSource : RimCloudDataSourceCollection::instance()->sumoDataSources() ) + { + options.push_back( { sumoDataSource->name(), sumoDataSource } ); + } + } + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryEnsembleSumo::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) +{ + if ( changedField == &m_sumoDataSource ) + { + clearCachedData(); + updateResultAddresses(); + updateName(); + buildMetaData(); + + updateConnectedEditors(); + + RiaSummaryTools::reloadSummaryEnsemble( this ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryEnsembleSumo::updateResultAddresses() +{ + m_resultAddresses.clear(); + + if ( !m_sumoDataSource() ) return; + + auto vectorNames = m_sumoDataSource->vectorNames(); + for ( auto vectorName : vectorNames ) + { + auto adr = RifEclipseSummaryAddress::fromEclipseTextAddress( vectorName.toStdString() ); + m_resultAddresses.insert( adr ); + } + + auto caseName = m_sumoDataSource->caseId().get(); + auto ensName = m_sumoDataSource->ensembleName(); + + RiaLogging::info( QString( "Case: %1, ens: %2, vector count: %3" ).arg( caseName ).arg( ensName ).arg( m_resultAddresses.size() ) ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryEnsembleSumo::clearCachedData() +{ + m_resultAddresses.clear(); + m_parquetTable.clear(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryEnsembleSumo::onLoadDataAndUpdate() +{ + if ( m_sumoDataSource() ) + { + auto realizationIds = m_sumoDataSource->realizationIds(); + if ( realizationIds.size() != m_cases.size() ) + { + m_cases.deleteChildren(); + + for ( auto realId : realizationIds ) + { + auto realization = new RimSummaryCaseSumo(); + realization->setEnsemble( this ); + realization->setRealizationName( QString( "real-%1" ).arg( realId ) ); + realization->setRealizationNumber( realId.toInt() ); + realization->updateAutoShortName(); + + realization->setShowVectorItemsInProjectTree( m_cases.empty() ); + + // Create realization parameters, required to make derived ensemble cases work + // See RimDerivedEnsembleCaseCollection::createDerivedEnsembleCases() + auto parameters = std::shared_ptr( new RigCaseRealizationParameters() ); + + int realizationNumber = realId.toInt(); + parameters->setRealizationNumber( realizationNumber ); + parameters->addParameter( RiaDefines::summaryRealizationNumber(), realizationNumber ); + + realization->setCaseRealizationParameters( parameters ); + + m_cases.push_back( realization ); + } + } + } + + updateName(); + updateResultAddresses(); + + buildMetaData(); + + // call the base class method after data has been loaded + RimSummaryCaseCollection::onLoadDataAndUpdate(); +} diff --git a/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryEnsembleSumo.h b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryEnsembleSumo.h new file mode 100644 index 0000000000..ee81686d0a --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummaryEnsembleSumo.h @@ -0,0 +1,92 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RimSummaryCaseCollection.h" + +#include "Cloud/RiaSumoConnector.h" + +#include "cafPdmPtrField.h" + +#include + +class RimSummarySumoDataSource; + +//================================================================================================== +// +// +// +//================================================================================================== + +struct ParquetKey +{ + SumoCaseId caseId; + QString ensembleId; + QString vectorName; + + auto operator<=>( const ParquetKey& other ) const + { + return std::tie( caseId, ensembleId, vectorName ) <=> std::tie( other.caseId, other.ensembleId, other.vectorName ); + } +}; + +namespace arrow +{ +class Table; +} + +class RimSummaryEnsembleSumo : public RimSummaryCaseCollection +{ + CAF_PDM_HEADER_INIT; + +public: + RimSummaryEnsembleSumo(); + + void setSumoDataSource( RimSummarySumoDataSource* sumoDataSource ); + void updateName(); + + void loadSummaryData( const RifEclipseSummaryAddress& resultAddress ); + std::string unitName( const RifEclipseSummaryAddress& resultAddress ); + RiaDefines::EclipseUnitSystem unitSystem() const; + std::set allResultAddresses() const; + +protected: + void onLoadDataAndUpdate() override; + +private: + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override; + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + + void updateResultAddresses(); + void clearCachedData(); + + QByteArray loadParquetData( const ParquetKey& parquetKey ); + + void distributeDataToRealizations( const RifEclipseSummaryAddress& resultAddress, std::shared_ptr table ); + void buildMetaData(); + +private: + caf::PdmPtrField m_sumoDataSource; + + QPointer m_sumoConnector; + + std::set m_resultAddresses; + std::map> m_parquetTable; +}; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummarySumoDataSource.cpp b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummarySumoDataSource.cpp new file mode 100644 index 0000000000..7a5e915f02 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummarySumoDataSource.cpp @@ -0,0 +1,207 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimSummarySumoDataSource.h" + +#include "RiaStdStringTools.h" + +#include "cafCmdFeatureMenuBuilder.h" +#include "cafPdmUiTreeSelectionEditor.h" + +CAF_PDM_SOURCE_INIT( RimSummarySumoDataSource, "RimSummarySumoDataSource" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummarySumoDataSource::RimSummarySumoDataSource() +{ + CAF_PDM_InitObject( "Sumo Data Source", ":/SummaryCase.svg" ); + + CAF_PDM_InitFieldNoDefault( &m_caseId, "CaseId", "Case Id" ); + CAF_PDM_InitFieldNoDefault( &m_caseName, "CaseName", "Case Name" ); + CAF_PDM_InitFieldNoDefault( &m_ensembleName, "EnsembleName", "Ensemble Name" ); + CAF_PDM_InitFieldNoDefault( &m_customName, "CustomName", "Custom Name" ); + + CAF_PDM_InitFieldNoDefault( &m_realizationIds, "RealizationIds", "Realizations Ids" ); + m_realizationIds.uiCapability()->setUiHidden( true ); + + CAF_PDM_InitFieldNoDefault( &m_realizationInfo, "NameProxy", "Realization Info" ); + m_realizationInfo.registerGetMethod( this, &RimSummarySumoDataSource::realizationInfoText ); + + CAF_PDM_InitFieldNoDefault( &m_vectorNames, "VectorNames", "Vector Names" ); + m_vectorNames.uiCapability()->setUiReadOnly( true ); + + setDeletable( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +SumoCaseId RimSummarySumoDataSource::caseId() const +{ + return SumoCaseId( m_caseId() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummarySumoDataSource::setCaseId( const SumoCaseId& caseId ) +{ + m_caseId = caseId.get(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummarySumoDataSource::caseName() const +{ + return m_caseName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummarySumoDataSource::setCaseName( const QString& caseName ) +{ + m_caseName = caseName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummarySumoDataSource::ensembleName() const +{ + return m_ensembleName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummarySumoDataSource::setEnsembleName( const QString& ensembleName ) +{ + m_ensembleName = ensembleName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSummarySumoDataSource::realizationIds() const +{ + return m_realizationIds(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummarySumoDataSource::setRealizationIds( const std::vector& realizationIds ) +{ + m_realizationIds = realizationIds; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSummarySumoDataSource::vectorNames() const +{ + return m_vectorNames(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummarySumoDataSource::setVectorNames( const std::vector& vectorNames ) +{ + m_vectorNames = vectorNames; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummarySumoDataSource::updateName() +{ + if ( !m_customName().isEmpty() ) + { + setName( m_customName() ); + return; + } + + auto name = QString( "%1 (%2)" ).arg( ensembleName(), caseName() ); + + setName( name ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummarySumoDataSource::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const +{ + menuBuilder.addCmdFeature( "RicCreateSumoEnsembleFeature" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummarySumoDataSource::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) +{ + if ( field == &m_vectorNames ) + { + if ( auto attr = dynamic_cast( attribute ) ) + { + attr->showCheckBoxes = false; + attr->showContextMenu = false; + attr->showToggleAllCheckbox = false; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummarySumoDataSource::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + auto group = uiOrdering.addNewGroup( "General" ); + group->add( nameField() ); + group->add( &m_caseId ); + group->add( &m_caseName ); + group->add( &m_ensembleName ); + group->add( &m_customName ); + + auto summaryInfo = uiOrdering.addNewGroup( "Info" ); + summaryInfo->add( &m_realizationInfo ); + summaryInfo->add( &m_vectorNames ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummarySumoDataSource::realizationInfoText() const +{ + std::vector intValues; + for ( const auto& realizationId : realizationIds() ) + { + bool ok = false; + int value = realizationId.toInt( &ok ); + if ( ok ) + { + intValues.push_back( value ); + } + } + + auto rangeString = RiaStdStringTools::formatRangeSelection( intValues ); + return QString::fromStdString( rangeString ); +} diff --git a/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummarySumoDataSource.h b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummarySumoDataSource.h new file mode 100644 index 0000000000..948c7cc5ac --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/Sumo/RimSummarySumoDataSource.h @@ -0,0 +1,73 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RimNamedObject.h" + +#include "Cloud/RiaSumoConnector.h" + +#include "cafPdmProxyValueField.h" + +//================================================================================================== +// +// +// +//================================================================================================== + +class RimSummarySumoDataSource : public RimNamedObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimSummarySumoDataSource(); + + SumoCaseId caseId() const; + void setCaseId( const SumoCaseId& caseId ); + + QString caseName() const; + void setCaseName( const QString& caseName ); + + QString ensembleName() const; + void setEnsembleName( const QString& ensembleName ); + + std::vector realizationIds() const; + void setRealizationIds( const std::vector& realizationIds ); + + std::vector vectorNames() const; + void setVectorNames( const std::vector& vectorNames ); + + void updateName(); + +private: + void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override; + void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + + QString realizationInfoText() const; + +private: + caf::PdmField m_caseId; + caf::PdmField m_caseName; + caf::PdmField m_ensembleName; + caf::PdmField m_customName; + + caf::PdmProxyValueField m_realizationInfo; + caf::PdmField> m_realizationIds; + + caf::PdmField> m_vectorNames; +};