#2659 Ensemble statistics. Use resampling during statistics calculations

This commit is contained in:
Bjørn Erik Jensen 2018-06-12 14:22:32 +02:00
parent 848d774440
commit 4491b1de63
7 changed files with 133 additions and 70 deletions

View File

@ -478,14 +478,24 @@ RifEclipseSummaryAddress RifEclipseSummaryAddress::importedAddress(const std::st
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddress RifEclipseSummaryAddress::ensembleStatisticsAddress(const std::string& quantityName) RifEclipseSummaryAddress RifEclipseSummaryAddress::ensembleStatisticsAddress(const std::string& quantityName,
const std::string& dataQuantityName)
{ {
RifEclipseSummaryAddress addr; RifEclipseSummaryAddress addr;
addr.m_variableCategory = SUMMARY_ENSEMBLE_STATISTICS; addr.m_variableCategory = SUMMARY_ENSEMBLE_STATISTICS;
addr.m_quantityName = quantityName; addr.m_quantityName = quantityName + ":" + dataQuantityName;
return addr; return addr;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::string RifEclipseSummaryAddress::ensembleStatisticsQuantityName() const
{
QString qName = QString::fromStdString(m_quantityName);
return qName.split(":")[0].toStdString();
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -657,6 +667,14 @@ bool RifEclipseSummaryAddress::isValid() const
return true; return true;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseSummaryAddress::hasAccumulatedData() const
{
return QString::fromStdString(m_quantityName).endsWith("T");
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

View File

@ -141,7 +141,7 @@ public:
static RifEclipseSummaryAddress blockLgrAddress(const std::string& quantityName, const std::string& lgrName, int i, int j, int k); static RifEclipseSummaryAddress blockLgrAddress(const std::string& quantityName, const std::string& lgrName, int i, int j, int k);
static RifEclipseSummaryAddress calculatedAddress(const std::string& quantityName); static RifEclipseSummaryAddress calculatedAddress(const std::string& quantityName);
static RifEclipseSummaryAddress importedAddress(const std::string& quantityName); static RifEclipseSummaryAddress importedAddress(const std::string& quantityName);
static RifEclipseSummaryAddress ensembleStatisticsAddress(const std::string& quantityName); static RifEclipseSummaryAddress ensembleStatisticsAddress(const std::string& quantityName, const std::string& dataQuantityName);
// Access methods // Access methods
@ -160,6 +160,8 @@ public:
int cellK() const { return m_cellK; } int cellK() const { return m_cellK; }
int aquiferNumber() const { return m_aquiferNumber; } int aquiferNumber() const { return m_aquiferNumber; }
const std::string ensembleStatisticsQuantityName() const;
// Derived properties // Derived properties
std::string uiText() const; std::string uiText() const;
@ -174,6 +176,7 @@ public:
void setAsErrorResult() { m_isErrorResult = true; } void setAsErrorResult() { m_isErrorResult = true; }
bool isErrorResult() const { return m_isErrorResult; } bool isErrorResult() const { return m_isErrorResult; }
bool hasAccumulatedData() const;
private: private:

View File

@ -32,10 +32,10 @@ RifEnsembleStatisticsReader::RifEnsembleStatisticsReader(RimEnsembleStatisticsCa
m_allResultAddresses = std::vector<RifEclipseSummaryAddress>( m_allResultAddresses = std::vector<RifEclipseSummaryAddress>(
{ {
RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P10_QUANTITY_NAME), RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P10_QUANTITY_NAME, ""),
RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P50_QUANTITY_NAME), RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P50_QUANTITY_NAME, ""),
RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P90_QUANTITY_NAME), RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P90_QUANTITY_NAME, ""),
RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_MEAN_QUANTITY_NAME) RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_MEAN_QUANTITY_NAME, "")
}); });
} }
@ -55,10 +55,12 @@ bool RifEnsembleStatisticsReader::values(const RifEclipseSummaryAddress& resultA
if (!validateAddress(resultAddress)) return false; if (!validateAddress(resultAddress)) return false;
const std::vector<double>* sourceData = nullptr; const std::vector<double>* sourceData = nullptr;
if (resultAddress.quantityName() == ENSEMBLE_STAT_P10_QUANTITY_NAME) sourceData = &m_ensembleStatCase->p10(); auto quantityName = resultAddress.ensembleStatisticsQuantityName();
else if (resultAddress.quantityName() == ENSEMBLE_STAT_P50_QUANTITY_NAME) sourceData = &m_ensembleStatCase->p50();
else if (resultAddress.quantityName() == ENSEMBLE_STAT_P90_QUANTITY_NAME) sourceData = &m_ensembleStatCase->p90(); if (quantityName == ENSEMBLE_STAT_P10_QUANTITY_NAME) sourceData = &m_ensembleStatCase->p10();
else if (resultAddress.quantityName() == ENSEMBLE_STAT_MEAN_QUANTITY_NAME) sourceData = &m_ensembleStatCase->mean(); else if (quantityName == ENSEMBLE_STAT_P50_QUANTITY_NAME) sourceData = &m_ensembleStatCase->p50();
else if (quantityName == ENSEMBLE_STAT_P90_QUANTITY_NAME) sourceData = &m_ensembleStatCase->p90();
else if (quantityName == ENSEMBLE_STAT_MEAN_QUANTITY_NAME) sourceData = &m_ensembleStatCase->mean();
if (!sourceData) return false; if (!sourceData) return false;

View File

@ -929,7 +929,7 @@ void RimEnsembleCurveSet::updateStatisticsCurves(bool calculate = true)
if (calculate) if (calculate)
{ {
// Calculate // Calculate
m_ensembleStatCase->calculate(m_yValuesSummaryGroup, m_yValuesCurveVariable->address()); m_ensembleStatCase->calculate();
} }
RimSummaryPlot* plot = nullptr; RimSummaryPlot* plot = nullptr;
@ -939,10 +939,12 @@ void RimEnsembleCurveSet::updateStatisticsCurves(bool calculate = true)
std::vector<RifEclipseSummaryAddress> addresses; std::vector<RifEclipseSummaryAddress> addresses;
if (m_statistics->isActive()) if (m_statistics->isActive())
{ {
if (m_statistics->showP10Curve()) addresses.push_back(SAddr::ensembleStatisticsAddress(ENSEMBLE_STAT_P10_QUANTITY_NAME)); RifEclipseSummaryAddress dataAddress = m_yValuesCurveVariable->address();
if (m_statistics->showP50Curve()) addresses.push_back(SAddr::ensembleStatisticsAddress(ENSEMBLE_STAT_P50_QUANTITY_NAME));
if (m_statistics->showP90Curve()) addresses.push_back(SAddr::ensembleStatisticsAddress(ENSEMBLE_STAT_P90_QUANTITY_NAME)); if (m_statistics->showP10Curve()) addresses.push_back(SAddr::ensembleStatisticsAddress(ENSEMBLE_STAT_P10_QUANTITY_NAME, dataAddress.quantityName()));
if (m_statistics->showMeanCurve()) addresses.push_back(SAddr::ensembleStatisticsAddress(ENSEMBLE_STAT_MEAN_QUANTITY_NAME)); if (m_statistics->showP50Curve()) addresses.push_back(SAddr::ensembleStatisticsAddress(ENSEMBLE_STAT_P50_QUANTITY_NAME, dataAddress.quantityName()));
if (m_statistics->showP90Curve()) addresses.push_back(SAddr::ensembleStatisticsAddress(ENSEMBLE_STAT_P90_QUANTITY_NAME, dataAddress.quantityName()));
if (m_statistics->showMeanCurve()) addresses.push_back(SAddr::ensembleStatisticsAddress(ENSEMBLE_STAT_MEAN_QUANTITY_NAME, dataAddress.quantityName()));
} }
deleteStatisticsCurves(); deleteStatisticsCurves();

View File

@ -22,9 +22,11 @@
#include "RigStatisticsMath.h" #include "RigStatisticsMath.h"
#include "RiaTimeHistoryCurveMerger.h" #include "RiaTimeHistoryCurveMerger.h"
#include "RiaTimeHistoryCurveResampler.h"
#include "RimEnsembleCurveSet.h" #include "RimEnsembleCurveSet.h"
#include <limits>
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
@ -109,33 +111,41 @@ const RimEnsembleCurveSet* RimEnsembleStatisticsCase::curveSet() const
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RimEnsembleStatisticsCase::calculate(const RimSummaryCaseCollection* ensemble, const RifEclipseSummaryAddress& inputAddress) void RimEnsembleStatisticsCase::calculate()
{ {
RiaTimeHistoryCurveMerger curveMerger; auto inputAddress = m_curveSet->summaryAddress();
int caseCount = (int)ensemble->allSummaryCases().size(); auto ensemble = m_curveSet->summaryCaseCollection();
if (m_statisticsReader && ensemble && inputAddress.isValid())
{ {
for (const auto& sumCase : ensemble->allSummaryCases()) calculate(validSummaryCases(ensemble->allSummaryCases(), inputAddress), inputAddress);
{
const auto& reader = sumCase->summaryReader();
if (reader)
{
std::vector<time_t> timeSteps = reader->timeSteps(inputAddress);
std::vector<double> values;
reader->values(inputAddress, &values);
curveMerger.addCurveData(values, timeSteps);
}
}
curveMerger.computeInterpolatedValues();
} }
}
const std::vector<time_t>& allTimeSteps = curveMerger.allTimeSteps(); //--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleStatisticsCase::calculate(const std::vector<RimSummaryCase*> sumCases, const RifEclipseSummaryAddress& inputAddress)
{
std::vector<time_t> allTimeSteps;
std::vector<std::vector<double>> allValues; std::vector<std::vector<double>> allValues;
allValues.reserve(sumCases.size());
for (const auto& sumCase : sumCases)
{ {
for (int c = 0; c < caseCount; c++) const auto& reader = sumCase->summaryReader();
if (reader)
{ {
allValues.push_back(curveMerger.interpolatedCurveValuesForAllTimeSteps(c)); std::vector<time_t> timeSteps = reader->timeSteps(inputAddress);
std::vector<double> values;
reader->values(inputAddress, &values);
RiaTimeHistoryCurveResampler resampler;
resampler.setCurveData(values, timeSteps);
if (inputAddress.hasAccumulatedData()) resampler.resampleAndComputePeriodEndValues(DateTimePeriod::DAY);
else resampler.resampleAndComputeWeightedMeanValues(DateTimePeriod::DAY);
if (allTimeSteps.empty()) allTimeSteps = resampler.resampledTimeSteps();
allValues.push_back(std::vector<double>(resampler.resampledValues().begin(), resampler.resampledValues().end()));
} }
} }
@ -145,49 +155,33 @@ void RimEnsembleStatisticsCase::calculate(const RimSummaryCaseCollection* ensemb
for (int t = 0; t < (int)allTimeSteps.size(); t++) for (int t = 0; t < (int)allTimeSteps.size(); t++)
{ {
std::vector<double> valuesForTimeSteps; std::vector<double> valuesForTimeSteps;
valuesForTimeSteps.reserve(caseCount); valuesForTimeSteps.reserve(sumCases.size());
for (int c = 0; c < caseCount; c++) for (int c = 0; c < sumCases.size(); c++)
{ {
valuesForTimeSteps.push_back(allValues[c][t]); valuesForTimeSteps.push_back(allValues[c][t]);
} }
{ double min, max, range, mean, stdev;
double min, max, range, mean, stdev; RigStatisticsMath::calculateBasicStatistics(valuesForTimeSteps, &min, &max, nullptr, &range, &mean, &stdev);
RigStatisticsMath::calculateBasicStatistics(valuesForTimeSteps, &min, &max, nullptr, &range, &mean, &stdev);
std::vector<size_t> histogram; std::vector<size_t> histogram;
RigHistogramCalculator histCalc(min, max, 100, &histogram); RigHistogramCalculator histCalc(min, max, 100, &histogram);
histCalc.addData(valuesForTimeSteps); histCalc.addData(valuesForTimeSteps);
double p10, p50, p90; double p10, p50, p90;
p10 = histCalc.calculatePercentil(0.1); p10 = histCalc.calculatePercentil(0.1);
p50 = histCalc.calculatePercentil(0.5); p50 = histCalc.calculatePercentil(0.5);
p90 = histCalc.calculatePercentil(0.9); p90 = histCalc.calculatePercentil(0.9);
m_p10Data.push_back(p10);
m_p50Data.push_back(p50);
m_p90Data.push_back(p90);
m_meanData.push_back(mean);
}
m_p10Data.push_back(p10);
m_p50Data.push_back(p50);
m_p90Data.push_back(p90);
m_meanData.push_back(mean);
} }
m_addressUsedInLastCalculation = inputAddress; m_addressUsedInLastCalculation = inputAddress;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleStatisticsCase::calculate()
{
auto inputAddress = m_curveSet->summaryAddress();
auto ensemble = m_curveSet->summaryCaseCollection();
if (m_statisticsReader && ensemble && inputAddress.isValid())
{
calculate(ensemble, inputAddress);
}
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -200,3 +194,46 @@ void RimEnsembleStatisticsCase::clearData()
m_meanData.clear(); m_meanData.clear();
m_addressUsedInLastCalculation = RifEclipseSummaryAddress(); m_addressUsedInLastCalculation = RifEclipseSummaryAddress();
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCase*> RimEnsembleStatisticsCase::validSummaryCases(const std::vector<RimSummaryCase*> allSumCases, const RifEclipseSummaryAddress& inputAddress)
{
std::vector<RimSummaryCase*> validCases;
std::vector<std::tuple<RimSummaryCase*, time_t, time_t>> times;
time_t minTimeStep = std::numeric_limits<time_t>::max();
time_t maxTimeStep = 0;
for (auto& sumCase : allSumCases)
{
const auto& reader = sumCase->summaryReader();
if (reader)
{
std::vector<time_t> timeSteps = reader->timeSteps(inputAddress);
if (!timeSteps.empty())
{
time_t firstTimeStep = timeSteps.front();
time_t lastTimeStep = timeSteps.back();
if (firstTimeStep < minTimeStep) minTimeStep = firstTimeStep;
if (lastTimeStep > maxTimeStep) maxTimeStep = lastTimeStep;
times.push_back(std::make_tuple(sumCase, firstTimeStep, lastTimeStep));
}
}
}
for (auto& item : times)
{
RimSummaryCase* sumCase = std::get<0>(item);
time_t firstTimeStep = std::get<1>(item);
time_t lastTimeStep = std::get<2>(item);
if (firstTimeStep == minTimeStep && lastTimeStep == maxTimeStep)
{
validCases.push_back(sumCase);
}
}
return validCases;
}

View File

@ -50,10 +50,11 @@ public:
const RimEnsembleCurveSet* curveSet() const; const RimEnsembleCurveSet* curveSet() const;
void calculate(); void calculate();
void calculate(const RimSummaryCaseCollection* ensemble, const RifEclipseSummaryAddress& inputAddress);
private: private:
void calculate(const std::vector<RimSummaryCase*> sumCases, const RifEclipseSummaryAddress& inputAddress);
void clearData(); void clearData();
std::vector<RimSummaryCase*> validSummaryCases(const std::vector<RimSummaryCase*> allSumCases, const RifEclipseSummaryAddress& inputAddress);
private: private:
std::unique_ptr<RifEnsembleStatisticsReader> m_statisticsReader; std::unique_ptr<RifEnsembleStatisticsReader> m_statisticsReader;

View File

@ -890,8 +890,8 @@ void RimSummaryCurve::calculateCurveInterpolationFromAddress()
if (m_yValuesCurveVariable()) if (m_yValuesCurveVariable())
{ {
auto category = m_yValuesCurveVariable()->address().category(); auto category = m_yValuesCurveVariable()->address().category();
QString quantityName = QString::fromUtf8(m_yValuesCurveVariable()->address().quantityName().c_str()); auto address = m_yValuesCurveVariable()->address();
if (quantityName.endsWith("T") || category == RifEclipseSummaryAddress::SUMMARY_ENSEMBLE_STATISTICS) if (address.hasAccumulatedData())
{ {
m_curveInterpolation = INTERPOLATION_POINT_TO_POINT; m_curveInterpolation = INTERPOLATION_POINT_TO_POINT;
} }