mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#4013 Sort ensemble parameters by variation
This commit is contained in:
parent
8a5cbf60fd
commit
eb498ad0dc
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
|
@ -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
|
||||
|
50
ApplicationCode/UnitTests/RimSummaryCaseCollection-Test.cpp
Normal file
50
ApplicationCode/UnitTests/RimSummaryCaseCollection-Test.cpp
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user