Support ensemble cross plot curves

* Remove use of RifEnsembleStatisticsReader
* Add RimSummaryAddressSelector and RimEnsembleCrossPlotStatisticsCase
* Remove RifEnsembleStatisticsReader
* Add support for cross plot x-axis selection
* Support source stepping on ensemble cross plot curves
* Add isXAxisSummaryVector
This commit is contained in:
Magne Sjaastad
2023-09-25 12:45:47 +02:00
committed by GitHub
parent 55687c4e3e
commit fb288f602d
21 changed files with 1219 additions and 352 deletions

View File

@@ -41,11 +41,11 @@ RiaSummaryCurveDefinition::RiaSummaryCurveDefinition()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaSummaryCurveDefinition::RiaSummaryCurveDefinition( RimSummaryCase* summaryCase,
const RifEclipseSummaryAddress& summaryAddress,
RiaSummaryCurveDefinition::RiaSummaryCurveDefinition( RimSummaryCase* summaryCaseY,
const RifEclipseSummaryAddress& summaryAddressY,
bool isEnsembleCurve )
: m_summaryCaseY( summaryCase )
, m_summaryAddressY( summaryAddress )
: m_summaryCaseY( summaryCaseY )
, m_summaryAddressY( summaryAddressY )
, m_summaryCaseX( nullptr )
, m_summaryAddressX( RifEclipseSummaryAddress::timeAddress() )
, m_ensemble( nullptr )
@@ -56,9 +56,9 @@ RiaSummaryCurveDefinition::RiaSummaryCurveDefinition( RimSummaryCase*
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaSummaryCurveDefinition::RiaSummaryCurveDefinition( RimSummaryCaseCollection* ensemble, const RifEclipseSummaryAddress& summaryAddress )
RiaSummaryCurveDefinition::RiaSummaryCurveDefinition( RimSummaryCaseCollection* ensemble, const RifEclipseSummaryAddress& summaryAddressY )
: m_summaryCaseY( nullptr )
, m_summaryAddressY( summaryAddress )
, m_summaryAddressY( summaryAddressY )
, m_summaryCaseX( nullptr )
, m_summaryAddressX( RifEclipseSummaryAddress::timeAddress() )
, m_ensemble( ensemble )

View File

@@ -38,8 +38,8 @@ class RiaSummaryCurveDefinition
{
public:
RiaSummaryCurveDefinition();
explicit RiaSummaryCurveDefinition( RimSummaryCase* summaryCase, const RifEclipseSummaryAddress& summaryAddress, bool isEnsembleCurve );
explicit RiaSummaryCurveDefinition( RimSummaryCaseCollection* ensemble, const RifEclipseSummaryAddress& summaryAddress );
explicit RiaSummaryCurveDefinition( RimSummaryCase* summaryCaseY, const RifEclipseSummaryAddress& summaryAddressY, bool isEnsembleCurve );
explicit RiaSummaryCurveDefinition( RimSummaryCaseCollection* ensemble, const RifEclipseSummaryAddress& summaryAddressY );
// Y Axis
RimSummaryCase* summaryCaseY() const;

View File

@@ -45,7 +45,6 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCaseRestartSelector.h
${CMAKE_CURRENT_LIST_DIR}/RifCaseRealizationParametersReader.h
${CMAKE_CURRENT_LIST_DIR}/RifFileParseTools.h
${CMAKE_CURRENT_LIST_DIR}/RifEnsembleStatisticsReader.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderEnsembleStatisticsRft.h
${CMAKE_CURRENT_LIST_DIR}/RifDerivedEnsembleReader.h
${CMAKE_CURRENT_LIST_DIR}/RifActiveCellsReader.h
@@ -136,7 +135,6 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCaseRestartSelector.cpp
${CMAKE_CURRENT_LIST_DIR}/RifCaseRealizationParametersReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifFileParseTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEnsembleStatisticsReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifDerivedEnsembleReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifActiveCellsReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifCsvDataTableFormatter.cpp

View File

@@ -1,116 +0,0 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifEnsembleStatisticsReader.h"
#include "RimEnsembleCurveSet.h"
#include "RimEnsembleStatisticsCase.h"
#include "RimSummaryCaseCollection.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEnsembleStatisticsReader::RifEnsembleStatisticsReader( RimEnsembleStatisticsCase* ensStatCase )
{
CVF_ASSERT( ensStatCase );
m_ensembleStatCase = ensStatCase;
m_allResultAddresses =
std::set<RifEclipseSummaryAddress>( { RifEclipseSummaryAddress::ensembleStatisticsAddress( ENSEMBLE_STAT_P10_QUANTITY_NAME, "" ),
RifEclipseSummaryAddress::ensembleStatisticsAddress( ENSEMBLE_STAT_P50_QUANTITY_NAME, "" ),
RifEclipseSummaryAddress::ensembleStatisticsAddress( ENSEMBLE_STAT_P90_QUANTITY_NAME, "" ),
RifEclipseSummaryAddress::ensembleStatisticsAddress( ENSEMBLE_STAT_MEAN_QUANTITY_NAME, "" ) } );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<time_t> RifEnsembleStatisticsReader::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{
if ( !validateAddress( resultAddress ) ) return {};
return m_ensembleStatCase->timeSteps();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEnsembleStatisticsReader::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{
if ( !validateAddress( resultAddress ) ) return false;
const std::vector<double>* sourceData = nullptr;
auto quantityName = resultAddress.ensembleStatisticsVectorName();
if ( quantityName == ENSEMBLE_STAT_P10_QUANTITY_NAME )
sourceData = &m_ensembleStatCase->p10();
else if ( quantityName == ENSEMBLE_STAT_P50_QUANTITY_NAME )
sourceData = &m_ensembleStatCase->p50();
else if ( quantityName == ENSEMBLE_STAT_P90_QUANTITY_NAME )
sourceData = &m_ensembleStatCase->p90();
else if ( quantityName == ENSEMBLE_STAT_MEAN_QUANTITY_NAME )
sourceData = &m_ensembleStatCase->mean();
if ( !sourceData ) return false;
values->clear();
values->reserve( sourceData->size() );
for ( auto val : *sourceData )
values->push_back( val );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RifEnsembleStatisticsReader::unitName( const RifEclipseSummaryAddress& resultAddress ) const
{
std::string retval;
// The stat case does not have a unit set, so pick up the unit from one of the input cases, if possible
auto cases = m_ensembleStatCase->curveSet()->summaryCaseCollection()->allSummaryCases();
if ( cases.size() > 0 )
{
QString qName = QString::fromStdString( resultAddress.vectorName() );
std::string orgQName = qName.split( ":" )[1].toStdString();
RifEclipseSummaryAddress address = RifEclipseSummaryAddress( resultAddress );
address.setVectorName( orgQName );
retval = cases[0]->summaryReader()->unitName( address );
}
return retval;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaDefines::EclipseUnitSystem RifEnsembleStatisticsReader::unitSystem() const
{
return m_ensembleStatCase->unitSystem();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEnsembleStatisticsReader::validateAddress( const RifEclipseSummaryAddress& address ) const
{
return address.category() == RifEclipseSummaryAddressDefines::SummaryCategory::SUMMARY_ENSEMBLE_STATISTICS &&
!address.vectorName().empty();
}

View File

@@ -77,18 +77,16 @@ void RimDataSourceSteppingTools::modifyCurrentIndex( caf::PdmValueField*
bool RimDataSourceSteppingTools::updateAddressIfMatching( const QVariant& oldValue,
const QVariant& newValue,
RifEclipseSummaryAddressDefines::SummaryCategory category,
RifEclipseSummaryAddress* adr )
RifEclipseSummaryAddress& adr )
{
if ( !adr ) return false;
if ( category == RifEclipseSummaryAddressDefines::SummaryCategory::SUMMARY_REGION )
{
int oldInt = oldValue.toInt();
int newInt = newValue.toInt();
if ( adr->regionNumber() == oldInt )
if ( adr.regionNumber() == oldInt )
{
adr->setRegion( newInt );
adr.setRegion( newInt );
return true;
}
@@ -98,9 +96,9 @@ bool RimDataSourceSteppingTools::updateAddressIfMatching( const QVariant&
int oldInt = oldValue.toInt();
int newInt = newValue.toInt();
if ( adr->aquiferNumber() == oldInt )
if ( adr.aquiferNumber() == oldInt )
{
adr->setAquiferNumber( newInt );
adr.setAquiferNumber( newInt );
return true;
}
@@ -110,9 +108,9 @@ bool RimDataSourceSteppingTools::updateAddressIfMatching( const QVariant&
std::string oldString = oldValue.toString().toStdString();
std::string newString = newValue.toString().toStdString();
if ( adr->groupName() == oldString )
if ( adr.groupName() == oldString )
{
adr->setGroupName( newString );
adr.setGroupName( newString );
return true;
}
@@ -122,9 +120,9 @@ bool RimDataSourceSteppingTools::updateAddressIfMatching( const QVariant&
std::string oldString = oldValue.toString().toStdString();
std::string newString = newValue.toString().toStdString();
if ( adr->networkName() == oldString )
if ( adr.networkName() == oldString )
{
adr->setNetworkName( newString );
adr.setNetworkName( newString );
return true;
}
@@ -134,9 +132,9 @@ bool RimDataSourceSteppingTools::updateAddressIfMatching( const QVariant&
std::string oldString = oldValue.toString().toStdString();
std::string newString = newValue.toString().toStdString();
if ( adr->wellName() == oldString )
if ( adr.wellName() == oldString )
{
adr->setWellName( newString );
adr.setWellName( newString );
return true;
}
@@ -146,9 +144,9 @@ bool RimDataSourceSteppingTools::updateAddressIfMatching( const QVariant&
{
std::string oldString = oldValue.toString().toStdString();
std::string newString = newValue.toString().toStdString();
if ( adr->blockAsString() == oldString )
if ( adr.blockAsString() == oldString )
{
adr->setCellIjk( newString );
adr.setCellIjk( newString );
return true;
}
@@ -157,11 +155,11 @@ bool RimDataSourceSteppingTools::updateAddressIfMatching( const QVariant&
{
std::string oldString = oldValue.toString().toStdString();
std::string newString = newValue.toString().toStdString();
if ( adr->formatUiTextRegionToRegion() == oldString )
if ( adr.formatUiTextRegionToRegion() == oldString )
{
auto [region1, region2] = RifEclipseSummaryAddress::regionToRegionPairFromUiText( newString );
adr->setRegion( region1 );
adr->setRegion2( region2 );
adr.setRegion( region1 );
adr.setRegion2( region2 );
return true;
}
@@ -170,9 +168,9 @@ bool RimDataSourceSteppingTools::updateAddressIfMatching( const QVariant&
{
int oldInt = oldValue.toInt();
int newInt = newValue.toInt();
if ( adr->wellSegmentNumber() == oldInt )
if ( adr.wellSegmentNumber() == oldInt )
{
adr->setWellSegmentNumber( newInt );
adr.setWellSegmentNumber( newInt );
return true;
}
@@ -184,48 +182,14 @@ bool RimDataSourceSteppingTools::updateAddressIfMatching( const QVariant&
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDataSourceSteppingTools::updateHistoryAndSummaryQuantityIfMatching( const QVariant& oldValue,
const QVariant& newValue,
RifEclipseSummaryAddress* adr )
bool RimDataSourceSteppingTools::updateQuantityIfMatching( const QVariant& oldValue, const QVariant& newValue, RifEclipseSummaryAddress& adr )
{
if ( !adr ) return false;
std::string oldString = oldValue.toString().toStdString();
std::string newString = newValue.toString().toStdString();
if ( adr->vectorName() == oldString )
if ( adr.vectorName() == oldString )
{
adr->setVectorName( newString );
return true;
}
std::string correspondingOldString = RiaSummaryAddressAnalyzer::correspondingHistorySummaryCurveName( oldString );
std::string correspondingNewString = RiaSummaryAddressAnalyzer::correspondingHistorySummaryCurveName( newString );
if ( adr->vectorName() == correspondingOldString )
{
adr->setVectorName( correspondingNewString );
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDataSourceSteppingTools::updateQuantityIfMatching( const QVariant& oldValue, const QVariant& newValue, RifEclipseSummaryAddress* adr )
{
if ( !adr ) return false;
std::string oldString = oldValue.toString().toStdString();
std::string newString = newValue.toString().toStdString();
if ( adr->vectorName() == oldString )
{
adr->setVectorName( newString );
adr.setVectorName( newString );
return true;
}

View File

@@ -39,9 +39,7 @@ public:
static bool updateAddressIfMatching( const QVariant& oldValue,
const QVariant& newValue,
RifEclipseSummaryAddressDefines::SummaryCategory category,
RifEclipseSummaryAddress* adr );
RifEclipseSummaryAddress& adr );
static bool updateHistoryAndSummaryQuantityIfMatching( const QVariant& oldValue, const QVariant& newValue, RifEclipseSummaryAddress* adr );
static bool updateQuantityIfMatching( const QVariant& oldValue, const QVariant& newValue, RifEclipseSummaryAddress* adr );
static bool updateQuantityIfMatching( const QVariant& oldValue, const QVariant& newValue, RifEclipseSummaryAddress& adr );
};

View File

@@ -292,7 +292,7 @@ void RimSummaryCalculation::substituteVariables( std::vector<SummaryCalculationV
{
if ( v.summaryAddress.category() == address.category() )
{
RimDataSourceSteppingTools::updateAddressIfMatching( oldValue, newValue, address.category(), &v.summaryAddress );
RimDataSourceSteppingTools::updateAddressIfMatching( oldValue, newValue, address.category(), v.summaryAddress );
}
}
}

View File

@@ -52,6 +52,8 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimSummaryTableTools.h
${CMAKE_CURRENT_LIST_DIR}/RimSummaryDeclineCurve.h
${CMAKE_CURRENT_LIST_DIR}/RimSummaryRegressionAnalysisCurve.h
${CMAKE_CURRENT_LIST_DIR}/RimSummaryAddressSelector.h
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleCrossPlotStatisticsCase.h
)
set(SOURCE_GROUP_SOURCE_FILES
@@ -108,6 +110,8 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimSummaryTableTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryDeclineCurve.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryRegressionAnalysisCurve.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryAddressSelector.cpp
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleCrossPlotStatisticsCase.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})

View File

@@ -0,0 +1,277 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimEnsembleCrossPlotStatisticsCase.h"
#include "RiaSummaryTools.h"
#include "RiaTimeHistoryCurveResampler.h"
#include "RigStatisticsMath.h"
#include "RimEnsembleCurveSet.h"
#include "RimEnsembleStatisticsCase.h"
#include "RimSummaryCaseCollection.h"
#include <limits>
#include <set>
#include <vector>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleCrossPlotStatisticsCase::RimEnsembleCrossPlotStatisticsCase()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimEnsembleCrossPlotStatisticsCase::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{
if ( m_adrX.isValid() )
{
auto stringToTest = resultAddress.vectorName();
auto it = stringToTest.find( m_adrX.vectorName() );
if ( it != std::string::npos )
{
*values = m_binnedXValues;
return true;
}
}
auto quantityName = resultAddress.ensembleStatisticsVectorName();
if ( quantityName == ENSEMBLE_STAT_P10_QUANTITY_NAME )
*values = m_p10Data;
else if ( quantityName == ENSEMBLE_STAT_P50_QUANTITY_NAME )
*values = m_p50Data;
else if ( quantityName == ENSEMBLE_STAT_P90_QUANTITY_NAME )
*values = m_p90Data;
else if ( quantityName == ENSEMBLE_STAT_MEAN_QUANTITY_NAME )
*values = m_meanData;
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimEnsembleCrossPlotStatisticsCase::unitName( const RifEclipseSummaryAddress& resultAddress ) const
{
if ( m_firstSummaryCase && m_firstSummaryCase->summaryReader() )
{
return m_firstSummaryCase->summaryReader()->unitName( resultAddress );
}
return "Ensemble Cross Plot - Undefined Unit";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimEnsembleCrossPlotStatisticsCase::caseName() const
{
return "Ensemble Statistics";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleCrossPlotStatisticsCase::createSummaryReaderInterface()
{
// Nothing to do, as RimEnsembleCrossPlotStatisticsCase inherits RifSummaryReaderInterface
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifSummaryReaderInterface* RimEnsembleCrossPlotStatisticsCase::summaryReader()
{
return this;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleCrossPlotStatisticsCase::calculate( const std::vector<RimSummaryCase*>& sumCases,
const RifEclipseSummaryAddress& inputAddressX,
const RifEclipseSummaryAddress& inputAddressY,
bool includeIncompleteCurves,
int binCount,
int sampleCountThreshold )
{
if ( !inputAddressX.isValid() || !inputAddressY.isValid() ) return;
if ( sumCases.empty() ) return;
clearData();
// Use first summary case to get unit system and other meta data
m_firstSummaryCase = sumCases.front();
m_adrX = inputAddressX;
m_adrY = inputAddressY;
std::vector<std::pair<double, double>> pairs;
auto [minTimeStep, maxTimeStep] = RimEnsembleStatisticsCase::findMinMaxTimeStep( sumCases, inputAddressX );
RiaDefines::DateTimePeriod period = RimEnsembleStatisticsCase::findBestResamplingPeriod( minTimeStep, maxTimeStep );
for ( const auto& sumCase : sumCases )
{
const auto& reader = sumCase->summaryReader();
if ( reader )
{
const std::vector<time_t>& timeSteps = reader->timeSteps( inputAddressX );
std::vector<double> valuesX;
reader->values( inputAddressX, &valuesX );
if ( valuesX.empty() ) continue;
std::vector<double> valuesY;
reader->values( inputAddressY, &valuesY );
if ( valuesY.empty() ) continue;
if ( !includeIncompleteCurves && timeSteps.size() != valuesX.size() ) continue;
if ( !includeIncompleteCurves && timeSteps.size() != valuesY.size() ) continue;
auto [resampledTimeStepsX, resampledValuesX] =
RiaSummaryTools::resampledValuesForPeriod( inputAddressX, timeSteps, valuesX, period );
auto [resampledTimeStepsY, resampledValuesY] =
RiaSummaryTools::resampledValuesForPeriod( inputAddressY, timeSteps, valuesY, period );
size_t minimumCount = std::min( resampledValuesX.size(), resampledValuesY.size() );
for ( size_t i = 0; i < minimumCount; i++ )
{
pairs.emplace_back( std::make_pair( resampledValuesX[i], resampledValuesY[i] ) );
}
}
}
// Sort on X values
std::sort( pairs.begin(), pairs.end(), []( const auto& lhs, const auto& rhs ) { return lhs.first < rhs.first; } );
const auto p = std::minmax_element( pairs.begin(), pairs.end() );
auto minX = p.first->first;
auto maxX = p.second->first;
auto rangeX = maxX - minX;
auto deltaRangeX = rangeX / binCount;
double currentX = minX;
std::vector<double> binnedYValues;
for ( auto v : pairs )
{
if ( v.first < currentX + deltaRangeX )
{
binnedYValues.emplace_back( v.second );
}
else
{
// Add statistics for current bin if sample count is above threshold
// TODO: Add option to skip bin if unique realization count is below threshold
if ( static_cast<int>( binnedYValues.size() ) > sampleCountThreshold )
{
double p10, p50, p90, mean;
RigStatisticsMath::calculateStatisticsCurves( binnedYValues, &p10, &p50, &p90, &mean, RigStatisticsMath::PercentileStyle::SWITCHED );
m_p10Data.push_back( p10 );
m_p50Data.push_back( p50 );
m_p90Data.push_back( p90 );
m_meanData.push_back( mean );
m_binnedXValues.emplace_back( currentX );
}
currentX += deltaRangeX;
binnedYValues.clear();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimEnsembleCrossPlotStatisticsCase::hasP10Data() const
{
return !m_p10Data.empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimEnsembleCrossPlotStatisticsCase::hasP50Data() const
{
return !m_p50Data.empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimEnsembleCrossPlotStatisticsCase::hasP90Data() const
{
return !m_p90Data.empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimEnsembleCrossPlotStatisticsCase::hasMeanData() const
{
return !m_meanData.empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaDefines::EclipseUnitSystem RimEnsembleCrossPlotStatisticsCase::unitSystem() const
{
if ( m_firstSummaryCase && m_firstSummaryCase->summaryReader() )
{
return m_firstSummaryCase->summaryReader()->unitSystem();
}
return RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<time_t> RimEnsembleCrossPlotStatisticsCase::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{
if ( m_firstSummaryCase && m_firstSummaryCase->summaryReader() )
{
return m_firstSummaryCase->summaryReader()->timeSteps( resultAddress );
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleCrossPlotStatisticsCase::clearData()
{
m_binnedXValues.clear();
m_p10Data.clear();
m_p50Data.clear();
m_p90Data.clear();
m_meanData.clear();
m_firstSummaryCase = nullptr;
}

View File

@@ -1,6 +1,6 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
// Copyright (C) 2023- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,28 +18,57 @@
#pragma once
#include "RiaDateTimeDefines.h"
#include "RiaDefines.h"
#include "RifSummaryReaderInterface.h"
class RimEnsembleStatisticsCase;
#include "RimSummaryCase.h"
class RifEclipseSummaryAddress;
//==================================================================================================
///
//==================================================================================================
class RifEnsembleStatisticsReader : public RifSummaryReaderInterface
class RimEnsembleCrossPlotStatisticsCase : public RimSummaryCase, public RifSummaryReaderInterface
{
public:
RifEnsembleStatisticsReader( RimEnsembleStatisticsCase* ensStatCase );
RimEnsembleCrossPlotStatisticsCase();
void calculate( const std::vector<RimSummaryCase*>& sumCases,
const RifEclipseSummaryAddress& inputAddressX,
const RifEclipseSummaryAddress& inputAddressY,
bool includeIncompleteCurves,
int binCount,
int sampleCountThreshold );
bool hasP10Data() const;
bool hasP50Data() const;
bool hasP90Data() const;
bool hasMeanData() const;
QString caseName() const override;
void createSummaryReaderInterface() override;
RifSummaryReaderInterface* summaryReader() override;
RiaDefines::EclipseUnitSystem unitSystem() const override;
std::vector<time_t> timeSteps( const RifEclipseSummaryAddress& resultAddress ) const override;
bool values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const override;
std::string unitName( const RifEclipseSummaryAddress& resultAddress ) const override;
RiaDefines::EclipseUnitSystem unitSystem() const override;
private:
void clearData();
private:
bool validateAddress( const RifEclipseSummaryAddress& address ) const;
std::vector<double> m_p10Data;
std::vector<double> m_p50Data;
std::vector<double> m_p90Data;
std::vector<double> m_meanData;
private:
RimEnsembleStatisticsCase* m_ensembleStatCase;
RifEclipseSummaryAddress m_adrX;
RifEclipseSummaryAddress m_adrY;
std::vector<double> m_binnedXValues;
caf::PdmPointer<RimSummaryCase> m_firstSummaryCase;
};

View File

@@ -30,8 +30,6 @@
#include "RimSummaryCalculationCollection.h"
#include "SummaryPlotCommands/RicSummaryPlotEditorUi.h"
#include "RifEnsembleStatisticsReader.h"
#include "RimCustomObjectiveFunction.h"
#include "RimCustomObjectiveFunctionCollection.h"
#include "RimDerivedEnsembleCaseCollection.h"
@@ -43,10 +41,12 @@
#include "RimEnsembleStatisticsCase.h"
#include "RimObjectiveFunction.h"
#include "RimObjectiveFunctionTools.h"
#include "RimPlotAxisProperties.h"
#include "RimPlotAxisPropertiesInterface.h"
#include "RimProject.h"
#include "RimRegularLegendConfig.h"
#include "RimSummaryAddress.h"
#include "RimSummaryAddressSelector.h"
#include "RimSummaryCalculationCollection.h"
#include "RimSummaryCase.h"
#include "RimSummaryCaseCollection.h"
@@ -139,6 +139,19 @@ RimEnsembleCurveSet::RimEnsembleCurveSet()
CAF_PDM_InitFieldNoDefault( &m_resampling, "Resampling", "Resampling" );
// X Axis
CAF_PDM_InitField( &m_xAxisType,
"HorizontalAxisType",
caf::AppEnum<RiaDefines::HorizontalAxisType>( RiaDefines::HorizontalAxisType::TIME ),
"Axis Type" );
CAF_PDM_InitFieldNoDefault( &m_xAddressSelector, "XAddressSelector", "" );
m_xAddressSelector = new RimSummaryAddressSelector;
m_xAddressSelector.uiCapability()->setUiTreeHidden( true );
m_xAddressSelector.uiCapability()->setUiTreeChildrenHidden( true );
m_xAddressSelector->addressChanged.connect( this, &RimEnsembleCurveSet::onXAxisAddressChanged );
CAF_PDM_InitField( &m_colorMode, "ColorMode", caf::AppEnum<ColorMode>( ColorMode::SINGLE_COLOR_WITH_ALPHA ), "Coloring Mode" );
CAF_PDM_InitField( &m_colorForRealizations, "Color", RiaColorTools::textColor3f(), "Color" );
@@ -228,9 +241,8 @@ RimEnsembleCurveSet::RimEnsembleCurveSet()
m_summaryAddressNameTools = new RimSummaryCurveAutoName;
m_ensembleStatCase.reset( new RimEnsembleStatisticsCase( this ) );
m_ensembleStatCase->createSummaryReaderInterface();
m_ensembleStatCase->createRftReaderInterface();
m_ensembleStatCaseY.reset( new RimEnsembleStatisticsCase() );
m_ensembleStatCaseXY.reset( new RimEnsembleCrossPlotStatisticsCase() );
m_disableStatisticCurves = false;
m_isCurveSetFiltered = false;
@@ -406,6 +418,31 @@ void RimEnsembleCurveSet::setSummaryAddress( RifEclipseSummaryAddress address )
m_objectiveValuesSummaryAddresses.push_back( summaryAddress );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleCurveSet::setCurveAddress( RiaSummaryCurveAddress address )
{
setSummaryAddress( address.summaryAddressY() );
setSummaryAddressX( address.summaryAddressX() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleCurveSet::setSummaryAddressX( RifEclipseSummaryAddress address )
{
m_xAddressSelector->setAddress( address );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimEnsembleCurveSet::isXAxisSummaryVector() const
{
return m_xAxisType() == RiaDefines::HorizontalAxisType::SUMMARY_VECTOR;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -429,7 +466,12 @@ RifEclipseSummaryAddress RimEnsembleCurveSet::summaryAddress() const
//--------------------------------------------------------------------------------------------------
RiaSummaryCurveAddress RimEnsembleCurveSet::curveAddress() const
{
return RiaSummaryCurveAddress( summaryAddress(), RifEclipseSummaryAddress::timeAddress() );
if ( m_xAxisType() == RiaDefines::HorizontalAxisType::TIME )
{
return RiaSummaryCurveAddress( RifEclipseSummaryAddress::timeAddress(), summaryAddress() );
}
return RiaSummaryCurveAddress( m_xAddressSelector->summaryAddress(), summaryAddress() );
}
//--------------------------------------------------------------------------------------------------
@@ -678,6 +720,42 @@ void RimEnsembleCurveSet::fieldChangedByUi( const caf::PdmFieldHandle* changedFi
updateTextInPlot = true;
}
else if ( &m_xAxisType == changedField )
{
if ( m_xAxisType() == RiaDefines::HorizontalAxisType::TIME )
{
// TODO: How to handle this?
// m_xPlotAxisProperties = plot->timeAxisProperties();
}
else if ( isXAxisSummaryVector() )
{
if ( !m_xAddressSelector->ensemble() )
{
m_xAddressSelector->setEnsemble( summaryCaseCollection() );
m_xAddressSelector->setAddress( summaryAddress() );
}
if ( !m_xAddressSelector->plotAxisProperties() )
{
RiuPlotAxis plotAxis = RiuPlotAxis::defaultBottomForSummaryVectors();
if ( auto axis = plot->axisPropertiesForPlotAxis( plotAxis ) )
{
m_xAddressSelector->setPlotAxisProperties( axis );
}
else
{
RimPlotAxisProperties* newPlotAxisProperties =
plot->addNewAxisProperties( RiaDefines::PlotAxis::PLOT_AXIS_BOTTOM, "Bottom Axis" );
plot->updateConnectedEditors();
m_xAddressSelector->setPlotAxisProperties( newPlotAxisProperties );
}
}
}
plot->updateAxes();
plot->updatePlotTitle();
updateAllCurves();
}
else if ( changedField == &m_resampling )
{
updateAllCurves();
@@ -914,8 +992,10 @@ void RimEnsembleCurveSet::defineObjectEditorAttribute( QString uiConfigName, caf
//--------------------------------------------------------------------------------------------------
void RimEnsembleCurveSet::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
m_yValuesSummaryAddressUiField = m_yValuesSummaryAddress->address();
{
caf::PdmUiGroup* curveDataGroup = uiOrdering.addNewGroup( "Summary Vector Y" );
caf::PdmUiGroup* curveDataGroup = uiOrdering.addNewGroup( "Summary Vector" );
curveDataGroup->add( &m_yValuesSummaryCaseCollection );
curveDataGroup->add( &m_yValuesSummaryAddressUiField );
curveDataGroup->add( &m_yPushButtonSelectSummaryAddress, { false, 1, 0 } );
@@ -923,6 +1003,16 @@ void RimEnsembleCurveSet::defineUiOrdering( QString uiConfigName, caf::PdmUiOrde
curveDataGroup->add( &m_plotAxisProperties );
}
{
caf::PdmUiGroup* curveDataGroup = uiOrdering.addNewGroup( "Summary Vector X Axis" );
curveDataGroup->add( &m_xAxisType );
if ( isXAxisSummaryVector() )
{
m_xAddressSelector->uiOrdering( uiConfigName, *curveDataGroup );
}
}
appendColorGroup( uiOrdering );
{
@@ -986,6 +1076,14 @@ void RimEnsembleCurveSet::onCustomObjectiveFunctionChanged( const caf::SignalEmi
updateObjectiveFunctionLegend();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleCurveSet::onXAxisAddressChanged( const caf::SignalEmitter* emitter )
{
updateAllCurves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -1790,8 +1888,6 @@ void RimEnsembleCurveSet::updateEnsembleCurves( const std::vector<RimSummaryCase
if ( m_statistics->hideEnsembleCurves() ) return;
setLeftOrRightAxisY( axisY() );
RimSummaryAddress* addr = m_yValuesSummaryAddress();
if ( plot && addr->address().category() != RifEclipseSummaryAddressDefines::SummaryCategory::SUMMARY_INVALID )
{
@@ -1817,6 +1913,14 @@ void RimEnsembleCurveSet::updateEnsembleCurves( const std::vector<RimSummaryCase
addCurve( curve );
curve->setLeftOrRightAxisY( axisY() );
if ( isXAxisSummaryVector() )
{
curve->setAxisTypeX( RiaDefines::HorizontalAxisType::SUMMARY_VECTOR );
curve->setSummaryCaseX( sumCase );
curve->setSummaryAddressX( m_xAddressSelector->summaryAddress() );
if ( m_xAddressSelector->plotAxisProperties() )
curve->setTopOrBottomAxisX( m_xAddressSelector->plotAxisProperties()->plotAxis() );
}
newSummaryCurves.push_back( curve );
}
@@ -1877,22 +1981,70 @@ void RimEnsembleCurveSet::updateStatisticsCurves( const std::vector<RimSummaryCa
else
statCases = group->allSummaryCases();
}
m_ensembleStatCase->calculate( statCases, m_statistics->includeIncompleteCurves() );
if ( isXAxisSummaryVector() )
{
m_ensembleStatCaseXY->calculate( statCases,
m_xAddressSelector->summaryAddress(),
summaryAddress(),
m_statistics->includeIncompleteCurves(),
m_statistics->crossPlotCurvesBinCount(),
m_statistics->crossPlotCurvesSampleCountThresholdPerBin() );
}
else
{
m_ensembleStatCaseY->calculate( statCases, summaryAddress(), m_statistics->includeIncompleteCurves() );
}
}
std::vector<RifEclipseSummaryAddress> addresses;
std::vector<RiaSummaryCurveAddress> addresses;
if ( m_statistics->isActive() )
{
RifEclipseSummaryAddress dataAddress = m_yValuesSummaryAddress->address();
if ( isXAxisSummaryVector() )
{
RifEclipseSummaryAddress dataAddressY = m_yValuesSummaryAddress->address();
RifEclipseSummaryAddress dataAddressX = m_xAddressSelector->summaryAddress();
if ( m_statistics->showP10Curve() && m_ensembleStatCase->hasP10Data() )
addresses.push_back( SAddr::ensembleStatisticsAddress( ENSEMBLE_STAT_P10_QUANTITY_NAME, dataAddress.vectorName() ) );
if ( m_statistics->showP50Curve() && m_ensembleStatCase->hasP50Data() )
addresses.push_back( SAddr::ensembleStatisticsAddress( ENSEMBLE_STAT_P50_QUANTITY_NAME, dataAddress.vectorName() ) );
if ( m_statistics->showP90Curve() && m_ensembleStatCase->hasP90Data() )
addresses.push_back( SAddr::ensembleStatisticsAddress( ENSEMBLE_STAT_P90_QUANTITY_NAME, dataAddress.vectorName() ) );
if ( m_statistics->showMeanCurve() && m_ensembleStatCase->hasMeanData() )
addresses.push_back( SAddr::ensembleStatisticsAddress( ENSEMBLE_STAT_MEAN_QUANTITY_NAME, dataAddress.vectorName() ) );
auto getStatisticsAddress = []( const std::string& statisticsVectorName,
const RifEclipseSummaryAddress& addrX,
const RifEclipseSummaryAddress& addrY ) -> RiaSummaryCurveAddress
{
auto xStatAddress = SAddr::ensembleStatisticsAddress( statisticsVectorName, addrX.vectorName() );
auto yStatAddress = SAddr::ensembleStatisticsAddress( statisticsVectorName, addrY.vectorName() );
return RiaSummaryCurveAddress( xStatAddress, yStatAddress );
};
if ( m_statistics->showP10Curve() && m_ensembleStatCaseXY->hasP10Data() )
addresses.push_back( getStatisticsAddress( ENSEMBLE_STAT_P10_QUANTITY_NAME, dataAddressX, dataAddressY ) );
if ( m_statistics->showP50Curve() && m_ensembleStatCaseXY->hasP50Data() )
addresses.push_back( getStatisticsAddress( ENSEMBLE_STAT_P50_QUANTITY_NAME, dataAddressX, dataAddressY ) );
if ( m_statistics->showP90Curve() && m_ensembleStatCaseXY->hasP90Data() )
addresses.push_back( getStatisticsAddress( ENSEMBLE_STAT_P90_QUANTITY_NAME, dataAddressX, dataAddressY ) );
if ( m_statistics->showMeanCurve() && m_ensembleStatCaseXY->hasMeanData() )
addresses.push_back( getStatisticsAddress( ENSEMBLE_STAT_MEAN_QUANTITY_NAME, dataAddressX, dataAddressY ) );
}
else
{
RifEclipseSummaryAddress dataAddressY = m_yValuesSummaryAddress->address();
auto getStatisticsAddress = []( const std::string& statisticsVectorName, const RifEclipseSummaryAddress& addrY ) -> RiaSummaryCurveAddress
{
auto xStatAddress = RifEclipseSummaryAddress::timeAddress();
auto yStatAddress = SAddr::ensembleStatisticsAddress( statisticsVectorName, addrY.vectorName() );
return RiaSummaryCurveAddress( xStatAddress, yStatAddress );
};
if ( m_statistics->showP10Curve() && m_ensembleStatCaseY->hasP10Data() )
addresses.push_back( getStatisticsAddress( ENSEMBLE_STAT_P10_QUANTITY_NAME, dataAddressY ) );
if ( m_statistics->showP50Curve() && m_ensembleStatCaseY->hasP50Data() )
addresses.push_back( getStatisticsAddress( ENSEMBLE_STAT_P50_QUANTITY_NAME, dataAddressY ) );
if ( m_statistics->showP90Curve() && m_ensembleStatCaseY->hasP90Data() )
addresses.push_back( getStatisticsAddress( ENSEMBLE_STAT_P90_QUANTITY_NAME, dataAddressY ) );
if ( m_statistics->showMeanCurve() && m_ensembleStatCaseY->hasMeanData() )
addresses.push_back( getStatisticsAddress( ENSEMBLE_STAT_MEAN_QUANTITY_NAME, dataAddressY ) );
}
}
deleteStatisticsCurves();
@@ -1900,6 +2052,13 @@ void RimEnsembleCurveSet::updateStatisticsCurves( const std::vector<RimSummaryCa
auto plot = firstAncestorOrThisOfType<RimSummaryPlot>();
if ( plot && plot->plotWidget() )
{
RimSummaryCase* summaryCase = nullptr;
if ( isXAxisSummaryVector() )
summaryCase = m_ensembleStatCaseXY.get();
else
summaryCase = m_ensembleStatCaseY.get();
for ( auto address : addresses )
{
auto curve = new RimSummaryCurve();
@@ -1908,19 +2067,28 @@ void RimEnsembleCurveSet::updateStatisticsCurves( const std::vector<RimSummaryCa
curve->setColor( m_statistics->color() );
curve->setResampling( m_resampling() );
auto symbol = statisticsCurveSymbolFromAddress( address );
auto symbol = statisticsCurveSymbolFromAddress( address.summaryAddressY() );
curve->setSymbol( symbol );
curve->setSymbolSize( statisticsCurveSymbolSize( symbol ) );
curve->setSymbolSkipDistance( 150 );
if ( m_statistics->showCurveLabels() )
{
curve->setSymbolLabel( QString::fromStdString( address.ensembleStatisticsVectorName() ) );
curve->setSymbolLabel( QString::fromStdString( address.summaryAddressY().ensembleStatisticsVectorName() ) );
}
curve->setLineStyle( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID );
curve->setSummaryCaseY( m_ensembleStatCase.get() );
curve->setSummaryAddressYAndApplyInterpolation( address );
curve->setSummaryCaseY( summaryCase );
curve->setSummaryAddressYAndApplyInterpolation( address.summaryAddressY() );
curve->setLeftOrRightAxisY( axisY() );
if ( isXAxisSummaryVector() )
{
curve->setAxisTypeX( RiaDefines::HorizontalAxisType::SUMMARY_VECTOR );
curve->setSummaryCaseX( summaryCase );
curve->setSummaryAddressX( address.summaryAddressX() );
if ( m_xAddressSelector->plotAxisProperties() )
curve->setTopOrBottomAxisX( m_xAddressSelector->plotAxisProperties()->plotAxis() );
}
curve->setShowInLegend( m_statistics->showStatisticsCurveLegends() );
curve->updateCurveVisibility();
@@ -2058,7 +2226,9 @@ bool RimEnsembleCurveSet::isFiltered() const
//--------------------------------------------------------------------------------------------------
bool RimEnsembleCurveSet::hasP10Data() const
{
return m_ensembleStatCase->hasP10Data();
if ( isXAxisSummaryVector() ) return m_ensembleStatCaseXY->hasP10Data();
return m_ensembleStatCaseY->hasP10Data();
}
//--------------------------------------------------------------------------------------------------
@@ -2066,7 +2236,9 @@ bool RimEnsembleCurveSet::hasP10Data() const
//--------------------------------------------------------------------------------------------------
bool RimEnsembleCurveSet::hasP50Data() const
{
return m_ensembleStatCase->hasP50Data();
if ( isXAxisSummaryVector() ) return m_ensembleStatCaseXY->hasP50Data();
return m_ensembleStatCaseY->hasP50Data();
}
//--------------------------------------------------------------------------------------------------
@@ -2074,7 +2246,9 @@ bool RimEnsembleCurveSet::hasP50Data() const
//--------------------------------------------------------------------------------------------------
bool RimEnsembleCurveSet::hasP90Data() const
{
return m_ensembleStatCase->hasP90Data();
if ( isXAxisSummaryVector() ) return m_ensembleStatCaseXY->hasP90Data();
return m_ensembleStatCaseY->hasP90Data();
}
//--------------------------------------------------------------------------------------------------
@@ -2082,7 +2256,9 @@ bool RimEnsembleCurveSet::hasP90Data() const
//--------------------------------------------------------------------------------------------------
bool RimEnsembleCurveSet::hasMeanData() const
{
return m_ensembleStatCase->hasMeanData();
if ( isXAxisSummaryVector() ) return m_ensembleStatCaseXY->hasMeanData();
return m_ensembleStatCaseY->hasMeanData();
}
//--------------------------------------------------------------------------------------------------

View File

@@ -25,7 +25,9 @@
#include "RiaDateTimeDefines.h"
#include "RiaPlotDefines.h"
#include "RiaSummaryCurveAddress.h"
#include "RiaSummaryDefines.h"
#include "RimEnsembleCrossPlotStatisticsCase.h"
#include "RimEnsembleCurveSetColorManager.h"
#include "RimEnsembleCurveSetInterface.h"
#include "RimTimeStepFilter.h"
@@ -64,6 +66,7 @@ class RiuSummaryVectorSelectionDialog;
class RiuPlotWidget;
class RiuPlotCurve;
class RimPlotAxisPropertiesInterface;
class RimSummaryAddressSelector;
class QwtPlot;
class QwtPlotCurve;
@@ -111,6 +114,7 @@ public:
void deleteCurve( RimSummaryCurve* curve );
void setSummaryAddress( RifEclipseSummaryAddress address );
void setCurveAddress( RiaSummaryCurveAddress address );
void setSummaryAddressAndStatisticsFlag( RifEclipseSummaryAddress address );
RifEclipseSummaryAddress summaryAddress() const;
RiaSummaryCurveAddress curveAddress() const;
@@ -215,10 +219,14 @@ private:
void onObjectiveFunctionChanged( const caf::SignalEmitter* emitter );
void onCustomObjectiveFunctionChanged( const caf::SignalEmitter* emitter );
void onXAxisAddressChanged( const caf::SignalEmitter* emitter );
void setTransparentCurveColor();
void onColorTagClicked( const SignalEmitter* emitter, size_t index );
void setSummaryAddressX( RifEclipseSummaryAddress address );
bool isXAxisSummaryVector() const;
private:
caf::PdmField<bool> m_showCurves;
caf::PdmChildArrayField<RimSummaryCurve*> m_curves;
@@ -231,6 +239,9 @@ private:
caf::PdmField<bool> m_yPushButtonSelectSummaryAddress;
caf::PdmField<RiaDefines::DateTimePeriodEnum> m_resampling;
caf::PdmField<caf::AppEnum<RiaDefines::HorizontalAxisType>> m_xAxisType;
caf::PdmChildField<RimSummaryAddressSelector*> m_xAddressSelector;
caf::PdmField<ColorModeEnum> m_colorMode;
caf::PdmField<cvf::Color3f> m_mainEnsembleColor;
caf::PdmField<cvf::Color3f> m_colorForRealizations;
@@ -270,7 +281,8 @@ private:
QPointer<RiuDraggableOverlayFrame> m_filterOverlayFrame;
QPointer<RiuDraggableOverlayFrame> m_objectiveFunctionOverlayFrame;
std::unique_ptr<RimEnsembleStatisticsCase> m_ensembleStatCase;
std::unique_ptr<RimEnsembleStatisticsCase> m_ensembleStatCaseY;
std::unique_ptr<RimEnsembleCrossPlotStatisticsCase> m_ensembleStatCaseXY;
std::unique_ptr<RiaSummaryCurveDefinitionAnalyser> m_analyserOfSelectedCurveDefs;

View File

@@ -46,6 +46,12 @@ RimEnsembleStatistics::RimEnsembleStatistics( RimEnsembleCurveSetInterface* pare
CAF_PDM_InitField( &m_showCurveLabels, "ShowCurveLabels", true, "Show Curve Labels" );
CAF_PDM_InitField( &m_includeIncompleteCurves, "IncludeIncompleteCurves", false, "Include Incomplete Curves" );
CAF_PDM_InitField( &m_crossPlotCurvesBinCount, "CrossPlotCurvesBinCount", 100, "Bin Count" );
CAF_PDM_InitField( &m_crossPlotCurvesStatisticsSampleCountThresholdPerBin,
"CrossPlotCurvesStatisticsSampleCountThresholdPerBin",
100,
"Sample Threshold per Bin" );
CAF_PDM_InitField( &m_warningLabel, "WarningLabel", QString( "Warning: Ensemble time range mismatch" ), "" );
CAF_PDM_InitField( &m_color, "Color", RiaColorTools::textColor3f(), "Color" );
@@ -79,6 +85,22 @@ void RimEnsembleStatistics::setShowStatisticsCurves( bool show )
m_active = show;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RimEnsembleStatistics::crossPlotCurvesBinCount() const
{
return m_crossPlotCurvesBinCount;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RimEnsembleStatistics::crossPlotCurvesSampleCountThresholdPerBin() const
{
return m_crossPlotCurvesStatisticsSampleCountThresholdPerBin;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -124,27 +146,23 @@ void RimEnsembleStatistics::showColorField( bool show )
//--------------------------------------------------------------------------------------------------
void RimEnsembleStatistics::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
if ( changedField == &m_active || changedField == &m_basedOnFilteredCases || changedField == &m_showP10Curve ||
changedField == &m_showP50Curve || changedField == &m_showP90Curve || changedField == &m_showMeanCurve ||
changedField == &m_showCurveLabels || changedField == &m_color || changedField == &m_includeIncompleteCurves ||
changedField == &m_showStatisticsCurveLegends )
{
auto curveSet = m_parentCurveSet;
if ( !curveSet ) return;
curveSet->updateStatisticsCurves();
// Trigger update of tree view editor for ensemble curve set as they depend on these fields
if ( changedField == &m_active || changedField == &m_basedOnFilteredCases || changedField == &m_color ) curveSet->updateEditors();
}
if ( changedField == &m_hideEnsembleCurves )
{
auto curveSet = m_parentCurveSet;
if ( !curveSet ) return;
curveSet->updateAllCurves();
return;
}
auto curveSet = m_parentCurveSet;
if ( !curveSet ) return;
curveSet->updateStatisticsCurves();
// Trigger update of tree view editor for ensemble curve set as they depend on these fields
if ( changedField == &m_active || changedField == &m_basedOnFilteredCases || changedField == &m_color ) curveSet->updateEditors();
}
//--------------------------------------------------------------------------------------------------
@@ -162,6 +180,10 @@ void RimEnsembleStatistics::defineUiOrdering( QString uiConfigName, caf::PdmUiOr
uiOrdering.add( &m_includeIncompleteCurves );
uiOrdering.add( &m_showCurveLabels );
auto crossPlotGroup = uiOrdering.addNewGroup( "Cross Plot" );
crossPlotGroup->add( &m_crossPlotCurvesBinCount );
crossPlotGroup->add( &m_crossPlotCurvesStatisticsSampleCountThresholdPerBin );
if ( m_showColorField ) uiOrdering.add( &m_color );
auto group = uiOrdering.addNewGroup( "Curves" );

View File

@@ -52,6 +52,9 @@ public:
bool includeIncompleteCurves() const { return m_includeIncompleteCurves; }
int crossPlotCurvesBinCount() const;
int crossPlotCurvesSampleCountThresholdPerBin() const;
void disableP10Curve( bool disable );
void disableP50Curve( bool disable );
void disableP90Curve( bool disable );
@@ -76,6 +79,10 @@ private:
caf::PdmField<bool> m_showCurveLabels;
caf::PdmField<bool> m_includeIncompleteCurves;
// Ensemble cross plot settings
caf::PdmField<int> m_crossPlotCurvesBinCount;
caf::PdmField<int> m_crossPlotCurvesStatisticsSampleCountThresholdPerBin;
caf::PdmField<QString> m_warningLabel;
bool m_showColorField;

View File

@@ -18,8 +18,6 @@
#include "RimEnsembleStatisticsCase.h"
#include "RifEnsembleStatisticsReader.h"
#include "RiaSummaryTools.h"
#include "RiaTimeHistoryCurveResampler.h"
@@ -40,9 +38,8 @@
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleStatisticsCase::RimEnsembleStatisticsCase( RimEnsembleCurveSet* curveSet )
RimEnsembleStatisticsCase::RimEnsembleStatisticsCase()
{
m_curveSet = curveSet;
}
//--------------------------------------------------------------------------------------------------
@@ -56,33 +53,73 @@ const std::vector<time_t>& RimEnsembleStatisticsCase::timeSteps() const
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<double>& RimEnsembleStatisticsCase::p10() const
std::vector<time_t> RimEnsembleStatisticsCase::timeSteps( const RifEclipseSummaryAddress& resultAddress ) const
{
return m_p10Data;
return m_timeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<double>& RimEnsembleStatisticsCase::p50() const
bool RimEnsembleStatisticsCase::hasP10Data() const
{
return m_p50Data;
return !m_p10Data.empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<double>& RimEnsembleStatisticsCase::p90() const
bool RimEnsembleStatisticsCase::hasP50Data() const
{
return m_p90Data;
return !m_p50Data.empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<double>& RimEnsembleStatisticsCase::mean() const
bool RimEnsembleStatisticsCase::hasP90Data() const
{
return m_meanData;
return !m_p90Data.empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimEnsembleStatisticsCase::hasMeanData() const
{
return !m_meanData.empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimEnsembleStatisticsCase::values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const
{
auto quantityName = resultAddress.ensembleStatisticsVectorName();
if ( quantityName == ENSEMBLE_STAT_P10_QUANTITY_NAME )
*values = m_p10Data;
else if ( quantityName == ENSEMBLE_STAT_P50_QUANTITY_NAME )
*values = m_p50Data;
else if ( quantityName == ENSEMBLE_STAT_P90_QUANTITY_NAME )
*values = m_p90Data;
else if ( quantityName == ENSEMBLE_STAT_MEAN_QUANTITY_NAME )
*values = m_meanData;
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimEnsembleStatisticsCase::unitName( const RifEclipseSummaryAddress& resultAddress ) const
{
if ( m_firstSummaryCase && m_firstSummaryCase->summaryReader() )
{
return m_firstSummaryCase->summaryReader()->unitName( resultAddress );
}
return "Ensemble Statistics Case - Undefined Unit";
}
//--------------------------------------------------------------------------------------------------
@@ -98,7 +135,7 @@ QString RimEnsembleStatisticsCase::caseName() const
//--------------------------------------------------------------------------------------------------
void RimEnsembleStatisticsCase::createSummaryReaderInterface()
{
m_statisticsReader.reset( new RifEnsembleStatisticsReader( this ) );
// Nothing to do here as RimEnsembleStatisticsCase inherits from RifSummaryReaderInterface
}
//--------------------------------------------------------------------------------------------------
@@ -106,33 +143,7 @@ void RimEnsembleStatisticsCase::createSummaryReaderInterface()
//--------------------------------------------------------------------------------------------------
RifSummaryReaderInterface* RimEnsembleStatisticsCase::summaryReader()
{
if ( !m_statisticsReader )
{
createSummaryReaderInterface();
}
return m_statisticsReader.get();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RimEnsembleCurveSet* RimEnsembleStatisticsCase::curveSet() const
{
return m_curveSet;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleStatisticsCase::calculate( const std::vector<RimSummaryCase*>& sumCases, bool includeIncompleteCurves )
{
auto inputAddress = m_curveSet->summaryAddress();
if ( m_statisticsReader && inputAddress.isValid() )
{
const std::vector<RimSummaryCase*>& validCases = validSummaryCases( sumCases, inputAddress, includeIncompleteCurves );
calculate( validCases, inputAddress, includeIncompleteCurves );
}
return this;
}
//--------------------------------------------------------------------------------------------------
@@ -142,15 +153,18 @@ void RimEnsembleStatisticsCase::calculate( const std::vector<RimSummaryCase*>& s
const RifEclipseSummaryAddress& inputAddress,
bool includeIncompleteCurves )
{
std::vector<time_t> allTimeSteps;
std::vector<std::vector<double>> caseAndTimeStepValues;
clearData();
if ( !inputAddress.isValid() ) return;
if ( sumCases.empty() ) return;
auto [minTimeStep, maxTimeStep] = findMinMaxTimeStep( sumCases, inputAddress );
// Use first summary case to get unit system and other meta data
m_firstSummaryCase = sumCases.front();
auto [minTimeStep, maxTimeStep] = findMinMaxTimeStep( sumCases, inputAddress );
RiaDefines::DateTimePeriod period = findBestResamplingPeriod( minTimeStep, maxTimeStep );
std::vector<time_t> allTimeSteps;
std::vector<std::vector<double>> caseAndTimeStepValues;
caseAndTimeStepValues.reserve( sumCases.size() );
for ( const auto& sumCase : sumCases )
{
@@ -172,7 +186,6 @@ void RimEnsembleStatisticsCase::calculate( const std::vector<RimSummaryCase*>& s
}
}
clearData();
m_timeSteps = allTimeSteps;
for ( size_t timeStepIndex = 0; timeStepIndex < allTimeSteps.size(); timeStepIndex++ )
@@ -202,10 +215,11 @@ void RimEnsembleStatisticsCase::calculate( const std::vector<RimSummaryCase*>& s
//--------------------------------------------------------------------------------------------------
RiaDefines::EclipseUnitSystem RimEnsembleStatisticsCase::unitSystem() const
{
if ( m_curveSet )
if ( m_firstSummaryCase && m_firstSummaryCase->summaryReader() )
{
return m_curveSet->summaryCaseCollection()->unitSystem();
return m_firstSummaryCase->summaryReader()->unitSystem();
}
return RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN;
}
@@ -219,6 +233,7 @@ void RimEnsembleStatisticsCase::clearData()
m_p50Data.clear();
m_p90Data.clear();
m_meanData.clear();
m_firstSummaryCase = nullptr;
}
//--------------------------------------------------------------------------------------------------

View File

@@ -21,43 +21,38 @@
#include "RiaDateTimeDefines.h"
#include "RiaDefines.h"
#include "RifSummaryReaderInterface.h"
#include "RimSummaryCase.h"
class RifEnsembleStatisticsReader;
class RimEnsembleCurveSet;
class RifEclipseSummaryAddress;
//==================================================================================================
///
//==================================================================================================
class RimEnsembleStatisticsCase : public RimSummaryCase
class RimEnsembleStatisticsCase : public RimSummaryCase, public RifSummaryReaderInterface
{
public:
RimEnsembleStatisticsCase( RimEnsembleCurveSet* curveSet );
RimEnsembleStatisticsCase();
const std::vector<time_t>& timeSteps() const;
const std::vector<double>& p10() const;
const std::vector<double>& p50() const;
const std::vector<double>& p90() const;
const std::vector<double>& mean() const;
bool hasP10Data() const { return !m_p10Data.empty(); }
bool hasP50Data() const { return !m_p50Data.empty(); }
bool hasP90Data() const { return !m_p90Data.empty(); }
bool hasMeanData() const { return !m_meanData.empty(); }
bool hasP10Data() const;
bool hasP50Data() const;
bool hasP90Data() const;
bool hasMeanData() const;
QString caseName() const override;
void createSummaryReaderInterface() override;
RifSummaryReaderInterface* summaryReader() override;
QString caseName() const override;
void createSummaryReaderInterface() override;
RifSummaryReaderInterface* summaryReader() override;
RiaDefines::EclipseUnitSystem unitSystem() const override;
const RimEnsembleCurveSet* curveSet() const;
void calculate( const std::vector<RimSummaryCase*>& sumCases, bool includeIncompleteCurves );
RiaDefines::EclipseUnitSystem unitSystem() const;
private:
void calculate( const std::vector<RimSummaryCase*>& sumCases, const RifEclipseSummaryAddress& inputAddress, bool includeIncompleteCurves );
void clearData();
std::vector<time_t> timeSteps( const RifEclipseSummaryAddress& resultAddress ) const override;
bool values( const RifEclipseSummaryAddress& resultAddress, std::vector<double>* values ) const override;
std::string unitName( const RifEclipseSummaryAddress& resultAddress ) const override;
static std::vector<RimSummaryCase*> validSummaryCases( const std::vector<RimSummaryCase*>& allSumCases,
const RifEclipseSummaryAddress& inputAddress,
bool includeIncompleteCurves );
@@ -66,12 +61,14 @@ private:
static RiaDefines::DateTimePeriod findBestResamplingPeriod( time_t minTimeStep, time_t maxTimeStep );
private:
std::unique_ptr<RifEnsembleStatisticsReader> m_statisticsReader;
RimEnsembleCurveSet* m_curveSet;
void clearData();
private:
std::vector<time_t> m_timeSteps;
std::vector<double> m_p10Data;
std::vector<double> m_p50Data;
std::vector<double> m_p90Data;
std::vector<double> m_meanData;
caf::PdmPointer<RimSummaryCase> m_firstSummaryCase;
};

View File

@@ -0,0 +1,360 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimSummaryAddressSelector.h"
#include "RiaResultNames.h"
#include "RiaSummaryCurveDefinition.h"
#include "RiaSummaryTools.h"
#include "RifSummaryReaderInterface.h"
#include "RimPlotAxisPropertiesInterface.h"
#include "RimProject.h"
#include "RimSummaryAddress.h"
#include "RimSummaryCase.h"
#include "RimSummaryCaseCollection.h"
#include "RimSummaryPlot.h"
#include "RiuSummaryVectorSelectionDialog.h"
#include "cafPdmUiLineEditor.h"
#include "cafPdmUiPushButtonEditor.h"
CAF_PDM_SOURCE_INIT( RimSummaryAddressSelector, "RimSummaryAddressSelector" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryAddressSelector::RimSummaryAddressSelector()
: addressChanged( this )
{
CAF_PDM_InitFieldNoDefault( &m_summaryCase, "SummaryCase", "Case" );
m_summaryCase.uiCapability()->setUiTreeChildrenHidden( true );
m_summaryCase.uiCapability()->setAutoAddingOptionFromValue( false );
CAF_PDM_InitFieldNoDefault( &m_summaryCaseCollection, "SummaryCaseCollection", "Ensemble" );
m_summaryCaseCollection.uiCapability()->setUiTreeChildrenHidden( true );
m_summaryCaseCollection.uiCapability()->setAutoAddingOptionFromValue( false );
CAF_PDM_InitFieldNoDefault( &m_summaryAddressUiField, "summaryAddressUiField", "Vector" );
m_summaryAddressUiField.xmlCapability()->disableIO();
m_summaryAddressUiField.uiCapability()->setUiEditorTypeName( caf::PdmUiLineEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_summaryAddress, "SummaryAddress", "Summary Address" );
m_summaryAddress.uiCapability()->setUiTreeHidden( true );
m_summaryAddress.uiCapability()->setUiTreeChildrenHidden( true );
CAF_PDM_InitFieldNoDefault( &m_pushButtonSelectSummaryAddress, "SelectAddress", "" );
caf::PdmUiPushButtonEditor::configureEditorForField( &m_pushButtonSelectSummaryAddress );
m_pushButtonSelectSummaryAddress.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
m_pushButtonSelectSummaryAddress = false;
CAF_PDM_InitFieldNoDefault( &m_plotAxisProperties, "PlotAxisProperties", "Axis" );
m_summaryAddress = new RimSummaryAddress;
CAF_PDM_InitFieldNoDefault( &m_resamplingPeriod, "Resampling", "Resampling" );
m_dataSource = SummaryDataSource::SINGLE_CASE;
m_showDataSource = true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryAddressSelector::setSummaryCase( RimSummaryCase* summaryCase )
{
m_summaryCase = summaryCase;
m_dataSource = SummaryDataSource::SINGLE_CASE;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryAddressSelector::setEnsemble( RimSummaryCaseCollection* ensemble )
{
m_summaryCaseCollection = ensemble;
m_dataSource = SummaryDataSource::ENSEMBLE;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryAddressSelector::setAddress( const RifEclipseSummaryAddress& address )
{
m_summaryAddress->setAddress( address );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryAddressSelector::setResamplingPeriod( RiaDefines::DateTimePeriodEnum resampling )
{
m_resamplingPeriod = resampling;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryAddressSelector::setPlotAxisProperties( RimPlotAxisPropertiesInterface* plotAxisProperties )
{
m_plotAxisProperties = plotAxisProperties;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryAddressSelector::setShowDataSource( bool enable )
{
m_showDataSource = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryCase* RimSummaryAddressSelector::summaryCase() const
{
return m_summaryCase();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryCaseCollection* RimSummaryAddressSelector::ensemble() const
{
return m_summaryCaseCollection();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddress RimSummaryAddressSelector::summaryAddress() const
{
return m_summaryAddress()->address();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaDefines::DateTimePeriodEnum RimSummaryAddressSelector::resamplingPeriod() const
{
return m_resamplingPeriod();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimPlotAxisPropertiesInterface* RimSummaryAddressSelector::plotAxisProperties() const
{
return m_plotAxisProperties();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryAddressSelector::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
if ( changedField == &m_pushButtonSelectSummaryAddress )
{
RiuSummaryVectorSelectionDialog dlg( nullptr );
if ( m_dataSource == SummaryDataSource::SINGLE_CASE )
{
dlg.hideEnsembles();
dlg.setCaseAndAddress( m_summaryCase(), m_summaryAddress->address() );
}
else if ( m_dataSource == SummaryDataSource::ENSEMBLE )
{
dlg.hideSummaryCases();
dlg.setEnsembleAndAddress( m_summaryCaseCollection(), m_summaryAddress->address() );
}
if ( dlg.exec() == QDialog::Accepted )
{
auto curveSelection = dlg.curveSelection();
if ( !curveSelection.empty() )
{
m_summaryCase = curveSelection[0].summaryCaseY();
m_summaryCaseCollection = curveSelection[0].ensemble();
auto addr = curveSelection[0].summaryAddressY();
m_summaryAddress->setAddress( addr );
m_summaryAddressUiField = addr;
}
}
m_pushButtonSelectSummaryAddress = false;
}
else if ( changedField == &m_summaryAddressUiField )
{
m_summaryAddress->setAddress( m_summaryAddressUiField() );
}
addressChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
auto createOptionsForSummaryCase = []() -> QList<caf::PdmOptionItemInfo>
{
RimProject* proj = RimProject::current();
std::vector<RimSummaryCase*> cases = proj->allSummaryCases();
auto options = RiaSummaryTools::optionsForSummaryCases( cases );
if ( !options.empty() )
{
options.push_front( caf::PdmOptionItemInfo( "None", nullptr ) );
}
return options;
};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
auto createOptionsForEnsemble = []() -> QList<caf::PdmOptionItemInfo>
{
QList<caf::PdmOptionItemInfo> options;
RimProject* proj = RimProject::current();
std::vector<RimSummaryCaseCollection*> groups = proj->summaryGroups();
for ( RimSummaryCaseCollection* group : groups )
{
if ( group->isEnsemble() ) options.push_back( caf::PdmOptionItemInfo( group->name(), group ) );
}
options.push_front( caf::PdmOptionItemInfo( "None", nullptr ) );
return options;
};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
auto createOptionsForAddresses = []( const std::set<RifEclipseSummaryAddress>& allAddresses ) -> QList<caf::PdmOptionItemInfo>
{
QList<caf::PdmOptionItemInfo> options;
for ( auto& address : allAddresses )
{
if ( address.isErrorResult() ) continue;
std::string name = address.uiText();
QString s = QString::fromStdString( name );
options.push_back( caf::PdmOptionItemInfo( s, QVariant::fromValue( address ) ) );
}
options.push_front( caf::PdmOptionItemInfo( RiaResultNames::undefinedResultName(), QVariant::fromValue( RifEclipseSummaryAddress() ) ) );
return options;
};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimSummaryAddressSelector::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
if ( fieldNeedingOptions == &m_summaryCase )
{
return createOptionsForSummaryCase();
}
if ( fieldNeedingOptions == &m_summaryCaseCollection )
{
return createOptionsForEnsemble();
}
if ( fieldNeedingOptions == &m_summaryAddressUiField )
{
std::set<RifEclipseSummaryAddress> addresses;
if ( m_dataSource == SummaryDataSource::SINGLE_CASE && m_summaryCase() )
{
RifSummaryReaderInterface* reader = m_summaryCase()->summaryReader();
if ( reader )
{
addresses = reader->allResultAddresses();
}
}
else if ( m_dataSource == SummaryDataSource::ENSEMBLE && m_summaryCaseCollection() )
{
addresses = m_summaryCaseCollection()->ensembleSummaryAddresses();
}
return createOptionsForAddresses( addresses );
}
if ( fieldNeedingOptions == &m_plotAxisProperties )
{
if ( auto plot = firstAncestorOrThisOfTypeAsserted<RimSummaryPlot>() )
{
QList<caf::PdmOptionItemInfo> options;
for ( auto axis : plot->plotAxes() )
{
options.push_back( caf::PdmOptionItemInfo( axis->objectName(), axis ) );
}
return options;
}
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryAddressSelector::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
if ( m_showDataSource )
{
if ( m_dataSource == SummaryDataSource::SINGLE_CASE )
{
uiOrdering.add( &m_summaryCase );
}
else
{
uiOrdering.add( &m_summaryCaseCollection );
}
}
// Update the UI field, as this is not serialized to file
m_summaryAddressUiField = m_summaryAddress->address();
uiOrdering.add( &m_summaryAddressUiField, { true, 2, 1 } );
uiOrdering.add( &m_pushButtonSelectSummaryAddress, { false, 1, 0 } );
uiOrdering.add( &m_resamplingPeriod, { true, 3, 1 } );
uiOrdering.add( &m_plotAxisProperties, { true, 3, 1 } );
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryAddressSelector::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( &m_pushButtonSelectSummaryAddress == field )
{
auto attrib = dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute );
if ( attrib )
{
attrib->m_buttonText = "...";
}
}
}

View File

@@ -0,0 +1,82 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaDateTimeDefines.h"
#include "RifEclipseSummaryAddress.h"
#include "RifEclipseSummaryAddressQMetaType.h"
#include "cafPdmChildField.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmPtrField.h"
class RimSummaryCase;
class RimSummaryCaseCollection;
class RimSummaryAddress;
class RimPlotAxisPropertiesInterface;
class RimSummaryAddressSelector : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
enum class SummaryDataSource
{
SINGLE_CASE,
ENSEMBLE
};
caf::Signal<> addressChanged;
public:
RimSummaryAddressSelector();
void setSummaryCase( RimSummaryCase* summaryCase );
void setEnsemble( RimSummaryCaseCollection* ensemble );
void setAddress( const RifEclipseSummaryAddress& address );
void setResamplingPeriod( RiaDefines::DateTimePeriodEnum resampling );
void setPlotAxisProperties( RimPlotAxisPropertiesInterface* plotAxisProperties );
void setShowDataSource( bool enable );
RimSummaryCase* summaryCase() const;
RimSummaryCaseCollection* ensemble() const;
RifEclipseSummaryAddress summaryAddress() const;
RiaDefines::DateTimePeriodEnum resamplingPeriod() const;
RimPlotAxisPropertiesInterface* plotAxisProperties() const;
private:
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
private:
caf::PdmPtrField<RimSummaryCase*> m_summaryCase;
caf::PdmPtrField<RimSummaryCaseCollection*> m_summaryCaseCollection;
caf::PdmChildField<RimSummaryAddress*> m_summaryAddress;
caf::PdmField<RifEclipseSummaryAddress> m_summaryAddressUiField;
caf::PdmField<bool> m_pushButtonSelectSummaryAddress;
caf::PdmPtrField<RimPlotAxisPropertiesInterface*> m_plotAxisProperties;
caf::PdmField<RiaDefines::DateTimePeriodEnum> m_resamplingPeriod;
SummaryDataSource m_dataSource;
bool m_showDataSource;
};

View File

@@ -525,7 +525,7 @@ QList<caf::PdmOptionItemInfo> RimSummaryCurve::calculateValueOptions( const caf:
options = RiaSummaryTools::optionsForSummaryCases( cases );
if ( options.size() > 0 )
if ( !options.empty() )
{
options.push_front( caf::PdmOptionItemInfo( "None", nullptr ) );
}
@@ -643,38 +643,53 @@ void RimSummaryCurve::onLoadDataAndUpdate( bool updateParentPlot )
if ( m_xAxisType == RiaDefines::HorizontalAxisType::SUMMARY_VECTOR )
{
auto curveValuesX = valuesX();
auto curveTimeStepsX = timeStepsX();
auto curveTimeStepsY = timeStepsY();
if ( curveValuesY.empty() || curveValuesX.empty() )
if ( m_xValuesSummaryAddress()->address().category() == SummaryCategory::SUMMARY_ENSEMBLE_STATISTICS )
{
shouldPopulateViewWithEmptyData = true;
std::vector<double> curveValuesX;
std::vector<double> curveValuesY;
// Read x and y values from ensemble statistics (not time steps are read)
RifSummaryReaderInterface* reader = m_xValuesSummaryCase()->summaryReader();
reader->values( m_xValuesSummaryAddress->address(), &curveValuesX );
reader->values( m_yValuesSummaryAddress->address(), &curveValuesY );
setSamplesFromXYValues( curveValuesX, curveValuesY, useLogarithmicScale );
}
else
{
RiaTimeHistoryCurveMerger curveMerger;
curveMerger.addCurveData( curveTimeStepsX, curveValuesX );
curveMerger.addCurveData( curveTimeStepsY, curveValuesY );
curveMerger.computeInterpolatedValues();
auto curveValuesX = valuesX();
auto curveTimeStepsX = timeStepsX();
auto curveTimeStepsY = timeStepsY();
if ( curveMerger.allXValues().size() > 0 )
if ( curveValuesY.empty() || curveValuesX.empty() )
{
setSamplesFromXYValues( curveMerger.interpolatedYValuesForAllXValues( 0 ),
curveMerger.interpolatedYValuesForAllXValues( 1 ),
useLogarithmicScale );
shouldPopulateViewWithEmptyData = true;
}
else
{
shouldPopulateViewWithEmptyData = true;
RiaTimeHistoryCurveMerger curveMerger;
curveMerger.addCurveData( curveTimeStepsX, curveValuesX );
curveMerger.addCurveData( curveTimeStepsY, curveValuesY );
curveMerger.computeInterpolatedValues();
if ( !curveMerger.allXValues().empty() )
{
setSamplesFromXYValues( curveMerger.interpolatedYValuesForAllXValues( 0 ),
curveMerger.interpolatedYValuesForAllXValues( 1 ),
useLogarithmicScale );
}
else
{
shouldPopulateViewWithEmptyData = true;
}
}
}
}
else
{
std::vector<time_t> curveTimeStepsY = timeStepsY();
if ( plot->timeAxisProperties() && curveTimeStepsY.size() > 0 && curveTimeStepsY.size() == curveValuesY.size() )
if ( plot->timeAxisProperties() && !curveTimeStepsY.empty() && curveTimeStepsY.size() == curveValuesY.size() )
{
if ( plot->timeAxisProperties()->timeMode() == RimSummaryTimeAxisProperties::DATE )
{
@@ -732,7 +747,7 @@ void RimSummaryCurve::onLoadDataAndUpdate( bool updateParentPlot )
double timeScale = plot->timeAxisProperties()->fromTimeTToDisplayUnitScale();
std::vector<double> timeFromSimulationStart;
if ( curveTimeStepsY.size() )
if ( !curveTimeStepsY.empty() )
{
time_t startDate = curveTimeStepsY[0];
for ( const auto& date : curveTimeStepsY )
@@ -1193,7 +1208,7 @@ void RimSummaryCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
if ( dlg.exec() == QDialog::Accepted )
{
auto curveSelection = dlg.curveSelection();
if ( curveSelection.size() > 0 )
if ( !curveSelection.empty() )
{
m_yValuesSummaryCase = curveSelection[0].summaryCaseY();
m_yValuesSummaryAddress->setAddress( curveSelection[0].summaryAddressY() );
@@ -1227,7 +1242,7 @@ void RimSummaryCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
if ( dlg.exec() == QDialog::Accepted )
{
auto curveSelection = dlg.curveSelection();
if ( curveSelection.size() > 0 )
if ( !curveSelection.empty() )
{
m_xValuesSummaryCase = curveSelection[0].summaryCaseY();
m_xValuesSummaryAddress->setAddress( curveSelection[0].summaryAddressY() );
@@ -1255,7 +1270,7 @@ void RimSummaryCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
curveMerger.addCurveData( curveTimeStepsY, curveValuesY );
curveMerger.computeInterpolatedValues();
if ( curveMerger.validIntervalsForAllXValues().size() == 0 )
if ( curveMerger.validIntervalsForAllXValues().empty() )
{
QString description;

View File

@@ -270,8 +270,17 @@ QString RimSummaryPlotAxisFormatter::autoAxisTitle() const
for ( const RiaSummaryCurveDefinition& curveDef : m_curveDefinitions )
{
std::string unitText;
RifEclipseSummaryAddress sumAddress = curveDef.summaryAddressY();
RifEclipseSummaryAddress sumAddress;
if ( m_axisProperties->plotAxis().isHorizontal() )
{
sumAddress = curveDef.summaryAddressX();
}
else
{
sumAddress = curveDef.summaryAddressY();
}
std::string unitText;
if ( curveDef.ensemble() )
{
std::vector<RimSummaryCase*> sumCases = curveDef.ensemble()->allSummaryCases();
@@ -285,8 +294,7 @@ QString RimSummaryPlotAxisFormatter::autoAxisTitle() const
RimSummaryCase* sumCase = curveDef.summaryCaseY();
if ( m_axisProperties->plotAxis().isHorizontal() )
{
sumCase = curveDef.summaryCaseX();
sumAddress = curveDef.summaryAddressX();
sumCase = curveDef.summaryCaseX();
}
if ( sumCase && sumCase->summaryReader() )

View File

@@ -329,6 +329,7 @@ void RimSummaryPlotSourceStepping::fieldChangedByUi( const caf::PdmFieldHandle*
if ( dataSourceSteppingObject() ) curves = dataSourceSteppingObject()->allCurves( m_sourceSteppingType );
bool isAutoZoomAllowed = false;
bool doZoomAll = false;
if ( changedField == &m_stepDimension )
{
@@ -361,6 +362,25 @@ void RimSummaryPlotSourceStepping::fieldChangedByUi( const caf::PdmFieldHandle*
bool triggerLoadDataAndUpdate = false;
auto updateEnsembleAddresses = [&doZoomAll, &oldValue, &newValue]( const std::vector<RimEnsembleCurveSet*>& curveSets )
{
for ( auto curveSet : curveSets )
{
auto curveAdr = curveSet->curveAddress();
auto yAddressToModify = curveAdr.summaryAddressY();
RimDataSourceSteppingTools::updateQuantityIfMatching( oldValue, newValue, yAddressToModify );
auto xAddressToModify = curveAdr.summaryAddressX();
RimDataSourceSteppingTools::updateQuantityIfMatching( oldValue, newValue, xAddressToModify );
curveSet->setCurveAddress( RiaSummaryCurveAddress( xAddressToModify, yAddressToModify ) );
curveSet->updateConnectedEditors();
doZoomAll = true;
}
};
if ( changedField == &m_summaryCase )
{
if ( m_summaryCase() )
@@ -431,11 +451,7 @@ void RimSummaryPlotSourceStepping::fieldChangedByUi( const caf::PdmFieldHandle*
if ( dataSourceSteppingObject() )
{
for ( auto curveSet : dataSourceSteppingObject()->curveSets() )
{
auto adr = curveSet->summaryAddress();
if ( RimDataSourceSteppingTools::updateQuantityIfMatching( oldValue, newValue, &adr ) ) curveSet->setSummaryAddress( adr );
}
updateEnsembleAddresses( dataSourceSteppingObject()->curveSets() );
}
m_vectorName.uiCapability()->updateConnectedEditors();
@@ -486,26 +502,21 @@ void RimSummaryPlotSourceStepping::fieldChangedByUi( const caf::PdmFieldHandle*
if ( isYAxisStepping() )
{
RifEclipseSummaryAddress adr = curve->summaryAddressY();
RimDataSourceSteppingTools::updateAddressIfMatching( oldValue, newValue, summaryCategoryToModify, &adr );
RimDataSourceSteppingTools::updateAddressIfMatching( oldValue, newValue, summaryCategoryToModify, adr );
curve->setSummaryAddressY( adr );
}
if ( isXAxisStepping() )
{
RifEclipseSummaryAddress adr = curve->summaryAddressX();
RimDataSourceSteppingTools::updateAddressIfMatching( oldValue, newValue, summaryCategoryToModify, &adr );
RimDataSourceSteppingTools::updateAddressIfMatching( oldValue, newValue, summaryCategoryToModify, adr );
curve->setSummaryAddressX( adr );
}
}
if ( dataSourceSteppingObject() )
{
for ( auto curveSet : dataSourceSteppingObject()->curveSets() )
{
auto adr = curveSet->summaryAddress();
RimDataSourceSteppingTools::updateAddressIfMatching( oldValue, newValue, summaryCategoryToModify, &adr );
curveSet->setSummaryAddress( adr );
}
updateEnsembleAddresses( dataSourceSteppingObject()->curveSets() );
}
triggerLoadDataAndUpdate = true;
@@ -522,7 +533,15 @@ void RimSummaryPlotSourceStepping::fieldChangedByUi( const caf::PdmFieldHandle*
summaryMultiPlot->updatePlots();
summaryMultiPlot->updatePlotTitles();
if ( isAutoZoomAllowed ) summaryMultiPlot->zoomAllYAxes();
if ( doZoomAll )
{
summaryMultiPlot->zoomAll();
}
else if ( isAutoZoomAllowed )
{
// The time axis can be zoomed and will be used for all plots. Do not zoom time axis in this case.
summaryMultiPlot->zoomAllYAxes();
}
RiuPlotMainWindow* mainPlotWindow = RiaGuiApplication::instance()->mainPlotWindow();
mainPlotWindow->updateMultiPlotToolBar();
@@ -1261,13 +1280,13 @@ void RimSummaryPlotSourceStepping::updateVectorNameInCurves( std::vector<RimSumm
if ( isYAxisStepping() )
{
auto adr = curve->summaryAddressY();
if ( RimDataSourceSteppingTools::updateQuantityIfMatching( oldValue, newValue, &adr ) ) curve->setSummaryAddressY( adr );
if ( RimDataSourceSteppingTools::updateQuantityIfMatching( oldValue, newValue, adr ) ) curve->setSummaryAddressY( adr );
}
if ( isXAxisStepping() )
{
auto adr = curve->summaryAddressX();
if ( RimDataSourceSteppingTools::updateQuantityIfMatching( oldValue, newValue, &adr ) ) curve->setSummaryAddressX( adr );
if ( RimDataSourceSteppingTools::updateQuantityIfMatching( oldValue, newValue, adr ) ) curve->setSummaryAddressX( adr );
}
if ( m_autoUpdateAppearance )