#4013 Sort ensemble parameters by variation

This commit is contained in:
Gaute Lindkvist 2019-01-29 15:04:04 +01:00
parent 8a5cbf60fd
commit eb498ad0dc
7 changed files with 174 additions and 15 deletions

View File

@ -133,10 +133,10 @@ QList<caf::PdmOptionItemInfo> RimEnsembleCurveFilter::calculateValueOptions(cons
auto curveSet = parentCurveSet();
if (curveSet)
{
auto names = curveSet->ensembleParameterNames();
for (auto& name : names)
auto nameParameterPairs = curveSet->ensembleParameters();
for (auto& nameParamPair : nameParameterPairs)
{
options.push_back(caf::PdmOptionItemInfo(name, name));
options.push_back(caf::PdmOptionItemInfo(RimEnsembleCurveSet::ensembleParameterUiName(nameParamPair), nameParamPair.first));
}
}
}
@ -348,10 +348,10 @@ void RimEnsembleCurveFilter::setInitialValues(bool forceDefault)
{
if (!selectedEnsembleParameter().isValid())
{
auto parameterNames = parentCurveSet()->ensembleParameterNames();
auto parameterNames = parentCurveSet()->ensembleParameters();
if (!parameterNames.empty())
{
m_ensembleParameterName = parameterNames.front();
m_ensembleParameterName = parameterNames.front().first;
updateConnectedEditors();
}
}

View File

@ -444,6 +444,32 @@ EnsembleParameter::Type RimEnsembleCurveSet::currentEnsembleParameterType() cons
return EnsembleParameter::TYPE_NONE;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimEnsembleCurveSet::ensembleParameterUiName(const RimEnsembleCurveSet::NameParameterPair& paramPair)
{
QString stem = paramPair.first;
QString variationString;
if (paramPair.second.isNumeric())
{
switch (paramPair.second.logarithmicVariationIndex())
{
case -1:
variationString = QString(" (No variation)");
case 0:
variationString = QString(" (Low variation)");
break;
case 1:
break;
case 2:
variationString = QString(" (High variation)");
break;
}
}
return QString("%1%2").arg(stem).arg(variationString);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -518,8 +544,8 @@ void RimEnsembleCurveSet::fieldChangedByUi(const caf::PdmFieldHandle* changedFie
{
if (m_ensembleParameter().isEmpty())
{
auto params = ensembleParameterNames();
m_ensembleParameter = !params.empty() ? params.front() : "";
auto params = ensembleParameters();
m_ensembleParameter = !params.empty() ? params.front().first : "";
}
updateCurveColors();
@ -741,16 +767,16 @@ QList<caf::PdmOptionItemInfo> RimEnsembleCurveSet::calculateValueOptions(const c
auto byEnsParamOption = caf::AppEnum<RimEnsembleCurveSet::ColorMode>(RimEnsembleCurveSet::BY_ENSEMBLE_PARAM);
options.push_back(caf::PdmOptionItemInfo(singleColorOption.uiText(), RimEnsembleCurveSet::SINGLE_COLOR));
if (!ensembleParameterNames().empty())
if (!ensembleParameters().empty())
{
options.push_back(caf::PdmOptionItemInfo(byEnsParamOption.uiText(), RimEnsembleCurveSet::BY_ENSEMBLE_PARAM));
}
}
else if (fieldNeedingOptions == &m_ensembleParameter)
{
for (const auto& param : ensembleParameterNames())
for (const auto& paramPair : ensembleParameters())
{
options.push_back(caf::PdmOptionItemInfo(param, param));
options.push_back(caf::PdmOptionItemInfo(ensembleParameterUiName(paramPair), paramPair.first));
}
}
else if (fieldNeedingOptions == &m_yValuesUiFilterResultSelection)
@ -1121,7 +1147,7 @@ void RimEnsembleCurveSet::updateAllTextInPlot()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<QString> RimEnsembleCurveSet::ensembleParameterNames() const
std::vector<RimEnsembleCurveSet::NameParameterPair> RimEnsembleCurveSet::ensembleParameters() const
{
RimSummaryCaseCollection* group = m_yValuesSummaryGroup;
@ -1137,7 +1163,21 @@ std::vector<QString> RimEnsembleCurveSet::ensembleParameterNames() const
}
}
}
return std::vector<QString>(paramSet.begin(), paramSet.end());
std::vector<NameParameterPair> parameterVector;
parameterVector.reserve(paramSet.size());
for (const QString& parameterName : paramSet)
{
parameterVector.push_back(std::make_pair(parameterName, group->ensembleParameter(parameterName)));
}
// Sort by variation index (highest first) but keep name as sorting parameter when parameters have the same variation index
std::stable_sort(parameterVector.begin(), parameterVector.end(), [](const NameParameterPair& lhs, const NameParameterPair& rhs)
{
return lhs.second.logarithmicVariationIndex() > rhs.second.logarithmicVariationIndex();
});
return parameterVector;
}
//--------------------------------------------------------------------------------------------------

View File

@ -65,6 +65,8 @@ class RimEnsembleCurveSet : public caf::PdmObject
public:
enum ColorMode {SINGLE_COLOR, BY_ENSEMBLE_PARAM};
typedef std::pair<QString, EnsembleParameter> NameParameterPair;
RimEnsembleCurveSet();
~RimEnsembleCurveSet() override;
@ -97,6 +99,7 @@ public:
ColorMode colorMode() const;
void updateEnsembleLegendItem();
EnsembleParameter::Type currentEnsembleParameterType() const;
static QString ensembleParameterUiName(const NameParameterPair& paramPair);
void updateAllCurves();
void updateStatisticsCurves();
@ -107,7 +110,7 @@ public:
void markCachedDataForPurge();
void updateAllTextInPlot();
std::vector<QString> ensembleParameterNames() const;
std::vector<NameParameterPair> ensembleParameters() const;
std::vector<RimSummaryCase*> filterEnsembleCases(const std::vector<RimSummaryCase*>& sumCases);
void disableStatisticCurves();
@ -144,7 +147,6 @@ private:
QString createAutoName() const;
void updateLegendMappingMode();
private:
caf::PdmField<bool> m_showCurves;
caf::PdmChildArrayField<RimSummaryCurve*> m_curves;

View File

@ -36,6 +36,60 @@
CAF_PDM_SOURCE_INIT(RimSummaryCaseCollection, "SummaryCaseSubCollection");
//--------------------------------------------------------------------------------------------------
/// Return an integer derived from the logarithm of the range.
/// -1 if there is practically no variation and a rising positive integer for non-zero range.
//--------------------------------------------------------------------------------------------------
int EnsembleParameter::logarithmicVariationIndex() const
{
const double eps = 1.0e-4;
double maxAbs = std::max(std::abs(maxValue), std::abs(minValue));
if (maxAbs < eps)
{
return -1;
}
double normalisedStdDevPercent = 2.0 * m_stdDeviation / maxAbs * 100.0;
if (normalisedStdDevPercent < eps)
{
return -1;
}
// Should always yield an index from and including -1 to and including 2
// As the maximum normalisedStdDevPercent is ~282
// Found with two values symmetric around 0 so min = -X and max = +X
// normalisedStdDevPercent is then 2 * sqrt(2X^2) / X * 100 = sqrt(2) * 100 = ~282.
// And log10 value is ~2.45.
int variationIndex = std::max(-1, (int) std::round(std::log10(normalisedStdDevPercent)));
//CVF_ASSERT(variationIndex >= -1 && variationIndex <= 2);
return variationIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void EnsembleParameter::calculateStdDeviation()
{
m_stdDeviation = 0.0;
double N = static_cast<double>(values.size());
if (N > 1 && isNumeric())
{
double sumValues = 0.0;
double sumValuesSquared = 0.0;
for (const QVariant& variant : values)
{
double value = variant.toDouble();
sumValues += value;
sumValuesSquared += value * value;
}
m_stdDeviation = std::sqrt((N * sumValuesSquared - sumValues * sumValues) / (N * (N - 1.0)));
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -283,6 +337,9 @@ EnsembleParameter RimSummaryCaseCollection::ensembleParameter(const QString& par
eParam.values.push_back(QVariant(val));
}
}
eParam.calculateStdDeviation();
return eParam;
}

View File

@ -46,11 +46,20 @@ public:
EnsembleParameter() :
type(TYPE_NONE),
minValue(std::numeric_limits<double>::infinity()),
maxValue(-std::numeric_limits<double>::infinity()) { }
maxValue(-std::numeric_limits<double>::infinity()),
m_stdDeviation(0.0)
{}
bool isValid() const { return !name.isEmpty() && type != TYPE_NONE; }
bool isNumeric() const { return type == TYPE_NUMERIC; }
bool isText() const { return type == TYPE_TEXT; }
double range() const { return std::abs(maxValue - minValue); }
void calculateStdDeviation();
int logarithmicVariationIndex() const;
private:
double m_stdDeviation;
};
//==================================================================================================

View File

@ -54,6 +54,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaCellDividingTools-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/Intersect-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifPerforationIntervalReader-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RimWellPathCompletions-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCaseCollection-Test.cpp
)
list(APPEND CODE_HEADER_FILES

View File

@ -0,0 +1,50 @@
#include "gtest/gtest.h"
#include "RimSummaryCaseCollection.h"
#include <random>
#include <QDebug>
TEST(RimSummaryCaseCollection, logarithmicVariationIndex)
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> meanDistribution(-10000.0, 10000.0);
std::uniform_real_distribution<double> variationDistribution(0.0, 5000.0);
std::uniform_int_distribution<size_t> countDistribution(1u, 1000u);
size_t N = 1000;
std::map<int, size_t> indexCounts;
for (size_t i = 0; i < N; ++i)
{
EnsembleParameter param;
param.type = EnsembleParameter::TYPE_NUMERIC;
size_t valueCount = countDistribution(gen);
double meanValue = meanDistribution(gen);
double range = variationDistribution(gen);
std::uniform_real_distribution<double> valueDistribution(meanValue - range, meanValue + range);
double maxValue = -std::numeric_limits<double>::max();
double minValue = std::numeric_limits<double>::max();
for (size_t j = 0; j < valueCount; ++j)
{
double value = valueDistribution(gen);
maxValue = std::max(maxValue, value);
minValue = std::min(minValue, value);
param.values.push_back(QVariant(value));
}
param.calculateStdDeviation();
param.minValue = minValue;
param.maxValue = maxValue;
int variationIndex = param.logarithmicVariationIndex();
EXPECT_GE(variationIndex, -1);
EXPECT_LE(variationIndex, 2);
indexCounts[variationIndex]++;
}
for (auto countPair : indexCounts)
{
qDebug() << "Variation index " << countPair.first << " count = " << countPair.second;
}
}