2013-04-05 03:49:39 -05:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS
|
2019-09-06 03:40:57 -05:00
|
|
|
|
//
|
2013-04-05 03:49:39 -05:00
|
|
|
|
// 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.
|
2019-09-06 03:40:57 -05:00
|
|
|
|
//
|
2013-04-05 03:49:39 -05:00
|
|
|
|
// 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.
|
2019-09-06 03:40:57 -05:00
|
|
|
|
//
|
|
|
|
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
2013-04-05 03:49:39 -05:00
|
|
|
|
// for more details.
|
|
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
#include "RigStatisticsMath.h"
|
2019-03-15 05:50:21 -05:00
|
|
|
|
|
|
|
|
|
#include "cvfMath.h"
|
|
|
|
|
|
2013-04-05 03:49:39 -05:00
|
|
|
|
#include <algorithm>
|
2021-02-25 09:38:56 -06:00
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <cmath>
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
|
/// A function to do basic statistical calculations
|
2013-04-05 03:49:39 -05:00
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
|
2019-11-04 07:35:41 -06:00
|
|
|
|
void RigStatisticsMath::calculateBasicStatistics( const std::vector<double>& values,
|
|
|
|
|
double* min,
|
|
|
|
|
double* max,
|
|
|
|
|
double* sum,
|
|
|
|
|
double* range,
|
|
|
|
|
double* mean,
|
|
|
|
|
double* dev )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
double m_min( HUGE_VAL );
|
|
|
|
|
double m_max( -HUGE_VAL );
|
|
|
|
|
double m_mean( HUGE_VAL );
|
|
|
|
|
double m_dev( HUGE_VAL );
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
double m_sum = 0.0;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
double sumSquared = 0.0;
|
|
|
|
|
|
|
|
|
|
size_t validValueCount = 0;
|
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
for ( size_t i = 0; i < values.size(); i++ )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
|
|
|
|
double val = values[i];
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( RiaStatisticsTools::isInvalidNumber<double>( val ) ) continue;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
|
|
|
|
validValueCount++;
|
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( val < m_min ) m_min = val;
|
|
|
|
|
if ( val > m_max ) m_max = val;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2016-08-09 08:32:43 -05:00
|
|
|
|
m_sum += val;
|
2019-09-06 03:40:57 -05:00
|
|
|
|
sumSquared += ( val * val );
|
2013-04-05 03:49:39 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( validValueCount > 0 )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
2016-08-09 08:32:43 -05:00
|
|
|
|
m_mean = m_sum / validValueCount;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
|
|
|
|
// http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
|
|
|
|
|
// Running standard deviation
|
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
double s0 = static_cast<double>( validValueCount );
|
2016-08-09 08:32:43 -05:00
|
|
|
|
double s1 = m_sum;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
double s2 = sumSquared;
|
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
m_dev = sqrt( ( s0 * s2 ) - ( s1 * s1 ) ) / s0;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( min ) *min = m_min;
|
|
|
|
|
if ( max ) *max = m_max;
|
|
|
|
|
if ( sum ) *sum = m_sum;
|
|
|
|
|
if ( range ) *range = m_max - m_min;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( mean ) *mean = m_mean;
|
|
|
|
|
if ( dev ) *dev = m_dev;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-25 00:38:46 -05:00
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
/// Algorithm:
|
|
|
|
|
/// https://en.wikipedia.org/wiki/Percentile#Third_variant,_'%22%60UNIQ--postMath-00000052-QINU%60%22'
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-11-04 07:35:41 -06:00
|
|
|
|
void RigStatisticsMath::calculateStatisticsCurves( const std::vector<double>& values,
|
|
|
|
|
double* p10,
|
|
|
|
|
double* p50,
|
|
|
|
|
double* p90,
|
2021-09-16 03:38:27 -05:00
|
|
|
|
double* mean,
|
|
|
|
|
PercentileStyle percentileStyle )
|
2019-07-25 00:38:46 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
CVF_ASSERT( p10 && p50 && p90 && mean );
|
2019-07-25 00:38:46 -05:00
|
|
|
|
|
2020-12-18 00:33:23 -06:00
|
|
|
|
if ( values.empty() ) return;
|
|
|
|
|
|
2019-07-25 00:38:46 -05:00
|
|
|
|
enum PValue
|
|
|
|
|
{
|
|
|
|
|
P10,
|
|
|
|
|
P50,
|
|
|
|
|
P90
|
|
|
|
|
};
|
|
|
|
|
|
2022-06-07 14:09:36 -05:00
|
|
|
|
std::vector<double> sortedValues = values;
|
2019-07-25 00:38:46 -05:00
|
|
|
|
|
2022-06-07 14:09:36 -05:00
|
|
|
|
sortedValues.erase( std::remove_if( sortedValues.begin(),
|
|
|
|
|
sortedValues.end(),
|
|
|
|
|
[]( double x ) { return !RiaStatisticsTools::isValidNumber( x ); } ),
|
|
|
|
|
sortedValues.end() );
|
|
|
|
|
|
|
|
|
|
std::sort( sortedValues.begin(), sortedValues.end() );
|
|
|
|
|
|
|
|
|
|
double valueSum = std::accumulate( sortedValues.begin(), sortedValues.end(), 0.0 );
|
2019-07-25 00:38:46 -05:00
|
|
|
|
|
|
|
|
|
int valueCount = (int)sortedValues.size();
|
2020-11-06 03:46:38 -06:00
|
|
|
|
double percentiles[] = { 0.1, 0.5, 0.9 };
|
|
|
|
|
double pValues[] = { HUGE_VAL, HUGE_VAL, HUGE_VAL };
|
2019-07-25 00:38:46 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
for ( int i = P10; i <= P90; i++ )
|
2019-07-25 00:38:46 -05:00
|
|
|
|
{
|
|
|
|
|
// Check valid params
|
2023-02-26 03:48:40 -06:00
|
|
|
|
if ( ( percentiles[i] < 1.0 / ( (double)valueCount + 1 ) ) || ( percentiles[i] > (double)valueCount / ( (double)valueCount + 1 ) ) )
|
2019-07-25 00:38:46 -05:00
|
|
|
|
continue;
|
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
double rank = percentiles[i] * ( valueCount + 1 ) - 1;
|
2019-07-25 00:38:46 -05:00
|
|
|
|
double rankRem;
|
2019-09-06 03:40:57 -05:00
|
|
|
|
double rankFrac = std::modf( rank, &rankRem );
|
|
|
|
|
int rankInt = static_cast<int>( rankRem );
|
2019-07-25 00:38:46 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( rankInt < valueCount - 1 )
|
2019-07-25 00:38:46 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
pValues[i] = sortedValues[rankInt] + rankFrac * ( sortedValues[rankInt + 1] - sortedValues[rankInt] );
|
2019-07-25 00:38:46 -05:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pValues[i] = sortedValues.back();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-16 03:38:27 -05:00
|
|
|
|
*p50 = pValues[P50];
|
|
|
|
|
|
|
|
|
|
if ( percentileStyle == PercentileStyle::REGULAR )
|
|
|
|
|
{
|
|
|
|
|
*p10 = pValues[P10];
|
|
|
|
|
*p90 = pValues[P90];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CVF_ASSERT( percentileStyle == PercentileStyle::SWITCHED );
|
|
|
|
|
*p10 = pValues[P90];
|
|
|
|
|
*p90 = pValues[P10];
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-25 00:38:46 -05:00
|
|
|
|
*mean = valueSum / valueCount;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-05 03:49:39 -05:00
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
/// Calculate the percentiles of /a inputValues at the pValPosition percentages using the "Nearest Rank"
|
|
|
|
|
/// method. This method treats HUGE_VAL as "undefined" values, and ignores these. Will return HUGE_VAL if
|
|
|
|
|
/// the inputValues does not contain any valid values
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
|
2023-02-26 03:48:40 -06:00
|
|
|
|
std::vector<double> RigStatisticsMath::calculateNearestRankPercentiles( const std::vector<double>& inputValues,
|
|
|
|
|
const std::vector<double>& pValPositions,
|
2021-09-16 03:38:27 -05:00
|
|
|
|
RigStatisticsMath::PercentileStyle percentileStyle )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
|
|
|
|
std::vector<double> sortedValues;
|
2019-09-06 03:40:57 -05:00
|
|
|
|
sortedValues.reserve( inputValues.size() );
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
for ( size_t i = 0; i < inputValues.size(); ++i )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( RiaStatisticsTools::isValidNumber<double>( inputValues[i] ) )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
sortedValues.push_back( inputValues[i] );
|
2013-04-05 03:49:39 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
std::sort( sortedValues.begin(), sortedValues.end() );
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
std::vector<double> percentiles( pValPositions.size(), HUGE_VAL );
|
|
|
|
|
if ( sortedValues.size() )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
for ( size_t i = 0; i < pValPositions.size(); ++i )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
|
|
|
|
double pVal = HUGE_VAL;
|
|
|
|
|
|
2021-09-16 03:38:27 -05:00
|
|
|
|
double pValPosition = cvf::Math::abs( pValPositions[i] ) / 100;
|
|
|
|
|
if ( percentileStyle == RigStatisticsMath::PercentileStyle::SWITCHED ) pValPosition = 1.0 - pValPosition;
|
|
|
|
|
|
|
|
|
|
size_t pValIndex = static_cast<size_t>( sortedValues.size() * pValPosition );
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( pValIndex >= sortedValues.size() ) pValIndex = sortedValues.size() - 1;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
pVal = sortedValues[pValIndex];
|
2013-04-05 03:49:39 -05:00
|
|
|
|
percentiles[i] = pVal;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return percentiles;
|
|
|
|
|
};
|
|
|
|
|
|
2013-04-30 04:36:50 -05:00
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
/// Calculate the percentiles of /a inputValues at the pValPosition percentages by interpolating input values.
|
|
|
|
|
/// This method treats HUGE_VAL as "undefined" values, and ignores these. Will return HUGE_VAL if
|
|
|
|
|
/// the inputValues does not contain any valid values
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2023-02-26 03:48:40 -06:00
|
|
|
|
std::vector<double> RigStatisticsMath::calculateInterpolatedPercentiles( const std::vector<double>& inputValues,
|
|
|
|
|
const std::vector<double>& pValPositions,
|
2021-09-16 03:38:27 -05:00
|
|
|
|
RigStatisticsMath::PercentileStyle percentileStyle )
|
2013-04-30 04:36:50 -05:00
|
|
|
|
{
|
|
|
|
|
std::vector<double> sortedValues;
|
2019-09-06 03:40:57 -05:00
|
|
|
|
sortedValues.reserve( inputValues.size() );
|
2013-04-30 04:36:50 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
for ( size_t i = 0; i < inputValues.size(); ++i )
|
2013-04-30 04:36:50 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( RiaStatisticsTools::isValidNumber<double>( inputValues[i] ) )
|
2013-04-30 04:36:50 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
sortedValues.push_back( inputValues[i] );
|
2013-04-30 04:36:50 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
std::sort( sortedValues.begin(), sortedValues.end() );
|
2013-04-30 04:36:50 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
std::vector<double> percentiles( pValPositions.size(), HUGE_VAL );
|
|
|
|
|
if ( sortedValues.size() )
|
2013-04-30 04:36:50 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
for ( size_t i = 0; i < pValPositions.size(); ++i )
|
2013-04-30 04:36:50 -05:00
|
|
|
|
{
|
|
|
|
|
double pVal = HUGE_VAL;
|
|
|
|
|
|
2021-09-16 03:38:27 -05:00
|
|
|
|
double pValPosition = cvf::Math::abs( pValPositions[i] ) / 100.0;
|
|
|
|
|
if ( percentileStyle == RigStatisticsMath::PercentileStyle::SWITCHED ) pValPosition = 1.0 - pValPosition;
|
|
|
|
|
|
|
|
|
|
double doubleIndex = ( sortedValues.size() - 1 ) * pValPosition;
|
2013-04-30 04:36:50 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
size_t lowerValueIndex = static_cast<size_t>( floor( doubleIndex ) );
|
2013-04-30 04:36:50 -05:00
|
|
|
|
size_t upperValueIndex = lowerValueIndex + 1;
|
|
|
|
|
|
2013-04-30 06:08:04 -05:00
|
|
|
|
double upperValueWeight = doubleIndex - lowerValueIndex;
|
2019-09-06 03:40:57 -05:00
|
|
|
|
assert( upperValueWeight < 1.0 );
|
2013-04-30 04:36:50 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( upperValueIndex < sortedValues.size() )
|
2013-04-30 04:36:50 -05:00
|
|
|
|
{
|
2023-02-26 03:48:40 -06:00
|
|
|
|
pVal = ( 1.0 - upperValueWeight ) * sortedValues[lowerValueIndex] + upperValueWeight * sortedValues[upperValueIndex];
|
2013-04-30 06:08:04 -05:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pVal = sortedValues[lowerValueIndex];
|
2013-04-30 04:36:50 -05:00
|
|
|
|
}
|
|
|
|
|
percentiles[i] = pVal;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return percentiles;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-05 03:49:39 -05:00
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
|
///
|
2013-04-05 03:49:39 -05:00
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
|
RigHistogramCalculator::RigHistogramCalculator( double min, double max, size_t nBins, std::vector<size_t>* histogram )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
assert( histogram );
|
|
|
|
|
assert( nBins > 0 );
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( max == min )
|
|
|
|
|
{
|
|
|
|
|
nBins = 1;
|
|
|
|
|
} // Avoid dividing on 0 range
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
m_histogram = histogram;
|
|
|
|
|
m_min = min;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
m_observationCount = 0;
|
|
|
|
|
|
|
|
|
|
// Initialize bins
|
2019-09-06 03:40:57 -05:00
|
|
|
|
m_histogram->resize( nBins );
|
|
|
|
|
for ( size_t i = 0; i < m_histogram->size(); ++i )
|
|
|
|
|
( *m_histogram )[i] = 0;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
m_range = max - min;
|
|
|
|
|
m_maxIndex = nBins - 1;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
|
///
|
2013-04-05 03:49:39 -05:00
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
|
void RigHistogramCalculator::addValue( double value )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( RiaStatisticsTools::isInvalidNumber<double>( value ) ) return;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2015-11-06 03:18:55 -06:00
|
|
|
|
size_t index = 0;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2023-04-13 00:05:53 -05:00
|
|
|
|
if ( m_maxIndex > 0 ) index = (size_t)( m_maxIndex * ( value - m_min ) / m_range );
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( index < m_histogram->size() ) // Just clip to the max min range (-index will overflow to positive )
|
2015-11-06 03:18:55 -06:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
( *m_histogram )[index]++;
|
2015-11-06 03:18:55 -06:00
|
|
|
|
m_observationCount++;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
|
///
|
2015-06-04 08:58:21 -05:00
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
|
void RigHistogramCalculator::addData( const std::vector<double>& data )
|
2015-06-04 08:58:21 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
assert( m_histogram );
|
|
|
|
|
for ( size_t i = 0; i < data.size(); ++i )
|
2015-06-04 08:58:21 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
addValue( data[i] );
|
2015-11-06 03:18:55 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-04 08:58:21 -05:00
|
|
|
|
|
2015-11-06 03:18:55 -06:00
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
|
///
|
2015-11-06 03:18:55 -06:00
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
|
void RigHistogramCalculator::addData( const std::vector<float>& data )
|
2015-11-06 03:18:55 -06:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
assert( m_histogram );
|
|
|
|
|
for ( size_t i = 0; i < data.size(); ++i )
|
2015-11-06 03:18:55 -06:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
addValue( data[i] );
|
2015-06-04 08:58:21 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
|
///
|
2013-04-05 03:49:39 -05:00
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-09-16 03:38:27 -05:00
|
|
|
|
double RigHistogramCalculator::calculatePercentil( double pVal, RigStatisticsMath::PercentileStyle percentileStyle )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
assert( m_histogram );
|
|
|
|
|
assert( m_histogram->size() );
|
2020-05-20 03:38:28 -05:00
|
|
|
|
auto pValClamped = cvf::Math::clamp( pVal, 0.0, 1.0 );
|
|
|
|
|
assert( 0.0 <= pValClamped && pValClamped <= 1.0 );
|
2021-09-16 03:38:27 -05:00
|
|
|
|
if ( percentileStyle == RigStatisticsMath::PercentileStyle::SWITCHED )
|
|
|
|
|
{
|
|
|
|
|
pValClamped = 1.0 - pValClamped;
|
|
|
|
|
}
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
2020-05-20 03:38:28 -05:00
|
|
|
|
double pValObservationCount = pValClamped * m_observationCount;
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( pValObservationCount == 0.0 ) return m_min;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
|
|
|
|
size_t accObsCount = 0;
|
2019-09-06 03:40:57 -05:00
|
|
|
|
double binWidth = m_range / m_histogram->size();
|
|
|
|
|
for ( size_t binIdx = 0; binIdx < m_histogram->size(); ++binIdx )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
size_t binObsCount = ( *m_histogram )[binIdx];
|
2013-04-05 03:49:39 -05:00
|
|
|
|
|
|
|
|
|
accObsCount += binObsCount;
|
2019-09-06 03:40:57 -05:00
|
|
|
|
if ( accObsCount >= pValObservationCount )
|
2013-04-05 03:49:39 -05:00
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
|
double domainValueAtEndOfBin = m_min + ( binIdx + 1 ) * binWidth;
|
|
|
|
|
double unusedFractionOfLastBin = (double)( accObsCount - pValObservationCount ) / binObsCount;
|
2019-03-15 05:50:21 -05:00
|
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
|
double histogramBasedEstimate = domainValueAtEndOfBin - unusedFractionOfLastBin * binWidth;
|
2019-03-15 05:50:21 -05:00
|
|
|
|
|
|
|
|
|
// See https://resinsight.org/docs/casegroupsandstatistics/#percentile-methods for details
|
|
|
|
|
|
|
|
|
|
return histogramBasedEstimate;
|
2013-04-05 03:49:39 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-06 03:40:57 -05:00
|
|
|
|
assert( false );
|
2018-11-23 03:13:58 -06:00
|
|
|
|
|
2013-04-05 03:49:39 -05:00
|
|
|
|
return HUGE_VAL;
|
|
|
|
|
}
|