mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#4117 Refactor Grid Cross plot result extraction and categorisation
This commit is contained in:
parent
b6348b8374
commit
1b9a0fe5a7
@ -86,9 +86,11 @@ RimGridCrossPlotCurve::RimGridCrossPlotCurve()
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
void RimGridCrossPlotCurve::setSamples(const QVector<QPointF>& samples)
|
void RimGridCrossPlotCurve::setSamples(const std::vector<double>& xValues, const std::vector<double>& yValues)
|
||||||
{
|
{
|
||||||
m_qwtPlotCurve->setSamples(samples);
|
CVF_ASSERT(xValues.size() == yValues.size());
|
||||||
|
|
||||||
|
m_qwtPlotCurve->setSamples(&xValues[0], &yValues[0], static_cast<int>(xValues.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
@ -41,7 +41,7 @@ public:
|
|||||||
RimGridCrossPlotCurve();
|
RimGridCrossPlotCurve();
|
||||||
~RimGridCrossPlotCurve() override = default;
|
~RimGridCrossPlotCurve() override = default;
|
||||||
void determineColorAndSymbol(int curveSetIndex, int categoryIndex, int nCategories, bool contrastColors = false);
|
void determineColorAndSymbol(int curveSetIndex, int categoryIndex, int nCategories, bool contrastColors = false);
|
||||||
void setSamples(const QVector<QPointF>& samples);
|
void setSamples(const std::vector<double>& xValues, const std::vector<double>& yValues);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void updateZoomInParentPlot() override;
|
void updateZoomInParentPlot() override;
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include "RigActiveCellInfo.h"
|
#include "RigActiveCellInfo.h"
|
||||||
#include "RigActiveCellsResultAccessor.h"
|
#include "RigActiveCellsResultAccessor.h"
|
||||||
#include "RigCaseCellResultCalculator.h"
|
#include "RigCaseCellResultCalculator.h"
|
||||||
|
#include "RigEclipseCrossPlotDataExtractor.h"
|
||||||
|
|
||||||
#include "RigFormationNames.h"
|
#include "RigFormationNames.h"
|
||||||
#include "RigMainGrid.h"
|
#include "RigMainGrid.h"
|
||||||
|
|
||||||
@ -37,20 +39,20 @@
|
|||||||
#include "cafPdmUiComboBoxEditor.h"
|
#include "cafPdmUiComboBoxEditor.h"
|
||||||
#include "cafPdmUiSliderEditor.h"
|
#include "cafPdmUiSliderEditor.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
CAF_PDM_SOURCE_INIT(RimGridCrossPlotCurveSet, "GridCrossPlotCurveSet");
|
CAF_PDM_SOURCE_INIT(RimGridCrossPlotCurveSet, "GridCrossPlotCurveSet");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace caf
|
namespace caf
|
||||||
{
|
{
|
||||||
template<>
|
template<>
|
||||||
void AppEnum<RimGridCrossPlotCurveSet::CurveCategorization>::setUp()
|
void RimGridCrossPlotCurveSet::CurveCategorizationEnum::setUp()
|
||||||
{
|
{
|
||||||
addItem(RimGridCrossPlotCurveSet::NO_CATEGORIZATION, "NONE", "None");
|
addItem(RigGridCrossPlotCurveCategorization::NO_CATEGORIZATION, "NONE", "None");
|
||||||
addItem(RimGridCrossPlotCurveSet::TIME_CATEGORIZATION, "TIME", "Time");
|
addItem(RigGridCrossPlotCurveCategorization::TIME_CATEGORIZATION, "TIME", "Time");
|
||||||
addItem(RimGridCrossPlotCurveSet::FORMATION_CATEGORIZATION, "FORMATION", "Formations");
|
addItem(RigGridCrossPlotCurveCategorization::FORMATION_CATEGORIZATION, "FORMATION", "Formations");
|
||||||
addItem(RimGridCrossPlotCurveSet::RESULT_CATEGORIZATION, "RESULT", "Result Property");
|
addItem(RigGridCrossPlotCurveCategorization::RESULT_CATEGORIZATION, "RESULT", "Result Property");
|
||||||
setDefault(RimGridCrossPlotCurveSet::TIME_CATEGORIZATION);
|
setDefault(RigGridCrossPlotCurveCategorization::TIME_CATEGORIZATION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,63 +219,6 @@ void RimGridCrossPlotCurveSet::initAfterRead()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RigEclipseResultBinSorter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RigEclipseResultBinSorter(const std::vector<std::vector<double>>& allDataValues, int binCount)
|
|
||||||
: m_allDataValues(allDataValues)
|
|
||||||
, m_binCount(binCount)
|
|
||||||
, m_minValue(std::numeric_limits<double>::infinity())
|
|
||||||
, m_maxValue(-std::numeric_limits<double>::infinity())
|
|
||||||
, m_binSize(0.0)
|
|
||||||
{
|
|
||||||
calculateRange();
|
|
||||||
}
|
|
||||||
|
|
||||||
int binNumber(double value) const
|
|
||||||
{
|
|
||||||
double distFromMin = value - m_minValue;
|
|
||||||
return std::min(m_binCount - 1, static_cast<int>(distFromMin / m_binSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<double, double> binRange(int binNumber)
|
|
||||||
{
|
|
||||||
double minBinValue = m_minValue + m_binSize * binNumber;
|
|
||||||
double maxBinBalue = minBinValue + m_binSize;
|
|
||||||
return std::make_pair(minBinValue, maxBinBalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void calculateRange()
|
|
||||||
{
|
|
||||||
for (const std::vector<double>& doubleRange : m_allDataValues)
|
|
||||||
{
|
|
||||||
if (!doubleRange.empty())
|
|
||||||
{
|
|
||||||
for (double value : doubleRange)
|
|
||||||
{
|
|
||||||
if (value != std::numeric_limits<double>::infinity())
|
|
||||||
{
|
|
||||||
m_minValue = std::min(m_minValue, value);
|
|
||||||
m_maxValue = std::max(m_maxValue, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_maxValue > m_minValue)
|
|
||||||
{
|
|
||||||
m_binSize = (m_maxValue - m_minValue) / m_binCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
const std::vector<std::vector<double>>& m_allDataValues;
|
|
||||||
int m_binCount;
|
|
||||||
double m_minValue;
|
|
||||||
double m_maxValue;
|
|
||||||
double m_binSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@ -284,14 +229,18 @@ void RimGridCrossPlotCurveSet::onLoadDataAndUpdate(bool updateParentPlot)
|
|||||||
detachAllCurves();
|
detachAllCurves();
|
||||||
m_crossPlotCurves.deleteAllChildObjects();
|
m_crossPlotCurves.deleteAllChildObjects();
|
||||||
|
|
||||||
std::map<int, QVector<QPointF>> samples;
|
if (m_case() == nullptr)
|
||||||
|
|
||||||
if (m_case())
|
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>(m_case.value());
|
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>(m_case.value());
|
||||||
|
|
||||||
if (eclipseCase)
|
if (eclipseCase == nullptr)
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!eclipseCase->ensureReservoirCaseIsOpen())
|
if (!eclipseCase->ensureReservoirCaseIsOpen())
|
||||||
{
|
{
|
||||||
RiaLogging::warning(QString("Failed to open eclipse grid file %1").arg(eclipseCase->gridFileName()));
|
RiaLogging::warning(QString("Failed to open eclipse grid file %1").arg(eclipseCase->gridFileName()));
|
||||||
@ -299,120 +248,17 @@ void RimGridCrossPlotCurveSet::onLoadDataAndUpdate(bool updateParentPlot)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RigCaseCellResultsData* resultData = eclipseCase->results(RiaDefines::MATRIX_MODEL);
|
|
||||||
RigFormationNames* activeFormationNames = resultData->activeFormationNames();
|
|
||||||
|
|
||||||
RigEclipseResultAddress xAddress(m_xAxisProperty->resultType(), m_xAxisProperty->resultVariable());
|
RigEclipseResultAddress xAddress(m_xAxisProperty->resultType(), m_xAxisProperty->resultVariable());
|
||||||
RigEclipseResultAddress yAddress(m_yAxisProperty->resultType(), m_yAxisProperty->resultVariable());
|
RigEclipseResultAddress yAddress(m_yAxisProperty->resultType(), m_yAxisProperty->resultVariable());
|
||||||
RigEclipseResultAddress catAddress(m_categoryProperty->resultType(), m_categoryProperty->resultVariable());
|
RigEclipseResultAddress catAddress(m_categoryProperty->resultType(), m_categoryProperty->resultVariable());
|
||||||
|
|
||||||
std::unique_ptr<RigEclipseResultBinSorter> catBinSorter;
|
RigEclipseCrossPlotResult result = RigEclipseCrossPlotDataExtractor::extract(
|
||||||
const std::vector<std::vector<double>>* catValuesForAllSteps = nullptr;
|
eclipseCase->eclipseCaseData(), m_timeStep(), xAddress, yAddress, m_categorization(), catAddress, m_categoryBinCount);
|
||||||
|
|
||||||
if (xAddress.isValid() && yAddress.isValid())
|
for (const auto& sampleCategory : result.categorySamplesMap)
|
||||||
{
|
|
||||||
RigActiveCellInfo* activeCellInfo = resultData->activeCellInfo();
|
|
||||||
const RigMainGrid* mainGrid = eclipseCase->mainGrid();
|
|
||||||
|
|
||||||
resultData->ensureKnownResultLoaded(xAddress);
|
|
||||||
resultData->ensureKnownResultLoaded(yAddress);
|
|
||||||
|
|
||||||
const std::vector<std::vector<double>>& xValuesForAllSteps = resultData->cellScalarResults(xAddress);
|
|
||||||
const std::vector<std::vector<double>>& yValuesForAllSteps = resultData->cellScalarResults(yAddress);
|
|
||||||
|
|
||||||
if (m_categorization() == RESULT_CATEGORIZATION && catAddress.isValid())
|
|
||||||
{
|
|
||||||
resultData->ensureKnownResultLoaded(catAddress);
|
|
||||||
catValuesForAllSteps = &resultData->cellScalarResults(catAddress);
|
|
||||||
catBinSorter.reset(new RigEclipseResultBinSorter(*catValuesForAllSteps, m_categoryBinCount));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<int> timeStepsToInclude;
|
|
||||||
if (m_timeStep() == -1)
|
|
||||||
{
|
|
||||||
size_t nStepsInData = std::max(xValuesForAllSteps.size(), yValuesForAllSteps.size());
|
|
||||||
CVF_ASSERT(xValuesForAllSteps.size() == 1u || xValuesForAllSteps.size() == nStepsInData);
|
|
||||||
CVF_ASSERT(yValuesForAllSteps.size() == 1u || yValuesForAllSteps.size() == nStepsInData);
|
|
||||||
for (size_t i = 0; i < nStepsInData; ++i)
|
|
||||||
{
|
|
||||||
timeStepsToInclude.insert((int)i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
timeStepsToInclude.insert(static_cast<size_t>(m_timeStep()));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int timeStep : timeStepsToInclude)
|
|
||||||
{
|
|
||||||
int xIndex = timeStep >= (int)xValuesForAllSteps.size() ? 0 : timeStep;
|
|
||||||
int yIndex = timeStep >= (int)yValuesForAllSteps.size() ? 0 : timeStep;
|
|
||||||
|
|
||||||
RigActiveCellsResultAccessor xAccessor(mainGrid, &xValuesForAllSteps[xIndex], activeCellInfo);
|
|
||||||
RigActiveCellsResultAccessor yAccessor(mainGrid, &yValuesForAllSteps[yIndex], activeCellInfo);
|
|
||||||
std::unique_ptr<RigActiveCellsResultAccessor> catAccessor;
|
|
||||||
if (catValuesForAllSteps)
|
|
||||||
{
|
|
||||||
int catIndex = timeStep >= (int)catValuesForAllSteps->size() ? 0 : timeStep;
|
|
||||||
catAccessor.reset(new RigActiveCellsResultAccessor(mainGrid, &(catValuesForAllSteps->at(catIndex)), activeCellInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t globalCellIdx = 0; globalCellIdx < activeCellInfo->reservoirCellCount(); ++globalCellIdx)
|
|
||||||
{
|
|
||||||
double xValue = xAccessor.cellScalarGlobIdx(globalCellIdx);
|
|
||||||
double yValue = yAccessor.cellScalarGlobIdx(globalCellIdx);
|
|
||||||
|
|
||||||
int category = 0;
|
|
||||||
if (m_categorization() == TIME_CATEGORIZATION)
|
|
||||||
{
|
|
||||||
category = timeStep;
|
|
||||||
}
|
|
||||||
else if (m_categorization() == FORMATION_CATEGORIZATION && activeFormationNames)
|
|
||||||
{
|
|
||||||
size_t i(cvf::UNDEFINED_SIZE_T), j(cvf::UNDEFINED_SIZE_T), k(cvf::UNDEFINED_SIZE_T);
|
|
||||||
if (mainGrid->ijkFromCellIndex(globalCellIdx, &i, &j, &k))
|
|
||||||
{
|
|
||||||
category = activeFormationNames->formationIndexFromKLayerIdx(k);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (catAccessor && catBinSorter)
|
|
||||||
{
|
|
||||||
double catValue = catAccessor->cellScalarGlobIdx(globalCellIdx);
|
|
||||||
category = catBinSorter->binNumber(catValue);
|
|
||||||
}
|
|
||||||
if (xValue != HUGE_VAL && yValue != HUGE_VAL)
|
|
||||||
{
|
|
||||||
samples[category].push_back(QPointF(xValue, yValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList timeStepNames = m_case->timeStepStrings();
|
|
||||||
|
|
||||||
int curveSetIndex = indexInPlot();
|
|
||||||
|
|
||||||
for (const auto& sampleCategory : samples)
|
|
||||||
{
|
{
|
||||||
RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve();
|
RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve();
|
||||||
QString categoryName;
|
QString categoryName = result.categoryNameMap[sampleCategory.first];
|
||||||
if (m_categorization() == TIME_CATEGORIZATION)
|
|
||||||
{
|
|
||||||
bool staticResultsOnly = staticResultsOnly = m_xAxisProperty->hasStaticResult() && m_yAxisProperty->hasStaticResult();
|
|
||||||
if (!staticResultsOnly && sampleCategory.first < timeStepNames.size())
|
|
||||||
{
|
|
||||||
categoryName = timeStepNames[sampleCategory.first];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_categorization() == FORMATION_CATEGORIZATION && activeFormationNames)
|
|
||||||
{
|
|
||||||
categoryName = activeFormationNames->formationNameFromKLayerIdx(sampleCategory.first);
|
|
||||||
}
|
|
||||||
else if (catBinSorter)
|
|
||||||
{
|
|
||||||
std::pair<double, double> binRange = catBinSorter->binRange(sampleCategory.first);
|
|
||||||
categoryName = QString("%1 [%2, %3]").arg(m_categoryProperty->resultVariableUiShortName()).arg(binRange.first).arg(binRange.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (categoryName.isEmpty())
|
if (categoryName.isEmpty())
|
||||||
{
|
{
|
||||||
@ -422,16 +268,14 @@ void RimGridCrossPlotCurveSet::onLoadDataAndUpdate(bool updateParentPlot)
|
|||||||
{
|
{
|
||||||
curve->setCustomName(QString("%1 : %2").arg(createAutoName()).arg(categoryName));
|
curve->setCustomName(QString("%1 : %2").arg(createAutoName()).arg(categoryName));
|
||||||
}
|
}
|
||||||
curve->determineColorAndSymbol(curveSetIndex, sampleCategory.first, (int)samples.size(), m_categorization() == FORMATION_CATEGORIZATION);
|
curve->determineColorAndSymbol(indexInPlot(), sampleCategory.first, (int)result.categorySamplesMap.size(), m_categorization() == FORMATION_CATEGORIZATION);
|
||||||
curve->setSamples(sampleCategory.second);
|
curve->setSamples(sampleCategory.second.first, sampleCategory.second.second);
|
||||||
curve->updateCurveAppearance();
|
curve->updateCurveAppearance();
|
||||||
curve->updateCurveNameAndUpdatePlotLegendAndTitle();
|
curve->updateCurveNameAndUpdatePlotLegendAndTitle();
|
||||||
curve->updateUiIconFromPlotSymbol();
|
curve->updateUiIconFromPlotSymbol();
|
||||||
|
|
||||||
m_crossPlotCurves.push_back(curve);
|
m_crossPlotCurves.push_back(curve);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateParentPlot)
|
if (updateParentPlot)
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "RigGridCrossPlotCurveCategorization.h"
|
||||||
|
|
||||||
#include "RimCheckableNamedObject.h"
|
#include "RimCheckableNamedObject.h"
|
||||||
#include "RimNameConfig.h"
|
#include "RimNameConfig.h"
|
||||||
|
|
||||||
@ -27,11 +29,14 @@
|
|||||||
#include "cafPdmObject.h"
|
#include "cafPdmObject.h"
|
||||||
#include "cafPdmPtrField.h"
|
#include "cafPdmPtrField.h"
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
class RimCase;
|
class RimCase;
|
||||||
class RimGridCrossPlotCurve;
|
class RimGridCrossPlotCurve;
|
||||||
class RimEclipseResultDefinition;
|
class RimEclipseResultDefinition;
|
||||||
class QwtPlot;
|
class QwtPlot;
|
||||||
class QwtPlotCurve;
|
class QwtPlotCurve;
|
||||||
|
class QString;
|
||||||
|
|
||||||
class RimGridCrossPlotCurveSetNameConfig : public RimNameConfig
|
class RimGridCrossPlotCurveSetNameConfig : public RimNameConfig
|
||||||
{
|
{
|
||||||
@ -58,14 +63,8 @@ class RimGridCrossPlotCurveSet : public RimCheckableNamedObject, public RimNameC
|
|||||||
CAF_PDM_HEADER_INIT;
|
CAF_PDM_HEADER_INIT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum CurveCategorization
|
|
||||||
{
|
typedef caf::AppEnum<RigGridCrossPlotCurveCategorization> CurveCategorizationEnum;
|
||||||
NO_CATEGORIZATION,
|
|
||||||
TIME_CATEGORIZATION,
|
|
||||||
FORMATION_CATEGORIZATION,
|
|
||||||
RESULT_CATEGORIZATION
|
|
||||||
};
|
|
||||||
typedef caf::AppEnum<CurveCategorization> CurveCategorizationEnum;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RimGridCrossPlotCurveSet();
|
RimGridCrossPlotCurveSet();
|
||||||
|
@ -53,6 +53,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RigCellGeometryTools.h
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RigWellPathIntersectionTools.h
|
${CMAKE_CURRENT_LIST_DIR}/RigWellPathIntersectionTools.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultInfo.h
|
${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultInfo.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultAddress.h
|
${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultAddress.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultBinSorter.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigTofAccumulatedPhaseFractionsCalculator.h
|
${CMAKE_CURRENT_LIST_DIR}/RigTofAccumulatedPhaseFractionsCalculator.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigTransmissibilityEquations.h
|
${CMAKE_CURRENT_LIST_DIR}/RigTransmissibilityEquations.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigNumberOfFloodedPoreVolumesCalculator.h
|
${CMAKE_CURRENT_LIST_DIR}/RigNumberOfFloodedPoreVolumesCalculator.h
|
||||||
@ -67,6 +68,9 @@ ${CMAKE_CURRENT_LIST_DIR}/RigCaseRealizationParameters.h
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RigGeoMechBoreHoleStressCalculator.h
|
${CMAKE_CURRENT_LIST_DIR}/RigGeoMechBoreHoleStressCalculator.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigPolyLinesData.h
|
${CMAKE_CURRENT_LIST_DIR}/RigPolyLinesData.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigCaseCellResultCalculator.h
|
${CMAKE_CURRENT_LIST_DIR}/RigCaseCellResultCalculator.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RigGridCrossPlotCurveCategorization.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RigEclipseCrossPlotDataExtractor.h
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -118,6 +122,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RigTesselatorTools.cpp
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RigCellGeometryTools.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigCellGeometryTools.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigWellPathIntersectionTools.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigWellPathIntersectionTools.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultInfo.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultInfo.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultBinSorter.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigTofAccumulatedPhaseFractionsCalculator.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigTofAccumulatedPhaseFractionsCalculator.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigTransmissibilityEquations.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigTransmissibilityEquations.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigNumberOfFloodedPoreVolumesCalculator.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigNumberOfFloodedPoreVolumesCalculator.cpp
|
||||||
@ -132,6 +137,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RigCaseRealizationParameters.cpp
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RigGeoMechBoreHoleStressCalculator.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigGeoMechBoreHoleStressCalculator.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigPolyLinesData.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigPolyLinesData.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigCaseCellResultCalculator.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigCaseCellResultCalculator.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RigEclipseCrossPlotDataExtractor.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND CODE_HEADER_FILES
|
list(APPEND CODE_HEADER_FILES
|
||||||
|
@ -17,25 +17,147 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
#include "RigEclipseCrossPlotDataExtractor.h"
|
#include "RigEclipseCrossPlotDataExtractor.h"
|
||||||
|
|
||||||
#include "RigEclipseCaseData.h"
|
|
||||||
#include "RigCaseCellResultsData.h"
|
|
||||||
#include "RigEclipseResultAddress.h"
|
|
||||||
#include "RigActiveCellInfo.h"
|
#include "RigActiveCellInfo.h"
|
||||||
|
#include "RigActiveCellsResultAccessor.h"
|
||||||
|
#include "RigCaseCellResultsData.h"
|
||||||
|
#include "RigEclipseCaseData.h"
|
||||||
|
#include "RigEclipseResultAddress.h"
|
||||||
|
#include "RigEclipseResultBinSorter.h"
|
||||||
|
#include "RigFormationNames.h"
|
||||||
|
#include "RigMainGrid.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
std::vector<std::pair<double, double>> RigEclipseCrossPlotDataExtractor::extract(RigEclipseCaseData* caseData,
|
RigEclipseCrossPlotResult RigEclipseCrossPlotDataExtractor::extract(RigEclipseCaseData* caseData,
|
||||||
int timeStep,
|
int resultTimeStep,
|
||||||
const RigEclipseResultAddress& xAxisProperty,
|
const RigEclipseResultAddress& xAddress,
|
||||||
const RigEclipseResultAddress& yAxisProperty)
|
const RigEclipseResultAddress& yAddress,
|
||||||
|
RigGridCrossPlotCurveCategorization categorizationType,
|
||||||
|
const RigEclipseResultAddress& catAddress,
|
||||||
|
int categoryBinCount)
|
||||||
{
|
{
|
||||||
RigCaseCellResultsData* resultData = caseData->results(RiaDefines::MATRIX_MODEL);
|
RigEclipseCrossPlotResult result;
|
||||||
std::vector<double> xValues = resultData->cellScalarResults(xAxisProperty)[timeStep];
|
RigEclipseCrossPlotResult::CategorySamplesMap& categorySamplesMap = result.categorySamplesMap;
|
||||||
std::vector<double> yValues = resultData->cellScalarResults(xAxisProperty)[timeStep];
|
RigEclipseCrossPlotResult::CategoryNameMap& categoryNameMap = result.categoryNameMap;
|
||||||
size_t reservoirCellIndex = m_grid->reservoirCellIndex(gridLocalCellIndex);
|
|
||||||
size_t resultValueIndex = m_activeCellInfo->cellResultIndex(reservoirCellIndex);
|
|
||||||
if (resultValueIndex == cvf::UNDEFINED_SIZE_T) return HUGE_VAL;
|
|
||||||
|
|
||||||
if (resultValueIndex < m_reservoirResultValues->size()) return m_reservoirResultValues->at(resultValueIndex);
|
RigCaseCellResultsData* resultData = caseData->results(RiaDefines::MATRIX_MODEL);
|
||||||
|
RigFormationNames* activeFormationNames = resultData->activeFormationNames();
|
||||||
|
|
||||||
|
std::unique_ptr<RigEclipseResultBinSorter> catBinSorter;
|
||||||
|
const std::vector<std::vector<double>>* catValuesForAllSteps = nullptr;
|
||||||
|
|
||||||
|
if (xAddress.isValid() && yAddress.isValid())
|
||||||
|
{
|
||||||
|
RigActiveCellInfo* activeCellInfo = resultData->activeCellInfo();
|
||||||
|
const RigMainGrid* mainGrid = caseData->mainGrid();
|
||||||
|
|
||||||
|
resultData->ensureKnownResultLoaded(xAddress);
|
||||||
|
resultData->ensureKnownResultLoaded(yAddress);
|
||||||
|
|
||||||
|
const std::vector<std::vector<double>>& xValuesForAllSteps = resultData->cellScalarResults(xAddress);
|
||||||
|
const std::vector<std::vector<double>>& yValuesForAllSteps = resultData->cellScalarResults(yAddress);
|
||||||
|
|
||||||
|
if (categorizationType == RESULT_CATEGORIZATION && catAddress.isValid())
|
||||||
|
{
|
||||||
|
resultData->ensureKnownResultLoaded(catAddress);
|
||||||
|
catValuesForAllSteps = &resultData->cellScalarResults(catAddress);
|
||||||
|
catBinSorter.reset(new RigEclipseResultBinSorter(*catValuesForAllSteps, categoryBinCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<int> timeStepsToInclude;
|
||||||
|
if (resultTimeStep == -1)
|
||||||
|
{
|
||||||
|
size_t nStepsInData = std::max(xValuesForAllSteps.size(), yValuesForAllSteps.size());
|
||||||
|
CVF_ASSERT(xValuesForAllSteps.size() == 1u || xValuesForAllSteps.size() == nStepsInData);
|
||||||
|
CVF_ASSERT(yValuesForAllSteps.size() == 1u || yValuesForAllSteps.size() == nStepsInData);
|
||||||
|
for (size_t i = 0; i < nStepsInData; ++i)
|
||||||
|
{
|
||||||
|
timeStepsToInclude.insert((int)i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timeStepsToInclude.insert(static_cast<size_t>(resultTimeStep));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int timeStep : timeStepsToInclude)
|
||||||
|
{
|
||||||
|
int xIndex = timeStep >= (int)xValuesForAllSteps.size() ? 0 : timeStep;
|
||||||
|
int yIndex = timeStep >= (int)yValuesForAllSteps.size() ? 0 : timeStep;
|
||||||
|
|
||||||
|
RigActiveCellsResultAccessor xAccessor(mainGrid, &xValuesForAllSteps[xIndex], activeCellInfo);
|
||||||
|
RigActiveCellsResultAccessor yAccessor(mainGrid, &yValuesForAllSteps[yIndex], activeCellInfo);
|
||||||
|
std::unique_ptr<RigActiveCellsResultAccessor> catAccessor;
|
||||||
|
if (catValuesForAllSteps)
|
||||||
|
{
|
||||||
|
int catIndex = timeStep >= (int)catValuesForAllSteps->size() ? 0 : timeStep;
|
||||||
|
catAccessor.reset(
|
||||||
|
new RigActiveCellsResultAccessor(mainGrid, &(catValuesForAllSteps->at(catIndex)), activeCellInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t globalCellIdx = 0; globalCellIdx < activeCellInfo->reservoirCellCount(); ++globalCellIdx)
|
||||||
|
{
|
||||||
|
double xValue = xAccessor.cellScalarGlobIdx(globalCellIdx);
|
||||||
|
double yValue = yAccessor.cellScalarGlobIdx(globalCellIdx);
|
||||||
|
|
||||||
|
int category = 0;
|
||||||
|
if (categorizationType == TIME_CATEGORIZATION)
|
||||||
|
{
|
||||||
|
category = timeStep;
|
||||||
|
}
|
||||||
|
else if (categorizationType == FORMATION_CATEGORIZATION && activeFormationNames)
|
||||||
|
{
|
||||||
|
size_t i(cvf::UNDEFINED_SIZE_T), j(cvf::UNDEFINED_SIZE_T), k(cvf::UNDEFINED_SIZE_T);
|
||||||
|
if (mainGrid->ijkFromCellIndex(globalCellIdx, &i, &j, &k))
|
||||||
|
{
|
||||||
|
category = activeFormationNames->formationIndexFromKLayerIdx(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (catAccessor && catBinSorter)
|
||||||
|
{
|
||||||
|
double catValue = catAccessor->cellScalarGlobIdx(globalCellIdx);
|
||||||
|
category = catBinSorter->binNumber(catValue);
|
||||||
|
}
|
||||||
|
if (xValue != HUGE_VAL && yValue != HUGE_VAL)
|
||||||
|
{
|
||||||
|
categorySamplesMap[category].first.push_back(xValue);
|
||||||
|
categorySamplesMap[category].second.push_back(yValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<QDateTime> timeStepDates = resultData->timeStepDates();
|
||||||
|
|
||||||
|
for (const auto& sampleCategory : categorySamplesMap)
|
||||||
|
{
|
||||||
|
QString categoryName;
|
||||||
|
if (categorizationType == TIME_CATEGORIZATION && categorySamplesMap.size() > 1u)
|
||||||
|
{
|
||||||
|
if (sampleCategory.first < timeStepDates.size())
|
||||||
|
{
|
||||||
|
categoryName = timeStepDates[sampleCategory.first].toString(Qt::ISODate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (categorizationType == FORMATION_CATEGORIZATION && activeFormationNames)
|
||||||
|
{
|
||||||
|
categoryName = activeFormationNames->formationNameFromKLayerIdx(sampleCategory.first);
|
||||||
|
}
|
||||||
|
else if (catBinSorter)
|
||||||
|
{
|
||||||
|
std::pair<double, double> binRange = catBinSorter->binRange(sampleCategory.first);
|
||||||
|
|
||||||
|
categoryName = QString("%1 [%2, %3]")
|
||||||
|
.arg(catAddress.m_resultName)
|
||||||
|
.arg(binRange.first)
|
||||||
|
.arg(binRange.second);
|
||||||
|
}
|
||||||
|
categoryNameMap.insert(std::make_pair(sampleCategory.first, categoryName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,36 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "RigGridCrossPlotCurveCategorization.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class RigEclipseCaseData;
|
class RigEclipseCaseData;
|
||||||
class RigEclipseResultAddress;
|
class RigEclipseResultAddress;
|
||||||
|
|
||||||
class RigEclipseCrossPlotDataExtractor
|
class QString;
|
||||||
|
|
||||||
|
struct RigEclipseCrossPlotResult
|
||||||
{
|
{
|
||||||
static std::vector<std::pair<double, double>> extract(RigEclipseCaseData* caseData,
|
typedef std::pair<std::vector<double>, std::vector<double>> ResultXYValues;
|
||||||
int timeStep,
|
|
||||||
const RigEclipseResultAddress& xAxisProperty,
|
typedef std::map<int, ResultXYValues> CategorySamplesMap;
|
||||||
const RigEclipseResultAddress& yAxisProperty);
|
typedef std::map<int, QString> CategoryNameMap;
|
||||||
|
|
||||||
|
CategorySamplesMap categorySamplesMap;
|
||||||
|
CategoryNameMap categoryNameMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RigEclipseCrossPlotDataExtractor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static RigEclipseCrossPlotResult extract(RigEclipseCaseData* eclipseCase,
|
||||||
|
int resultTimeStep,
|
||||||
|
const RigEclipseResultAddress& xAddress,
|
||||||
|
const RigEclipseResultAddress& yAddress,
|
||||||
|
RigGridCrossPlotCurveCategorization categorizationType,
|
||||||
|
const RigEclipseResultAddress& categoryAddress,
|
||||||
|
int categoryBinCount);
|
||||||
|
};
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019- Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#include "RigEclipseResultBinSorter.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RigEclipseResultBinSorter::RigEclipseResultBinSorter(const std::vector<std::vector<double>>& allDataValues, int binCount)
|
||||||
|
: m_allDataValues(allDataValues)
|
||||||
|
, m_binCount(binCount)
|
||||||
|
, m_minValue(std::numeric_limits<double>::infinity())
|
||||||
|
, m_maxValue(-std::numeric_limits<double>::infinity())
|
||||||
|
, m_binSize(0.0)
|
||||||
|
{
|
||||||
|
calculateRange();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
int RigEclipseResultBinSorter::binNumber(double value) const
|
||||||
|
{
|
||||||
|
double distFromMin = value - m_minValue;
|
||||||
|
return std::min(m_binCount - 1, static_cast<int>(distFromMin / m_binSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::pair<double, double> RigEclipseResultBinSorter::binRange(int binNumber) const
|
||||||
|
{
|
||||||
|
double minBinValue = m_minValue + m_binSize * binNumber;
|
||||||
|
double maxBinBalue = minBinValue + m_binSize;
|
||||||
|
return std::make_pair(minBinValue, maxBinBalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RigEclipseResultBinSorter::calculateRange()
|
||||||
|
{
|
||||||
|
for (const std::vector<double>& doubleRange : m_allDataValues)
|
||||||
|
{
|
||||||
|
if (!doubleRange.empty())
|
||||||
|
{
|
||||||
|
for (double value : doubleRange)
|
||||||
|
{
|
||||||
|
if (value != std::numeric_limits<double>::infinity())
|
||||||
|
{
|
||||||
|
m_minValue = std::min(m_minValue, value);
|
||||||
|
m_maxValue = std::max(m_maxValue, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_maxValue > m_minValue)
|
||||||
|
{
|
||||||
|
m_binSize = (m_maxValue - m_minValue) / m_binCount;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019- Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
///
|
||||||
|
///
|
||||||
|
//==================================================================================================
|
||||||
|
class RigEclipseResultBinSorter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RigEclipseResultBinSorter(const std::vector<std::vector<double>>& allDataValues, int binCount);
|
||||||
|
|
||||||
|
int binNumber(double value) const;
|
||||||
|
std::pair<double, double> binRange(int binNumber) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void calculateRange();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::vector<std::vector<double>>& m_allDataValues;
|
||||||
|
int m_binCount;
|
||||||
|
double m_minValue;
|
||||||
|
double m_maxValue;
|
||||||
|
double m_binSize;
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,27 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019- Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum RigGridCrossPlotCurveCategorization
|
||||||
|
{
|
||||||
|
NO_CATEGORIZATION,
|
||||||
|
TIME_CATEGORIZATION,
|
||||||
|
FORMATION_CATEGORIZATION,
|
||||||
|
RESULT_CATEGORIZATION
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user