mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 07:00:17 -05:00
#7750 Histogram Plot: Add logarithmic binning and user-defined bin range
Add BinningMode (Linear/Logarithmic) and OutOfRangeHandling (Exclude/Include in Boundary Bins) to RigHistogramCalculator, with defaulted constructor arguments so existing callers are unaffected. All four histogram plot data sources get shared options for binning mode and an optional user-defined bin range through new PDM fields on RimHistogramDataSource. The grid statistics data source computes non-default histograms through a new non-caching RigStatisticsDataCache::computeHistogram() pass-through, leaving the cached statistics used by the 3D overlay and the P10/P90/mean annotation lines untouched. Selecting logarithmic binning enables logarithmic scale on the plot X axis once, via a new signal handled by RimHistogramCurve. Also fix the bin index computation to use uniform bins of width range/nBins, consistent with calculatePercentil() and the bin edges drawn by the plots. The previous divisor (nBins - 1) shifted counts by up to one bin width relative to the drawn bars and slightly biased histogram-based percentile estimates.
This commit is contained in:
1 parent
f742fdcac4
commit
d96159fb7c
23 files changed
+927
-55
No files matched your search
@@ -283,6 +283,22 @@ const std::vector<size_t>& RigStatisticsDataCache::cellScalarValuesHistogram( si
|
||||
return m_statsPrTs[timeStepIndex].m_histogram;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigStatisticsDataCache::computeHistogram( RigHistogramCalculator& histogramCalculator )
|
||||
{
|
||||
m_statisticsCalculator->addDataToHistogramCalculator( histogramCalculator );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigStatisticsDataCache::computeHistogram( size_t timeStepIndex, RigHistogramCalculator& histogramCalculator )
|
||||
{
|
||||
m_statisticsCalculator->addDataToHistogramCalculator( timeStepIndex, histogramCalculator );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -57,6 +57,10 @@ public:
|
||||
const std::vector<size_t>& cellScalarValuesHistogram();
|
||||
const std::vector<size_t>& cellScalarValuesHistogram( size_t timeStepIndex );
|
||||
|
||||
// Fills the supplied histogram calculator from the underlying data. Nothing is cached.
|
||||
void computeHistogram( RigHistogramCalculator& histogramCalculator );
|
||||
void computeHistogram( size_t timeStepIndex, RigHistogramCalculator& histogramCalculator );
|
||||
|
||||
const std::vector<int>& uniqueCellScalarValues();
|
||||
const std::vector<int>& uniqueCellScalarValues( size_t timeStepIndex );
|
||||
|
||||
|
||||
@@ -451,7 +451,12 @@ double RigStatisticsMath::calculateMean( const std::vector<double>& values )
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigHistogramCalculator::RigHistogramCalculator( double min, double max, size_t nBins, std::vector<size_t>* histogram )
|
||||
RigHistogramCalculator::RigHistogramCalculator( double min,
|
||||
double max,
|
||||
size_t nBins,
|
||||
std::vector<size_t>* histogram,
|
||||
BinningMode binningMode,
|
||||
OutOfRangeHandling outOfRangeHandling )
|
||||
{
|
||||
assert( histogram );
|
||||
assert( nBins > 0 );
|
||||
@@ -461,16 +466,33 @@ RigHistogramCalculator::RigHistogramCalculator( double min, double max, size_t n
|
||||
nBins = 1;
|
||||
} // Avoid dividing on 0 range
|
||||
|
||||
m_histogram = histogram;
|
||||
m_min = min;
|
||||
m_observationCount = 0;
|
||||
// Logarithmic binning requires a positive range
|
||||
if ( binningMode == BinningMode::LOGARITHMIC && min <= 0.0 )
|
||||
{
|
||||
binningMode = BinningMode::LINEAR;
|
||||
}
|
||||
|
||||
m_histogram = histogram;
|
||||
m_binningMode = binningMode;
|
||||
m_outOfRangeHandling = outOfRangeHandling;
|
||||
m_observationCount = 0;
|
||||
|
||||
// Initialize bins
|
||||
m_histogram->resize( nBins );
|
||||
for ( size_t i = 0; i < m_histogram->size(); ++i )
|
||||
( *m_histogram )[i] = 0;
|
||||
|
||||
m_range = max - min;
|
||||
if ( m_binningMode == BinningMode::LOGARITHMIC )
|
||||
{
|
||||
m_min = std::log10( min );
|
||||
m_max = std::log10( max );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_min = min;
|
||||
m_max = max;
|
||||
}
|
||||
m_range = m_max - m_min;
|
||||
m_maxIndex = nBins - 1;
|
||||
}
|
||||
|
||||
@@ -481,15 +503,37 @@ void RigHistogramCalculator::addValue( double value )
|
||||
{
|
||||
if ( RigStatisticsTools::isInvalidNumber<double>( value ) ) return;
|
||||
|
||||
double transformed = value;
|
||||
if ( m_binningMode == BinningMode::LOGARITHMIC )
|
||||
{
|
||||
if ( value <= 0.0 )
|
||||
{
|
||||
// Non-positive values cannot be represented on a logarithmic scale and are below any valid range
|
||||
if ( m_outOfRangeHandling != OutOfRangeHandling::INCLUDE_IN_BOUNDARY_BINS ) return;
|
||||
( *m_histogram )[0]++;
|
||||
m_observationCount++;
|
||||
return;
|
||||
}
|
||||
transformed = std::log10( value );
|
||||
}
|
||||
|
||||
if ( transformed < m_min || transformed > m_max )
|
||||
{
|
||||
if ( m_outOfRangeHandling != OutOfRangeHandling::INCLUDE_IN_BOUNDARY_BINS ) return;
|
||||
size_t boundaryIndex = transformed < m_min ? 0 : m_maxIndex;
|
||||
( *m_histogram )[boundaryIndex]++;
|
||||
m_observationCount++;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
if ( m_maxIndex > 0 ) index = (size_t)( m_maxIndex * ( value - m_min ) / m_range );
|
||||
// Uniform bins of width m_range / nBins, consistent with calculatePercentil() and the bin edges
|
||||
// drawn by the histogram plots. The maximum value is included in the last bin.
|
||||
if ( m_maxIndex > 0 ) index = std::min( (size_t)( m_histogram->size() * ( transformed - m_min ) / m_range ), m_maxIndex );
|
||||
|
||||
if ( index < m_histogram->size() ) // Just clip to the max min range (-index will overflow to positive )
|
||||
{
|
||||
( *m_histogram )[index]++;
|
||||
m_observationCount++;
|
||||
}
|
||||
( *m_histogram )[index]++;
|
||||
m_observationCount++;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -545,8 +589,11 @@ double RigHistogramCalculator::calculatePercentil( double pVal, RigStatisticsMat
|
||||
pValClamped = 1.0 - pValClamped;
|
||||
}
|
||||
|
||||
auto toDomainValue = [this]( double binSpaceValue )
|
||||
{ return m_binningMode == BinningMode::LOGARITHMIC ? std::pow( 10.0, binSpaceValue ) : binSpaceValue; };
|
||||
|
||||
double pValObservationCount = pValClamped * m_observationCount;
|
||||
if ( pValObservationCount == 0.0 ) return m_min;
|
||||
if ( pValObservationCount == 0.0 ) return toDomainValue( m_min );
|
||||
|
||||
size_t accObsCount = 0;
|
||||
double binWidth = m_range / m_histogram->size();
|
||||
@@ -564,7 +611,8 @@ double RigHistogramCalculator::calculatePercentil( double pVal, RigStatisticsMat
|
||||
|
||||
// See https://resinsight.org/docs/casegroupsandstatistics/#percentile-methods for details
|
||||
|
||||
return histogramBasedEstimate;
|
||||
// For logarithmic binning the interpolation happens in log10 space
|
||||
return toDomainValue( histogramBasedEstimate );
|
||||
}
|
||||
}
|
||||
assert( false );
|
||||
|
||||
@@ -65,7 +65,24 @@ public:
|
||||
class RigHistogramCalculator
|
||||
{
|
||||
public:
|
||||
RigHistogramCalculator( double min, double max, size_t nBins, std::vector<size_t>* histogram );
|
||||
enum class BinningMode
|
||||
{
|
||||
LINEAR,
|
||||
LOGARITHMIC
|
||||
};
|
||||
|
||||
enum class OutOfRangeHandling
|
||||
{
|
||||
EXCLUDE,
|
||||
INCLUDE_IN_BOUNDARY_BINS
|
||||
};
|
||||
|
||||
RigHistogramCalculator( double min,
|
||||
double max,
|
||||
size_t nBins,
|
||||
std::vector<size_t>* histogram,
|
||||
BinningMode binningMode = BinningMode::LINEAR,
|
||||
OutOfRangeHandling outOfRangeHandling = OutOfRangeHandling::EXCLUDE );
|
||||
|
||||
void addData( const std::vector<double>& data );
|
||||
void addData( const std::vector<float>& data );
|
||||
@@ -74,7 +91,7 @@ public:
|
||||
|
||||
/// Calculates the estimated percentile from the histogram.
|
||||
/// the percentile is the domain value at which pVal of the observations are below it.
|
||||
/// Will only consider observed values between min and max, as all other values are discarded from the histogram
|
||||
/// The estimate is only meaningful when the histogram covers the full range of the observed values.
|
||||
|
||||
double calculatePercentil( double pVal, RigStatisticsMath::PercentileStyle percentileStyle );
|
||||
|
||||
@@ -82,6 +99,9 @@ private:
|
||||
size_t m_maxIndex;
|
||||
double m_range;
|
||||
double m_min;
|
||||
double m_max;
|
||||
BinningMode m_binningMode;
|
||||
OutOfRangeHandling m_outOfRangeHandling;
|
||||
size_t m_observationCount;
|
||||
std::vector<size_t>* m_histogram;
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user