From 4de91e885bf8a9fd00d0f154d39d5741bae19447 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Jun 2021 16:25:19 +0200 Subject: [PATCH] #7761 Objective Function : Change formula and add several options --- .../RicNewCustomObjectiveFunctionFeature.cpp | 6 +- ...ewCustomObjectiveFunctionWeightFeature.cpp | 17 +- ...cNewCustomObjectiveFunctionWeightFeature.h | 5 +- .../RicNewEnsembleCurveFilterFeature.cpp | 7 +- .../RimCustomObjectiveFunction.cpp | 135 +++-- .../RimCustomObjectiveFunction.h | 16 +- .../RimCustomObjectiveFunctionWeight.cpp | 6 +- .../Summary/CMakeLists_files.cmake | 2 + .../Summary/RimEnsembleCurveFilter.cpp | 64 ++- .../Summary/RimEnsembleCurveFilter.h | 30 +- .../Summary/RimEnsembleCurveSet.cpp | 185 +++--- .../Summary/RimEnsembleCurveSet.h | 35 +- .../RimEnsembleCurveSetColorManager.cpp | 29 +- .../Summary/RimEnsembleCurveSetColorManager.h | 13 +- .../Summary/RimObjectiveFunction.cpp | 526 +++++++++--------- .../Summary/RimObjectiveFunction.h | 82 ++- .../Summary/RimObjectiveFunctionTools.cpp | 95 ++++ .../Summary/RimObjectiveFunctionTools.h | 36 ++ .../Summary/RimSummaryCaseCollection.cpp | 27 - .../Summary/RimSummaryCaseCollection.h | 5 - .../RiuSummaryVectorSelectionDialog.cpp | 24 + .../RiuSummaryVectorSelectionDialog.h | 4 + .../RiuSummaryVectorSelectionUi.cpp | 63 +++ .../RiuSummaryVectorSelectionUi.h | 8 + 24 files changed, 883 insertions(+), 537 deletions(-) create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunctionTools.cpp create mode 100644 ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunctionTools.h diff --git a/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionFeature.cpp b/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionFeature.cpp index 77edeac454..7bf8a01b8a 100644 --- a/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionFeature.cpp +++ b/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionFeature.cpp @@ -20,8 +20,7 @@ #include "RimCustomObjectiveFunction.h" #include "RimCustomObjectiveFunctionCollection.h" -#include "RimCustomObjectiveFunctionWeight.h" -#include "RimEnsembleCurveSet.h" +#include "RimObjectiveFunctionTools.h" #include "RiuPlotMainWindowTools.h" @@ -53,8 +52,7 @@ void RicNewCustomObjectiveFunctionFeature::onActionTriggered( bool isChecked ) if ( coll.size() == 1 ) { RimCustomObjectiveFunction* newFunc = coll[0]->addObjectiveFunction(); - RimCustomObjectiveFunctionWeight* newWeight = newFunc->addWeight(); - newWeight->setSummaryAddress( newWeight->parentCurveSet()->summaryAddress() ); + RimCustomObjectiveFunctionWeight* newWeight = RimObjectiveFunctionTools::addWeight( newFunc ); coll[0]->updateConnectedEditors(); RiuPlotMainWindowTools::selectAsCurrentItem( newFunc ); RiuPlotMainWindowTools::setExpanded( coll.front() ); diff --git a/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionWeightFeature.cpp b/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionWeightFeature.cpp index 380f6856a5..d50a37dfb4 100644 --- a/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionWeightFeature.cpp +++ b/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionWeightFeature.cpp @@ -20,7 +20,7 @@ #include "RimCustomObjectiveFunction.h" #include "RimCustomObjectiveFunctionWeight.h" -#include "RimEnsembleCurveSet.h" +#include "RimObjectiveFunctionTools.h" #include "RiuPlotMainWindowTools.h" @@ -51,16 +51,11 @@ void RicNewCustomObjectiveFunctionWeightFeature::onActionTriggered( bool isCheck if ( func.size() == 1 ) { - RimCustomObjectiveFunctionWeight* newWeight = func[0]->addWeight(); - if ( func[0]->weights().size() > 1 ) - { - newWeight->setSummaryAddress( func[0]->weights()[0]->summaryAddresses().front() ); - } - else - { - newWeight->setSummaryAddress( newWeight->parentCurveSet()->summaryAddress() ); - } - func[0]->updateConnectedEditors(); + auto firstObjectiveFunction = func.front(); + + auto newWeight = RimObjectiveFunctionTools::addWeight( firstObjectiveFunction ); + + firstObjectiveFunction->updateConnectedEditors(); RiuPlotMainWindowTools::selectAsCurrentItem( newWeight ); RiuPlotMainWindowTools::setExpanded( func.front() ); } diff --git a/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionWeightFeature.h b/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionWeightFeature.h index bcdd127d4f..bab0f9800e 100644 --- a/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionWeightFeature.h +++ b/ApplicationLibCode/Commands/RicNewCustomObjectiveFunctionWeightFeature.h @@ -28,8 +28,7 @@ class RicNewCustomObjectiveFunctionWeightFeature : public caf::CmdFeature CAF_CMD_HEADER_INIT; protected: - // Overrides bool isCommandEnabled() override; - void onActionTriggered(bool isChecked) override; - void setupActionLook(QAction* actionToSetup) override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; }; diff --git a/ApplicationLibCode/Commands/SummaryPlotCommands/RicNewEnsembleCurveFilterFeature.cpp b/ApplicationLibCode/Commands/SummaryPlotCommands/RicNewEnsembleCurveFilterFeature.cpp index ef274cf728..c922fccd22 100644 --- a/ApplicationLibCode/Commands/SummaryPlotCommands/RicNewEnsembleCurveFilterFeature.cpp +++ b/ApplicationLibCode/Commands/SummaryPlotCommands/RicNewEnsembleCurveFilterFeature.cpp @@ -21,6 +21,7 @@ #include "RimEnsembleCurveFilter.h" #include "RimEnsembleCurveFilterCollection.h" #include "RimEnsembleCurveSet.h" +#include "RimObjectiveFunctionTools.h" #include "RiuPlotMainWindowTools.h" @@ -67,7 +68,11 @@ void RicNewEnsembleCurveFilterFeature::onActionTriggered( bool isChecked ) else { std::vector addresses; - addresses.push_back( newFilter->parentCurveSet()->summaryAddress() ); + + auto candidateAdr = newFilter->parentCurveSet()->summaryAddress(); + auto nativeQuantityName = RimObjectiveFunctionTools::nativeQuantityName( candidateAdr.quantityName() ); + candidateAdr.setQuantityName( nativeQuantityName ); + addresses.push_back( candidateAdr ); newFilter->setSummaryAddresses( addresses ); } newFilter->loadDataAndUpdate(); diff --git a/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunction.cpp b/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunction.cpp index 9b1e6e9aa4..89c44328f5 100644 --- a/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunction.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunction.cpp @@ -45,6 +45,21 @@ RimCustomObjectiveFunction::RimCustomObjectiveFunction() CAF_PDM_InitFieldNoDefault( &m_weights, "Weights", "", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_objectiveFunctions, "ObjectiveFunctions", "Objective Functions", "", "", "" ); + + { + auto objFunc1 = new RimObjectiveFunction(); + objFunc1->setFunctionType( RimObjectiveFunction::FunctionType::F1 ); + m_objectiveFunctions.push_back( objFunc1 ); + objFunc1->changed.connect( this, &RimCustomObjectiveFunction::onObjectiveFunctionChanged ); + } + { + auto objFunc1 = new RimObjectiveFunction(); + objFunc1->setFunctionType( RimObjectiveFunction::FunctionType::F2 ); + m_objectiveFunctions.push_back( objFunc1 ); + objFunc1->changed.connect( this, &RimCustomObjectiveFunction::onObjectiveFunctionChanged ); + } + m_isValid = true; setDeletable( true ); @@ -71,32 +86,21 @@ std::vector RimCustomObjectiveFunction::weigh //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RimCustomObjectiveFunction::values() const +std::vector RimCustomObjectiveFunction::functionValueForAllCases() const { - std::vector values; + if ( m_weights.empty() ) return {}; + RimSummaryCaseCollection* caseCollection = parentCurveSet()->summaryCaseCollection(); - for ( auto weight : m_weights ) + if ( !caseCollection || caseCollection->allSummaryCases().empty() ) return {}; + + std::vector values; + + for ( auto sumCase : caseCollection->allSummaryCases() ) { - std::vector functionValues = - caseCollection->objectiveFunction( weight->objectiveFunction() )->values( weight->summaryAddresses() ); - if ( values.size() == 0 ) - { - for ( size_t i = 0; i < functionValues.size(); i++ ) - { - values.push_back( weight->weightValue() * functionValues[i] ); - } - } - else - { - for ( size_t i = 0; i < functionValues.size(); i++ ) - { - if ( values.size() > i + 1 ) - { - values[i] += weight->weightValue() * functionValues[i]; - } - } - } + auto functionValue = value( sumCase ); + values.push_back( functionValue ); } + return values; } @@ -105,15 +109,23 @@ std::vector RimCustomObjectiveFunction::values() const //-------------------------------------------------------------------------------------------------- double RimCustomObjectiveFunction::value( RimSummaryCase* summaryCase ) const { - double value = 0.0; - RimSummaryCaseCollection* caseCollection = parentCurveSet()->summaryCaseCollection(); + if ( m_functionValueForAllCases.count( summaryCase ) > 0 ) + { + return m_functionValueForAllCases[summaryCase]; + } + + double value = 0.0; for ( auto weight : m_weights ) { double functionValue = - caseCollection->objectiveFunction( weight->objectiveFunction() )->value( summaryCase, weight->summaryAddresses() ); + objectiveFunction( weight->objectiveFunction() ) + ->value( summaryCase, weight->summaryAddresses(), parentCurveSet()->objectiveFunctionTimeConfig() ); value += weight->weightValue() * functionValue; } + + m_functionValueForAllCases[summaryCase] = value; + return value; } @@ -125,7 +137,7 @@ std::pair RimCustomObjectiveFunction::minMaxValues() const double minValue = std::numeric_limits::infinity(); double maxValue = -std::numeric_limits::infinity(); - for ( auto value : values() ) + for ( auto value : functionValueForAllCases() ) { if ( value != std::numeric_limits::infinity() ) { @@ -196,6 +208,7 @@ bool RimCustomObjectiveFunction::isValid() const //-------------------------------------------------------------------------------------------------- void RimCustomObjectiveFunction::onWeightChanged() { + m_functionValueForAllCases.clear(); parentCollection()->onObjectiveFunctionChanged( this ); } @@ -220,17 +233,23 @@ QString RimCustomObjectiveFunction::formulaString( std::vectorweightValue() ) - .arg( parentCurveSet() - ->summaryCaseCollection() - ->objectiveFunction( weight->objectiveFunction() ) - ->formulaString( vectorSummaryAddresses ) ); + weightFormulae + << QString( "%0 * %1" ) + .arg( weight->weightValue() ) + .arg( objectiveFunction( weight->objectiveFunction() )->formulaString( vectorSummaryAddresses ) ); } formula += weightFormulae.join( " + " ); return formula; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCustomObjectiveFunction::clearCache() +{ + m_functionValueForAllCases.clear(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -239,6 +258,14 @@ caf::PdmFieldHandle* RimCustomObjectiveFunction::userDescriptionField() return &m_functionTitle; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCustomObjectiveFunction::onObjectiveFunctionChanged( const caf::SignalEmitter* emitter ) +{ + onWeightChanged(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -269,6 +296,35 @@ void RimCustomObjectiveFunction::defineEditorAttribute( const caf::PdmFieldHandl } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCustomObjectiveFunction::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + uiOrdering.add( &m_customFunctionTitle ); + + { + auto objFunc1 = objectiveFunction( RimObjectiveFunction::FunctionType::F1 ); + if ( objFunc1 ) + { + auto equationGroup = uiOrdering.addNewGroup( "Equation for Time Range" ); + + objFunc1->hideFunctionSelection(); + objFunc1->uiOrdering( "", *equationGroup ); + } + } + + { + auto objFunc2 = objectiveFunction( RimObjectiveFunction::FunctionType::F2 ); + { + auto equationGroup = uiOrdering.addNewGroup( "Equation for Selected Time Range" ); + + objFunc2->hideFunctionSelection(); + objFunc2->uiOrdering( "", *equationGroup ); + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -288,3 +344,18 @@ RimCustomObjectiveFunctionCollection* RimCustomObjectiveFunction::parentCollecti firstAncestorOrThisOfType( collection ); return collection; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimObjectiveFunction* RimCustomObjectiveFunction::objectiveFunction( RimObjectiveFunction::FunctionType functionType ) const +{ + for ( auto objectiveFunc : m_objectiveFunctions.childObjects() ) + { + if ( objectiveFunc->functionType() == functionType ) + { + return objectiveFunc; + } + } + return nullptr; +} diff --git a/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunction.h b/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunction.h index 61c2bae461..5dbb6fa5ea 100644 --- a/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunction.h +++ b/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunction.h @@ -22,6 +22,7 @@ #include "RimObjectiveFunction.h" #include "cafPdmChildArrayField.h" +#include "cafPdmChildField.h" #include "cafPdmField.h" #include "cafPdmObject.h" #include "cafPdmProxyValueField.h" @@ -44,7 +45,7 @@ public: RimCustomObjectiveFunctionWeight* addWeight(); std::vector weights() const; - std::vector values() const; + std::vector functionValueForAllCases() const; double value( RimSummaryCase* summaryCase ) const; std::pair minMaxValues() const; bool weightContainsFunctionType( RimObjectiveFunction::FunctionType functionType ) const; @@ -55,20 +56,31 @@ public: void invalidate(); QString formulaString( std::vector vectorSummaryAddresses ) const; + void clearCache(); + private: void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /* = "" */ ) override; void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; RimEnsembleCurveSet* parentCurveSet() const; RimCustomObjectiveFunctionCollection* parentCollection() const; + RimObjectiveFunction* objectiveFunction( RimObjectiveFunction::FunctionType functionType ) const; + caf::PdmFieldHandle* userDescriptionField() override; + void onObjectiveFunctionChanged( const caf::SignalEmitter* emitter ); + private: caf::PdmProxyValueField m_functionTitle; caf::PdmField m_customFunctionTitle; caf::PdmChildArrayField m_weights; - bool m_isValid; + caf::PdmChildArrayField m_objectiveFunctions; + + mutable std::map m_functionValueForAllCases; + + bool m_isValid; }; diff --git a/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunctionWeight.cpp b/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunctionWeight.cpp index 173de72921..540f71f520 100644 --- a/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunctionWeight.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimCustomObjectiveFunctionWeight.cpp @@ -23,6 +23,7 @@ #include "RimCustomObjectiveFunction.h" #include "RimEnsembleCurveSet.h" +#include "RimObjectiveFunctionTools.h" #include "RimSummaryAddress.h" #include "RiuSummaryVectorSelectionDialog.h" @@ -83,7 +84,7 @@ QString RimCustomObjectiveFunctionWeight::title() const } return QString( "%0 * %1::%2%3%4" ) .arg( m_weightValue, 0, 'f', 2 ) - .arg( caf::AppEnum( m_objectiveFunction() ).uiText() ) + .arg( caf::AppEnum( m_objectiveFunction() ).text() ) .arg( addressVector.size() > 1 ? "(" : "" ) .arg( QString::fromStdString( RifEclipseSummaryAddress::generateStringFromAddresses( addressVector, " + " ) ) ) .arg( addressVector.size() > 1 ? ")" : "" ); @@ -156,7 +157,7 @@ void RimCustomObjectiveFunctionWeight::fieldChangedByUi( const caf::PdmFieldHand else if ( changedField == &m_objectiveValuesSelectSummaryAddressPushButton ) { RiuSummaryVectorSelectionDialog dlg( nullptr ); - dlg.enableMultiSelect( true ); + RimObjectiveFunctionTools::configureDialogForObjectiveFunctions( &dlg ); RimSummaryCaseCollection* candidateEnsemble = parentCurveSet()->summaryCaseCollection(); std::vector candidateAddresses; @@ -165,7 +166,6 @@ void RimCustomObjectiveFunctionWeight::fieldChangedByUi( const caf::PdmFieldHand candidateAddresses.push_back( address->address() ); } - dlg.hideSummaryCases(); dlg.setEnsembleAndAddresses( candidateEnsemble, candidateAddresses ); if ( dlg.exec() == QDialog::Accepted ) diff --git a/ApplicationLibCode/ProjectDataModel/Summary/CMakeLists_files.cmake b/ApplicationLibCode/ProjectDataModel/Summary/CMakeLists_files.cmake index 936ae0663e..f6ceffd2be 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/CMakeLists_files.cmake +++ b/ApplicationLibCode/ProjectDataModel/Summary/CMakeLists_files.cmake @@ -38,6 +38,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RimDerivedSummaryCase.h ${CMAKE_CURRENT_LIST_DIR}/RimDerivedEnsembleCaseCollection.h ${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotFilterTextCurveSetEditor.h ${CMAKE_CURRENT_LIST_DIR}/RimObjectiveFunction.h +${CMAKE_CURRENT_LIST_DIR}/RimObjectiveFunctionTools.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -79,6 +80,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RimDerivedSummaryCase.cpp ${CMAKE_CURRENT_LIST_DIR}/RimDerivedEnsembleCaseCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotFilterTextCurveSetEditor.cpp ${CMAKE_CURRENT_LIST_DIR}/RimObjectiveFunction.cpp +${CMAKE_CURRENT_LIST_DIR}/RimObjectiveFunctionTools.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.cpp index 6ea1ab3ab6..3b0ebed67b 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.cpp @@ -25,6 +25,7 @@ #include "RimCustomObjectiveFunctionCollection.h" #include "RimEnsembleCurveFilterCollection.h" #include "RimEnsembleCurveSet.h" +#include "RimObjectiveFunctionTools.h" #include "RimSummaryAddress.h" #include "RimSummaryCase.h" @@ -98,7 +99,11 @@ RimEnsembleCurveFilter::RimEnsembleCurveFilter() m_objectiveValuesSelectSummaryAddressPushButton = false; CAF_PDM_InitFieldNoDefault( &m_objectiveFunction, "ObjectiveFunction", "Objective Function", "", "", "" ); - m_objectiveFunction.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); + m_objectiveFunction = new RimObjectiveFunction(); + m_objectiveFunction.uiCapability()->setUiHidden( true ); + m_objectiveFunction.uiCapability()->setUiTreeHidden( true ); + m_objectiveFunction.uiCapability()->setUiTreeChildrenHidden( true ); + m_objectiveFunction->changed.connect( this, &RimEnsembleCurveFilter::onObjectionFunctionChanged ); CAF_PDM_InitFieldNoDefault( &m_customObjectiveFunction, "CustomObjectiveFunction", "Custom Objective Function", "", "", "" ); m_customObjectiveFunction.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); @@ -202,7 +207,7 @@ QString RimEnsembleCurveFilter::description() const } descriptor = QString( "%1::%2%3%4" ) - .arg( caf::AppEnum( m_objectiveFunction() ).uiText() ) + .arg( m_objectiveFunction()->shortName() ) .arg( addressVector.size() > 1 ? "(" : "" ) .arg( QString::fromStdString( RifEclipseSummaryAddress::generateStringFromAddresses( addressVector, "+" ) ) ) .arg( addressVector.size() > 1 ? ")" : "" ); @@ -359,7 +364,12 @@ void RimEnsembleCurveFilter::fieldChangedByUi( const caf::PdmFieldHandle* change if ( m_objectiveValuesSummaryAddresses.size() == 0 ) { RimSummaryAddress* summaryAddress = new RimSummaryAddress(); - summaryAddress->setAddress( parentCurveSet()->summaryAddress() ); + + RifEclipseSummaryAddress candidateAdr = parentCurveSet()->summaryAddress(); + + auto nativeQuantityName = RimObjectiveFunctionTools::nativeQuantityName( candidateAdr.quantityName() ); + candidateAdr.setQuantityName( nativeQuantityName ); + summaryAddress->setAddress( candidateAdr ); m_objectiveValuesSummaryAddresses.push_back( summaryAddress ); updateAddressesUiField(); } @@ -377,7 +387,7 @@ void RimEnsembleCurveFilter::fieldChangedByUi( const caf::PdmFieldHandle* change else if ( changedField == &m_objectiveValuesSelectSummaryAddressPushButton ) { RiuSummaryVectorSelectionDialog dlg( nullptr ); - dlg.enableMultiSelect( true ); + RimObjectiveFunctionTools::configureDialogForObjectiveFunctions( &dlg ); RimSummaryCaseCollection* candidateEnsemble = parentCurveSet()->summaryCaseCollection(); std::vector candidateAddresses; @@ -386,7 +396,6 @@ void RimEnsembleCurveFilter::fieldChangedByUi( const caf::PdmFieldHandle* change candidateAddresses.push_back( address->address() ); } - dlg.hideSummaryCases(); dlg.setEnsembleAndAddresses( candidateEnsemble, candidateAddresses ); if ( dlg.exec() == QDialog::Accepted ) @@ -394,10 +403,11 @@ void RimEnsembleCurveFilter::fieldChangedByUi( const caf::PdmFieldHandle* change auto curveSelection = dlg.curveSelection(); if ( !curveSelection.empty() ) { + m_objectiveValuesSummaryAddresses.clear(); for ( auto address : curveSelection ) { RimSummaryAddress* summaryAddress = new RimSummaryAddress(); - summaryAddress->setAddress( parentCurveSet()->summaryAddress() ); + summaryAddress->setAddress( address.summaryAddress() ); m_objectiveValuesSummaryAddresses.push_back( summaryAddress ); } this->loadDataAndUpdate(); @@ -455,6 +465,11 @@ void RimEnsembleCurveFilter::defineUiOrdering( QString uiConfigName, caf::PdmUiO { uiOrdering.add( &m_objectiveValuesSummaryAddressesUiField ); uiOrdering.add( &m_objectiveValuesSelectSummaryAddressPushButton, { false, 1, 0 } ); + { + auto equationGroup = uiOrdering.addNewGroup( "Equation" ); + m_objectiveFunction->uiOrdering( "", *equationGroup ); + } + uiOrdering.add( &m_objectiveFunction ); } else if ( m_filterMode() == FilterMode::BY_CUSTOM_OBJECTIVE_FUNCTION ) @@ -543,8 +558,7 @@ std::vector RimEnsembleCurveFilter::applyFilter( const std::vec } else if ( m_filterMode() == FilterMode::BY_OBJECTIVE_FUNCTION ) { - auto objectiveFunction = ensemble->objectiveFunction( m_objectiveFunction() ); - bool hasWarning = false; + bool hasWarning = false; std::vector addresses; for ( auto address : m_objectiveValuesSummaryAddresses() ) @@ -552,7 +566,8 @@ std::vector RimEnsembleCurveFilter::applyFilter( const std::vec addresses.push_back( address->address() ); } - double value = objectiveFunction->value( sumCase, addresses, &hasWarning ); + double value = + m_objectiveFunction->value( sumCase, addresses, curveSet->objectiveFunctionTimeConfig(), &hasWarning ); if ( hasWarning ) continue; if ( value < m_minValue() || value > m_maxValue ) @@ -610,6 +625,25 @@ RimEnsembleCurveSet* RimEnsembleCurveFilter::parentCurveSet() const return curveSet; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEnsembleCurveFilter::onObjectionFunctionChanged( const caf::SignalEmitter* emitter ) +{ + updateMaxMinAndDefaultValues( true ); + + parentCurveSet()->updateAllCurves(); + parentCurveSet()->updateFilterLegend(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEnsembleCurveFilter::updateMaxMinAndDefaultValuesFromParent() +{ + updateMaxMinAndDefaultValues( true ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -653,18 +687,20 @@ void RimEnsembleCurveFilter::updateMaxMinAndDefaultValues( bool forceDefault ) } else if ( m_filterMode() == FilterMode::BY_OBJECTIVE_FUNCTION ) { - auto objectiveFunction = parentCurveSet()->summaryCaseCollection()->objectiveFunction( m_objectiveFunction() ); + auto objectiveFunction = m_objectiveFunction(); std::vector addresses; for ( auto address : m_objectiveValuesSummaryAddresses() ) { addresses.push_back( address->address() ); } - if ( objectiveFunction->isValid( addresses ) ) { - std::pair minMaxValues = objectiveFunction->minMaxValues( addresses ); + auto summaryCases = parentCurveSet()->summaryCaseCollection()->allSummaryCases(); - m_lowerLimit = minMaxValues.first; - m_upperLimit = minMaxValues.second; + auto [minObjValue, maxObjValue] = + objectiveFunction->minMaxValues( summaryCases, addresses, parentCurveSet()->objectiveFunctionTimeConfig() ); + + m_lowerLimit = minObjValue; + m_upperLimit = maxObjValue; if ( forceDefault || !( m_minValue >= m_lowerLimit && m_minValue <= m_upperLimit ) ) m_minValue = m_lowerLimit; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.h b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.h index 9a8b2e1d90..6547150e03 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.h @@ -24,6 +24,7 @@ #include "RimObjectiveFunction.h" #include "cafPdmChildArrayField.h" +#include "cafPdmChildField.h" #include "cafPdmField.h" #include "cafPdmObject.h" #include "cafPdmProxyValueField.h" @@ -84,6 +85,9 @@ public: RimEnsembleCurveSet* parentCurveSet() const; + void onObjectionFunctionChanged( const caf::SignalEmitter* emitter ); + void updateMaxMinAndDefaultValuesFromParent(); + protected: caf::PdmFieldHandle* objectToggleField() override; @@ -92,18 +96,20 @@ private: void updateMaxMinAndDefaultValues( bool forceDefault ); private: - caf::PdmProxyValueField m_filterTitle; - caf::PdmField m_active; - caf::PdmField> m_filterMode; - caf::PdmField m_ensembleParameterName; - caf::PdmChildArrayField m_objectiveValuesSummaryAddresses; - caf::PdmField m_objectiveValuesSummaryAddressesUiField; - caf::PdmField m_objectiveValuesSelectSummaryAddressPushButton; - caf::PdmField> m_objectiveFunction; - caf::PdmPtrField m_customObjectiveFunction; - caf::PdmField m_minValue; - caf::PdmField m_maxValue; - caf::PdmField> m_categories; + caf::PdmProxyValueField m_filterTitle; + caf::PdmField m_active; + caf::PdmField> m_filterMode; + caf::PdmField m_ensembleParameterName; + + caf::PdmChildArrayField m_objectiveValuesSummaryAddresses; + caf::PdmField m_objectiveValuesSummaryAddressesUiField; + caf::PdmField m_objectiveValuesSelectSummaryAddressPushButton; + caf::PdmChildField m_objectiveFunction; + caf::PdmPtrField m_customObjectiveFunction; + + caf::PdmField m_minValue; + caf::PdmField m_maxValue; + caf::PdmField> m_categories; double m_lowerLimit; double m_upperLimit; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp index 7f673eb2ff..921af0d5c0 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp @@ -43,6 +43,7 @@ #include "RimEnsembleStatistics.h" #include "RimEnsembleStatisticsCase.h" #include "RimObjectiveFunction.h" +#include "RimObjectiveFunctionTools.h" #include "RimProject.h" #include "RimRegularLegendConfig.h" #include "RimSummaryAddress.h" @@ -155,13 +156,10 @@ RimEnsembleCurveSet::RimEnsembleCurveSet() m_objectiveValuesSelectSummaryAddressPushButton.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); m_objectiveValuesSelectSummaryAddressPushButton = false; - CAF_PDM_InitFieldNoDefault( &m_objectiveFunction, "ObjectiveFunction", "Objective Function", "", "", "" ); - m_objectiveFunction.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); - CAF_PDM_InitFieldNoDefault( &m_customObjectiveFunction, "CustomObjectiveFunction", "Objective Function", "", "", "" ); m_customObjectiveFunction.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); - CAF_PDM_InitField( &m_showObjectiveFunctionFormula, "ShowObjectiveFunctionFormula", true, "Show Formula in Plot", "", "", "" ); + CAF_PDM_InitField( &m_showObjectiveFunctionFormula, "ShowObjectiveFunctionFormula", true, "Show Text Box in Plot", "", "", "" ); CAF_PDM_InitFieldNoDefault( &m_minDateRange, "MinDateRange", "From", "", "", "" ); m_minDateRange.uiCapability()->setUiEditorTypeName( caf::PdmUiDateEditor::uiEditorTypeName() ); @@ -200,7 +198,13 @@ RimEnsembleCurveSet::RimEnsembleCurveSet() "", "" ); m_customObjectiveFunctions = new RimCustomObjectiveFunctionCollection(); - m_customObjectiveFunctions->objectiveFunctionChanged.connect( this, &RimEnsembleCurveSet::onObjectiveFunctionChanged ); + m_customObjectiveFunctions->objectiveFunctionChanged.connect( this, + &RimEnsembleCurveSet::onCustomObjectiveFunctionChanged ); + + CAF_PDM_InitFieldNoDefault( &m_objectiveFunction, "ObjectiveFunction", "Objective Function", "", "", "" ); + m_objectiveFunction = new RimObjectiveFunction(); + m_objectiveFunction.uiCapability()->setUiHidden( true ); + m_objectiveFunction->changed.connect( this, &RimEnsembleCurveSet::onObjectiveFunctionChanged ); CAF_PDM_InitFieldNoDefault( &m_statistics, "Statistics", "Statistics", "", "", "" ); m_statistics = new RimEnsembleStatistics(); @@ -309,6 +313,7 @@ void RimEnsembleCurveSet::loadDataAndUpdate( bool updateParentPlot ) updateAllCurves(); updateFilterLegend(); updateObjectiveFunctionLegend(); + updateTimeAnnotations(); if ( updateParentPlot ) { @@ -602,7 +607,7 @@ void RimEnsembleCurveSet::setTimeSteps( const std::vector& timeStepIndic //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RimEnsembleCurveSet::selectedTimeSteps() +std::vector RimEnsembleCurveSet::selectedTimeSteps() const { std::vector selectedTimeTTimeSteps; for ( const QDateTime& dateTime : m_selectedTimeSteps.v() ) @@ -648,8 +653,6 @@ void RimEnsembleCurveSet::fieldChangedByUi( const caf::PdmFieldHandle* changedFi } else if ( changedField == &m_yValuesSummaryCaseCollection ) { - // Empty address cache - // m_allAddressesCache.clear(); updateAllCurves(); updateTextInPlot = true; @@ -669,19 +672,12 @@ void RimEnsembleCurveSet::fieldChangedByUi( const caf::PdmFieldHandle* changedFi updateLegendMappingMode(); updateCurveColors(); } - else if ( changedField == &m_objectiveFunction ) - { - updateLegendMappingMode(); - updateCurveColors(); - updateTimeAnnotations(); - updateObjectiveFunctionLegend(); - } else if ( changedField == &m_objectiveValuesSummaryAddressesUiField ) { updateAddressesUiField(); std::vector indices; - indices.push_back( summaryCaseCollection()->objectiveFunction( m_objectiveFunction() )->range().first ); + indices.push_back( 0 ); setTimeSteps( indices ); updateMaxMinAndDefaultValues(); @@ -697,7 +693,6 @@ void RimEnsembleCurveSet::fieldChangedByUi( const caf::PdmFieldHandle* changedFi else if ( changedField == &m_colorMode ) { m_ensembleParameter.uiCapability()->setUiHidden( m_colorMode() != ColorMode::BY_ENSEMBLE_PARAM ); - m_objectiveFunction.uiCapability()->setUiHidden( m_colorMode() != ColorMode::BY_OBJECTIVE_FUNCTION ); if ( m_colorMode() == ColorMode::BY_ENSEMBLE_PARAM ) { @@ -736,10 +731,10 @@ void RimEnsembleCurveSet::fieldChangedByUi( const caf::PdmFieldHandle* changedFi } else if ( changedField == &m_selectedTimeSteps ) { - summaryCaseCollection()->objectiveFunction( m_objectiveFunction() )->setTimeStepList( selectedTimeSteps() ); updateCurveColors(); updateTimeAnnotations(); updateObjectiveFunctionLegend(); + updateMaxMinAndDefaultValues(); } else if ( changedField == &m_minTimeStep || changedField == &m_maxTimeStep ) { @@ -812,7 +807,7 @@ void RimEnsembleCurveSet::fieldChangedByUi( const caf::PdmFieldHandle* changedFi else if ( changedField == &m_objectiveValuesSelectSummaryAddressPushButton ) { RiuSummaryVectorSelectionDialog dlg( nullptr ); - dlg.enableMultiSelect( true ); + RimObjectiveFunctionTools::configureDialogForObjectiveFunctions( &dlg ); RimSummaryCaseCollection* candidateEnsemble = m_yValuesSummaryCaseCollection(); std::vector candidateAddresses; @@ -821,7 +816,6 @@ void RimEnsembleCurveSet::fieldChangedByUi( const caf::PdmFieldHandle* changedFi candidateAddresses.push_back( address->address() ); } - dlg.hideSummaryCases(); dlg.setEnsembleAndAddresses( candidateEnsemble, candidateAddresses ); if ( dlg.exec() == QDialog::Accepted ) @@ -846,11 +840,10 @@ void RimEnsembleCurveSet::fieldChangedByUi( const caf::PdmFieldHandle* changedFi { if ( m_customObjectiveFunction() ) { - if ( m_customObjectiveFunction()->weightContainsFunctionType( RimObjectiveFunction::FunctionType::M2 ) ) + if ( m_customObjectiveFunction()->weightContainsFunctionType( RimObjectiveFunction::FunctionType::F2 ) ) { std::vector indices; - indices.push_back( - summaryCaseCollection()->objectiveFunction( RimObjectiveFunction::FunctionType::M2 )->range().first ); + indices.push_back( 0 ); setTimeSteps( indices ); } @@ -915,7 +908,25 @@ void RimEnsembleCurveSet::updateMaxMinAndDefaultValues() m_minDateRange = QDateTime::fromSecsSinceEpoch( m_minTimeStep ).date(); m_maxDateRange = QDateTime::fromSecsSinceEpoch( m_maxTimeStep ).date(); - summaryCaseCollection()->objectiveFunction( m_objectiveFunction() )->setTimeStepRange( m_minTimeStep(), m_maxTimeStep() ); + for ( auto filter : m_curveFilters->filters() ) + { + filter->updateMaxMinAndDefaultValuesFromParent(); + } + + for ( auto objFunc : m_customObjectiveFunctions->objectiveFunctions() ) + { + objFunc->clearCache(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEnsembleCurveSet::onCustomObjectiveFunctionChanged( const caf::SignalEmitter* emitter ) +{ + updateCurveColors(); + updateFilterLegend(); + updateObjectiveFunctionLegend(); } //-------------------------------------------------------------------------------------------------- @@ -926,6 +937,7 @@ void RimEnsembleCurveSet::onObjectiveFunctionChanged( const caf::SignalEmitter* updateCurveColors(); updateFilterLegend(); updateObjectiveFunctionLegend(); + updateTimeAnnotations(); } //-------------------------------------------------------------------------------------------------- @@ -950,32 +962,41 @@ void RimEnsembleCurveSet::appendColorGroup( caf::PdmUiOrdering& uiOrdering ) { if ( m_colorMode == ColorMode::BY_OBJECTIVE_FUNCTION ) { - m_objectiveFunction.uiCapability()->setUiReadOnly( !m_yValuesSummaryCaseCollection() ); colorsGroup->add( &m_objectiveValuesSummaryAddressesUiField ); colorsGroup->add( &m_objectiveValuesSelectSummaryAddressPushButton, { false, 1, 0 } ); - colorsGroup->add( &m_objectiveFunction ); + + { + auto equationGroup = colorsGroup->addNewGroup( "Equation" ); + m_objectiveFunction->uiOrdering( "", *equationGroup ); + equationGroup->add( &m_showObjectiveFunctionFormula ); + } } else { colorsGroup->add( &m_customObjectiveFunction ); + colorsGroup->add( &m_showObjectiveFunctionFormula ); } - colorsGroup->add( &m_showObjectiveFunctionFormula ); - if ( ( m_colorMode == ColorMode::BY_OBJECTIVE_FUNCTION && - m_objectiveFunction() == RimObjectiveFunction::FunctionType::M1 ) || - ( m_colorMode == ColorMode::BY_CUSTOM_OBJECTIVE_FUNCTION && m_customObjectiveFunction() && - m_customObjectiveFunction()->weightContainsFunctionType( RimObjectiveFunction::FunctionType::M1 ) ) ) + { - colorsGroup->add( &m_minDateRange ); - colorsGroup->add( &m_minTimeStep ); - colorsGroup->add( &m_maxDateRange ); - colorsGroup->add( &m_maxTimeStep ); - } - if ( m_objectiveFunction() == RimObjectiveFunction::FunctionType::M2 || - ( m_customObjectiveFunction() && - m_customObjectiveFunction()->weightContainsFunctionType( RimObjectiveFunction::FunctionType::M2 ) ) ) - { - colorsGroup->add( &m_timeStepFilter ); - colorsGroup->add( &m_selectedTimeSteps ); + auto timeSelectionGroup = colorsGroup->addNewGroup( "Time Selection" ); + + if ( ( m_colorMode == ColorMode::BY_OBJECTIVE_FUNCTION && + m_objectiveFunction()->functionType() == RimObjectiveFunction::FunctionType::F1 ) || + ( m_colorMode == ColorMode::BY_CUSTOM_OBJECTIVE_FUNCTION && m_customObjectiveFunction() && + m_customObjectiveFunction()->weightContainsFunctionType( RimObjectiveFunction::FunctionType::F1 ) ) ) + { + timeSelectionGroup->add( &m_minDateRange ); + timeSelectionGroup->add( &m_minTimeStep ); + timeSelectionGroup->add( &m_maxDateRange ); + timeSelectionGroup->add( &m_maxTimeStep ); + } + if ( m_objectiveFunction()->functionType() == RimObjectiveFunction::FunctionType::F2 || + ( m_customObjectiveFunction() && + m_customObjectiveFunction()->weightContainsFunctionType( RimObjectiveFunction::FunctionType::F2 ) ) ) + { + timeSelectionGroup->add( &m_timeStepFilter ); + timeSelectionGroup->add( &m_selectedTimeSteps ); + } } } } @@ -1354,13 +1375,10 @@ void RimEnsembleCurveSet::updateObjectiveFunctionLegend() addresses.push_back( address->address() ); } - title = "Objective Function"; - description = - QString( "%0 = %1" ) - .arg( m_yValuesSummaryCaseCollection()->objectiveFunction( m_objectiveFunction() )->uiName() ) - .arg( m_yValuesSummaryCaseCollection() - ->objectiveFunction( m_objectiveFunction() ) - ->formulaString( addresses ) ); + title = "Objective Function"; + description = QString( "%0::%1" ) + .arg( m_objectiveFunction()->shortName() ) + .arg( m_objectiveFunction()->formulaString( addresses ) ); } else if ( m_colorMode() == ColorMode::BY_CUSTOM_OBJECTIVE_FUNCTION && m_customObjectiveFunction() ) { @@ -1391,6 +1409,14 @@ void RimEnsembleCurveSet::updateObjectiveFunctionLegend() plot->viewer()->scheduleReplot(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +ObjectiveFunctionTimeConfig RimEnsembleCurveSet::objectiveFunctionTimeConfig() const +{ + return { m_minTimeStep(), m_maxTimeStep(), selectedTimeSteps() }; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1403,16 +1429,7 @@ void RimEnsembleCurveSet::updateCurveColors() QString parameterName = m_ensembleParameter(); { - QString legendTitle; - if ( m_isUsingAutoName ) - { - legendTitle = m_autoGeneratedName(); - } - else - { - legendTitle += m_userDefinedName(); - } - + QString legendTitle = "Ensemble Parameter"; legendTitle += "\n"; legendTitle += parameterName; @@ -1454,33 +1471,29 @@ void RimEnsembleCurveSet::updateCurveColors() RimSummaryCaseCollection* group = m_yValuesSummaryCaseCollection(); { - QString legendTitle; - if ( m_isUsingAutoName ) - { - legendTitle = m_autoGeneratedName(); - } - else - { - legendTitle += m_userDefinedName(); - } + QString legendTitle = "Objective Function"; legendTitle += "\n"; - legendTitle += caf::AppEnum( m_objectiveFunction() ).uiText(); + legendTitle += + caf::AppEnum( m_objectiveFunction()->functionType() ).uiText(); m_legendConfig->setTitle( legendTitle ); } if ( group && !group->allSummaryCases().empty() ) { - auto objectiveFunction = group->objectiveFunction( m_objectiveFunction() ); + auto objectiveFunction = m_objectiveFunction(); std::vector summaryAddresses; for ( auto address : m_objectiveValuesSummaryAddresses() ) { summaryAddresses.push_back( address->address() ); } - if ( objectiveFunction->isValid( summaryAddresses ) ) { - RimEnsembleCurveSetColorManager::initializeLegendConfig( m_legendConfig, objectiveFunction, summaryAddresses ); + RimEnsembleCurveSetColorManager::initializeLegendConfig( m_legendConfig, + objectiveFunction, + group->allSummaryCases(), + summaryAddresses, + objectiveFunctionTimeConfig() ); for ( auto& curve : m_curves ) { if ( curve->summaryAddressY().category() == RifEclipseSummaryAddress::SUMMARY_ENSEMBLE_STATISTICS ) @@ -1489,15 +1502,12 @@ void RimEnsembleCurveSet::updateCurveColors() cvf::Color3f curveColor = RimEnsembleCurveSetColorManager::caseColor( m_legendConfig, rimCase, objectiveFunction, - summaryAddresses ); + summaryAddresses, + objectiveFunctionTimeConfig() ); curve->setColor( curveColor ); curve->updateCurveAppearance(); } } - else if ( m_legendOverlayFrame ) - { - m_legendOverlayFrame->hide(); - } } } else if ( m_colorMode == ColorMode::BY_CUSTOM_OBJECTIVE_FUNCTION ) @@ -1505,16 +1515,7 @@ void RimEnsembleCurveSet::updateCurveColors() RimSummaryCaseCollection* group = m_yValuesSummaryCaseCollection(); { - QString legendTitle; - if ( m_isUsingAutoName ) - { - legendTitle = m_autoGeneratedName(); - } - else - { - legendTitle += m_userDefinedName(); - } - + QString legendTitle = "Custom\nObjective Function"; legendTitle += "\n"; if ( m_customObjectiveFunction() && m_customObjectiveFunction()->isValid() ) { @@ -1589,17 +1590,17 @@ void RimEnsembleCurveSet::updateTimeAnnotations() plot->removeAllTimeAnnotations(); if ( ( m_colorMode() == ColorMode::BY_OBJECTIVE_FUNCTION && - m_objectiveFunction() == RimObjectiveFunction::FunctionType::M1 ) || + m_objectiveFunction()->functionType() == RimObjectiveFunction::FunctionType::F1 ) || ( m_colorMode() == ColorMode::BY_CUSTOM_OBJECTIVE_FUNCTION && m_customObjectiveFunction() && - m_customObjectiveFunction()->weightContainsFunctionType( RimObjectiveFunction::FunctionType::M1 ) ) ) + m_customObjectiveFunction()->weightContainsFunctionType( RimObjectiveFunction::FunctionType::F1 ) ) ) { plot->addTimeRangeAnnotation( m_minTimeStep, m_maxTimeStep ); } if ( ( m_colorMode() == ColorMode::BY_OBJECTIVE_FUNCTION && - m_objectiveFunction() == RimObjectiveFunction::FunctionType::M2 ) || + m_objectiveFunction()->functionType() == RimObjectiveFunction::FunctionType::F2 ) || ( m_colorMode() == ColorMode::BY_CUSTOM_OBJECTIVE_FUNCTION && m_customObjectiveFunction() && - m_customObjectiveFunction()->weightContainsFunctionType( RimObjectiveFunction::FunctionType::M2 ) ) ) + m_customObjectiveFunction()->weightContainsFunctionType( RimObjectiveFunction::FunctionType::F2 ) ) ) { for ( QDateTime timeStep : m_selectedTimeSteps() ) { @@ -1801,7 +1802,7 @@ RimEnsembleCurveSet* RimEnsembleCurveSet::clone() const { RimEnsembleCurveSet* copy = dynamic_cast( this->xmlCapability()->copyByXmlSerialization( caf::PdmDefaultObjectFactory::instance() ) ); - copy->m_yValuesSummaryCaseCollection = m_yValuesSummaryCaseCollection(); + copy->setSummaryCaseCollection( m_yValuesSummaryCaseCollection() ); // Update summary case references for ( size_t i = 0; i < m_curves.size(); i++ ) diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h index 780cef25d4..c61b89b3d7 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h @@ -59,6 +59,7 @@ class RimObjectiveFunction; class RiuDraggableOverlayFrame; class RiaSummaryCurveDefinitionAnalyser; class RiaSummaryCurveDefinition; +class RiuSummaryVectorSelectionDialog; class QwtPlot; class QwtPlotCurve; @@ -125,7 +126,7 @@ public: void updateAllCurves(); void setTimeSteps( const std::vector& timeStepIndices ); - std::vector selectedTimeSteps(); + std::vector selectedTimeSteps() const; void updateStatisticsCurves(); RimEnsembleCurveSet* clone() const; @@ -153,6 +154,8 @@ public: void updateFilterLegend(); void updateObjectiveFunctionLegend(); + ObjectiveFunctionTimeConfig objectiveFunctionTimeConfig() const; + private: void updateEnsembleCurves( const std::vector& sumCases ); void updateStatisticsCurves( const std::vector& sumCases ); @@ -186,6 +189,7 @@ private: void updateAddressesUiField(); void onObjectiveFunctionChanged( const caf::SignalEmitter* emitter ); + void onCustomObjectiveFunctionChanged( const caf::SignalEmitter* emitter ); private: caf::PdmField m_showCurves; @@ -203,25 +207,26 @@ private: caf::PdmField m_color; caf::PdmField m_ensembleParameter; - caf::PdmChildArrayField m_objectiveValuesSummaryAddresses; - caf::PdmField m_objectiveValuesSummaryAddressesUiField; - caf::PdmField m_objectiveValuesSelectSummaryAddressPushButton; - caf::PdmField> m_objectiveFunction; - caf::PdmPtrField m_customObjectiveFunction; - caf::PdmField m_minTimeStep; - caf::PdmField m_maxTimeStep; - caf::PdmField m_minDateRange; - caf::PdmField m_maxDateRange; - caf::PdmField m_timeStepFilter; - caf::PdmField> m_selectedTimeSteps; + caf::PdmChildArrayField m_objectiveValuesSummaryAddresses; + caf::PdmField m_objectiveValuesSummaryAddressesUiField; + caf::PdmField m_objectiveValuesSelectSummaryAddressPushButton; + caf::PdmPtrField m_customObjectiveFunction; + caf::PdmField m_minTimeStep; + caf::PdmField m_maxTimeStep; + caf::PdmField m_minDateRange; + caf::PdmField m_maxDateRange; + caf::PdmField m_timeStepFilter; + caf::PdmField> m_selectedTimeSteps; caf::PdmField> m_plotAxis; - caf::PdmChildField m_legendConfig; - caf::PdmChildField m_curveFilters; - caf::PdmChildField m_statistics; + caf::PdmChildField m_legendConfig; + caf::PdmChildField m_curveFilters; + caf::PdmChildField m_statistics; + caf::PdmChildField m_customObjectiveFunctions; caf::PdmField m_showObjectiveFunctionFormula; + caf::PdmChildField m_objectiveFunction; caf::PdmField m_isUsingAutoName; caf::PdmField m_userDefinedName; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSetColorManager.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSetColorManager.cpp index 49c7a0230e..9dd25882e9 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSetColorManager.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSetColorManager.cpp @@ -133,21 +133,13 @@ void RimEnsembleCurveSetColorManager::initializeLegendConfig( RimRegularLegendCo //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimEnsembleCurveSetColorManager::initializeLegendConfig( RimRegularLegendConfig* legendConfig, - std::shared_ptr objectiveFunction, - std::vector vectorSummaryAddresses ) +void RimEnsembleCurveSetColorManager::initializeLegendConfig( RimRegularLegendConfig* legendConfig, + RimObjectiveFunction* objectiveFunction, + const std::vector& summaryCases, + const std::vector& vectorSummaryAddresses, + const ObjectiveFunctionTimeConfig& timeConfig ) { - double minValue = std::numeric_limits::infinity(); - double maxValue = -std::numeric_limits::infinity(); - - for ( auto value : objectiveFunction->values( vectorSummaryAddresses ) ) - { - if ( value != std::numeric_limits::infinity() ) - { - if ( value < minValue ) minValue = value; - if ( value > maxValue ) maxValue = value; - } - } + auto [minValue, maxValue] = objectiveFunction->minMaxValues( summaryCases, vectorSummaryAddresses, timeConfig ); legendConfig->setAutomaticRanges( minValue, maxValue, minValue, maxValue ); } @@ -161,7 +153,7 @@ void RimEnsembleCurveSetColorManager::initializeLegendConfig( RimRegularLegendCo double minValue = std::numeric_limits::infinity(); double maxValue = -std::numeric_limits::infinity(); - for ( auto value : customObjectiveFunction->values() ) + for ( auto value : customObjectiveFunction->functionValueForAllCases() ) { if ( value != std::numeric_limits::infinity() ) { @@ -210,10 +202,11 @@ cvf::Color3f RimEnsembleCurveSetColorManager::caseColor( const RimRegularLegendC //-------------------------------------------------------------------------------------------------- cvf::Color3f RimEnsembleCurveSetColorManager::caseColor( const RimRegularLegendConfig* legendConfig, RimSummaryCase* summaryCase, - std::shared_ptr objectiveFunction, - std::vector vectorSummaryAddresses ) + RimObjectiveFunction* objectiveFunction, + std::vector vectorSummaryAddresses, + const ObjectiveFunctionTimeConfig& timeConfig ) { - double value = objectiveFunction->value( summaryCase, vectorSummaryAddresses ); + double value = objectiveFunction->value( summaryCase, vectorSummaryAddresses, timeConfig ); if ( value != std::numeric_limits::infinity() ) { return cvf::Color3f( legendConfig->scalarMapper()->mapToColor( value ) ); diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSetColorManager.h b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSetColorManager.h index ec211ee2bf..57f7bd07ac 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSetColorManager.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimEnsembleCurveSetColorManager.h @@ -59,9 +59,11 @@ public: } static void initializeLegendConfig( RimRegularLegendConfig* legendConfig, const EnsembleParameter& parameter ); - static void initializeLegendConfig( RimRegularLegendConfig* legendConfig, - std::shared_ptr objectiveFunction, - std::vector vectorSummaryAddresses ); + static void initializeLegendConfig( RimRegularLegendConfig* legendConfig, + RimObjectiveFunction* objectiveFunction, + const std::vector& summaryCases, + const std::vector& vectorSummaryAddresses, + const ObjectiveFunctionTimeConfig& timeConfig ); static void initializeLegendConfig( RimRegularLegendConfig* legendConfig, caf::PdmPointer customObjectiveFunction ); @@ -72,8 +74,9 @@ public: static cvf::Color3f caseColor( const RimRegularLegendConfig* legendConfig, RimSummaryCase* summaryCase, - std::shared_ptr objectiveFunction, - std::vector vectorSummaryAddresses ); + RimObjectiveFunction* objectiveFunction, + std::vector vectorSummaryAddresses, + const ObjectiveFunctionTimeConfig& timeConfig ); static cvf::Color3f caseColor( const RimRegularLegendConfig* legendConfig, RimSummaryCase* summaryCase, diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunction.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunction.cpp index 26868c0ba0..9f8ff311a9 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunction.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunction.cpp @@ -37,244 +37,145 @@ namespace caf template <> void caf::AppEnum::setUp() { - addItem( RimObjectiveFunction::FunctionType::M1, "M1", "M1" ); - addItem( RimObjectiveFunction::FunctionType::M2, "M2", "M2" ); - setDefault( RimObjectiveFunction::FunctionType::M1 ); + addItem( RimObjectiveFunction::FunctionType::F1, "F1", "Time Range (F1)" ); + addItem( RimObjectiveFunction::FunctionType::F2, "F2", "Selected Time Steps (F2)" ); + setDefault( RimObjectiveFunction::FunctionType::F1 ); } } // namespace caf +CAF_PDM_SOURCE_INIT( RimObjectiveFunction, "RimObjectiveFunction" ); + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString RimObjectiveFunction::uiName() const +RimObjectiveFunction::RimObjectiveFunction() + : changed( this ) + { - if ( m_functionType == FunctionType::M1 ) - { - return QString( "M1" ); - } - else if ( m_functionType == FunctionType::M2 ) - { - return QString( "M2" ); - } - return QString(); + CAF_PDM_InitObject( "Objective Function", "", "", "" ); + + CAF_PDM_InitFieldNoDefault( &m_functionType, "FunctionType", "Function Type", "", "", "" ); + + CAF_PDM_InitField( &m_normalizeByNumberOfObservations, + "NormalizeByNumberOfObservations", + true, + "Normalize by Number of Observations", + "", + "", + "" ); + + CAF_PDM_InitField( &m_normalizeByNumberOfVectors, + "NormalizeByNumberOfVectors", + true, + "Normalize by Number of Vectors", + "", + "", + "" ); + + CAF_PDM_InitField( &m_errorEstimatePercentage, "ErrorEstimatePercentage", 100.0, "Error Estimate [0..100 %]", "", "", "" ); + + CAF_PDM_InitField( &m_useSquaredError, "UseSquaredError", true, "Use Squared Error Term", "", "", "" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimObjectiveFunction::FunctionType RimObjectiveFunction::functionType() +void RimObjectiveFunction::setFunctionType( FunctionType functionType ) { - return m_functionType; + m_functionType = functionType; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimObjectiveFunction::setTimeStepRange( time_t startTimeStep, time_t endTimeStep ) +QString RimObjectiveFunction::shortName() const { - m_startTimeStep = startTimeStep; - m_endTimeStep = endTimeStep; + return caf::AppEnum::text( m_functionType() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimObjectiveFunction::setTimeStepList( std::vector timeSteps ) +RimObjectiveFunction::FunctionType RimObjectiveFunction::functionType() const { - m_timeSteps = timeSteps; + return m_functionType(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimObjectiveFunction::RimObjectiveFunction( const RimSummaryCaseCollection* summaryCaseCollection, FunctionType type ) -{ - m_summaryCaseCollection = summaryCaseCollection; - m_functionType = type; - m_startTimeStep = 0; - m_endTimeStep = INT_MAX; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RimObjectiveFunction::value( size_t caseIndex, - std::vector vectorSummaryAddresses, - bool* hasWarning ) const -{ - auto summaryCases = m_summaryCaseCollection->allSummaryCases(); - - if ( caseIndex < summaryCases.size() ) - { - return value( summaryCases[caseIndex], vectorSummaryAddresses, hasWarning ); - } - return 0.0; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RimObjectiveFunction::value( RimSummaryCase* summaryCase, - std::vector vectorSummaryAddresses, - bool* hasWarning ) const +double RimObjectiveFunction::value( RimSummaryCase* summaryCase, + const std::vector& vectorSummaryAddresses, + const ObjectiveFunctionTimeConfig& timeConfig, + bool* hasWarning ) const { RifSummaryReaderInterface* readerInterface = summaryCase->summaryReader(); if ( readerInterface ) { - if ( m_functionType == FunctionType::M1 ) + double aggregatedObjectiveFunctionValue = 0.0; + + for ( auto vectorSummaryAddress : vectorSummaryAddresses ) { - double sumValues = 0.0; - double sumValuesSquared = 0.0; - double N = 0.0; - for ( auto vectorSummaryAddress : vectorSummaryAddresses ) + std::string s = vectorSummaryAddress.quantityName() + RifReaderEclipseSummary::differenceIdentifier(); + if ( !vectorSummaryAddress.quantityName().empty() ) { - std::string s = vectorSummaryAddress.quantityName() + RifReaderEclipseSummary::differenceIdentifier(); - if ( !vectorSummaryAddress.quantityName().empty() ) + if ( vectorSummaryAddress.quantityName().find( RifReaderEclipseSummary::differenceIdentifier() ) != + std::string::npos ) { - if ( vectorSummaryAddress.quantityName().find( RifReaderEclipseSummary::differenceIdentifier() ) != - std::string::npos ) - { - s = vectorSummaryAddress.quantityName(); - } - RifEclipseSummaryAddress vectorSummaryAddressDiff = vectorSummaryAddress; - vectorSummaryAddressDiff.setQuantityName( s ); + s = vectorSummaryAddress.quantityName(); + } + RifEclipseSummaryAddress vectorSummaryAddressDiff = vectorSummaryAddress; + vectorSummaryAddressDiff.setQuantityName( s ); - if ( readerInterface->allResultAddresses().count( vectorSummaryAddressDiff ) ) + RifEclipseSummaryAddress vectorSummaryAddressHistory = vectorSummaryAddress; + vectorSummaryAddressDiff.setQuantityName( vectorSummaryAddress.quantityName() + + RifReaderEclipseSummary::differenceIdentifier() ); + + if ( readerInterface->allResultAddresses().count( vectorSummaryAddressDiff ) ) + { + const std::vector& allTimeSteps = readerInterface->timeSteps( vectorSummaryAddressDiff ); + std::vector timeStepsForEvaluation = timeStepIndicesForEvaluation( allTimeSteps, timeConfig ); + + std::vector summaryDiffValues; + std::vector summaryHistoryValues; + + if ( readerInterface->values( vectorSummaryAddressDiff, &summaryDiffValues ) && + readerInterface->values( vectorSummaryAddressHistory, &summaryHistoryValues ) ) { - std::vector values; - if ( readerInterface->values( vectorSummaryAddressDiff, &values ) ) + const double functionValue = + computeFunctionValue( summaryDiffValues, summaryHistoryValues, timeStepsForEvaluation ); + + if ( functionValue != std::numeric_limits::infinity() ) { - const std::vector& timeSteps = readerInterface->timeSteps( vectorSummaryAddressDiff ); - - size_t index = 0; - - N += static_cast( values.size() ); - if ( values.size() > 1 ) - { - for ( time_t t : timeSteps ) - { - if ( t >= m_startTimeStep && t <= m_endTimeStep ) - { - const double& value = values[index]; - sumValues += std::abs( value ); - sumValuesSquared += value * value; - } - index++; - } - } - } - } - else - { - RiaLogging::info( "The selected summary address does not have a related difference address." ); - if ( hasWarning ) - { - *hasWarning = true; + aggregatedObjectiveFunctionValue += functionValue; } } } else { - RiaLogging::info( "Invalid summary address." ); - if ( hasWarning ) - { - *hasWarning = true; - } - } - if ( sumValues != 0 ) - { - return sumValues / std::sqrt( ( N * sumValuesSquared - sumValues * sumValues ) / ( N * ( N - 1.0 ) ) ); - } - } - } - else if ( m_functionType == FunctionType::M2 ) - { - double value = 0; - for ( auto vectorSummaryAddress : vectorSummaryAddresses ) - { - std::string s = vectorSummaryAddress.quantityName() + RifReaderEclipseSummary::differenceIdentifier(); - if ( !vectorSummaryAddress.quantityName().empty() ) - { - if ( vectorSummaryAddress.quantityName().find( RifReaderEclipseSummary::differenceIdentifier() ) != - std::string::npos ) - { - s = vectorSummaryAddress.quantityName(); - } - RifEclipseSummaryAddress vectorSummaryAddressDiff = vectorSummaryAddress; - vectorSummaryAddressDiff.setQuantityName( s ); - - if ( readerInterface->allResultAddresses().count( vectorSummaryAddressDiff ) ) - { - std::vector values; - if ( readerInterface->values( vectorSummaryAddressDiff, &values ) ) - { - const std::vector& timeSteps = readerInterface->timeSteps( vectorSummaryAddressDiff ); - - size_t index = 0; - - std::vector xValues( 2, 0 ); - std::vector yValues( 2, 0.0 ); - for ( time_t t : timeSteps ) - { - if ( t >= m_startTimeStep && t <= m_endTimeStep ) - { - if ( xValues.front() == 0 ) - { - xValues[0] = t; - yValues[0] = values[index]; - } - else if ( xValues.back() == 0 ) - { - xValues[1] = t; - yValues[1] = values[index]; - } - else - { - xValues[0] = xValues[1]; - xValues[1] = t; - yValues[0] = yValues[1]; - yValues[1] = values[index]; - } - if ( xValues.back() != 0 ) - { - for ( time_t timeStep : m_timeSteps ) - { - if ( xValues[0] <= timeStep && xValues[1] >= timeStep ) - { - double interpValue = std::abs( - RiaCurveMerger::interpolatedYValue( timeStep, xValues, yValues ) ); - if ( interpValue != HUGE_VAL ) - { - value += interpValue; - } - } - } - } - index++; - } - } - } - } - else - { - RiaLogging::info( "The selected summary address does not have a related difference address." ); - if ( hasWarning ) - { - *hasWarning = true; - } - } - } - else - { - RiaLogging::info( "Invalid summary address." ); + RiaLogging::info( "The selected summary address does not have a related difference address." ); if ( hasWarning ) { *hasWarning = true; } } } - return value; + else + { + RiaLogging::info( "Invalid summary address." ); + if ( hasWarning ) + { + *hasWarning = true; + } + } + + if ( m_normalizeByNumberOfVectors && vectorSummaryAddresses.size() > 0 ) + { + aggregatedObjectiveFunctionValue /= vectorSummaryAddresses.size(); + } + + return aggregatedObjectiveFunctionValue; } } return 0.0; @@ -284,102 +185,40 @@ double RimObjectiveFunction::value( RimSummaryCase* summar /// //-------------------------------------------------------------------------------------------------- std::pair - RimObjectiveFunction::minMaxValues( std::vector vectorSummaryAddresses ) const + RimObjectiveFunction::minMaxValues( const std::vector& summaryCases, + const std::vector& vectorSummaryAddresses, + const ObjectiveFunctionTimeConfig& timeConfig ) const { double minValue = std::numeric_limits::infinity(); double maxValue = -std::numeric_limits::infinity(); - for ( auto value : values( vectorSummaryAddresses ) ) + for ( auto sumCase : summaryCases ) { - if ( value != std::numeric_limits::infinity() ) + auto objValue = value( sumCase, vectorSummaryAddresses, timeConfig ); { - if ( value < minValue ) minValue = value; - if ( value > maxValue ) maxValue = value; + if ( objValue != std::numeric_limits::infinity() ) + { + if ( objValue < minValue ) minValue = objValue; + if ( objValue > maxValue ) maxValue = objValue; + } } } return std::make_pair( minValue, maxValue ); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::pair RimObjectiveFunction::range() const -{ - return std::make_pair( m_startTimeStep, m_endTimeStep ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RimObjectiveFunction::values( std::vector vectorSummaryAddresses ) const -{ - std::vector values; - auto summaryCases = m_summaryCaseCollection->allSummaryCases(); - - bool hasWarning = false; - - for ( size_t index = 0; index < summaryCases.size(); index++ ) - { - values.push_back( value( index, vectorSummaryAddresses, &hasWarning ) ); - if ( hasWarning ) - { - return std::vector(); - } - } - - return values; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimObjectiveFunction::isValid( std::vector vectorSummaryAddresses ) const -{ - bool hasWarning = false; - if ( m_summaryCaseCollection && m_summaryCaseCollection->allSummaryCases().size() > 0 && - m_summaryCaseCollection->allSummaryCases().front() ) - { - value( m_summaryCaseCollection->allSummaryCases().front(), vectorSummaryAddresses, &hasWarning ); - if ( hasWarning ) - { - return false; - } - } - else - { - return false; - } - return true; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimObjectiveFunction::formulaString( std::vector vectorSummaryAddresses ) { QString formula; - if ( m_functionType == FunctionType::M1 ) + + for ( RifEclipseSummaryAddress address : vectorSummaryAddresses ) { - formula += "(" + QString::fromWCharArray( L"\u03A3" ) + "(|"; - QStringList addresses; - for ( RifEclipseSummaryAddress address : vectorSummaryAddresses ) - { - addresses << QString::fromStdString( address.uiText() ); - } - formula += addresses.join( "| + |" ); - formula += "|))/(stdv)"; - } - else if ( m_functionType == FunctionType::M2 ) - { - formula += QString::fromWCharArray( L"\u03A3" ) + "(|"; - QStringList addresses; - for ( RifEclipseSummaryAddress address : vectorSummaryAddresses ) - { - addresses << QString::fromStdString( address.uiText() ); - } - formula += addresses.join( "| + |" ); - formula += "|)"; + QString text = QString::fromStdString( address.uiText() ); + formula += text + "\n"; } + return formula; } @@ -388,5 +227,164 @@ QString RimObjectiveFunction::formulaString( std::vectoruiName() < other.uiName(); + return this->shortName() < other.shortName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimObjectiveFunction::hideFunctionSelection() +{ + m_functionType.uiCapability()->setUiHidden( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimObjectiveFunction::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + uiOrdering.add( &m_functionType ); + uiOrdering.add( &m_normalizeByNumberOfObservations ); + uiOrdering.add( &m_normalizeByNumberOfVectors ); + uiOrdering.add( &m_errorEstimatePercentage ); + uiOrdering.add( &m_useSquaredError ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimObjectiveFunction::fieldChangedByUi( const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue ) +{ + double estimate = m_errorEstimatePercentage; + m_errorEstimatePercentage = std::clamp( estimate, 0.0, 100.0 ); + + changed.send(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimObjectiveFunction::errorEstimate() const +{ + return std::clamp( ( m_errorEstimatePercentage / 100.0 ), 0.0, 1.0 ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimObjectiveFunction::timeStepIndicesForEvaluation( const std::vector& allTimeSteps, + const ObjectiveFunctionTimeConfig& timeConfig ) const +{ + std::vector timeStepIndices; + if ( functionType() == FunctionType::F1 ) + { + for ( size_t i = 0; i < allTimeSteps.size(); i++ ) + { + const auto& t = allTimeSteps[i]; + if ( t >= timeConfig.m_startTimeStep && t <= timeConfig.m_endTimeStep ) + { + timeStepIndices.push_back( i ); + } + } + } + else if ( functionType() == FunctionType::F2 ) + { + for ( const auto& t : timeConfig.m_timeSteps ) + { + for ( size_t i = 0; i < allTimeSteps.size(); i++ ) + { + const auto& candidateTime = allTimeSteps[i]; + if ( t == candidateTime ) + { + timeStepIndices.push_back( i ); + } + } + } + } + + return timeStepIndices; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimObjectiveFunction::computeFunctionValue( const std::vector& summaryDiffValues, + const std::vector& summaryHistoryValues, + const std::vector& evaluationIndices ) const +{ + if ( summaryHistoryValues.size() != summaryDiffValues.size() ) return std::numeric_limits::infinity(); + + const double epsilonErrorEstimate = errorEstimate(); + + double sumValues = 0.0; + double sumValuesSquared = 0.0; + size_t valueCount = evaluationIndices.size(); + + double averageHistoryValue = 0.0; + if ( !summaryHistoryValues.empty() ) + { + for ( auto val : summaryHistoryValues ) + { + averageHistoryValue += val; + } + + averageHistoryValue /= summaryHistoryValues.size(); + } + + // + // 1 ( |ti - tHi| ) n + // value = - * SUM ( ---------- ) + // N ( eps * tHi ) + // + // N : observation count + // ti : simulated value at time step i + // Hti : observed (history) value at time step i + // eps : error estimate (0..1) + // n : 2 - squared error term + // + // https://github.com/OPM/ResInsight/issues/7761 + // + // + // + + const double epsilon = 1e-67; + + for ( size_t timeStepIndex : evaluationIndices ) + { + const double diffValue = std::abs( summaryDiffValues[timeStepIndex] ); + + double historyValue = summaryHistoryValues[timeStepIndex]; + double nominator = std::abs( epsilonErrorEstimate * historyValue ); + if ( nominator < epsilon ) + { + if ( averageHistoryValue > epsilon ) + nominator = averageHistoryValue; + else if ( diffValue > epsilon ) + nominator = diffValue; + else + nominator = 1.0; + } + + const double normalizedDiff = diffValue / nominator; + + sumValues += std::abs( normalizedDiff ); + sumValuesSquared += normalizedDiff * normalizedDiff; + } + + if ( valueCount > 0 ) + { + double functionValue = 0.0; + if ( m_useSquaredError ) + functionValue = sumValuesSquared; + else + functionValue = sumValues; + + if ( m_normalizeByNumberOfObservations ) functionValue /= valueCount; + + return functionValue; + } + + return std::numeric_limits::infinity(); } diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunction.h b/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunction.h index 16ed782bd0..71ced1b1c9 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunction.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunction.h @@ -18,6 +18,10 @@ #pragma once +#include "cafAppEnum.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + #include #include @@ -27,51 +31,71 @@ class RimSummaryCase; class RimSummaryCaseCollection; class RifEclipseSummaryAddress; +class ObjectiveFunctionTimeConfig +{ +public: + time_t m_startTimeStep; + time_t m_endTimeStep; + std::vector m_timeSteps; +}; + //================================================================================================== /// //================================================================================================== -class RimObjectiveFunction +class RimObjectiveFunction : public caf::PdmObject { + CAF_PDM_HEADER_INIT; + +public: + caf::Signal<> changed; + public: enum class FunctionType { - M1 = 0, - M2 + F1 = 0, + F2 }; - QString uiName() const; - RimObjectiveFunction::FunctionType functionType(); + QString shortName() const; + RimObjectiveFunction::FunctionType functionType() const; - void setTimeStepRange( time_t startTime, time_t endTime ); - void setTimeStepList( std::vector timeSteps ); + RimObjectiveFunction(); + void setFunctionType( RimObjectiveFunction::FunctionType functionType ); - RimObjectiveFunction( const RimSummaryCaseCollection* summaryCaseCollection, FunctionType type ); + double value( RimSummaryCase* summaryCase, + const std::vector& vectorSummaryAddresses, + const ObjectiveFunctionTimeConfig& timeConfig, + bool* hasWarning = nullptr ) const; - double value( size_t caseIndex, - std::vector vectorSummaryAddresses, - bool* hasWarning = nullptr ) const; - - double value( RimSummaryCase* summaryCase, - std::vector vectorSummaryAddresses, - bool* hasWarning = nullptr ) const; - - std::pair minMaxValues( std::vector vectorSummaryAddresses ) const; - - std::pair range() const; - - std::vector values( std::vector vectorSummaryAddresses ) const; - - bool isValid( std::vector vectorSummaryAddresses ) const; + std::pair minMaxValues( const std::vector& summaryCases, + const std::vector& vectorSummaryAddresses, + const ObjectiveFunctionTimeConfig& timeConfig ) const; QString formulaString( std::vector vectorSummaryAddresses ); bool operator<( const RimObjectiveFunction& other ) const; -private: - const RimSummaryCaseCollection* m_summaryCaseCollection; + void hideFunctionSelection(); - time_t m_startTimeStep; - time_t m_endTimeStep; - std::vector m_timeSteps; - FunctionType m_functionType; +protected: + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + +private: + double errorEstimate() const; + + std::vector timeStepIndicesForEvaluation( const std::vector& allTimeSteps, + const ObjectiveFunctionTimeConfig& timeConfig ) const; + + double computeFunctionValue( const std::vector& summaryDiffValues, + const std::vector& summaryHistoryValues, + const std::vector& evaluationIndices ) const; + +private: + caf::PdmField> m_functionType; + + caf::PdmField m_normalizeByNumberOfObservations; + caf::PdmField m_errorEstimatePercentage; + caf::PdmField m_useSquaredError; + caf::PdmField m_normalizeByNumberOfVectors; }; diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunctionTools.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunctionTools.cpp new file mode 100644 index 0000000000..8f462fd6b1 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunctionTools.cpp @@ -0,0 +1,95 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021 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 "RimObjectiveFunctionTools.h" + +#include "RifEclipseSummaryAddress.h" + +#include "RiaStdStringTools.h" +#include "RifReaderEclipseSummary.h" +#include "RimCustomObjectiveFunction.h" +#include "RimCustomObjectiveFunctionWeight.h" +#include "RimEnsembleCurveSet.h" +#include "RiuSummaryVectorSelectionDialog.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCustomObjectiveFunctionWeight* RimObjectiveFunctionTools::addWeight( RimCustomObjectiveFunction* customObjectiveFunction ) +{ + if ( !customObjectiveFunction ) return nullptr; + + RimCustomObjectiveFunctionWeight* newWeight = customObjectiveFunction->addWeight(); + + RifEclipseSummaryAddress candidateAdr; + if ( customObjectiveFunction->weights().size() > 1 ) + { + candidateAdr = customObjectiveFunction->weights().front()->summaryAddresses().front(); + } + else + { + candidateAdr = newWeight->parentCurveSet()->summaryAddress(); + } + + auto nativeQuantityName = RimObjectiveFunctionTools::nativeQuantityName( candidateAdr.quantityName() ); + + candidateAdr.setQuantityName( nativeQuantityName ); + newWeight->setSummaryAddress( candidateAdr ); + + return newWeight; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::string RimObjectiveFunctionTools::nativeQuantityName( const std::string& quantityName ) +{ + std::string nativeName = quantityName; + + { + auto stringToRemove = RifReaderEclipseSummary::differenceIdentifier(); + if ( RiaStdStringTools::endsWith( nativeName, stringToRemove ) ) + { + nativeName = nativeName.substr( 0, nativeName.size() - stringToRemove.size() ); + } + } + + { + auto stringToRemove = RifReaderEclipseSummary::historyIdentifier(); + if ( RiaStdStringTools::endsWith( nativeName, stringToRemove ) ) + { + nativeName = nativeName.substr( 0, nativeName.size() - stringToRemove.size() ); + } + } + + return nativeName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimObjectiveFunctionTools::configureDialogForObjectiveFunctions( RiuSummaryVectorSelectionDialog* dialog ) +{ + if ( !dialog ) return; + + dialog->enableMultiSelect( true ); + dialog->hideDifferenceVectors(); + dialog->hideHistoryVectors(); + dialog->hideVectorsWithNoHistory(); + dialog->hideSummaryCases(); +} diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunctionTools.h b/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunctionTools.h new file mode 100644 index 0000000000..b21a44abd5 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimObjectiveFunctionTools.h @@ -0,0 +1,36 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021 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 + +class RimCustomObjectiveFunctionWeight; +class RimCustomObjectiveFunction; +class RiuSummaryVectorSelectionDialog; + +namespace RimObjectiveFunctionTools +{ +RimCustomObjectiveFunctionWeight* addWeight( RimCustomObjectiveFunction* customObjectiveFunction ); + +// Returns a string without string endings 'H' and '_DIFF' +std::string nativeQuantityName( const std::string& quantityName ); + +void configureDialogForObjectiveFunctions( RiuSummaryVectorSelectionDialog* dialog ); + +}; // namespace RimObjectiveFunctionTools diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp index 980c6f062e..29f2622d93 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp @@ -213,9 +213,6 @@ RimSummaryCaseCollection::RimSummaryCaseCollection() m_statisticsEclipseRftReader = new RifReaderEnsembleStatisticsRft( this ); m_commonAddressCount = 0; - - m_objectiveFunctions.push_back( std::make_shared( this, RimObjectiveFunction::FunctionType::M1 ) ); - m_objectiveFunctions.push_back( std::make_shared( this, RimObjectiveFunction::FunctionType::M2 ) ); } //-------------------------------------------------------------------------------------------------- @@ -865,30 +862,6 @@ void RimSummaryCaseCollection::clearEnsembleParametersHashes() } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector> RimSummaryCaseCollection::objectiveFunctions() const -{ - return m_objectiveFunctions; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::shared_ptr - RimSummaryCaseCollection::objectiveFunction( RimObjectiveFunction::FunctionType functionType ) -{ - for ( auto objectiveFunc : m_objectiveFunctions ) - { - if ( objectiveFunc->functionType() == functionType ) - { - return objectiveFunc; - } - } - return m_objectiveFunctions.front(); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h index 935d90ca86..360e128eed 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h @@ -138,9 +138,6 @@ public: void calculateEnsembleParametersIntersectionHash(); void clearEnsembleParametersHashes(); - std::vector> objectiveFunctions() const; - std::shared_ptr objectiveFunction( RimObjectiveFunction::FunctionType functionType ); - void loadDataAndUpdate(); static bool validateEnsembleCases( const std::vector cases ); @@ -181,6 +178,4 @@ private: size_t m_commonAddressCount; // if different address count among cases, set to 0 mutable std::vector m_cachedSortedEnsembleParameters; - - std::vector> m_objectiveFunctions; }; diff --git a/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionDialog.cpp b/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionDialog.cpp index 570419c0d2..3911fe116a 100644 --- a/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionDialog.cpp +++ b/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionDialog.cpp @@ -186,6 +186,30 @@ void RiuSummaryVectorSelectionDialog::enableIndividualEnsembleCaseSelection( boo summaryAddressSelection()->enableIndividualEnsembleCaseSelection( enable ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSummaryVectorSelectionDialog::hideHistoryVectors() +{ + summaryAddressSelection()->hideHistoryVectors( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSummaryVectorSelectionDialog::hideDifferenceVectors() +{ + summaryAddressSelection()->hideDifferenceVectors( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSummaryVectorSelectionDialog::hideVectorsWithNoHistory() +{ + summaryAddressSelection()->hideVectorsWithoutHistory( true ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionDialog.h b/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionDialog.h index 30a17454aa..89f918f957 100644 --- a/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionDialog.h +++ b/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionDialog.h @@ -52,6 +52,10 @@ public: void enableMultiSelect( bool enable ); void enableIndividualEnsembleCaseSelection( bool enable ); + void hideHistoryVectors(); + void hideDifferenceVectors(); + void hideVectorsWithNoHistory(); + private: RiuSummaryVectorSelectionUi* summaryAddressSelection() const; void updateLabel(); diff --git a/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionUi.cpp b/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionUi.cpp index 0531a3ec1e..0393d1d962 100644 --- a/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionUi.cpp +++ b/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionUi.cpp @@ -23,6 +23,7 @@ #include "RiaSummaryCurveDefinition.h" #include "RifEclipseSummaryAddress.h" +#include "RifReaderEclipseSummary.h" #include "RifSummaryReaderInterface.h" #include "RimCalculatedSummaryCase.h" @@ -383,6 +384,10 @@ RiuSummaryVectorSelectionUi::RiuSummaryVectorSelectionUi() m_hideEnsembles = false; m_hideSummaryCases = false; + m_hideDifferenceVectors = false; + m_hideHistoryVectors = false; + m_hideVectorsWithoutHistory = false; + m_prevCurveCount = 0; m_prevCurveSetCount = 0; } @@ -566,6 +571,30 @@ void RiuSummaryVectorSelectionUi::enableIndividualEnsembleCaseSelection( bool en m_showIndividualEnsembleCases = enable; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSummaryVectorSelectionUi::hideDifferenceVectors( bool hide ) +{ + m_hideDifferenceVectors = hide; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSummaryVectorSelectionUi::hideHistoryVectors( bool hide ) +{ + m_hideHistoryVectors = hide; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSummaryVectorSelectionUi::hideVectorsWithoutHistory( bool hide ) +{ + m_hideVectorsWithoutHistory = hide; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1128,6 +1157,40 @@ std::set } } } + + if ( m_hideHistoryVectors || m_hideDifferenceVectors ) + { + std::set filteredAddresses; + + for ( const auto& adr : addrUnion ) + { + if ( m_hideHistoryVectors && adr.isHistoryQuantity() ) continue; + + if ( m_hideDifferenceVectors ) + { + const auto diffText = RifReaderEclipseSummary::differenceIdentifier(); + if ( RiaStdStringTools::endsWith( adr.quantityName(), diffText ) ) continue; + } + + if ( m_hideVectorsWithoutHistory ) + { + auto candidateName = adr.quantityName() + RifReaderEclipseSummary::historyIdentifier(); + + bool found = false; + for ( const auto& ad : addrUnion ) + { + if ( ad.quantityName() == candidateName ) found = true; + } + + if ( !found ) continue; + } + + filteredAddresses.insert( adr ); + } + + addrUnion.swap( filteredAddresses ); + } + return addrUnion; } diff --git a/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionUi.h b/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionUi.h index ab18be2bb6..ebf8fe2ef1 100644 --- a/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionUi.h +++ b/ApplicationLibCode/UserInterface/RiuSummaryVectorSelectionUi.h @@ -63,6 +63,10 @@ public: void hideSummaryCases( bool hide ); void enableIndividualEnsembleCaseSelection( bool enable ); + void hideDifferenceVectors( bool hide ); + void hideHistoryVectors( bool hide ); + void hideVectorsWithoutHistory( bool hide ); + void setFieldChangedHandler( const std::function& handlerFunc ); void setDefaultSelection( const std::vector& defaultCases ); @@ -129,6 +133,10 @@ private: bool m_hideSummaryCases; bool m_showIndividualEnsembleCases; + bool m_hideHistoryVectors; + bool m_hideVectorsWithoutHistory; + bool m_hideDifferenceVectors; + std::function m_toggleChangedHandler; size_t m_prevCurveCount;