mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#2659 Ensemble statistics. Use resampling during statistics calculations
This commit is contained in:
parent
848d774440
commit
4491b1de63
@ -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");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user