mirror of
https://github.com/OPM/ResInsight.git
synced 2026-11-02 20:30:46 -06:00
Add support for custom percentiles in ensemble statistics
Introduced custom percentile handling for ensemble statistics: - Added "CUSTOM" statistics type and percentile field to RifEclipseSummaryAddress - Refactored RimEnsembleStatisticsCase to store and compute arbitrary percentiles - RimEnsembleStatistics now parses custom percentiles from UI input - RimEnsembleCurveSet and related interfaces updated to handle custom percentile curves and labels - Hashing and statistics calculations now include custom percentiles for cache validity
This commit is contained in:
1 parent
8f365ea340
commit
a2b3445692
18 files changed
+350
-58
No files matched your search
@@ -21,6 +21,8 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
//
|
//
|
||||||
@@ -31,14 +33,29 @@ namespace RiaHashTools
|
|||||||
{
|
{
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
/// Variadic template function to combine multiple parameters into a single hash
|
/// Variadic template function to combine multiple parameters into a single hash
|
||||||
|
/// Constrained to non-range types (std::string is excluded as it has std::hash specialization)
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
requires( !std::ranges::range<T> || std::is_same_v<std::decay_t<T>, std::string> )
|
||||||
void combineHash( size_t& seed, const T& value )
|
void combineHash( size_t& seed, const T& value )
|
||||||
{
|
{
|
||||||
// Based on https://www.boost.org/doc/libs/1_84_0/libs/container_hash/doc/html/hash.html#notes_hash_combine
|
// Based on https://www.boost.org/doc/libs/1_84_0/libs/container_hash/doc/html/hash.html#notes_hash_combine
|
||||||
seed ^= std::hash<T>()( value ) + 0x9e3779b9 + ( seed << 6 ) + ( seed >> 2 );
|
seed ^= std::hash<T>()( value ) + 0x9e3779b9 + ( seed << 6 ) + ( seed >> 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Overload for range types (excluding std::string)
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
template <std::ranges::range Range>
|
||||||
|
requires( !std::is_same_v<std::decay_t<Range>, std::string> )
|
||||||
|
void combineHash( size_t& seed, const Range& range )
|
||||||
|
{
|
||||||
|
for ( const auto& elem : range )
|
||||||
|
{
|
||||||
|
combineHash( seed, elem );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ RifEclipseSummaryAddress::RifEclipseSummaryAddress( SummaryCategory category, st
|
|||||||
, m_number2( -1 )
|
, m_number2( -1 )
|
||||||
, m_isErrorResult( false )
|
, m_isErrorResult( false )
|
||||||
, m_id( -1 )
|
, m_id( -1 )
|
||||||
|
, m_percentile( -1 )
|
||||||
{
|
{
|
||||||
std::pair<int, int> reg2regPair;
|
std::pair<int, int> reg2regPair;
|
||||||
switch ( category )
|
switch ( category )
|
||||||
@@ -132,6 +133,7 @@ RifEclipseSummaryAddress::RifEclipseSummaryAddress( SummaryCategory category,
|
|||||||
, m_number2( -1 )
|
, m_number2( -1 )
|
||||||
, m_isErrorResult( isErrorResult )
|
, m_isErrorResult( isErrorResult )
|
||||||
, m_id( id )
|
, m_id( id )
|
||||||
|
, m_percentile( -1 )
|
||||||
{
|
{
|
||||||
switch ( category )
|
switch ( category )
|
||||||
{
|
{
|
||||||
@@ -196,6 +198,7 @@ RifEclipseSummaryAddress::RifEclipseSummaryAddress()
|
|||||||
, m_number2( -1 )
|
, m_number2( -1 )
|
||||||
, m_isErrorResult( false )
|
, m_isErrorResult( false )
|
||||||
, m_id( -1 )
|
, m_id( -1 )
|
||||||
|
, m_percentile( -1 )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -669,8 +672,17 @@ std::string RifEclipseSummaryAddress::uiText() const
|
|||||||
|
|
||||||
if ( isStatistics() )
|
if ( isStatistics() )
|
||||||
{
|
{
|
||||||
auto prefix = RifEclipseSummaryAddressDefines::statisticsTypeToString( statisticsType() );
|
std::string prefix;
|
||||||
text = prefix + ":" + text;
|
if ( statisticsType() == RifEclipseSummaryAddressDefines::StatisticsType::CUSTOM && m_percentile >= MIN_PERCENTILE &&
|
||||||
|
m_percentile <= MAX_PERCENTILE )
|
||||||
|
{
|
||||||
|
prefix = "P" + std::to_string( m_percentile );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prefix = RifEclipseSummaryAddressDefines::statisticsTypeToString( statisticsType() );
|
||||||
|
}
|
||||||
|
text = prefix + ":" + text;
|
||||||
}
|
}
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
@@ -1027,6 +1039,31 @@ void RifEclipseSummaryAddress::setId( int id )
|
|||||||
m_id = id;
|
m_id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
int RifEclipseSummaryAddress::percentile() const
|
||||||
|
{
|
||||||
|
return m_percentile;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RifEclipseSummaryAddress::setPercentile( int percentile )
|
||||||
|
{
|
||||||
|
// Validate percentile value: must be in valid range [0, 100] or -1 (unset)
|
||||||
|
if ( ( percentile >= MIN_PERCENTILE && percentile <= MAX_PERCENTILE ) || percentile == -1 )
|
||||||
|
{
|
||||||
|
m_percentile = percentile;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Invalid percentile value, set to -1 (unset)
|
||||||
|
m_percentile = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ public:
|
|||||||
bool isStatistics() const;
|
bool isStatistics() const;
|
||||||
StatisticsType statisticsType() const;
|
StatisticsType statisticsType() const;
|
||||||
void setStatisticsType( StatisticsType type );
|
void setStatisticsType( StatisticsType type );
|
||||||
|
int percentile() const;
|
||||||
|
void setPercentile( int percentile );
|
||||||
|
|
||||||
int regionNumber() const;
|
int regionNumber() const;
|
||||||
int regionNumber2() const;
|
int regionNumber2() const;
|
||||||
@@ -166,6 +168,10 @@ public:
|
|||||||
std::string formatUiTextRegionToRegion() const;
|
std::string formatUiTextRegionToRegion() const;
|
||||||
static std::pair<int, int> regionToRegionPairFromUiText( const std::string& s );
|
static std::pair<int, int> regionToRegionPairFromUiText( const std::string& s );
|
||||||
|
|
||||||
|
// Percentile constants
|
||||||
|
static constexpr int MIN_PERCENTILE = 0;
|
||||||
|
static constexpr int MAX_PERCENTILE = 100;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static RifEclipseSummaryAddress fromTokens( const std::vector<std::string>& tokens );
|
static RifEclipseSummaryAddress fromTokens( const std::vector<std::string>& tokens );
|
||||||
|
|
||||||
@@ -188,6 +194,7 @@ private:
|
|||||||
int m_number2;
|
int m_number2;
|
||||||
bool m_isErrorResult;
|
bool m_isErrorResult;
|
||||||
int m_id;
|
int m_id;
|
||||||
|
int m_percentile;
|
||||||
};
|
};
|
||||||
|
|
||||||
QTextStream& operator<<( QTextStream& str, const RifEclipseSummaryAddress& sobj );
|
QTextStream& operator<<( QTextStream& str, const RifEclipseSummaryAddress& sobj );
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ void caf::AppEnum<RifEclipseSummaryAddressDefines::StatisticsType>::setUp()
|
|||||||
addItem( RifEclipseSummaryAddressDefines::StatisticsType::P50, "P50", "P50" );
|
addItem( RifEclipseSummaryAddressDefines::StatisticsType::P50, "P50", "P50" );
|
||||||
addItem( RifEclipseSummaryAddressDefines::StatisticsType::P90, "P90", "P90" );
|
addItem( RifEclipseSummaryAddressDefines::StatisticsType::P90, "P90", "P90" );
|
||||||
addItem( RifEclipseSummaryAddressDefines::StatisticsType::MEAN, "MEAN", "Mean" );
|
addItem( RifEclipseSummaryAddressDefines::StatisticsType::MEAN, "MEAN", "Mean" );
|
||||||
|
addItem( RifEclipseSummaryAddressDefines::StatisticsType::CUSTOM, "CUSTOM", "Custom" );
|
||||||
setDefault( RifEclipseSummaryAddressDefines::StatisticsType::NONE );
|
setDefault( RifEclipseSummaryAddressDefines::StatisticsType::NONE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ enum class StatisticsType
|
|||||||
P10,
|
P10,
|
||||||
P50,
|
P50,
|
||||||
P90,
|
P90,
|
||||||
MEAN
|
MEAN,
|
||||||
|
CUSTOM
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class CurveType
|
enum class CurveType
|
||||||
|
|||||||
@@ -28,8 +28,9 @@ public:
|
|||||||
virtual void updateAllCurves() = 0;
|
virtual void updateAllCurves() = 0;
|
||||||
virtual void updateStatisticsCurves() = 0;
|
virtual void updateStatisticsCurves() = 0;
|
||||||
|
|
||||||
virtual bool hasP10Data() const = 0;
|
virtual bool hasP10Data() const = 0;
|
||||||
virtual bool hasP50Data() const = 0;
|
virtual bool hasP50Data() const = 0;
|
||||||
virtual bool hasP90Data() const = 0;
|
virtual bool hasP90Data() const = 0;
|
||||||
virtual bool hasMeanData() const = 0;
|
virtual bool hasMeanData() const = 0;
|
||||||
|
virtual bool hasPercentileData( int p ) const = 0;
|
||||||
};
|
};
|
||||||
@@ -280,6 +280,15 @@ bool RimEnsembleCrossPlotStatisticsCase::hasMeanData() const
|
|||||||
return !m_meanData.empty();
|
return !m_meanData.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimEnsembleCrossPlotStatisticsCase::hasPercentileData( int /*percentile*/ ) const
|
||||||
|
{
|
||||||
|
// Custom percentiles are not supported for cross-plot statistics
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public:
|
|||||||
bool hasP50Data() const;
|
bool hasP50Data() const;
|
||||||
bool hasP90Data() const;
|
bool hasP90Data() const;
|
||||||
bool hasMeanData() const;
|
bool hasMeanData() const;
|
||||||
|
bool hasPercentileData( int percentile ) const;
|
||||||
|
|
||||||
QString caseName() const override;
|
QString caseName() const override;
|
||||||
void createSummaryReaderInterface() override;
|
void createSummaryReaderInterface() override;
|
||||||
|
|||||||
@@ -2231,6 +2231,8 @@ void RimEnsembleCurveSet::updateStatisticsCurves( const std::vector<RimSummaryCa
|
|||||||
statCases = group->allSummaryCases();
|
statCases = group->allSummaryCases();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto percentiles = m_statistics->allPercentiles();
|
||||||
|
|
||||||
if ( isXAxisSummaryVector() )
|
if ( isXAxisSummaryVector() )
|
||||||
{
|
{
|
||||||
m_ensembleStatCaseXY->calculate( statCases,
|
m_ensembleStatCaseXY->calculate( statCases,
|
||||||
@@ -2242,7 +2244,7 @@ void RimEnsembleCurveSet::updateStatisticsCurves( const std::vector<RimSummaryCa
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_ensembleStatCaseY->calculate( statCases, summaryAddressY(), m_statistics->includeIncompleteCurves() );
|
m_ensembleStatCaseY->calculate( statCases, summaryAddressY(), m_statistics->includeIncompleteCurves(), percentiles );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2289,6 +2291,16 @@ void RimEnsembleCurveSet::updateStatisticsCurves( const std::vector<RimSummaryCa
|
|||||||
return RiaSummaryCurveAddress( xStatAddress, yStatAddress );
|
return RiaSummaryCurveAddress( xStatAddress, yStatAddress );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto getPercentileAddress = []( int percentile, const RifEclipseSummaryAddress& addrY ) -> RiaSummaryCurveAddress
|
||||||
|
{
|
||||||
|
auto xStatAddress = RifEclipseSummaryAddress::timeAddress();
|
||||||
|
auto yStatAddress = addrY;
|
||||||
|
yStatAddress.setStatisticsType( RifEclipseSummaryAddressDefines::StatisticsType::CUSTOM );
|
||||||
|
yStatAddress.setPercentile( percentile );
|
||||||
|
|
||||||
|
return RiaSummaryCurveAddress( xStatAddress, yStatAddress );
|
||||||
|
};
|
||||||
|
|
||||||
if ( m_statistics->showP10Curve() && m_ensembleStatCaseY->hasP10Data() )
|
if ( m_statistics->showP10Curve() && m_ensembleStatCaseY->hasP10Data() )
|
||||||
addresses.push_back( getStatisticsAddress( RifEclipseSummaryAddressDefines::StatisticsType::P10, dataAddressY ) );
|
addresses.push_back( getStatisticsAddress( RifEclipseSummaryAddressDefines::StatisticsType::P10, dataAddressY ) );
|
||||||
if ( m_statistics->showP50Curve() && m_ensembleStatCaseY->hasP50Data() )
|
if ( m_statistics->showP50Curve() && m_ensembleStatCaseY->hasP50Data() )
|
||||||
@@ -2297,6 +2309,18 @@ void RimEnsembleCurveSet::updateStatisticsCurves( const std::vector<RimSummaryCa
|
|||||||
addresses.push_back( getStatisticsAddress( RifEclipseSummaryAddressDefines::StatisticsType::P90, dataAddressY ) );
|
addresses.push_back( getStatisticsAddress( RifEclipseSummaryAddressDefines::StatisticsType::P90, dataAddressY ) );
|
||||||
if ( m_statistics->showMeanCurve() && m_ensembleStatCaseY->hasMeanData() )
|
if ( m_statistics->showMeanCurve() && m_ensembleStatCaseY->hasMeanData() )
|
||||||
addresses.push_back( getStatisticsAddress( RifEclipseSummaryAddressDefines::StatisticsType::MEAN, dataAddressY ) );
|
addresses.push_back( getStatisticsAddress( RifEclipseSummaryAddressDefines::StatisticsType::MEAN, dataAddressY ) );
|
||||||
|
|
||||||
|
// Add custom percentiles (excluding standard P10/P50/P90 if their checkbox is checked)
|
||||||
|
for ( int p : m_statistics->allPercentiles() )
|
||||||
|
{
|
||||||
|
bool isHandledByCheckbox = ( p == 10 && m_statistics->showP10Curve() ) || ( p == 50 && m_statistics->showP50Curve() ) ||
|
||||||
|
( p == 90 && m_statistics->showP90Curve() );
|
||||||
|
|
||||||
|
if ( !isHandledByCheckbox && m_ensembleStatCaseY->hasPercentileData( p ) )
|
||||||
|
{
|
||||||
|
addresses.push_back( getPercentileAddress( p, dataAddressY ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2332,8 +2356,17 @@ void RimEnsembleCurveSet::updateStatisticsCurves( const std::vector<RimSummaryCa
|
|||||||
|
|
||||||
if ( m_statistics->showCurveLabels() )
|
if ( m_statistics->showCurveLabels() )
|
||||||
{
|
{
|
||||||
curve->setSymbolLabel( QString::fromStdString(
|
QString label;
|
||||||
RifEclipseSummaryAddressDefines::statisticsTypeToString( address.summaryAddressY().statisticsType() ) ) );
|
auto yAddr = address.summaryAddressY();
|
||||||
|
if ( yAddr.statisticsType() == RifEclipseSummaryAddressDefines::StatisticsType::CUSTOM && yAddr.percentile() >= 0 )
|
||||||
|
{
|
||||||
|
label = QString( "P%1" ).arg( yAddr.percentile() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
label = QString::fromStdString( RifEclipseSummaryAddressDefines::statisticsTypeToString( yAddr.statisticsType() ) );
|
||||||
|
}
|
||||||
|
curve->setSymbolLabel( label );
|
||||||
}
|
}
|
||||||
curve->setLineStyle( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID );
|
curve->setLineStyle( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID );
|
||||||
}
|
}
|
||||||
@@ -2523,6 +2556,16 @@ bool RimEnsembleCurveSet::hasMeanData() const
|
|||||||
return m_ensembleStatCaseY->hasMeanData();
|
return m_ensembleStatCaseY->hasMeanData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimEnsembleCurveSet::hasPercentileData( int p ) const
|
||||||
|
{
|
||||||
|
if ( isXAxisSummaryVector() ) return m_ensembleStatCaseXY->hasPercentileData( p );
|
||||||
|
|
||||||
|
return m_ensembleStatCaseY->hasPercentileData( p );
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ public:
|
|||||||
bool hasP50Data() const override;
|
bool hasP50Data() const override;
|
||||||
bool hasP90Data() const override;
|
bool hasP90Data() const override;
|
||||||
bool hasMeanData() const override;
|
bool hasMeanData() const override;
|
||||||
|
bool hasPercentileData( int p ) const override;
|
||||||
|
|
||||||
const RimEnsembleStatistics* statisticsOptions() const;
|
const RimEnsembleStatistics* statisticsOptions() const;
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,16 @@
|
|||||||
#include "RimEnsembleStatistics.h"
|
#include "RimEnsembleStatistics.h"
|
||||||
|
|
||||||
#include "RiaColorTools.h"
|
#include "RiaColorTools.h"
|
||||||
|
#include "RiaTextStringTools.h"
|
||||||
|
|
||||||
#include "RimEnsembleCurveSet.h"
|
#include "RimEnsembleCurveSet.h"
|
||||||
#include "RimEnsembleCurveSetInterface.h"
|
#include "RimEnsembleCurveSetInterface.h"
|
||||||
#include "RimProject.h"
|
#include "RimProject.h"
|
||||||
|
|
||||||
|
#include "cafPdmUiLineEditor.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
CAF_PDM_SOURCE_INIT( RimEnsembleStatistics, "RimEnsembleStatistics" );
|
CAF_PDM_SOURCE_INIT( RimEnsembleStatistics, "RimEnsembleStatistics" );
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -50,6 +55,9 @@ RimEnsembleStatistics::RimEnsembleStatistics( RimEnsembleCurveSetInterface* pare
|
|||||||
CAF_PDM_InitField( &m_showP50Curve, "ShowP50Curve", false, "P50" );
|
CAF_PDM_InitField( &m_showP50Curve, "ShowP50Curve", false, "P50" );
|
||||||
CAF_PDM_InitField( &m_showP90Curve, "ShowP90Curve", true, "P90" );
|
CAF_PDM_InitField( &m_showP90Curve, "ShowP90Curve", true, "P90" );
|
||||||
CAF_PDM_InitField( &m_showMeanCurve, "ShowMeanCurve", true, "Mean" );
|
CAF_PDM_InitField( &m_showMeanCurve, "ShowMeanCurve", true, "Mean" );
|
||||||
|
CAF_PDM_InitField( &m_customPercentiles, "CustomPercentiles", QString(), "Custom Percentiles" );
|
||||||
|
m_customPercentiles.uiCapability()->setUiEditorTypeName( caf::PdmUiLineEditor::uiEditorTypeName() );
|
||||||
|
m_customPercentiles.setCustomValidationCallback( [this]() -> QString { return validateCustomPercentiles(); } );
|
||||||
CAF_PDM_InitField( &m_showCurveLabels, "ShowCurveLabels", true, "Show Curve Labels" );
|
CAF_PDM_InitField( &m_showCurveLabels, "ShowCurveLabels", true, "Show Curve Labels" );
|
||||||
CAF_PDM_InitField( &m_includeIncompleteCurves, "IncludeIncompleteCurves", false, "Include Incomplete Curves" );
|
CAF_PDM_InitField( &m_includeIncompleteCurves, "IncludeIncompleteCurves", false, "Include Incomplete Curves" );
|
||||||
|
|
||||||
@@ -149,6 +157,41 @@ bool RimEnsembleStatistics::showMeanCurve() const
|
|||||||
return m_showMeanCurve;
|
return m_showMeanCurve;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RimEnsembleStatistics::customPercentiles() const
|
||||||
|
{
|
||||||
|
return m_customPercentiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::vector<int> RimEnsembleStatistics::allPercentiles() const
|
||||||
|
{
|
||||||
|
std::set<int> uniquePercentiles;
|
||||||
|
|
||||||
|
// Add standard percentiles from checkboxes
|
||||||
|
if ( m_showP10Curve ) uniquePercentiles.insert( 10 );
|
||||||
|
if ( m_showP50Curve ) uniquePercentiles.insert( 50 );
|
||||||
|
if ( m_showP90Curve ) uniquePercentiles.insert( 90 );
|
||||||
|
|
||||||
|
// Parse custom percentiles string
|
||||||
|
QStringList parts = RiaTextStringTools::splitSkipEmptyParts( m_customPercentiles() );
|
||||||
|
for ( const auto& part : parts )
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
int value = part.trimmed().toInt( &ok );
|
||||||
|
if ( ok && value >= 0 && value <= 100 )
|
||||||
|
{
|
||||||
|
uniquePercentiles.insert( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { uniquePercentiles.begin(), uniquePercentiles.end() };
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -276,6 +319,7 @@ void RimEnsembleStatistics::defaultUiOrdering( bool showCrossPlotGroup, caf::Pdm
|
|||||||
group->add( &m_showP50Curve );
|
group->add( &m_showP50Curve );
|
||||||
group->add( &m_showMeanCurve );
|
group->add( &m_showMeanCurve );
|
||||||
group->add( &m_showP10Curve );
|
group->add( &m_showP10Curve );
|
||||||
|
group->add( &m_customPercentiles );
|
||||||
|
|
||||||
disableP10Curve( !m_active || !curveSet->hasP10Data() );
|
disableP10Curve( !m_active || !curveSet->hasP10Data() );
|
||||||
disableP50Curve( !m_active || !curveSet->hasP50Data() );
|
disableP50Curve( !m_active || !curveSet->hasP50Data() );
|
||||||
@@ -283,6 +327,7 @@ void RimEnsembleStatistics::defaultUiOrdering( bool showCrossPlotGroup, caf::Pdm
|
|||||||
disableMeanCurve( !m_active || !curveSet->hasMeanData() );
|
disableMeanCurve( !m_active || !curveSet->hasMeanData() );
|
||||||
m_showCurveLabels.uiCapability()->setUiReadOnly( !m_active );
|
m_showCurveLabels.uiCapability()->setUiReadOnly( !m_active );
|
||||||
m_color.uiCapability()->setUiReadOnly( !m_active );
|
m_color.uiCapability()->setUiReadOnly( !m_active );
|
||||||
|
m_customPercentiles.uiCapability()->setUiReadOnly( !m_active );
|
||||||
|
|
||||||
m_showP10Curve.uiCapability()->setUiName( curveSet->hasP10Data() ? "P10" : "P10 (Needs > 8 curves)" );
|
m_showP10Curve.uiCapability()->setUiName( curveSet->hasP10Data() ? "P10" : "P10 (Needs > 8 curves)" );
|
||||||
m_showP90Curve.uiCapability()->setUiName( curveSet->hasP90Data() ? "P90" : "P90 (Needs > 8 curves)" );
|
m_showP90Curve.uiCapability()->setUiName( curveSet->hasP90Data() ? "P90" : "P90 (Needs > 8 curves)" );
|
||||||
@@ -323,6 +368,20 @@ void RimEnsembleStatistics::defineUiOrdering( QString uiConfigName, caf::PdmUiOr
|
|||||||
defaultUiOrdering( showCrossPlot, uiOrdering );
|
defaultUiOrdering( showCrossPlot, uiOrdering );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimEnsembleStatistics::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
|
||||||
|
{
|
||||||
|
if ( field == &m_customPercentiles )
|
||||||
|
{
|
||||||
|
if ( auto lineEdAttr = dynamic_cast<caf::PdmUiLineEditorAttribute*>( attribute ) )
|
||||||
|
{
|
||||||
|
lineEdAttr->placeholderText = "E.g. 5 25 75 95";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -338,3 +397,25 @@ void RimEnsembleStatistics::onSetShowEnsembleCurves( const bool& enable )
|
|||||||
{
|
{
|
||||||
m_hideEnsembleCurves = !enable;
|
m_hideEnsembleCurves = !enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RimEnsembleStatistics::validateCustomPercentiles() const
|
||||||
|
{
|
||||||
|
QStringList parts = RiaTextStringTools::splitSkipEmptyParts( m_customPercentiles() );
|
||||||
|
for ( const auto& part : parts )
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
int value = part.trimmed().toInt( &ok );
|
||||||
|
if ( !ok )
|
||||||
|
{
|
||||||
|
return QString( "Invalid percentile value: '%1'" ).arg( part.trimmed() );
|
||||||
|
}
|
||||||
|
if ( value < 0 || value > 100 )
|
||||||
|
{
|
||||||
|
return QString( "Percentile value %1 must be in the range 0 to 100" ).arg( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
@@ -23,6 +23,8 @@
|
|||||||
#include "cafPdmObject.h"
|
#include "cafPdmObject.h"
|
||||||
#include "cafPdmProxyValueField.h"
|
#include "cafPdmProxyValueField.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class RimEnsembleCurveSetInterface;
|
class RimEnsembleCurveSetInterface;
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
@@ -45,6 +47,9 @@ public:
|
|||||||
bool showP90Curve() const;
|
bool showP90Curve() const;
|
||||||
bool showMeanCurve() const;
|
bool showMeanCurve() const;
|
||||||
|
|
||||||
|
QString customPercentiles() const;
|
||||||
|
std::vector<int> allPercentiles() const;
|
||||||
|
|
||||||
bool showCurveLabels() const;
|
bool showCurveLabels() const;
|
||||||
void enableCurveLabels( bool enable );
|
void enableCurveLabels( bool enable );
|
||||||
|
|
||||||
@@ -67,10 +72,12 @@ public:
|
|||||||
void defaultUiOrdering( bool showCrossPlotGroup, caf::PdmUiOrdering& uiOrdering );
|
void defaultUiOrdering( bool showCrossPlotGroup, caf::PdmUiOrdering& uiOrdering );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||||
bool onShowEnsembleCurves() const;
|
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
|
||||||
void onSetShowEnsembleCurves( const bool& enable );
|
bool onShowEnsembleCurves() const;
|
||||||
|
void onSetShowEnsembleCurves( const bool& enable );
|
||||||
|
QString validateCustomPercentiles() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RimEnsembleCurveSetInterface* m_parentCurveSet;
|
RimEnsembleCurveSetInterface* m_parentCurveSet;
|
||||||
@@ -84,6 +91,7 @@ private:
|
|||||||
caf::PdmField<bool> m_showP50Curve;
|
caf::PdmField<bool> m_showP50Curve;
|
||||||
caf::PdmField<bool> m_showP90Curve;
|
caf::PdmField<bool> m_showP90Curve;
|
||||||
caf::PdmField<bool> m_showMeanCurve;
|
caf::PdmField<bool> m_showMeanCurve;
|
||||||
|
caf::PdmField<QString> m_customPercentiles;
|
||||||
caf::PdmField<bool> m_showCurveLabels;
|
caf::PdmField<bool> m_showCurveLabels;
|
||||||
caf::PdmField<bool> m_includeIncompleteCurves;
|
caf::PdmField<bool> m_includeIncompleteCurves;
|
||||||
caf::PdmField<bool> m_customColor;
|
caf::PdmField<bool> m_customColor;
|
||||||
|
|||||||
@@ -24,8 +24,11 @@
|
|||||||
#include "RiaTimeHistoryCurveResampler.h"
|
#include "RiaTimeHistoryCurveResampler.h"
|
||||||
#include "Summary/RiaSummaryTools.h"
|
#include "Summary/RiaSummaryTools.h"
|
||||||
|
|
||||||
|
#include "RifEclipseSummaryAddress.h"
|
||||||
|
|
||||||
#include "RigStatisticsMath.h"
|
#include "RigStatisticsMath.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -41,7 +44,7 @@ std::vector<time_t> RimEnsembleStatisticsCase::timeSteps( const RifEclipseSummar
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
bool RimEnsembleStatisticsCase::hasP10Data() const
|
bool RimEnsembleStatisticsCase::hasP10Data() const
|
||||||
{
|
{
|
||||||
return !m_p10Data.empty();
|
return hasPercentileData( 10 );
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -49,7 +52,7 @@ bool RimEnsembleStatisticsCase::hasP10Data() const
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
bool RimEnsembleStatisticsCase::hasP50Data() const
|
bool RimEnsembleStatisticsCase::hasP50Data() const
|
||||||
{
|
{
|
||||||
return !m_p50Data.empty();
|
return hasPercentileData( 50 );
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -57,7 +60,7 @@ bool RimEnsembleStatisticsCase::hasP50Data() const
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
bool RimEnsembleStatisticsCase::hasP90Data() const
|
bool RimEnsembleStatisticsCase::hasP90Data() const
|
||||||
{
|
{
|
||||||
return !m_p90Data.empty();
|
return hasPercentileData( 90 );
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -68,6 +71,17 @@ bool RimEnsembleStatisticsCase::hasMeanData() const
|
|||||||
return !m_meanData.empty();
|
return !m_meanData.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimEnsembleStatisticsCase::hasPercentileData( int percentile ) const
|
||||||
|
{
|
||||||
|
if ( percentile < RifEclipseSummaryAddress::MIN_PERCENTILE || percentile > RifEclipseSummaryAddress::MAX_PERCENTILE ) return false;
|
||||||
|
|
||||||
|
auto it = m_percentileData.find( percentile );
|
||||||
|
return it != m_percentileData.end() && !it->second.empty();
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -75,19 +89,40 @@ std::pair<bool, std::vector<double>> RimEnsembleStatisticsCase::values( const Ri
|
|||||||
{
|
{
|
||||||
if ( resultAddress.isErrorResult() ) return { true, {} };
|
if ( resultAddress.isErrorResult() ) return { true, {} };
|
||||||
|
|
||||||
|
if ( resultAddress.statisticsType() == RifEclipseSummaryAddressDefines::StatisticsType::MEAN )
|
||||||
|
{
|
||||||
|
return { true, m_meanData };
|
||||||
|
}
|
||||||
|
|
||||||
|
int percentile = -1;
|
||||||
switch ( resultAddress.statisticsType() )
|
switch ( resultAddress.statisticsType() )
|
||||||
{
|
{
|
||||||
case RifEclipseSummaryAddressDefines::StatisticsType::P10:
|
case RifEclipseSummaryAddressDefines::StatisticsType::P10:
|
||||||
return { true, m_p10Data };
|
percentile = 10;
|
||||||
|
break;
|
||||||
case RifEclipseSummaryAddressDefines::StatisticsType::P50:
|
case RifEclipseSummaryAddressDefines::StatisticsType::P50:
|
||||||
return { true, m_p50Data };
|
percentile = 50;
|
||||||
|
break;
|
||||||
case RifEclipseSummaryAddressDefines::StatisticsType::P90:
|
case RifEclipseSummaryAddressDefines::StatisticsType::P90:
|
||||||
return { true, m_p90Data };
|
percentile = 90;
|
||||||
case RifEclipseSummaryAddressDefines::StatisticsType::MEAN:
|
break;
|
||||||
return { true, m_meanData };
|
case RifEclipseSummaryAddressDefines::StatisticsType::CUSTOM:
|
||||||
|
percentile = resultAddress.percentile();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return { true, {} };
|
return { true, {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( percentile >= RifEclipseSummaryAddress::MIN_PERCENTILE && percentile <= RifEclipseSummaryAddress::MAX_PERCENTILE )
|
||||||
|
{
|
||||||
|
auto it = m_percentileData.find( percentile );
|
||||||
|
if ( it != m_percentileData.end() )
|
||||||
|
{
|
||||||
|
return { true, it->second };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { true, {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -132,9 +167,10 @@ RifSummaryReaderInterface* RimEnsembleStatisticsCase::summaryReader()
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
void RimEnsembleStatisticsCase::calculate( const std::vector<RimSummaryCase*>& summaryCases,
|
void RimEnsembleStatisticsCase::calculate( const std::vector<RimSummaryCase*>& summaryCases,
|
||||||
const RifEclipseSummaryAddress& inputAddress,
|
const RifEclipseSummaryAddress& inputAddress,
|
||||||
bool includeIncompleteCurves )
|
bool includeIncompleteCurves,
|
||||||
|
const std::vector<int>& percentiles )
|
||||||
{
|
{
|
||||||
auto hash = RiaHashTools::hash( summaryCases, inputAddress.toEclipseTextAddress(), includeIncompleteCurves );
|
auto hash = RiaHashTools::hash( summaryCases, inputAddress.toEclipseTextAddress(), includeIncompleteCurves, percentiles );
|
||||||
if ( hash == m_hash ) return;
|
if ( hash == m_hash ) return;
|
||||||
|
|
||||||
auto startTime = RiaLogging::currentTime();
|
auto startTime = RiaLogging::currentTime();
|
||||||
@@ -143,6 +179,18 @@ void RimEnsembleStatisticsCase::calculate( const std::vector<RimSummaryCase*>& s
|
|||||||
|
|
||||||
clearData();
|
clearData();
|
||||||
|
|
||||||
|
m_requestedPercentiles = percentiles;
|
||||||
|
|
||||||
|
// Always include P10, P50, and P90
|
||||||
|
for ( int p : { 10, 50, 90 } )
|
||||||
|
{
|
||||||
|
if ( std::find( m_requestedPercentiles.begin(), m_requestedPercentiles.end(), p ) == m_requestedPercentiles.end() )
|
||||||
|
{
|
||||||
|
m_requestedPercentiles.push_back( p );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort( m_requestedPercentiles.begin(), m_requestedPercentiles.end() );
|
||||||
|
|
||||||
if ( !inputAddress.isValid() ) return;
|
if ( !inputAddress.isValid() ) return;
|
||||||
if ( summaryCases.empty() ) return;
|
if ( summaryCases.empty() ) return;
|
||||||
|
|
||||||
@@ -200,11 +248,14 @@ void RimEnsembleStatisticsCase::calculate( const std::vector<RimSummaryCase*>& s
|
|||||||
|
|
||||||
m_timeSteps = curveMerger.allXValues();
|
m_timeSteps = curveMerger.allXValues();
|
||||||
|
|
||||||
m_p10Data.reserve( m_timeSteps.size() );
|
|
||||||
m_p50Data.reserve( m_timeSteps.size() );
|
|
||||||
m_p90Data.reserve( m_timeSteps.size() );
|
|
||||||
m_meanData.reserve( m_timeSteps.size() );
|
m_meanData.reserve( m_timeSteps.size() );
|
||||||
|
|
||||||
|
// Initialize percentile storage
|
||||||
|
for ( int p : m_requestedPercentiles )
|
||||||
|
{
|
||||||
|
m_percentileData[p].reserve( m_timeSteps.size() );
|
||||||
|
}
|
||||||
|
|
||||||
for ( size_t timeStepIndex = 0; timeStepIndex < m_timeSteps.size(); timeStepIndex++ )
|
for ( size_t timeStepIndex = 0; timeStepIndex < m_timeSteps.size(); timeStepIndex++ )
|
||||||
{
|
{
|
||||||
std::vector<double> valuesAtTimeStep;
|
std::vector<double> valuesAtTimeStep;
|
||||||
@@ -215,12 +266,27 @@ void RimEnsembleStatisticsCase::calculate( const std::vector<RimSummaryCase*>& s
|
|||||||
valuesAtTimeStep.push_back( curveValues[curveIdx][timeStepIndex] );
|
valuesAtTimeStep.push_back( curveValues[curveIdx][timeStepIndex] );
|
||||||
}
|
}
|
||||||
|
|
||||||
double p10, p50, p90, mean;
|
double mean = RigStatisticsMath::calculateMean( valuesAtTimeStep );
|
||||||
RigStatisticsMath::calculateStatisticsCurves( valuesAtTimeStep, &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_meanData.push_back( mean );
|
||||||
|
|
||||||
|
// Calculate percentiles
|
||||||
|
std::vector<double> percentilePositions;
|
||||||
|
for ( int p : m_requestedPercentiles )
|
||||||
|
{
|
||||||
|
percentilePositions.push_back( static_cast<double>( p ) / 100.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto percentileValuesResult =
|
||||||
|
RigStatisticsMath::calculatePercentiles( valuesAtTimeStep, percentilePositions, RigStatisticsMath::PercentileStyle::SWITCHED );
|
||||||
|
|
||||||
|
if ( percentileValuesResult.has_value() )
|
||||||
|
{
|
||||||
|
const auto& percentileValues = *percentileValuesResult;
|
||||||
|
for ( size_t i = 0; i < m_requestedPercentiles.size(); i++ )
|
||||||
|
{
|
||||||
|
m_percentileData[m_requestedPercentiles[i]].push_back( percentileValues[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool showDebugTiming = false;
|
bool showDebugTiming = false;
|
||||||
@@ -250,10 +316,9 @@ RiaDefines::EclipseUnitSystem RimEnsembleStatisticsCase::unitSystem() const
|
|||||||
void RimEnsembleStatisticsCase::clearData()
|
void RimEnsembleStatisticsCase::clearData()
|
||||||
{
|
{
|
||||||
m_timeSteps.clear();
|
m_timeSteps.clear();
|
||||||
m_p10Data.clear();
|
|
||||||
m_p50Data.clear();
|
|
||||||
m_p90Data.clear();
|
|
||||||
m_meanData.clear();
|
m_meanData.clear();
|
||||||
|
m_percentileData.clear();
|
||||||
|
m_requestedPercentiles.clear();
|
||||||
m_firstSummaryCase = nullptr;
|
m_firstSummaryCase = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include "RimSummaryCase.h"
|
#include "RimSummaryCase.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
class RifEclipseSummaryAddress;
|
class RifEclipseSummaryAddress;
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
@@ -37,13 +39,17 @@ public:
|
|||||||
bool hasP50Data() const;
|
bool hasP50Data() const;
|
||||||
bool hasP90Data() const;
|
bool hasP90Data() const;
|
||||||
bool hasMeanData() const;
|
bool hasMeanData() const;
|
||||||
|
bool hasPercentileData( int percentile ) const;
|
||||||
|
|
||||||
QString caseName() const override;
|
QString caseName() const override;
|
||||||
void createSummaryReaderInterface() override;
|
void createSummaryReaderInterface() override;
|
||||||
RifSummaryReaderInterface* summaryReader() override;
|
RifSummaryReaderInterface* summaryReader() override;
|
||||||
RiaDefines::EclipseUnitSystem unitSystem() const override;
|
RiaDefines::EclipseUnitSystem unitSystem() const override;
|
||||||
|
|
||||||
void calculate( const std::vector<RimSummaryCase*>& summaryCases, const RifEclipseSummaryAddress& inputAddress, bool includeIncompleteCurves );
|
void calculate( const std::vector<RimSummaryCase*>& summaryCases,
|
||||||
|
const RifEclipseSummaryAddress& inputAddress,
|
||||||
|
bool includeIncompleteCurves,
|
||||||
|
const std::vector<int>& percentiles = { 10, 50, 90 } );
|
||||||
|
|
||||||
std::vector<time_t> timeSteps( const RifEclipseSummaryAddress& resultAddress ) const override;
|
std::vector<time_t> timeSteps( const RifEclipseSummaryAddress& resultAddress ) const override;
|
||||||
std::pair<bool, std::vector<double>> values( const RifEclipseSummaryAddress& resultAddress ) const override;
|
std::pair<bool, std::vector<double>> values( const RifEclipseSummaryAddress& resultAddress ) const override;
|
||||||
@@ -58,11 +64,10 @@ private:
|
|||||||
size_t keywordCount() const override;
|
size_t keywordCount() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<time_t> m_timeSteps;
|
std::vector<time_t> m_timeSteps;
|
||||||
std::vector<double> m_p10Data;
|
std::vector<double> m_meanData;
|
||||||
std::vector<double> m_p50Data;
|
std::map<int, std::vector<double>> m_percentileData;
|
||||||
std::vector<double> m_p90Data;
|
std::vector<int> m_requestedPercentiles;
|
||||||
std::vector<double> m_meanData;
|
|
||||||
|
|
||||||
caf::PdmPointer<RimSummaryCase> m_firstSummaryCase;
|
caf::PdmPointer<RimSummaryCase> m_firstSummaryCase;
|
||||||
size_t m_hash = 0;
|
size_t m_hash = 0;
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ RimSummaryAddress::RimSummaryAddress()
|
|||||||
|
|
||||||
CAF_PDM_InitField( &m_caseId, "CaseId", -1, "CaseId" );
|
CAF_PDM_InitField( &m_caseId, "CaseId", -1, "CaseId" );
|
||||||
CAF_PDM_InitField( &m_ensembleId, "EnsembleId", -1, "EnsembleId" );
|
CAF_PDM_InitField( &m_ensembleId, "EnsembleId", -1, "EnsembleId" );
|
||||||
|
CAF_PDM_InitField( &m_percentile, "Percentile", -1, "Percentile" );
|
||||||
|
|
||||||
m_category = RifEclipseSummaryAddressDefines::SummaryCategory::SUMMARY_INVALID;
|
m_category = RifEclipseSummaryAddressDefines::SummaryCategory::SUMMARY_INVALID;
|
||||||
m_statistics = RifEclipseSummaryAddressDefines::StatisticsType::NONE;
|
m_statistics = RifEclipseSummaryAddressDefines::StatisticsType::NONE;
|
||||||
@@ -138,6 +139,7 @@ void RimSummaryAddress::setAddress( const RifEclipseSummaryAddress& addr )
|
|||||||
m_cellJ = addr.cellJ();
|
m_cellJ = addr.cellJ();
|
||||||
m_cellK = addr.cellK();
|
m_cellK = addr.cellK();
|
||||||
m_calculationId = addr.id();
|
m_calculationId = addr.id();
|
||||||
|
m_percentile = addr.percentile();
|
||||||
|
|
||||||
setUiName( m_vectorName );
|
setUiName( m_vectorName );
|
||||||
setUiIconFromResourceString( iconResourceText() );
|
setUiIconFromResourceString( iconResourceText() );
|
||||||
@@ -148,23 +150,25 @@ void RimSummaryAddress::setAddress( const RifEclipseSummaryAddress& addr )
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
RifEclipseSummaryAddress RimSummaryAddress::address() const
|
RifEclipseSummaryAddress RimSummaryAddress::address() const
|
||||||
{
|
{
|
||||||
return RifEclipseSummaryAddress( m_category(),
|
auto addr = RifEclipseSummaryAddress( m_category(),
|
||||||
m_statistics(),
|
m_statistics(),
|
||||||
m_vectorName().toStdString(),
|
m_vectorName().toStdString(),
|
||||||
m_regionNumber(),
|
m_regionNumber(),
|
||||||
m_regionNumber2(),
|
m_regionNumber2(),
|
||||||
m_groupName().toStdString(),
|
m_groupName().toStdString(),
|
||||||
m_networkName().toStdString(),
|
m_networkName().toStdString(),
|
||||||
m_wellName().toStdString(),
|
m_wellName().toStdString(),
|
||||||
m_wellSegmentNumber(),
|
m_wellSegmentNumber(),
|
||||||
m_lgrName().toStdString(),
|
m_lgrName().toStdString(),
|
||||||
m_cellI(),
|
m_cellI(),
|
||||||
m_cellJ(),
|
m_cellJ(),
|
||||||
m_cellK(),
|
m_cellK(),
|
||||||
m_aquiferNumber,
|
m_aquiferNumber,
|
||||||
m_wellCompletionNumber(),
|
m_wellCompletionNumber(),
|
||||||
m_isErrorResult,
|
m_isErrorResult,
|
||||||
m_calculationId );
|
m_calculationId );
|
||||||
|
addr.setPercentile( m_percentile );
|
||||||
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -85,4 +85,5 @@ private:
|
|||||||
caf::PdmField<int> m_calculationId;
|
caf::PdmField<int> m_calculationId;
|
||||||
caf::PdmField<int> m_caseId;
|
caf::PdmField<int> m_caseId;
|
||||||
caf::PdmField<int> m_ensembleId;
|
caf::PdmField<int> m_ensembleId;
|
||||||
|
caf::PdmField<int> m_percentile;
|
||||||
};
|
};
|
||||||
@@ -1088,6 +1088,15 @@ bool RimEnsembleWellLogCurveSet::hasMeanData() const
|
|||||||
return m_ensembleWellLogStatistics->hasMeanData();
|
return m_ensembleWellLogStatistics->hasMeanData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimEnsembleWellLogCurveSet::hasPercentileData( int /*p*/ ) const
|
||||||
|
{
|
||||||
|
// Custom percentiles are not supported for well log statistics
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ public:
|
|||||||
bool hasP50Data() const override;
|
bool hasP50Data() const override;
|
||||||
bool hasP90Data() const override;
|
bool hasP90Data() const override;
|
||||||
bool hasMeanData() const override;
|
bool hasMeanData() const override;
|
||||||
|
bool hasPercentileData( int p ) const override;
|
||||||
|
|
||||||
void appendColorGroup( caf::PdmUiOrdering& uiOrdering );
|
void appendColorGroup( caf::PdmUiOrdering& uiOrdering );
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user