#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;
addr.m_variableCategory = SUMMARY_ENSEMBLE_STATISTICS;
addr.m_quantityName = quantityName;
addr.m_quantityName = quantityName + ":" + dataQuantityName;
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;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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 calculatedAddress(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
@ -160,6 +160,8 @@ public:
int cellK() const { return m_cellK; }
int aquiferNumber() const { return m_aquiferNumber; }
const std::string ensembleStatisticsQuantityName() const;
// Derived properties
std::string uiText() const;
@ -174,6 +176,7 @@ public:
void setAsErrorResult() { m_isErrorResult = true; }
bool isErrorResult() const { return m_isErrorResult; }
bool hasAccumulatedData() const;
private:

View File

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

View File

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

View File

@ -22,9 +22,11 @@
#include "RigStatisticsMath.h"
#include "RiaTimeHistoryCurveMerger.h"
#include "RiaTimeHistoryCurveResampler.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;
int caseCount = (int)ensemble->allSummaryCases().size();
auto inputAddress = m_curveSet->summaryAddress();
auto ensemble = m_curveSet->summaryCaseCollection();
if (m_statisticsReader && ensemble && inputAddress.isValid())
{
for (const auto& sumCase : ensemble->allSummaryCases())
{
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();
calculate(validSummaryCases(ensemble->allSummaryCases(), inputAddress), inputAddress);
}
}
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;
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++)
{
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]);
}
{
double min, max, range, mean, stdev;
RigStatisticsMath::calculateBasicStatistics(valuesForTimeSteps, &min, &max, nullptr, &range, &mean, &stdev);
double min, max, range, mean, stdev;
RigStatisticsMath::calculateBasicStatistics(valuesForTimeSteps, &min, &max, nullptr, &range, &mean, &stdev);
std::vector<size_t> histogram;
RigHistogramCalculator histCalc(min, max, 100, &histogram);
histCalc.addData(valuesForTimeSteps);
std::vector<size_t> histogram;
RigHistogramCalculator histCalc(min, max, 100, &histogram);
histCalc.addData(valuesForTimeSteps);
double p10, p50, p90;
p10 = histCalc.calculatePercentil(0.1);
p50 = histCalc.calculatePercentil(0.5);
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);
}
double p10, p50, p90;
p10 = histCalc.calculatePercentil(0.1);
p50 = histCalc.calculatePercentil(0.5);
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_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_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;
void calculate();
void calculate(const RimSummaryCaseCollection* ensemble, const RifEclipseSummaryAddress& inputAddress);
private:
void calculate(const std::vector<RimSummaryCase*> sumCases, const RifEclipseSummaryAddress& inputAddress);
void clearData();
std::vector<RimSummaryCase*> validSummaryCases(const std::vector<RimSummaryCase*> allSumCases, const RifEclipseSummaryAddress& inputAddress);
private:
std::unique_ptr<RifEnsembleStatisticsReader> m_statisticsReader;

View File

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