From 36e01523cb1319464518bab5450dd1b00d3df60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Herje?= <82032112+jorgenherje@users.noreply.github.com> Date: Thu, 23 Mar 2023 14:10:30 +0100 Subject: [PATCH] Summary table (#9997) Summary Table for showing summary vectors in table format - Resampling on date resolution - Active for group, region and well - Right click menu option from Summary case tree --- .../Application/Tools/RiaSummaryTools.cpp | 34 +- .../Application/Tools/RiaSummaryTools.h | 7 +- .../CMakeLists_files.cmake | 4 + .../RicDuplicateSummaryTableFeature.cpp | 91 +++ .../RicDuplicateSummaryTableFeature.h | 39 ++ .../RicNewSummaryTableFeature.cpp | 116 ++++ .../RicNewSummaryTableFeature.h | 43 ++ .../RimContextCommandBuilder.cpp | 12 + .../RimMainPlotCollection.cpp | 14 + .../ProjectDataModel/RimMainPlotCollection.h | 3 + .../ProjectDataModel/RimProject.cpp | 6 + .../Summary/CMakeLists_files.cmake | 4 + .../Summary/RimSummaryTable.cpp | 652 ++++++++++++++++++ .../Summary/RimSummaryTable.h | 120 ++++ .../Summary/RimSummaryTableCollection.cpp | 140 ++++ .../Summary/RimSummaryTableCollection.h | 58 ++ .../UserInterface/RiuMatrixPlotWidget.cpp | 10 + .../UserInterface/RiuMatrixPlotWidget.h | 3 + 18 files changed, 1354 insertions(+), 2 deletions(-) create mode 100644 ApplicationLibCode/Commands/SummaryPlotCommands/RicDuplicateSummaryTableFeature.cpp create mode 100644 ApplicationLibCode/Commands/SummaryPlotCommands/RicDuplicateSummaryTableFeature.h create mode 100644 ApplicationLibCode/Commands/SummaryPlotCommands/RicNewSummaryTableFeature.cpp create mode 100644 ApplicationLibCode/Commands/SummaryPlotCommands/RicNewSummaryTableFeature.h create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.cpp create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.h create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTableCollection.cpp create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTableCollection.h diff --git a/ApplicationLibCode/Application/Tools/RiaSummaryTools.cpp b/ApplicationLibCode/Application/Tools/RiaSummaryTools.cpp index b3a13f49bc..8d8eaadebf 100644 --- a/ApplicationLibCode/Application/Tools/RiaSummaryTools.cpp +++ b/ApplicationLibCode/Application/Tools/RiaSummaryTools.cpp @@ -40,6 +40,8 @@ #include "RimSummaryMultiPlot.h" #include "RimSummaryMultiPlotCollection.h" #include "RimSummaryPlot.h" +#include "RimSummaryTable.h" +#include "RimSummaryTableCollection.h" #include "cafPdmObject.h" @@ -203,6 +205,36 @@ bool RiaSummaryTools::isSummaryCrossPlot( const RimSummaryPlot* plot ) return dynamic_cast( plot ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryTable* RiaSummaryTools::parentSummaryTable( caf::PdmObject* object ) +{ + RimSummaryTable* summaryTable = nullptr; + + if ( object ) + { + object->firstAncestorOrThisOfType( summaryTable ); + } + + return summaryTable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryTableCollection* RiaSummaryTools::parentSummaryTableCollection( caf::PdmObject* object ) +{ + RimSummaryTableCollection* summaryTableColl = nullptr; + + if ( object ) + { + object->firstAncestorOrThisOfType( summaryTableColl ); + } + + return summaryTableColl; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -260,7 +292,7 @@ void RiaSummaryTools::getSummaryCasesAndAddressesForCalculation( int //-------------------------------------------------------------------------------------------------- std::pair, std::vector> RiaSummaryTools::resampledValuesForPeriod( const RifEclipseSummaryAddress& address, const std::vector& timeSteps, - std::vector& values, + const std::vector& values, RiaDefines::DateTimePeriod period ) { RiaTimeHistoryCurveResampler resampler; diff --git a/ApplicationLibCode/Application/Tools/RiaSummaryTools.h b/ApplicationLibCode/Application/Tools/RiaSummaryTools.h index 05aecd0164..ebb46308a9 100644 --- a/ApplicationLibCode/Application/Tools/RiaSummaryTools.h +++ b/ApplicationLibCode/Application/Tools/RiaSummaryTools.h @@ -33,6 +33,8 @@ class RimSummaryCrossPlotCollection; class RimSummaryCaseMainCollection; class RimSummaryCase; class RimSummaryCaseCollection; +class RimSummaryTable; +class RimSummaryTableCollection; class RimObservedDataCollection; class RifEclipseSummaryAddress; @@ -68,6 +70,9 @@ public: static RimSummaryCrossPlotCollection* parentCrossPlotCollection( caf::PdmObject* object ); static bool isSummaryCrossPlot( const RimSummaryPlot* plot ); + static RimSummaryTable* parentSummaryTable( caf::PdmObject* object ); + static RimSummaryTableCollection* parentSummaryTableCollection( caf::PdmObject* object ); + static bool hasAccumulatedData( const RifEclipseSummaryAddress& address ); static void getSummaryCasesAndAddressesForCalculation( int id, std::vector& cases, @@ -75,7 +80,7 @@ public: static std::pair, std::vector> resampledValuesForPeriod( const RifEclipseSummaryAddress& address, const std::vector& timeSteps, - std::vector& values, + const std::vector& values, RiaDefines::DateTimePeriod period ); static RimSummaryCase* summaryCaseById( int caseId ); diff --git a/ApplicationLibCode/Commands/SummaryPlotCommands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/SummaryPlotCommands/CMakeLists_files.cmake index 5688de25df..706b8a9f55 100644 --- a/ApplicationLibCode/Commands/SummaryPlotCommands/CMakeLists_files.cmake +++ b/ApplicationLibCode/Commands/SummaryPlotCommands/CMakeLists_files.cmake @@ -49,6 +49,8 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RicToggleYAxisLinkingFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicToggleXAxisLinkingFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicOpenSummaryPlotEditorFromMdiAreaFeature.h + ${CMAKE_CURRENT_LIST_DIR}/RicNewSummaryTableFeature.h + ${CMAKE_CURRENT_LIST_DIR}/RicDuplicateSummaryTableFeature.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -102,6 +104,8 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RicToggleYAxisLinkingFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicToggleXAxisLinkingFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicOpenSummaryPlotEditorFromMdiAreaFeature.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicNewSummaryTableFeature.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicDuplicateSummaryTableFeature.cpp ) list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) diff --git a/ApplicationLibCode/Commands/SummaryPlotCommands/RicDuplicateSummaryTableFeature.cpp b/ApplicationLibCode/Commands/SummaryPlotCommands/RicDuplicateSummaryTableFeature.cpp new file mode 100644 index 0000000000..22ee51e814 --- /dev/null +++ b/ApplicationLibCode/Commands/SummaryPlotCommands/RicDuplicateSummaryTableFeature.cpp @@ -0,0 +1,91 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- 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 "RicDuplicateSummaryTableFeature.h" + +#include "RiaSummaryTools.h" + +#include "RimMainPlotCollection.h" +#include "RimSummaryTable.h" +#include "RimSummaryTableCollection.h" + +#include "RiuPlotMainWindowTools.h" + +#include "cafSelectionManagerTools.h" + +#include "cvfAssert.h" + +#include + +CAF_CMD_SOURCE_INIT( RicDuplicateSummaryTableFeature, "RicDuplicateSummaryTableFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicDuplicateSummaryTableFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicDuplicateSummaryTableFeature::onActionTriggered( bool isChecked ) +{ + caf::PdmObject* selObj = dynamic_cast( caf::SelectionManager::instance()->selectedItem() ); + RimSummaryTable* summaryTable = RiaSummaryTools::parentSummaryTable( selObj ); + if ( !summaryTable ) return; + + copyTableAndAddToCollection( summaryTable ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicDuplicateSummaryTableFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setText( "Duplicate Summary Table" ); + actionToSetup->setIcon( QIcon( ":/CorrelationMatrixPlot16x16.png" ) ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicDuplicateSummaryTableFeature::copyTableAndAddToCollection( RimSummaryTable* sourceTable ) +{ + RimSummaryTableCollection* summaryTableColl = RimMainPlotCollection::current()->summaryTableCollection(); + if ( !summaryTableColl ) return; + + RimSummaryTable* newSummaryTable = + dynamic_cast( sourceTable->xmlCapability()->copyByXmlSerialization( caf::PdmDefaultObjectFactory::instance() ) ); + CVF_ASSERT( newSummaryTable ); + + // Add table to collection + summaryTableColl->addTable( newSummaryTable ); + + // Resolve references after object has been inserted into the data model + newSummaryTable->resolveReferencesRecursively(); + newSummaryTable->initAfterReadRecursively(); + + // Update name + QString nameOfCopy = QString( "Copy of " ) + sourceTable->description(); + newSummaryTable->setDescription( nameOfCopy ); + + summaryTableColl->updateConnectedEditors(); + newSummaryTable->loadDataAndUpdate(); +} diff --git a/ApplicationLibCode/Commands/SummaryPlotCommands/RicDuplicateSummaryTableFeature.h b/ApplicationLibCode/Commands/SummaryPlotCommands/RicDuplicateSummaryTableFeature.h new file mode 100644 index 0000000000..6e1b7aa876 --- /dev/null +++ b/ApplicationLibCode/Commands/SummaryPlotCommands/RicDuplicateSummaryTableFeature.h @@ -0,0 +1,39 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- 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 RimSummaryTable; + +//================================================================================================== +/// +//================================================================================================== +class RicDuplicateSummaryTableFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +private: + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; + +private: + void copyTableAndAddToCollection( RimSummaryTable* sourceTable ); +}; diff --git a/ApplicationLibCode/Commands/SummaryPlotCommands/RicNewSummaryTableFeature.cpp b/ApplicationLibCode/Commands/SummaryPlotCommands/RicNewSummaryTableFeature.cpp new file mode 100644 index 0000000000..823189c1ca --- /dev/null +++ b/ApplicationLibCode/Commands/SummaryPlotCommands/RicNewSummaryTableFeature.cpp @@ -0,0 +1,116 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- 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 "RicNewSummaryTableFeature.h" + +#include "RiaSummaryTools.h" + +#include "RimMainPlotCollection.h" +#include "RimSummaryAddress.h" +#include "RimSummaryTable.h" +#include "RimSummaryTableCollection.h" + +#include "RiuPlotMainWindowTools.h" + +#include "cafSelectionManagerTools.h" + +#include "cvfAssert.h" + +#include + +CAF_CMD_SOURCE_INIT( RicNewSummaryTableFeature, "RicNewSummaryTableFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewSummaryTableFeature::isCommandEnabled() +{ + RimSummaryTableCollection* tableColl = nullptr; + + // Summary table collection selection + caf::PdmObject* selObj = dynamic_cast( caf::SelectionManager::instance()->selectedItem() ); + if ( selObj ) + { + tableColl = RiaSummaryTools::parentSummaryTableCollection( selObj ); + } + if ( tableColl ) return true; + + // Summary Address selection - only for enabled categories + RimSummaryAddress* selectedSummaryAddress = nullptr; + if ( selObj ) + { + selObj->firstAncestorOrThisOfType( selectedSummaryAddress ); + } + if ( selectedSummaryAddress && m_enabledCategories.contains( selectedSummaryAddress->address().category() ) ) return true; + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewSummaryTableFeature::onActionTriggered( bool isChecked ) +{ + RimSummaryTableCollection* summaryTableColl = RimMainPlotCollection::current()->summaryTableCollection(); + if ( !summaryTableColl ) return; + + caf::PdmObject* selObj = dynamic_cast( caf::SelectionManager::instance()->selectedItem() ); + RimSummaryAddress* selectedSummaryAddress = nullptr; + if ( selObj ) + { + selObj->firstAncestorOrThisOfType( selectedSummaryAddress ); + } + + RimSummaryTable* summaryTable = nullptr; + if ( selectedSummaryAddress ) + { + const auto adrObj = selectedSummaryAddress->address(); + if ( !m_enabledCategories.contains( adrObj.category() ) ) return; + + RimSummaryCase* summaryCase = RiaSummaryTools::summaryCaseById( selectedSummaryAddress->caseId() ); + if ( !summaryCase ) return; + + summaryTable = summaryTableColl->createSummaryTableFromCategoryAndVectorName( summaryCase, + adrObj.category(), + QString::fromStdString( adrObj.vectorName() ) ); + } + else + { + summaryTable = summaryTableColl->createDefaultSummaryTable(); + } + + // Add summary table to collection + if ( summaryTable ) + { + summaryTableColl->addTable( summaryTable ); + summaryTableColl->updateConnectedEditors(); + summaryTable->loadDataAndUpdate(); + + RiuPlotMainWindowTools::showPlotMainWindow(); + RiuPlotMainWindowTools::onObjectAppended( summaryTable ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewSummaryTableFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setText( "New Summary Table" ); + actionToSetup->setIcon( QIcon( ":/CorrelationMatrixPlot16x16.png" ) ); +} diff --git a/ApplicationLibCode/Commands/SummaryPlotCommands/RicNewSummaryTableFeature.h b/ApplicationLibCode/Commands/SummaryPlotCommands/RicNewSummaryTableFeature.h new file mode 100644 index 0000000000..30990d6dd0 --- /dev/null +++ b/ApplicationLibCode/Commands/SummaryPlotCommands/RicNewSummaryTableFeature.h @@ -0,0 +1,43 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- 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" + +#include "RifEclipseSummaryAddress.h" + +#include + +//================================================================================================== +/// +//================================================================================================== +class RicNewSummaryTableFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +private: + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; + +private: + const std::set m_enabledCategories = { RifEclipseSummaryAddress::SUMMARY_WELL, + RifEclipseSummaryAddress::SUMMARY_REGION, + RifEclipseSummaryAddress::SUMMARY_GROUP }; +}; diff --git a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp index b1b02c845c..8b98018ef4 100644 --- a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -134,6 +134,8 @@ #include "RimSummaryMultiPlot.h" #include "RimSummaryMultiPlotCollection.h" #include "RimSummaryPlot.h" +#include "RimSummaryTable.h" +#include "RimSummaryTableCollection.h" #include "RimSummaryTimeAxisProperties.h" #include "RimSurface.h" #include "RimSurfaceCollection.h" @@ -609,6 +611,14 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "Separator"; menuBuilder << "RicNewSummaryCrossPlotFeature"; } + else if ( dynamic_cast( firstUiItem ) ) + { + menuBuilder << "RicNewSummaryTableFeature"; + } + else if ( dynamic_cast( firstUiItem ) ) + { + menuBuilder << "RicDuplicateSummaryTableFeature"; + } else if ( dynamic_cast( firstUiItem ) && !dynamic_cast( firstUiItem ) ) { menuBuilder << "RicPasteWellLogPlotFeature"; @@ -1244,6 +1254,8 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "RicNewSummaryMultiPlotFromDataVectorFeature"; menuBuilder << "RicAppendSummaryCurvesForSummaryAddressesFeature"; menuBuilder << "RicAppendSummaryPlotsForSummaryAddressesFeature"; + menuBuilder << "Separator"; + menuBuilder << "RicNewSummaryTableFeature"; } #ifdef USE_ODB_API else if ( dynamic_cast( firstUiItem ) ) diff --git a/ApplicationLibCode/ProjectDataModel/RimMainPlotCollection.cpp b/ApplicationLibCode/ProjectDataModel/RimMainPlotCollection.cpp index ef150fb11e..7e740ca615 100644 --- a/ApplicationLibCode/ProjectDataModel/RimMainPlotCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimMainPlotCollection.cpp @@ -45,6 +45,7 @@ #include "RimSummaryMultiPlot.h" #include "RimSummaryMultiPlotCollection.h" #include "RimSummaryPlotCollection.h" +#include "RimSummaryTableCollection.h" #include "RimVfpPlotCollection.h" #include "RimViewWindow.h" #include "RimWellLogPlot.h" @@ -97,6 +98,9 @@ RimMainPlotCollection::RimMainPlotCollection() CAF_PDM_InitFieldNoDefault( &m_summaryCrossPlotCollection, "SummaryCrossPlotCollection", "Summary Cross Plots" ); m_summaryCrossPlotCollection.uiCapability()->setUiTreeHidden( true ); + CAF_PDM_InitFieldNoDefault( &m_summaryTableCollection, "SummaryTableCollection", "Summary Tables" ); + m_summaryTableCollection.uiCapability()->setUiTreeHidden( true ); + CAF_PDM_InitFieldNoDefault( &m_flowPlotCollection, "FlowPlotCollection", "Flow Diagnostics Plots" ); m_flowPlotCollection.uiCapability()->setUiTreeHidden( true ); @@ -127,6 +131,7 @@ RimMainPlotCollection::RimMainPlotCollection() m_pltPlotCollection = new RimPltPlotCollection(); m_summaryMultiPlotCollection = new RimSummaryMultiPlotCollection(); m_summaryCrossPlotCollection = new RimSummaryCrossPlotCollection(); + m_summaryTableCollection = new RimSummaryTableCollection(); m_flowPlotCollection = new RimFlowPlotCollection(); m_gridCrossPlotCollection = new RimGridCrossPlotCollection; m_saturationPressurePlotCollection = new RimSaturationPressurePlotCollection; @@ -237,6 +242,14 @@ RimSummaryCrossPlotCollection* RimMainPlotCollection::summaryCrossPlotCollection return m_summaryCrossPlotCollection(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryTableCollection* RimMainPlotCollection::summaryTableCollection() const +{ + return m_summaryTableCollection(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -443,6 +456,7 @@ std::vector RimMainPlotCollection::allPlotCollections() cons plotCollections.push_back( wellLogPlotCollection() ); plotCollections.push_back( summaryMultiPlotCollection() ); plotCollections.push_back( summaryCrossPlotCollection() ); + plotCollections.push_back( summaryTableCollection() ); plotCollections.push_back( gridCrossPlotCollection() ); plotCollections.push_back( analysisPlotCollection() ); plotCollections.push_back( vfpPlotCollection() ); diff --git a/ApplicationLibCode/ProjectDataModel/RimMainPlotCollection.h b/ApplicationLibCode/ProjectDataModel/RimMainPlotCollection.h index 7c6bfd5a89..2c7ed7f63b 100644 --- a/ApplicationLibCode/ProjectDataModel/RimMainPlotCollection.h +++ b/ApplicationLibCode/ProjectDataModel/RimMainPlotCollection.h @@ -34,6 +34,7 @@ class RimGridCrossPlotCollection; class RimMultiPlotCollection; class RimSummaryMultiPlotCollection; class RimSummaryCrossPlotCollection; +class RimSummaryTableCollection; class RimSummaryPlot; class RimSummaryPlotCollection; class RifReaderEclipseSummary; @@ -68,6 +69,7 @@ public: RimPltPlotCollection* pltPlotCollection() const; RimSummaryMultiPlotCollection* summaryMultiPlotCollection() const; RimSummaryCrossPlotCollection* summaryCrossPlotCollection() const; + RimSummaryTableCollection* summaryTableCollection() const; RimAnalysisPlotCollection* analysisPlotCollection() const; RimCorrelationPlotCollection* correlationPlotCollection() const; RimFlowPlotCollection* flowPlotCollection() const; @@ -111,6 +113,7 @@ private: caf::PdmChildField m_pltPlotCollection; caf::PdmChildField m_summaryMultiPlotCollection; caf::PdmChildField m_summaryCrossPlotCollection; + caf::PdmChildField m_summaryTableCollection; caf::PdmChildField m_analysisPlotCollection; caf::PdmChildField m_correlationPlotCollection; caf::PdmChildField m_flowPlotCollection; diff --git a/ApplicationLibCode/ProjectDataModel/RimProject.cpp b/ApplicationLibCode/ProjectDataModel/RimProject.cpp index f49eb5d44b..04234644ec 100644 --- a/ApplicationLibCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimProject.cpp @@ -79,6 +79,7 @@ #include "RimSummaryCaseMainCollection.h" #include "RimSummaryCrossPlotCollection.h" #include "RimSummaryMultiPlotCollection.h" +#include "RimSummaryTableCollection.h" #include "RimSurfaceCollection.h" #include "RimTools.h" #include "RimUserDefinedPolylinesAnnotation.h" @@ -1412,6 +1413,11 @@ void RimProject::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, Q uiTreeOrdering.add( m_mainPlotCollection->summaryCrossPlotCollection() ); } + if ( m_mainPlotCollection->summaryTableCollection() ) + { + uiTreeOrdering.add( m_mainPlotCollection->summaryTableCollection() ); + } + if ( m_mainPlotCollection->wellLogPlotCollection() ) { uiTreeOrdering.add( m_mainPlotCollection->wellLogPlotCollection() ); diff --git a/ApplicationLibCode/ProjectDataModel/Summary/CMakeLists_files.cmake b/ApplicationLibCode/ProjectDataModel/Summary/CMakeLists_files.cmake index 42a227536f..3a36cd524c 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/CMakeLists_files.cmake +++ b/ApplicationLibCode/ProjectDataModel/Summary/CMakeLists_files.cmake @@ -47,6 +47,8 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RimSummaryAddressModifier.h ${CMAKE_CURRENT_LIST_DIR}/RimRftCase.h ${CMAKE_CURRENT_LIST_DIR}/RimCsvSummaryCase.h + ${CMAKE_CURRENT_LIST_DIR}/RimSummaryTable.h + ${CMAKE_CURRENT_LIST_DIR}/RimSummaryTableCollection.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -98,6 +100,8 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RimSummaryAddressModifier.cpp ${CMAKE_CURRENT_LIST_DIR}/RimRftCase.cpp ${CMAKE_CURRENT_LIST_DIR}/RimCsvSummaryCase.cpp + ${CMAKE_CURRENT_LIST_DIR}/RimSummaryTable.cpp + ${CMAKE_CURRENT_LIST_DIR}/RimSummaryTableCollection.cpp ) list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.cpp new file mode 100644 index 0000000000..5e7bf1e779 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.cpp @@ -0,0 +1,652 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- 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 "RimSummaryTable.h" + +#include "RiaPreferences.h" +#include "RiaQDateTimeTools.h" +#include "RiaSummaryTools.h" +#include "RiaTimeHistoryCurveResampler.h" + +#include "RifSummaryReaderInterface.h" + +#include "RimEclipseResultCase.h" +#include "RimEclipseView.h" +#include "RimRegularLegendConfig.h" +#include "RimSummaryCase.h" +#include "RimSummaryCaseMainCollection.h" +#include "RimTools.h" + +#include "RiuMatrixPlotWidget.h" + +#include "cafPdmUiComboBoxEditor.h" +#include "cafPdmUiPushButtonEditor.h" +#include "cafPdmUiToolButtonEditor.h" +#include "cafPdmUiTreeSelectionEditor.h" + +#include "cvfScalarMapper.h" + +CAF_PDM_SOURCE_INIT( RimSummaryTable, "RimSummaryTable" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryTable::RimSummaryTable() +{ + CAF_PDM_InitObject( "Summary Table", ":/CorrelationMatrixPlot16x16.png" ); + uiCapability()->setUiTreeChildrenHidden( true ); + + CAF_PDM_InitField( &m_tableName, "TableName", QString( "Summary Table" ), "Name" ); + CAF_PDM_InitField( &m_isAutomaticName, "AutomaticTableName", true, "Automatic Name" ); + + CAF_PDM_InitFieldNoDefault( &m_case, "SummaryCase", "Case" ); + m_case.uiCapability()->setUiTreeChildrenHidden( true ); + CAF_PDM_InitFieldNoDefault( &m_vector, "Vectors", "Vector" ); + m_vector.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() ); + CAF_PDM_InitFieldNoDefault( &m_categories, "Categories", "Category" ); + m_categories.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() ); + m_categories = RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_WELL; + + CAF_PDM_InitFieldNoDefault( &m_resamplingSelection, "ResamplingSelection", "Date Resampling" ); + m_resamplingSelection.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() ); + m_resamplingSelection = RiaDefines::DateTimePeriod::YEAR; + + CAF_PDM_InitField( &m_thresholdValue, "ThresholdValue", 0.0, "Threshold" ); + + // Table settings + CAF_PDM_InitField( &m_showValueLabels, "ShowValueLabels", false, "Show Value Labels" ); + + // Font control + CAF_PDM_InitFieldNoDefault( &m_axisTitleFontSize, "AxisTitleFontSize", "Axis Title Font Size" ); + CAF_PDM_InitFieldNoDefault( &m_axisLabelFontSize, "AxisLabelFontSize", "Axis Label Font Size" ); + CAF_PDM_InitFieldNoDefault( &m_valueLabelFontSize, "ValueLabelFontSize", "Value Label Font Size" ); + m_axisTitleFontSize = caf::FontTools::RelativeSize::Large; + m_axisLabelFontSize = caf::FontTools::RelativeSize::Medium; + + CAF_PDM_InitFieldNoDefault( &m_legendConfig, "LegendConfig", "" ); + m_legendConfig = new RimRegularLegendConfig(); + m_legendConfig->setShowLegend( true ); + m_legendConfig->setAutomaticRanges( 0.0, 100.0, 0.0, 100.0 ); + m_legendConfig->setColorLegend( RimRegularLegendConfig::mapToColorLegend( RimRegularLegendConfig::ColorRangesType::HEAT_MAP ) ); + + setLegendsVisible( true ); + setAsPlotMdiWindow(); + setShowWindow( true ); + setDeletable( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryTable::~RimSummaryTable() +{ + if ( isMdiWindow() ) removeMdiWindowFromMdiArea(); + + cleanupBeforeClose(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::setDefaultCaseAndCategoryAndVectorName() +{ + const auto summaryCases = getToplevelSummaryCases(); + m_case = nullptr; + m_categories = RifEclipseSummaryAddress::SUMMARY_WELL; + m_vector = ""; + m_tableName = createTableName(); + if ( summaryCases.empty() ) return; + + m_case = summaryCases.front(); + + const auto summaryReader = m_case->summaryReader(); + if ( !summaryReader ) return; + + const auto categoryVectors = getCategoryVectorsFromSummaryReader( summaryReader, m_categories() ); + if ( !categoryVectors.empty() ) + { + m_vector = *categoryVectors.begin(); + } + m_tableName = createTableName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::setFromCaseAndCategoryAndVectorName( RimSummaryCase* summaryCase, + RifEclipseSummaryAddress::SummaryVarCategory category, + const QString& vectorName ) +{ + m_case = summaryCase; + m_categories = category; + m_vector = vectorName; + m_tableName = createTableName(); + onLoadDataAndUpdate(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::setDescription( const QString& description ) +{ + m_tableName = description; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::cleanupBeforeClose() +{ + if ( m_matrixPlotWidget ) + { + m_matrixPlotWidget->qwtPlot()->detachItems(); + m_matrixPlotWidget->setParent( nullptr ); + delete m_matrixPlotWidget; + m_matrixPlotWidget = nullptr; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) +{ + RimViewWindow::fieldChangedByUi( changedField, oldValue, newValue ); + + if ( changedField == &m_case ) + { + if ( m_case ) + { + auto* summaryReader = m_case->summaryReader(); + const auto categoryVectors = getCategoryVectorsFromSummaryReader( summaryReader, m_categories() ); + if ( summaryReader && !categoryVectors.empty() ) + { + m_vector = *categoryVectors.begin(); + } + else + { + m_vector = QString( "" ); + } + } + if ( m_isAutomaticName ) + { + m_tableName = createTableName(); + } + onLoadDataAndUpdate(); + } + else if ( changedField == &m_categories ) + { + if ( m_case ) + { + auto* summaryReader = m_case->summaryReader(); + const auto categoryVectors = getCategoryVectorsFromSummaryReader( summaryReader, m_categories() ); + if ( summaryReader && !categoryVectors.empty() ) + { + m_vector = *categoryVectors.begin(); + } + else + { + m_vector = QString( "" ); + } + } + else + { + m_vector = QString( " " ); + } + if ( m_isAutomaticName ) + { + m_tableName = createTableName(); + } + onLoadDataAndUpdate(); + } + else if ( changedField == &m_vector || changedField == &m_resamplingSelection || changedField == &m_thresholdValue ) + { + if ( m_isAutomaticName ) + { + m_tableName = createTableName(); + } + onLoadDataAndUpdate(); + } + else if ( changedField == &m_isAutomaticName && m_isAutomaticName ) + { + m_tableName = createTableName(); + } + else if ( m_matrixPlotWidget && changedField == &m_showValueLabels ) + { + m_matrixPlotWidget->setShowValueLabel( m_showValueLabels ); + } + else if ( m_matrixPlotWidget && ( changedField == &m_titleFontSize || changedField == &m_legendFontSize || + changedField == &m_axisTitleFontSize || changedField == &m_axisLabelFontSize ) ) + { + m_matrixPlotWidget->setPlotTitleFontSize( titleFontSize() ); + m_matrixPlotWidget->setLegendFontSize( legendFontSize() ); + m_matrixPlotWidget->setAxisTitleFontSize( axisTitleFontSize() ); + m_matrixPlotWidget->setAxisLabelFontSize( axisLabelFontSize() ); + } + else if ( changedField == &m_valueLabelFontSize && m_matrixPlotWidget ) + { + m_matrixPlotWidget->setValueFontSize( valueLabelFontSize() ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) +{ + onLoadDataAndUpdate(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + RimViewWindow::defineUiOrdering( uiConfigName, uiOrdering ); + + caf::PdmUiGroup& dataGroup = *uiOrdering.addNewGroup( "Plot Data" ); + dataGroup.add( &m_tableName ); + dataGroup.add( &m_isAutomaticName ); + dataGroup.add( &m_case ); + dataGroup.add( &m_categories ); + dataGroup.add( &m_vector ); + dataGroup.add( &m_resamplingSelection ); + dataGroup.add( &m_thresholdValue ); + + caf::PdmUiGroup* tableSettingsGroup = uiOrdering.addNewGroup( "Table Settings" ); + tableSettingsGroup->add( &m_showValueLabels ); + m_legendConfig->uiOrdering( "FlagColorsAndMappingModeOnly", *tableSettingsGroup ); + + caf::PdmUiGroup* fontGroup = uiOrdering.addNewGroup( "Fonts" ); + fontGroup->setCollapsedByDefault(); + RimPlotWindow::uiOrderingForFonts( uiConfigName, *fontGroup ); + fontGroup->add( &m_axisTitleFontSize ); + fontGroup->add( &m_axisLabelFontSize ); + fontGroup->add( &m_valueLabelFontSize ); + + uiOrdering.skipRemainingFields( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimSummaryTable::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) +{ + QList options = RimPlotWindow::calculateValueOptions( fieldNeedingOptions ); + if ( !options.empty() ) + { + return options; + } + else if ( fieldNeedingOptions == &m_case ) + { + std::vector summaryCases = getToplevelSummaryCases(); + for ( auto* summaryCase : summaryCases ) + { + options.push_back( caf::PdmOptionItemInfo( summaryCase->displayCaseName(), summaryCase, false, summaryCase->uiIconProvider() ) ); + } + } + else if ( fieldNeedingOptions == &m_categories ) + { + options.push_back( caf::PdmOptionItemInfo( caf::AppEnum::uiText( + RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_WELL ), + RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_WELL ) ); + options.push_back( caf::PdmOptionItemInfo( caf::AppEnum::uiText( + RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_GROUP ), + RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_GROUP ) ); + options.push_back( caf::PdmOptionItemInfo( caf::AppEnum::uiText( + RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_REGION ), + RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_REGION ) ); + } + else if ( fieldNeedingOptions == &m_vector && m_case ) + { + auto* summaryReader = m_case->summaryReader(); + if ( summaryReader ) + { + const auto categoryVectorsUnion = getCategoryVectorsFromSummaryReader( summaryReader, m_categories() ); + for ( const auto& vectorName : categoryVectorsUnion ) + { + options.push_back( caf::PdmOptionItemInfo( vectorName, vectorName ) ); + } + } + } + else if ( fieldNeedingOptions == &m_axisTitleFontSize || fieldNeedingOptions == &m_axisLabelFontSize || + fieldNeedingOptions == &m_valueLabelFontSize ) + { + options = caf::FontTools::relativeSizeValueOptions( RiaPreferences::current()->defaultPlotFontSize() ); + } + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::onLoadDataAndUpdate() +{ + updateMdiWindowVisibility(); + + if ( m_matrixPlotWidget == nullptr || m_case == nullptr ) + { + return; + } + + const auto summaryReader = m_case->summaryReader(); + if ( !summaryReader ) + { + return; + } + + // Struct for storing vector data + struct VectorData + { + QString category; + QString name; + std::vector values; + time_t firstTimeStep; + time_t lastTimeStep; + bool hasValueAboveThreshold; + }; + + // Create time step value for vectors with no values above threshold + const time_t invalidTimeStep = 0; + + // Get all summary addresses for selected category (group, region, well) + std::vector vectorDataCollection; + std::set timeStepsUnion; + const auto summaryAddresses = getSummaryAddressesFromReader( summaryReader, m_categories(), m_vector() ); + QString unitName; + for ( const auto& adr : summaryAddresses ) + { + std::vector values; + summaryReader->values( adr, &values ); + const std::vector timeSteps = summaryReader->timeSteps( adr ); + const QString vectorName = QString::fromStdString( adr.vectorName() ); + const QString categoryName = getCategoryNameFromAddress( adr ); + unitName = QString::fromStdString( summaryReader->unitName( adr ) ); + + // Get re-sampled time steps and values + const auto [resampledTimeSteps, resampledValues] = + RiaSummaryTools::resampledValuesForPeriod( adr, timeSteps, values, m_resamplingSelection() ); + + // First and last time step with value above threshold and set flag (first and last should be valid/invalid simultaneously) + const auto firstItr = + std::find_if( resampledValues.begin(), resampledValues.end(), [&]( double value ) { return value > m_thresholdValue; } ); + const auto lastItr = + std::find_if( resampledValues.rbegin(), resampledValues.rend(), [&]( double value ) { return value > m_thresholdValue; } ); + const auto firstIdx = static_cast( std::distance( resampledValues.begin(), firstItr ) ); + const auto lastIdx = resampledValues.size() - static_cast( std::distance( resampledValues.rbegin(), lastItr ) ) - 1; + const bool hasValueAboveThreshold = firstIdx < resampledTimeSteps.size() && lastIdx < resampledTimeSteps.size(); + const auto firstTimeStep = hasValueAboveThreshold ? resampledTimeSteps[firstIdx] : invalidTimeStep; + const auto lastTimeStep = hasValueAboveThreshold ? resampledTimeSteps[lastIdx] : invalidTimeStep; + + // Add to vector of VectorData + VectorData vectorData{ .category = categoryName, + .name = vectorName, + .values = resampledValues, + .firstTimeStep = firstTimeStep, + .lastTimeStep = lastTimeStep, + .hasValueAboveThreshold = hasValueAboveThreshold }; + vectorDataCollection.push_back( vectorData ); + + // Build union of resampled time steps + timeStepsUnion.insert( resampledTimeSteps.begin(), resampledTimeSteps.end() ); + } + + // Sort vector data on date (vectors with no values above threshold placed last): + std::sort( vectorDataCollection.begin(), vectorDataCollection.end(), []( const VectorData& v1, const VectorData& v2 ) { + if ( !v1.hasValueAboveThreshold ) return false; + if ( v1.hasValueAboveThreshold && !v2.hasValueAboveThreshold ) return true; + if ( v1.firstTimeStep < v2.firstTimeStep ) return true; + if ( v1.firstTimeStep == v2.firstTimeStep && v1.lastTimeStep < v2.lastTimeStep ) return true; + return false; + } ); + + // Convert to strings + std::vector timeStepStrings; + for ( const auto& timeStep : timeStepsUnion ) + { + timeStepStrings.push_back( RiaQDateTimeTools::fromTime_t( timeStep ).toString( dateFormatString() ) ); + } + + // Clear matrix plot + m_matrixPlotWidget->clearPlotData(); + m_matrixPlotWidget->setColumnHeaders( timeStepStrings ); + double maxValue = 0.0; + double minValue = 0.0; + for ( const auto& vectorData : vectorDataCollection ) + { + const auto maxRowValue = *std::max_element( vectorData.values.begin(), vectorData.values.end() ); + const auto minRowValue = *std::min_element( vectorData.values.begin(), vectorData.values.end() ); + if ( maxRowValue < m_thresholdValue() ) continue; + maxValue = std::max( maxValue, maxRowValue ); + minValue = std::min( minValue, minRowValue ); + m_matrixPlotWidget->setRowValues( vectorData.category, vectorData.values ); + } + + if ( m_legendConfig ) + { + m_legendConfig->setAutomaticRanges( minValue, maxValue, 0.0, 0.0 ); + } + + // Set titles and font sizes + const QString title = + QString( "Summary Table - %1 [%2]
Date Resampling: %3
" ).arg( m_vector() ).arg( unitName ).arg( m_resamplingSelection().uiText() ); + m_matrixPlotWidget->setPlotTitle( title ); + m_matrixPlotWidget->setRowTitle( QString( "%1s" ).arg( m_categories().uiText() ) ); + m_matrixPlotWidget->setColumnTitle( "Time steps" ); + m_matrixPlotWidget->setPlotTitleFontSize( titleFontSize() ); + m_matrixPlotWidget->setLegendFontSize( legendFontSize() ); + m_matrixPlotWidget->setAxisTitleFontSize( axisTitleFontSize() ); + m_matrixPlotWidget->setAxisLabelFontSize( axisLabelFontSize() ); + + m_matrixPlotWidget->createPlot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* RimSummaryTable::viewWidget() +{ + return m_matrixPlotWidget; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QImage RimSummaryTable::snapshotWindowContent() +{ + QImage image; + + if ( m_matrixPlotWidget ) + { + QPixmap pix = m_matrixPlotWidget->grab(); + image = pix.toImage(); + } + + return image; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::zoomAll() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* RimSummaryTable::createViewWidget( QWidget* mainWindowParent ) +{ + m_matrixPlotWidget = new RiuMatrixPlotWidget( this, m_legendConfig, mainWindowParent ); + m_matrixPlotWidget->setShowValueLabel( m_showValueLabels ); + m_matrixPlotWidget->setUseInvalidValueColor( true ); + return m_matrixPlotWidget; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::deleteViewWidget() +{ + cleanupBeforeClose(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummaryTable::description() const +{ + return m_tableName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTable::doRenderWindowContent( QPaintDevice* paintDevice ) +{ + return; +} + +caf::PdmFieldHandle* RimSummaryTable::userDescriptionField() +{ + return &m_tableName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSummaryTable::axisTitleFontSize() const +{ + return caf::FontTools::absolutePointSize( RiaPreferences::current()->defaultPlotFontSize(), m_axisTitleFontSize() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSummaryTable::axisLabelFontSize() const +{ + return caf::FontTools::absolutePointSize( RiaPreferences::current()->defaultPlotFontSize(), m_axisLabelFontSize() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSummaryTable::valueLabelFontSize() const +{ + return caf::FontTools::absolutePointSize( RiaPreferences::current()->defaultPlotFontSize(), m_valueLabelFontSize() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummaryTable::createTableName() const +{ + return QString( "Summary Table - %1" ).arg( m_vector() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RimSummaryTable::createLegendMinMaxValues( const double maxTableValue ) const +{ + return std::make_pair( 0.0, maxTableValue ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummaryTable::dateFormatString() const +{ + return RiaQDateTimeTools::dateFormatString( RiaPreferences::current()->dateFormat(), + RiaDefines::DateFormatComponents::DATE_FORMAT_YEAR_MONTH_DAY ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RimSummaryTable::getSummaryAddressesFromReader( const RifSummaryReaderInterface* summaryReader, + RifEclipseSummaryAddress::SummaryVarCategory category, + const QString& vector ) const +{ + if ( !summaryReader ) return std::set(); + + std::set categoryAddresses; + const std::set allResultAddresses = summaryReader->allResultAddresses(); + const std::string selectedVector = vector.toStdString(); + for ( const auto& resAdr : allResultAddresses ) + { + if ( resAdr.category() != category || resAdr.vectorName() != selectedVector ) continue; + categoryAddresses.emplace( resAdr ); + } + return categoryAddresses; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RimSummaryTable::getCategoryVectorsFromSummaryReader( const RifSummaryReaderInterface* summaryReader, + RifEclipseSummaryAddress::SummaryVarCategory category ) const +{ + if ( !summaryReader ) return std::set(); + if ( category != RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_WELL && + category != RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_GROUP && + category != RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_REGION ) + { + return std::set(); + } + + std::set categoryVectors; + const std::set allResultAddresses = summaryReader->allResultAddresses(); + for ( const auto& resAdr : allResultAddresses ) + { + if ( resAdr.category() != category ) continue; + const QString vectorName = QString::fromStdString( resAdr.vectorName() ); + categoryVectors.emplace( vectorName ); + } + return categoryVectors; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSummaryTable::getCategoryNameFromAddress( const RifEclipseSummaryAddress& address ) const +{ + if ( address.category() == RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_WELL ) + { + return QString::fromStdString( address.wellName() ); + } + else if ( address.category() == RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_GROUP ) + { + return QString::fromStdString( address.groupName() ); + } + else if ( address.category() == RifEclipseSummaryAddress::SummaryVarCategory::SUMMARY_REGION ) + { + return QString( "Region %1" ).arg( address.regionNumber() ); + } + return QString(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSummaryTable::getToplevelSummaryCases() const +{ + RimSummaryCaseMainCollection* summaryCaseMainCollection = RiaSummaryTools::summaryCaseMainCollection(); + if ( !summaryCaseMainCollection ) return {}; + return summaryCaseMainCollection->topLevelSummaryCases(); +} diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.h new file mode 100644 index 0000000000..c2948495ae --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTable.h @@ -0,0 +1,120 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- 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 "RimPlotWindow.h" + +#include "RiaDateTimeDefines.h" + +#include "RifEclipseSummaryAddress.h" + +#include "cafPdmField.h" +#include "cafPdmPtrField.h" + +#include +#include +#include + +class RifSummaryReaderInterface; +class RimSummaryCase; +class RimRegularLegendConfig; +class RiuMatrixPlotWidget; + +//================================================================================================== +/// +//================================================================================================== +class RimSummaryTable : public RimPlotWindow +{ + CAF_PDM_HEADER_INIT; + +public: + RimSummaryTable(); + ~RimSummaryTable() override; + + void setDefaultCaseAndCategoryAndVectorName(); + void setFromCaseAndCategoryAndVectorName( RimSummaryCase* summaryCase, + RifEclipseSummaryAddress::SummaryVarCategory category, + const QString& vectorName ); + void setDescription( const QString& description ); + virtual QString description() const override; + +private: + void cleanupBeforeClose(); + + void onLoadDataAndUpdate() override; + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + void childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) override; + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + + QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override; + + // Inherited via RimPlotWindow + virtual void doRenderWindowContent( QPaintDevice* paintDevice ) override; + + // Inherited via RimViewWindow + virtual QWidget* viewWidget() override; + virtual QImage snapshotWindowContent() override; + virtual void zoomAll() override; + virtual QWidget* createViewWidget( QWidget* mainWindowParent ) override; + virtual void deleteViewWidget() override; + + // PDM methods + caf::PdmFieldHandle* userDescriptionField() override; + + int axisTitleFontSize() const; + int axisLabelFontSize() const; + int valueLabelFontSize() const; + + QString createTableName() const; + +private: + std::pair createLegendMinMaxValues( const double maxTableValue ) const; + QString dateFormatString() const; + + std::set getSummaryAddressesFromReader( const RifSummaryReaderInterface* summaryReader, + RifEclipseSummaryAddress::SummaryVarCategory category, + const QString& vector ) const; + std::set getCategoryVectorsFromSummaryReader( const RifSummaryReaderInterface* summaryReader, + RifEclipseSummaryAddress::SummaryVarCategory category ) const; + QString getCategoryNameFromAddress( const RifEclipseSummaryAddress& address ) const; + + std::vector getToplevelSummaryCases() const; + +private: + // Matrix plot for visualizing table data + QPointer m_matrixPlotWidget; + + caf::PdmField m_tableName; + caf::PdmField m_isAutomaticName; + caf::PdmPtrField m_case; + + caf::PdmField> m_categories; + caf::PdmField m_vector; + caf::PdmField> m_resamplingSelection; + caf::PdmField m_thresholdValue; + + caf::PdmChildField m_legendConfig; + + caf::PdmField m_axisTitleFontSize; + caf::PdmField m_axisLabelFontSize; + caf::PdmField m_valueLabelFontSize; + caf::PdmField m_showValueLabels; + + const int m_initialNumberOfTimeSteps = 10; +}; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTableCollection.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTableCollection.cpp new file mode 100644 index 0000000000..50d03a03a1 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTableCollection.cpp @@ -0,0 +1,140 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil 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 "RimSummaryTableCollection.h" + +#include "RimProject.h" +#include "RimSummaryCase.h" +#include "RimSummaryCrossPlot.h" +#include "RimSummaryPlot.h" + +#include "cafPdmFieldReorderCapability.h" + +CAF_PDM_SOURCE_INIT( RimSummaryTableCollection, "RimSummaryTableCollection" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryTableCollection::RimSummaryTableCollection() +{ + CAF_PDM_InitObject( "Summary Tables", ":/CorrelationMatrixPlot16x16.png" ); + + CAF_PDM_InitFieldNoDefault( &m_summaryTables, "SummaryTables", "Summary Tables" ); + m_summaryTables.uiCapability()->setUiTreeHidden( true ); + caf::PdmFieldReorderCapability::addToField( &m_summaryTables ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryTableCollection::~RimSummaryTableCollection() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTableCollection::deleteAllPlots() +{ + m_summaryTables.deleteChildren(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTableCollection::loadDataAndUpdateAllPlots() +{ + for ( RimSummaryTable* table : m_summaryTables ) + { + if ( !table ) continue; + + table->loadDataAndUpdate(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimSummaryTableCollection::plotCount() const +{ + return tableCount(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSummaryTableCollection::tables() const +{ + return m_summaryTables.children(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimSummaryTableCollection::tableCount() const +{ + return m_summaryTables.size(); +} + +void RimSummaryTableCollection::addTable( RimSummaryTable* table ) +{ + insertTable( table, tableCount() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTableCollection::insertTable( RimSummaryTable* table, size_t index ) +{ + m_summaryTables.insert( index, table ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTableCollection::removeTable( RimSummaryTable* table ) +{ + m_summaryTables.removeChild( table ); + updateAllRequiredEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryTable* RimSummaryTableCollection::createDefaultSummaryTable() +{ + RimSummaryTable* table = new RimSummaryTable(); + table->setDefaultCaseAndCategoryAndVectorName(); + table->setAsPlotMdiWindow(); + + return table; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryTable* RimSummaryTableCollection::createSummaryTableFromCategoryAndVectorName( RimSummaryCase* summaryCase, + RifEclipseSummaryAddress::SummaryVarCategory category, + const QString& vectorName ) +{ + RimSummaryTable* table = new RimSummaryTable(); + table->setFromCaseAndCategoryAndVectorName( summaryCase, category, vectorName ); + table->setAsPlotMdiWindow(); + + return table; +} diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTableCollection.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTableCollection.h new file mode 100644 index 0000000000..66be58da57 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryTableCollection.h @@ -0,0 +1,58 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- 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 "RimAbstractPlotCollection.h" +#include "RimSummaryTable.h" + +#include "cafPdmChildArrayField.h" +#include "cafPdmObject.h" + +class RimSummaryCase; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimSummaryTableCollection : public caf::PdmObject, public RimPlotCollection +{ + CAF_PDM_HEADER_INIT; + +public: + RimSummaryTableCollection(); + ~RimSummaryTableCollection() override; + + void deleteAllPlots() override; + void loadDataAndUpdateAllPlots() override; + size_t plotCount() const override; + + std::vector tables() const; + size_t tableCount() const; + void addTable( RimSummaryTable* table ); + void insertTable( RimSummaryTable* table, size_t index ); + void removeTable( RimSummaryTable* table ); + + RimSummaryTable* createDefaultSummaryTable(); + RimSummaryTable* createSummaryTableFromCategoryAndVectorName( RimSummaryCase* summaryCase, + RifEclipseSummaryAddress::SummaryVarCategory category, + const QString& vectorName ); + +private: + caf::PdmChildArrayField m_summaryTables; +}; diff --git a/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.cpp b/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.cpp index 6472f5da33..41fda9da6e 100644 --- a/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.cpp +++ b/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.cpp @@ -194,6 +194,16 @@ RimViewWindow* RiuMatrixPlotWidget::ownerViewWindow() const return m_ownerViewWindow; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMatrixPlotWidget::contextMenuEvent( QContextMenuEvent* ) +{ + // Added empty override to preventing menu for Mdi Area + // I.e.: RiuContextMenuLauncher for RiuPlotMainWindow (mdi area) + return; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.h b/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.h index 5fe941ab1a..6a3f05a850 100644 --- a/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.h +++ b/ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.h @@ -77,6 +77,9 @@ public: RimViewWindow* ownerViewWindow() const override; +protected: + void contextMenuEvent( QContextMenuEvent* ) override; + private slots: void onPlotItemSelected( std::shared_ptr plotItem, bool toggle, int sampleIndex );