Improve user control on resampling operations

Allow user to specify Accumulated or Rate for a summary curve. Default setting is Auto, and summary address is used to derive Accumulated/Rate. User can set curve type explicitly.
This commit is contained in:
Magne Sjaastad
2024-08-28 15:23:07 +02:00
committed by GitHub
parent 64a559756f
commit 27c46a65fd
12 changed files with 188 additions and 103 deletions

View File

@@ -28,6 +28,15 @@ void caf::AppEnum<RiaDefines::HorizontalAxisType>::setUp()
addItem( RiaDefines::HorizontalAxisType::SUMMARY_VECTOR, "SUMMARY_VECTOR", "Summary Vector" );
setDefault( RiaDefines::HorizontalAxisType::SUMMARY_VECTOR );
}
template <>
void caf::AppEnum<RiaDefines::SummaryCurveTypeMode>::setUp()
{
addItem( RiaDefines::SummaryCurveTypeMode::AUTO, "AUTO", "Auto" );
addItem( RiaDefines::SummaryCurveTypeMode::CUSTOM, "CUSTOM", "Custom" );
setDefault( RiaDefines::SummaryCurveTypeMode::AUTO );
}
} // namespace caf
//--------------------------------------------------------------------------------------------------

View File

@@ -35,6 +35,12 @@ enum class HorizontalAxisType
SUMMARY_VECTOR
};
enum class SummaryCurveTypeMode
{
AUTO,
CUSTOM
};
QString summaryField();
QString summaryAquifer();
QString summaryNetwork();

View File

@@ -175,7 +175,7 @@ RimSummaryTableCollection* RiaSummaryTools::parentSummaryTableCollection( caf::P
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaSummaryTools::hasAccumulatedData( const RifEclipseSummaryAddress& address )
RifEclipseSummaryAddressDefines::CurveType RiaSummaryTools::identifyCurveType( const RifEclipseSummaryAddress& address )
{
if ( address.isCalculated() )
{
@@ -187,15 +187,16 @@ bool RiaSummaryTools::hasAccumulatedData( const RifEclipseSummaryAddress& addres
{
if ( !variableAddress.hasAccumulatedData() )
{
return false;
return RifEclipseSummaryAddressDefines::CurveType::RATE;
}
}
// All the variables are accumulated
return true;
return RifEclipseSummaryAddressDefines::CurveType::ACCUMULATED;
}
return address.hasAccumulatedData();
return address.hasAccumulatedData() ? RifEclipseSummaryAddressDefines::CurveType::ACCUMULATED
: RifEclipseSummaryAddressDefines::CurveType::RATE;
}
//--------------------------------------------------------------------------------------------------
@@ -231,11 +232,27 @@ std::pair<std::vector<time_t>, std::vector<double>> RiaSummaryTools::resampledVa
const std::vector<time_t>& timeSteps,
const std::vector<double>& values,
RiaDefines::DateTimePeriod period )
{
// NB! The curve type can be overridden by the user, so there might be a discrepancy between the curve type and the curve type derived
// from the address
// See RimSummaryCurve::curveType()
return resampledValuesForPeriod( RiaSummaryTools::identifyCurveType( address ), timeSteps, values, period );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<std::vector<time_t>, std::vector<double>>
RiaSummaryTools::resampledValuesForPeriod( RifEclipseSummaryAddressDefines::CurveType accumulatedOrRate,
const std::vector<time_t>& timeSteps,
const std::vector<double>& values,
RiaDefines::DateTimePeriod period )
{
RiaTimeHistoryCurveResampler resampler;
resampler.setCurveData( values, timeSteps );
if ( RiaSummaryTools::hasAccumulatedData( address ) )
if ( accumulatedOrRate == CurveType::ACCUMULATED )
{
resampler.resampleAndComputePeriodEndValues( period );
}

View File

@@ -19,6 +19,9 @@
#pragma once
#include "RiaDateTimeDefines.h"
#include "RifEclipseSummaryAddressDefines.h"
#include "RimObservedDataCollection.h"
#include <QString>
@@ -66,7 +69,7 @@ public:
static RimSummaryTable* parentSummaryTable( caf::PdmObject* object );
static RimSummaryTableCollection* parentSummaryTableCollection( caf::PdmObject* object );
static bool hasAccumulatedData( const RifEclipseSummaryAddress& address );
static RifEclipseSummaryAddressDefines::CurveType identifyCurveType( const RifEclipseSummaryAddress& address );
static void getSummaryCasesAndAddressesForCalculation( int id,
std::vector<RimSummaryCase*>& cases,
std::vector<RifEclipseSummaryAddress>& addresses );
@@ -76,6 +79,12 @@ public:
const std::vector<double>& values,
RiaDefines::DateTimePeriod period );
static std::pair<std::vector<time_t>, std::vector<double>>
resampledValuesForPeriod( RifEclipseSummaryAddressDefines::CurveType accumulatedOrRate,
const std::vector<time_t>& timeSteps,
const std::vector<double>& values,
RiaDefines::DateTimePeriod period );
static RimSummaryCase* summaryCaseById( int caseId );
static RimSummaryEnsemble* ensembleById( int ensembleId );

View File

@@ -32,6 +32,15 @@ void caf::AppEnum<RifEclipseSummaryAddressDefines::StatisticsType>::setUp()
addItem( RifEclipseSummaryAddressDefines::StatisticsType::MEAN, "MEAN", "Mean" );
setDefault( RifEclipseSummaryAddressDefines::StatisticsType::NONE );
}
template <>
void caf::AppEnum<RifEclipseSummaryAddressDefines::CurveType>::setUp()
{
addItem( RifEclipseSummaryAddressDefines::CurveType::RATE, "RATE", "Rate" );
addItem( RifEclipseSummaryAddressDefines::CurveType::ACCUMULATED, "ACCUMULATED", "Accumulated" );
setDefault( RifEclipseSummaryAddressDefines::CurveType::ACCUMULATED );
}
} // namespace caf
//--------------------------------------------------------------------------------------------------

View File

@@ -73,6 +73,12 @@ enum class StatisticsType
MEAN
};
enum class CurveType
{
ACCUMULATED,
RATE
};
std::string statisticsNameP10();
std::string statisticsNameP50();
std::string statisticsNameP90();

View File

@@ -87,6 +87,9 @@ RimSummaryCurve::RimSummaryCurve()
CAF_PDM_InitFieldNoDefault( &m_yValuesResampling, "Resampling", "Resampling" );
CAF_PDM_InitFieldNoDefault( &m_yCurveTypeMode, "CurveTypeMode", "Curve Type" );
CAF_PDM_InitFieldNoDefault( &m_yCurveType, "CurveType", "" );
// X Values
CAF_PDM_InitField( &m_xAxisType,
@@ -419,6 +422,14 @@ void RimSummaryCurve::setOverrideCurveDataY( const std::vector<time_t>& dateTime
setSamplesFromTimeTAndYValues( dateTimes, yValues, true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddressDefines::CurveType RimSummaryCurve::curveType() const
{
return m_yCurveType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -899,9 +910,15 @@ void RimSummaryCurve::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering
curveDataGroup->add( &m_yValuesSummaryCase, { .newRow = true, .totalColumnSpan = 3, .leftLabelColumnSpan = 1 } );
curveDataGroup->add( &m_yValuesSummaryAddressUiField, { .newRow = true, .totalColumnSpan = 2, .leftLabelColumnSpan = 1 } );
curveDataGroup->add( &m_yPushButtonSelectSummaryAddress, { .newRow = false, .totalColumnSpan = 1, .leftLabelColumnSpan = 0 } );
curveDataGroup->add( &m_yValuesResampling, { .newRow = true, .totalColumnSpan = 3, .leftLabelColumnSpan = 1 } );
curveDataGroup->add( &m_yPlotAxisProperties, { .newRow = true, .totalColumnSpan = 3, .leftLabelColumnSpan = 1 } );
curveDataGroup->add( &m_showErrorBars );
caf::PdmUiGroup* detailGroup = curveDataGroup->addNewGroup( "Advanced Properties" );
detailGroup->setCollapsedByDefault();
detailGroup->add( &m_yValuesResampling );
detailGroup->add( &m_showErrorBars );
detailGroup->add( &m_yCurveTypeMode );
detailGroup->add( &m_yCurveType );
m_yCurveType.uiCapability()->setUiReadOnly( m_yCurveTypeMode() == RiaDefines::SummaryCurveTypeMode::AUTO );
}
if ( m_showXAxisGroup )
@@ -1251,6 +1268,10 @@ void RimSummaryCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
m_xPushButtonSelectSummaryAddress = false;
}
else if ( changedField == &m_yCurveTypeMode )
{
calculateCurveTypeFromAddress();
}
if ( crossPlotTestForMatchingTimeSteps )
{
@@ -1369,10 +1390,11 @@ std::vector<time_t> RimSummaryCurve::timeStepsX() const
//--------------------------------------------------------------------------------------------------
void RimSummaryCurve::calculateCurveInterpolationFromAddress()
{
if ( m_yValuesSummaryAddress() )
{
auto address = m_yValuesSummaryAddress()->address();
if ( RiaSummaryTools::hasAccumulatedData( address ) )
if ( !m_yValuesSummaryAddress() ) return;
calculateCurveTypeFromAddress();
if ( curveType() == RifEclipseSummaryAddressDefines::CurveType::ACCUMULATED )
{
m_curveAppearance->setInterpolation( RiuQwtPlotCurveDefines::CurveInterpolationEnum::INTERPOLATION_POINT_TO_POINT );
}
@@ -1381,6 +1403,18 @@ void RimSummaryCurve::calculateCurveInterpolationFromAddress()
m_curveAppearance->setInterpolation( RiuQwtPlotCurveDefines::CurveInterpolationEnum::INTERPOLATION_STEP_LEFT );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryCurve::calculateCurveTypeFromAddress()
{
if ( !m_yValuesSummaryAddress() ) return;
if ( m_yCurveTypeMode() == RiaDefines::SummaryCurveTypeMode::AUTO )
{
m_yCurveType = RiaSummaryTools::identifyCurveType( m_yValuesSummaryAddress()->address() );
}
}
//--------------------------------------------------------------------------------------------------

View File

@@ -29,7 +29,9 @@
#include "RiaSummaryCurveAddress.h"
#include "RiaSummaryDefines.h"
#include "RifEclipseSummaryAddressDefines.h"
#include "RifEclipseSummaryAddressQMetaType.h"
#include "RimStackablePlotCurve.h"
#include "cafAppEnum.h"
@@ -76,6 +78,8 @@ public:
double yValueAtTimeT( time_t time ) const;
void setOverrideCurveDataY( const std::vector<time_t>& xValues, const std::vector<double>& yValues );
RifEclipseSummaryAddressDefines::CurveType curveType() const;
// X Axis functions
void setAxisTypeX( RiaDefines::HorizontalAxisType axisType );
RiaDefines::HorizontalAxisType axisTypeX() const;
@@ -140,6 +144,7 @@ private:
RifSummaryReaderInterface* valuesSummaryReaderY() const;
void calculateCurveInterpolationFromAddress();
void calculateCurveTypeFromAddress();
static void appendOptionItemsForSummaryAddresses( QList<caf::PdmOptionItemInfo>* options, RimSummaryCase* summaryCase );
@@ -152,6 +157,9 @@ private:
caf::PdmPtrField<RimPlotAxisPropertiesInterface*> m_yPlotAxisProperties;
caf::PdmField<RiaDefines::DateTimePeriodEnum> m_yValuesResampling;
caf::PdmField<caf::AppEnum<RiaDefines::SummaryCurveTypeMode>> m_yCurveTypeMode;
caf::PdmField<caf::AppEnum<RifEclipseSummaryAddressDefines::CurveType>> m_yCurveType;
// X values
caf::PdmField<caf::AppEnum<RiaDefines::HorizontalAxisType>> m_xAxisType;
caf::PdmPtrField<RimSummaryCase*> m_xValuesSummaryCase;

View File

@@ -49,7 +49,7 @@ void RimSummaryCurvesData::populateTimeHistoryCurvesData( std::vector<RimGridTim
if ( !curve->isChecked() ) continue;
QString curveCaseName = curve->caseName();
CurveData curveData = { curve->curveExportDescription( {} ), RifEclipseSummaryAddress(), curve->yValues() };
CurveData curveData = { curve->curveExportDescription( {} ), RifEclipseSummaryAddressDefines::CurveType::ACCUMULATED, curve->yValues() };
curvesData->addCurveData( curveCaseName, "", curve->timeStepValues(), curveData );
}
@@ -68,7 +68,7 @@ void RimSummaryCurvesData::populateAsciiDataCurvesData( std::vector<RimAsciiData
{
if ( !curve->isChecked() ) continue;
CurveData curveData = { curve->curveExportDescription( {} ), RifEclipseSummaryAddress(), curve->yValues() };
CurveData curveData = { curve->curveExportDescription( {} ), RifEclipseSummaryAddressDefines::CurveType::ACCUMULATED, curve->yValues() };
curvesData->addCurveDataNoSearch( "", "", curve->timeSteps(), { curveData } );
}
@@ -145,30 +145,25 @@ QString RimSummaryCurvesData::createTextForExport( const std::vector<RimSummaryC
QString out;
RimSummaryCurvesData summaryCurvesGridData;
RimSummaryCurvesData summaryCurvesData;
RimSummaryCurvesData summaryCurvesObsData;
RimSummaryCurvesData::populateSummaryCurvesData( curves, SummaryCurveType::CURVE_TYPE_GRID, &summaryCurvesGridData );
RimSummaryCurvesData gridCurvesData;
RimSummaryCurvesData::populateSummaryCurvesData( curves, SummaryCurveType::CURVE_TYPE_SUMMARY, &summaryCurvesData );
RimSummaryCurvesData::populateSummaryCurvesData( curves, SummaryCurveType::CURVE_TYPE_OBSERVED, &summaryCurvesObsData );
RimSummaryCurvesData::populateTimeHistoryCurvesData( gridCurves, &gridCurvesData );
RimSummaryCurvesData timeHistoryCurvesData;
RimSummaryCurvesData::populateTimeHistoryCurvesData( gridCurves, &timeHistoryCurvesData );
// Export observed data
RimSummaryCurvesData::appendToExportData( out, { summaryCurvesObsData }, showTimeAsLongString );
std::vector<RimSummaryCurvesData> exportData( 2 );
// Summary grid data for export
RimSummaryCurvesData::prepareCaseCurvesForExport( resamplingPeriod, ResampleAlgorithm::DATA_DECIDES, summaryCurvesGridData, &exportData[0] );
RimSummaryCurvesData::prepareCaseCurvesForExport( resamplingPeriod, ResampleAlgorithm::DATA_DECIDES, summaryCurvesData, &exportData[0] );
RimSummaryCurvesData::prepareCaseCurvesForExport( resamplingPeriod, ResampleAlgorithm::PERIOD_END, gridCurvesData, &exportData[1] );
// Time history data for export
RimSummaryCurvesData::prepareCaseCurvesForExport( resamplingPeriod, ResampleAlgorithm::PERIOD_END, timeHistoryCurvesData, &exportData[1] );
// Export resampled summary and time history data
RimSummaryCurvesData::appendToExportData( out, exportData, showTimeAsLongString );
// Pasted observed data
{
// Handle observed data pasted into plot from clipboard
RimSummaryCurvesData asciiCurvesData;
RimSummaryCurvesData::populateAsciiDataCurvesData( asciiCurves, &asciiCurvesData );
@@ -239,7 +234,7 @@ void RimSummaryCurvesData::populateSummaryCurvesData( std::vector<RimSummaryCurv
if ( !curve->isChecked() ) continue;
if ( isObservedCurve && ( curveType != SummaryCurveType::CURVE_TYPE_OBSERVED ) ) continue;
if ( !isObservedCurve && ( curveType != SummaryCurveType::CURVE_TYPE_GRID ) ) continue;
if ( !isObservedCurve && ( curveType != SummaryCurveType::CURVE_TYPE_SUMMARY ) ) continue;
if ( !curve->summaryCaseY() ) continue;
QString curveCaseName = curve->summaryCaseY()->displayCaseName();
@@ -249,7 +244,7 @@ void RimSummaryCurvesData::populateSummaryCurvesData( std::vector<RimSummaryCurv
ensembleName = curve->curveDefinition().ensemble()->name();
}
CurveData curveData = { curve->curveExportDescription( {} ), curve->summaryAddressY(), curve->valuesY() };
CurveData curveData = { curve->curveExportDescription( {} ), curve->curveType(), curve->valuesY() };
CurveData errorCurveData;
// Error data
@@ -259,7 +254,7 @@ void RimSummaryCurvesData::populateSummaryCurvesData( std::vector<RimSummaryCurv
if ( hasErrorData )
{
errorCurveData.name = curve->curveExportDescription( curve->errorSummaryAddressY() );
errorCurveData.address = curve->errorSummaryAddressY();
errorCurveData.curveType = curve->curveType();
errorCurveData.values = errorValues;
}
@@ -307,7 +302,7 @@ void RimSummaryCurvesData::prepareCaseCurvesForExport( RiaDefines::DateTimePerio
for ( auto& curveDataItem : caseCurveData )
{
const auto [resampledTime, resampledValues] =
RiaSummaryTools::resampledValuesForPeriod( curveDataItem.address, caseTimeSteps, curveDataItem.values, period );
RiaSummaryTools::resampledValuesForPeriod( curveDataItem.curveType, caseTimeSteps, curveDataItem.values, period );
auto cd = curveDataItem;
cd.values = resampledValues;

View File

@@ -30,13 +30,13 @@ class RimAsciiDataCurve;
struct CurveData
{
QString name;
RifEclipseSummaryAddress address;
RifEclipseSummaryAddressDefines::CurveType curveType;
std::vector<double> values;
};
enum class SummaryCurveType
{
CURVE_TYPE_GRID = 0x1,
CURVE_TYPE_SUMMARY = 0x1,
CURVE_TYPE_OBSERVED = 0x2
};

View File

@@ -86,11 +86,7 @@ std::vector<double> RimSummaryDeclineCurve::valuesY() const
{
auto [minTimeStep, maxTimeStep] = selectedTimeStepRange();
return createDeclineCurveValues( RimSummaryCurve::valuesY(),
RimSummaryCurve::timeStepsY(),
minTimeStep,
maxTimeStep,
RiaSummaryTools::hasAccumulatedData( summaryAddressY() ) );
return createDeclineCurveValues( RimSummaryCurve::valuesY(), RimSummaryCurve::timeStepsY(), minTimeStep, maxTimeStep, curveType() );
}
//--------------------------------------------------------------------------------------------------
@@ -100,11 +96,7 @@ std::vector<double> RimSummaryDeclineCurve::valuesX() const
{
auto [minTimeStep, maxTimeStep] = selectedTimeStepRange();
return createDeclineCurveValues( RimSummaryCurve::valuesX(),
RimSummaryCurve::timeStepsX(),
minTimeStep,
maxTimeStep,
RiaSummaryTools::hasAccumulatedData( summaryAddressX() ) );
return createDeclineCurveValues( RimSummaryCurve::valuesX(), RimSummaryCurve::timeStepsX(), minTimeStep, maxTimeStep, curveType() );
}
//--------------------------------------------------------------------------------------------------
@@ -138,7 +130,7 @@ std::vector<double> RimSummaryDeclineCurve::createDeclineCurveValues( const std:
const std::vector<time_t>& timeSteps,
time_t minTimeStep,
time_t maxTimeStep,
bool isAccumulatedResult ) const
RifEclipseSummaryAddressDefines::CurveType curveType ) const
{
if ( values.empty() || timeSteps.empty() ) return values;
@@ -147,8 +139,7 @@ std::vector<double> RimSummaryDeclineCurve::createDeclineCurveValues( const std:
if ( timeStepsInRange.empty() || valuesInRange.empty() ) return values;
auto [initialProductionRate, initialDeclineRate] =
computeInitialProductionAndDeclineRate( valuesInRange, timeStepsInRange, isAccumulatedResult );
auto [initialProductionRate, initialDeclineRate] = computeInitialProductionAndDeclineRate( valuesInRange, timeStepsInRange, curveType );
if ( std::isinf( initialProductionRate ) || std::isnan( initialProductionRate ) || std::isinf( initialDeclineRate ) ||
std::isnan( initialDeclineRate ) )
{
@@ -162,8 +153,8 @@ std::vector<double> RimSummaryDeclineCurve::createDeclineCurveValues( const std:
for ( const QDateTime& futureTime : futureTimeSteps )
{
double timeSinceStart = futureTime.toSecsSinceEpoch() - initialTime.toSecsSinceEpoch();
double predictedValue = computePredictedValue( initialProductionRate, initialDeclineRate, timeSinceStart, isAccumulatedResult );
if ( isAccumulatedResult ) predictedValue += valuesInRange.back();
double predictedValue = computePredictedValue( initialProductionRate, initialDeclineRate, timeSinceStart, curveType );
if ( curveType == RifEclipseSummaryAddressDefines::CurveType::ACCUMULATED ) predictedValue += valuesInRange.back();
outValues.push_back( predictedValue );
}
@@ -175,13 +166,13 @@ std::vector<double> RimSummaryDeclineCurve::createDeclineCurveValues( const std:
//--------------------------------------------------------------------------------------------------
std::pair<double, double> RimSummaryDeclineCurve::computeInitialProductionAndDeclineRate( const std::vector<double>& values,
const std::vector<time_t>& timeSteps,
bool isAccumulatedResult )
RifEclipseSummaryAddressDefines::CurveType curveType )
{
CAF_ASSERT( values.size() == timeSteps.size() );
auto computeProductionRate = []( double t0, double v0, double t1, double v1 ) { return ( v1 - v0 ) / ( t1 - t0 ); };
if ( !isAccumulatedResult )
if ( curveType == RifEclipseSummaryAddressDefines::CurveType::RATE )
{
// Use the first (time step, value) pair as t0
const size_t idx0 = 0;
@@ -197,8 +188,7 @@ std::pair<double, double> RimSummaryDeclineCurve::computeInitialProductionAndDec
RigDeclineCurveCalculator::computeDeclineRate( t0.toSecsSinceEpoch(), v0, initialTime.toSecsSinceEpoch(), initialProductionRate );
return { initialProductionRate, initialDeclineRate };
}
else
{
// Select a point (t0) 1/4 into the user-specified range
const double historyStep = 0.25;
const size_t idx0 = static_cast<size_t>( timeSteps.size() * historyStep );
@@ -222,7 +212,6 @@ std::pair<double, double> RimSummaryDeclineCurve::computeInitialProductionAndDec
initialProductionRate );
return { initialProductionRate, initialDeclineRate };
}
}
//--------------------------------------------------------------------------------------------------
///
@@ -230,9 +219,9 @@ std::pair<double, double> RimSummaryDeclineCurve::computeInitialProductionAndDec
double RimSummaryDeclineCurve::computePredictedValue( double initialProductionRate,
double initialDeclineRate,
double timeSinceStart,
bool isAccumulatedResult ) const
RifEclipseSummaryAddressDefines::CurveType curveType ) const
{
if ( isAccumulatedResult )
if ( curveType == RifEclipseSummaryAddressDefines::CurveType::ACCUMULATED )
{
if ( m_declineCurveType == RimSummaryDeclineCurve::DeclineCurveType::EXPONENTIAL )
{

View File

@@ -76,7 +76,7 @@ private:
const std::vector<time_t>& timeSteps,
time_t minTimeStep,
time_t maxTimeStep,
bool isAccumulatedResult ) const;
RifEclipseSummaryAddressDefines::CurveType curveType ) const;
static std::pair<std::vector<time_t>, std::vector<double>>
getInRangeValues( const std::vector<time_t>& timeSteps, const std::vector<double>& values, time_t minTimeStep, time_t maxTimeStep );
@@ -87,9 +87,12 @@ private:
static std::pair<double, double> computeInitialProductionAndDeclineRate( const std::vector<double>& values,
const std::vector<time_t>& timeSteps,
bool isAccumulatedResult );
RifEclipseSummaryAddressDefines::CurveType curveType );
double computePredictedValue( double initialProductionRate, double initialDeclineRate, double timeSinceStart, bool isAccumulatedResult ) const;
double computePredictedValue( double initialProductionRate,
double initialDeclineRate,
double timeSinceStart,
RifEclipseSummaryAddressDefines::CurveType curveType ) const;
std::pair<time_t, time_t> fullTimeStepRange() const;
std::pair<time_t, time_t> selectedTimeStepRange() const;