Make it possible to exclude partial delta curves

Make sure statistics curves are recomputed on flag change

When toggling "Discard Missing or Incomplete Realizations", make sure the statistics is recomputed and the ensemble plots updated.
This commit is contained in:
Magne Sjaastad
2024-11-15 12:37:22 +01:00
parent dbea0e2593
commit 9b6e441386
20 changed files with 184 additions and 45 deletions

View File

@@ -21,6 +21,7 @@
#include "RiaCurveMerger.h"
#include "RiaLogging.h"
#include "RiaQDateTimeTools.h"
#include "Summary/RiaSummaryTools.h"
#include "RimDeltaSummaryEnsemble.h"
#include "RimProject.h"
@@ -96,7 +97,7 @@ std::pair<bool, std::vector<double>> RimDeltaSummaryCase::values( const RifEclip
if ( auto deltaEnsemble = firstAncestorOfType<RimDeltaSummaryEnsemble>() )
{
if ( deltaEnsemble->discardSummaryAddressOnlyPresentInOneCase() )
if ( deltaEnsemble->discardMissingOrIncompleteRealizations() )
{
RifSummaryReaderInterface* reader1 = m_summaryCase1 ? m_summaryCase1->summaryReader() : nullptr;
RifSummaryReaderInterface* reader2 = m_summaryCase2 ? m_summaryCase2->summaryReader() : nullptr;
@@ -125,6 +126,36 @@ std::pair<bool, std::vector<double>> RimDeltaSummaryCase::values( const RifEclip
return { false, {} };
}
if ( auto deltaEnsemble = firstAncestorOfType<RimDeltaSummaryEnsemble>() )
{
if ( deltaEnsemble->discardMissingOrIncompleteRealizations() )
{
auto ensembleTimeSteps = deltaEnsemble->ensembleTimeSteps();
auto caseTimeSteps = m_dataCache.at( resultAddress ).first;
if ( !ensembleTimeSteps.empty() && !caseTimeSteps.empty() )
{
const auto minTime = *std::min_element( ensembleTimeSteps.begin(), ensembleTimeSteps.end() );
const auto maxTime = *std::max_element( ensembleTimeSteps.begin(), ensembleTimeSteps.end() );
// The last time step for the individual realizations in an ensemble is usually identical. Add a small threshold to improve
// robustness.
const auto timeThreshold = RiaSummaryTools::calculateTimeThreshold( minTime, maxTime );
if ( *caseTimeSteps.rbegin() < timeThreshold )
{
QString txt = "Summary vector " + QString::fromStdString( resultAddress.toEclipseTextAddress() ) +
" has different time steps in the source ensembles, no values are calculated for this vector.";
RiaLogging::warning( txt );
return { false, {} };
}
}
}
}
return { true, m_dataCache.at( resultAddress ).second };
}
@@ -187,6 +218,8 @@ void RimDeltaSummaryCase::setSummaryCases( RimSummaryCase* sumCase1, RimSummaryC
{
m_summaryCase1 = sumCase1;
m_summaryCase2 = sumCase2;
clearCache();
}
//--------------------------------------------------------------------------------------------------
@@ -218,8 +251,15 @@ void RimDeltaSummaryCase::calculate( const RifEclipseSummaryAddress& address ) c
fixedTimeStepCase2 = m_fixedTimeStepIndex;
}
bool includeIncompleteCurves = true;
if ( auto deltaEnsemble = firstAncestorOfType<RimDeltaSummaryEnsemble>() )
{
includeIncompleteCurves = !deltaEnsemble->discardMissingOrIncompleteRealizations();
}
auto itAndIsInsertedPair = m_dataCache.insert(
std::make_pair( address, calculateDerivedValues( reader1, fixedTimeStepCase1, reader2, fixedTimeStepCase2, m_operator(), address ) ) );
std::make_pair( address,
calculateDerivedValues( reader1, fixedTimeStepCase1, reader2, fixedTimeStepCase2, m_operator(), address, includeIncompleteCurves ) ) );
// Check if we got any data. If not, erase the map entry to comply with previous behavior
@@ -237,7 +277,8 @@ std::pair<std::vector<time_t>, std::vector<double>> RimDeltaSummaryCase::calcula
RifSummaryReaderInterface* reader2,
int fixedTimeStepCase2,
DerivedSummaryOperator summaryOperator,
const RifEclipseSummaryAddress& address )
const RifEclipseSummaryAddress& address,
bool includeIncompleteCurves )
{
using ResultPair = std::pair<std::vector<time_t>, std::vector<double>>;
@@ -278,7 +319,7 @@ std::pair<std::vector<time_t>, std::vector<double>> RimDeltaSummaryCase::calcula
RiaTimeHistoryCurveMerger merger;
merger.addCurveData( reader1->timeSteps( address ), values1 );
merger.addCurveData( reader2->timeSteps( address ), values2 );
merger.computeInterpolatedValues();
merger.computeInterpolatedValues( includeIncompleteCurves );
const std::vector<double>& allValues1 = merger.interpolatedYValuesForAllXValues( 0 );
const std::vector<double>& allValues2 = merger.interpolatedYValuesForAllXValues( 1 );
@@ -321,12 +362,20 @@ QString RimDeltaSummaryCase::caseName() const
//--------------------------------------------------------------------------------------------------
void RimDeltaSummaryCase::createSummaryReaderInterface()
{
m_allResultAddresses.clear();
if ( m_summaryCase1 )
{
if ( !m_summaryCase1->summaryReader() )
{
m_summaryCase1->createSummaryReaderInterface();
}
if ( m_summaryCase1->summaryReader() )
{
auto adr = m_summaryCase1->summaryReader()->allResultAddresses();
m_allResultAddresses.insert( adr.begin(), adr.end() );
}
}
if ( m_summaryCase2 )
{
@@ -334,6 +383,12 @@ void RimDeltaSummaryCase::createSummaryReaderInterface()
{
m_summaryCase2->createSummaryReaderInterface();
}
if ( m_summaryCase2->summaryReader() )
{
auto adr = m_summaryCase2->summaryReader()->allResultAddresses();
m_allResultAddresses.insert( adr.begin(), adr.end() );
}
}
}
@@ -351,6 +406,8 @@ RifSummaryReaderInterface* RimDeltaSummaryCase::summaryReader()
void RimDeltaSummaryCase::setOperator( DerivedSummaryOperator oper )
{
m_operator = oper;
clearCache();
}
//--------------------------------------------------------------------------------------------------
@@ -380,6 +437,14 @@ void RimDeltaSummaryCase::clearData( const RifEclipseSummaryAddress& address ) c
m_dataCache.erase( address );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDeltaSummaryCase::clearCache()
{
m_dataCache.clear();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -75,7 +75,8 @@ public:
RifSummaryReaderInterface* reader2,
int fixedTimeStepCase2,
DerivedSummaryOperator m_operator,
const RifEclipseSummaryAddress& address );
const RifEclipseSummaryAddress& address,
bool includeIncompleteCurves );
void createSummaryReaderInterface() override;
RifSummaryReaderInterface* summaryReader() override;
@@ -98,6 +99,8 @@ private:
void calculate( const RifEclipseSummaryAddress& address ) const;
void clearData( const RifEclipseSummaryAddress& address ) const;
void clearCache();
private:
caf::PdmPtrField<RimSummaryCase*> m_summaryCase1;
caf::PdmPtrField<RimSummaryCase*> m_summaryCase2;

View File

@@ -76,11 +76,11 @@ RimDeltaSummaryEnsemble::RimDeltaSummaryEnsemble()
CAF_PDM_InitField( &m_matchOnParameters, "MatchOnParameters", false, "Match On Parameters" );
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_matchOnParameters );
CAF_PDM_InitField( &m_discardAddressPresentInOneSourceCase,
"DiscardAddressPresentInOneSourceCase",
false,
"Discard Vectors if Missing in One of the Source Ensembles" );
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_discardAddressPresentInOneSourceCase );
CAF_PDM_InitField( &m_discardMissingOrIncompleteRealizations,
"DiscardMissingOrIncompleteRealizations",
true,
"Discard Missing or Incomplete Realizations" );
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_discardMissingOrIncompleteRealizations );
CAF_PDM_InitFieldNoDefault( &m_useFixedTimeStep, "UseFixedTimeStep", "Use Fixed Time Step" );
CAF_PDM_InitField( &m_fixedTimeStepIndex, "FixedTimeStepIndex", 0, "Time Step" );
@@ -206,9 +206,9 @@ void RimDeltaSummaryEnsemble::createDerivedEnsembleCases()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDeltaSummaryEnsemble::discardSummaryAddressOnlyPresentInOneCase() const
bool RimDeltaSummaryEnsemble::discardMissingOrIncompleteRealizations() const
{
return m_discardAddressPresentInOneSourceCase();
return m_discardMissingOrIncompleteRealizations();
}
//--------------------------------------------------------------------------------------------------
@@ -314,7 +314,7 @@ void RimDeltaSummaryEnsemble::defineUiOrdering( QString uiConfigName, caf::PdmUi
}
uiOrdering.add( &m_matchOnParameters );
uiOrdering.add( &m_discardAddressPresentInOneSourceCase );
uiOrdering.add( &m_discardMissingOrIncompleteRealizations );
uiOrdering.skipRemainingFields( true );
@@ -337,7 +337,8 @@ void RimDeltaSummaryEnsemble::fieldChangedByUi( const caf::PdmFieldHandle* chang
doUpdateCases = true;
doShowDialog = true;
}
else if ( changedField == &m_operator || changedField == &m_useFixedTimeStep || changedField == &m_fixedTimeStepIndex )
else if ( changedField == &m_operator || changedField == &m_useFixedTimeStep || changedField == &m_fixedTimeStepIndex ||
changedField == &m_discardMissingOrIncompleteRealizations )
{
doUpdate = true;
doUpdateCases = true;
@@ -370,12 +371,12 @@ void RimDeltaSummaryEnsemble::fieldChangedByUi( const caf::PdmFieldHandle* chang
}
}
updateReferringCurveSets();
updateReferringCurveSetsZoomAll();
// If other derived ensembles are referring to this ensemble, update their cases as well
for ( auto refering : findReferringEnsembles() )
{
refering->updateReferringCurveSets();
refering->updateReferringCurveSetsZoomAll();
}
}
}

View File

@@ -62,7 +62,7 @@ public:
void createDerivedEnsembleCases();
bool discardSummaryAddressOnlyPresentInOneCase() const;
bool discardMissingOrIncompleteRealizations() const;
private:
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
@@ -93,7 +93,7 @@ private:
caf::PdmField<bool> m_swapEnsemblesButton;
caf::PdmField<QString> m_caseCount;
caf::PdmField<bool> m_matchOnParameters;
caf::PdmField<bool> m_discardAddressPresentInOneSourceCase;
caf::PdmField<bool> m_discardMissingOrIncompleteRealizations;
caf::PdmField<caf::AppEnum<FixedTimeStepMode>> m_useFixedTimeStep;
caf::PdmField<int> m_fixedTimeStepIndex;

View File

@@ -341,6 +341,9 @@ void RimEnsembleCurveSet::loadDataAndUpdate( bool updateParentPlot )
{
m_yValuesSummaryAddressUiField = m_yValuesSummaryAddress->address();
// Recreate the statistics case, as the statistics data is cached internally
m_ensembleStatCaseY = std::make_unique<RimEnsembleStatisticsCase>();
m_curveFilters->loadDataAndUpdate();
updateAddressesUiField();
@@ -1168,6 +1171,13 @@ void RimEnsembleCurveSet::defineUiOrdering( QString uiConfigName, caf::PdmUiOrde
m_statistics->defaultUiOrdering( isXAxisSummaryVector(), *statGroup );
bool enableIncomplete = true;
if ( dynamic_cast<RimDeltaSummaryEnsemble*>( m_yValuesSummaryEnsemble() ) )
{
enableIncomplete = false;
}
m_statistics->enableIncludeIncompleteCurves( enableIncomplete );
caf::PdmUiGroup* statAppearance = statGroup->addNewGroupWithKeyword( "Appearance", "StatisticsAppearance" );
statAppearance->add( &m_statisticsUseCustomAppearance );
if ( m_statisticsUseCustomAppearance() == AppearanceMode::CUSTOM )

View File

@@ -164,6 +164,14 @@ void RimEnsembleStatistics::enableCurveLabels( bool enable )
m_showCurveLabels = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleStatistics::enableIncludeIncompleteCurves( bool enable )
{
m_includeIncompleteCurves.uiCapability()->setUiReadOnly( !enable );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -48,6 +48,8 @@ public:
bool showCurveLabels() const;
void enableCurveLabels( bool enable );
void enableIncludeIncompleteCurves( bool enable );
cvf::Color3f color() const { return m_color; }
void setColor( const cvf::Color3f& color );

View File

@@ -143,14 +143,14 @@ void RimEnsembleStatisticsCase::calculate( const std::vector<RimSummaryCase*>& s
// Use first summary case to get unit system and other meta data
m_firstSummaryCase = summaryCases.front();
const auto [minTime, maxTime] = findMinMaxTime( summaryCases, inputAddress );
RiaDefines::DateTimePeriod period = findBestResamplingPeriod( minTime, maxTime );
const auto [minTime, maxTime] = findMinMaxTime( summaryCases, inputAddress );
// The last time step for the individual realizations in an ensemble is usually identical. Add a small threshold to improve robustness.
const auto timeThreshold = maxTime - ( maxTime - minTime ) * 0.01;
const auto timeThreshold = RiaSummaryTools::calculateTimeThreshold( minTime, maxTime );
RiaDefines::DateTimePeriod period = findBestResamplingPeriod( minTime, maxTime );
RiaTimeHistoryCurveMerger curveMerger;
for ( const auto& sumCase : summaryCases )
{
const auto& reader = sumCase->summaryReader();
@@ -169,7 +169,7 @@ void RimEnsembleStatisticsCase::calculate( const std::vector<RimSummaryCase*>& s
}
}
curveMerger.computeInterpolatedValues();
curveMerger.computeInterpolatedValues( includeIncompleteCurves );
std::vector<std::vector<double>> curveValues;
for ( size_t i = 0; i < curveMerger.curveCount(); i++ )

View File

@@ -201,7 +201,7 @@ void RimSummaryCaseMainCollection::removeCases( std::vector<RimSummaryCase*>& ca
for ( RimSummaryEnsemble* summaryCaseCollection : m_caseCollections )
{
summaryCaseCollection->updateReferringCurveSets();
summaryCaseCollection->updateReferringCurveSetsZoomAll();
}
dataSourceHasChanged.send();

View File

@@ -655,7 +655,9 @@ void RimSummaryCurve::onLoadDataAndUpdate( bool updateParentPlot )
RiaTimeHistoryCurveMerger curveMerger;
curveMerger.addCurveData( curveTimeStepsX, curveValuesX );
curveMerger.addCurveData( curveTimeStepsY, curveValuesY );
curveMerger.computeInterpolatedValues();
bool includeValuesFromPartialCurves = true;
curveMerger.computeInterpolatedValues( includeValuesFromPartialCurves );
if ( !curveMerger.allXValues().empty() )
{
@@ -1285,7 +1287,9 @@ void RimSummaryCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
RiaTimeHistoryCurveMerger curveMerger;
curveMerger.addCurveData( curveTimeStepsX, curveValuesX );
curveMerger.addCurveData( curveTimeStepsY, curveValuesY );
curveMerger.computeInterpolatedValues();
bool includeValuesFromPartialCurves = true;
curveMerger.computeInterpolatedValues( includeValuesFromPartialCurves );
if ( curveMerger.validIntervalsForAllXValues().empty() )
{

View File

@@ -32,6 +32,7 @@
#include "RimSummaryAddressCollection.h"
#include "RimSummaryCase.h"
#include "RimSummaryEnsembleTools.h"
#include "RimSummaryPlot.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmObjectScriptingCapability.h"
@@ -103,7 +104,7 @@ void RimSummaryEnsemble::removeCase( RimSummaryCase* summaryCase, bool notifyCha
if ( notifyChange )
{
updateReferringCurveSets();
updateReferringCurveSetsZoomAll();
}
if ( m_isEnsemble && m_cases.size() != caseCountBeforeRemove )
@@ -134,7 +135,7 @@ void RimSummaryEnsemble::addCase( RimSummaryCase* summaryCase )
if ( !derivedEnsemble ) continue;
derivedEnsemble->createDerivedEnsembleCases();
derivedEnsemble->updateReferringCurveSets();
derivedEnsemble->updateReferringCurveSetsZoomAll();
}
if ( m_isEnsemble )
@@ -143,7 +144,7 @@ void RimSummaryEnsemble::addCase( RimSummaryCase* summaryCase )
calculateEnsembleParametersIntersectionHash();
}
updateReferringCurveSets();
updateReferringCurveSetsZoomAll();
clearChildNodes();
}
@@ -616,7 +617,7 @@ void RimSummaryEnsemble::onLoadDataAndUpdate()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryEnsemble::updateReferringCurveSets()
void RimSummaryEnsemble::updateReferringCurveSets( bool doZoomAll )
{
// Update curve set referring to this group
std::vector<caf::PdmObject*> referringObjects = objectsWithReferringPtrFieldsOfType<PdmObject>();
@@ -629,10 +630,34 @@ void RimSummaryEnsemble::updateReferringCurveSets()
if ( curveSet )
{
curveSet->loadDataAndUpdate( updateParentPlot );
if ( doZoomAll )
{
if ( auto parentPlot = curveSet->firstAncestorOrThisOfType<RimSummaryPlot>() )
{
parentPlot->zoomAll();
}
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryEnsemble::updateReferringCurveSets()
{
updateReferringCurveSets( false );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryEnsemble::updateReferringCurveSetsZoomAll()
{
updateReferringCurveSets( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -98,6 +98,7 @@ public:
void onCalculationUpdated();
void updateReferringCurveSets();
void updateReferringCurveSetsZoomAll();
RiaSummaryAddressAnalyzer* addressAnalyzer();
@@ -110,6 +111,8 @@ private:
QString nameAndItemCount() const;
void updateIcon();
void updateReferringCurveSets( bool doZoomAll );
void initAfterRead() override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;