Refactor: make contour map calculation easier to reuse.

This commit is contained in:
Kristian Bendiksen 2024-10-17 14:29:59 +02:00
parent 2cdb388a0d
commit 293e19d820
7 changed files with 574 additions and 358 deletions

View File

@ -21,6 +21,7 @@
#include "RiaWeightedMeanCalculator.h"
#include "RigCellGeometryTools.h"
#include "RigContourMapCalculator.h"
#include "RigContourMapGrid.h"
#include "RigFemAddressDefines.h"
#include "RigFemPart.h"
@ -611,10 +612,15 @@ QList<caf::PdmOptionItemInfo> RimGeoMechContourMapProjection::calculateValueOpti
if ( fieldNeedingOptions == &m_resultAggregation )
{
std::vector<ResultAggregationEnum> validOptions =
{ RESULTS_TOP_VALUE, RESULTS_MEAN_VALUE, RESULTS_GEOM_VALUE, RESULTS_HARM_VALUE, RESULTS_MIN_VALUE, RESULTS_MAX_VALUE, RESULTS_SUM };
std::vector<RigContourMapCalculator::ResultAggregationEnum> validOptions = { RigContourMapCalculator::RESULTS_TOP_VALUE,
RigContourMapCalculator::RESULTS_MEAN_VALUE,
RigContourMapCalculator::RESULTS_GEOM_VALUE,
RigContourMapCalculator::RESULTS_HARM_VALUE,
RigContourMapCalculator::RESULTS_MIN_VALUE,
RigContourMapCalculator::RESULTS_MAX_VALUE,
RigContourMapCalculator::RESULTS_SUM };
for ( ResultAggregationEnum option : validOptions )
for ( RigContourMapCalculator::ResultAggregationEnum option : validOptions )
{
options.push_back( caf::PdmOptionItemInfo( ResultAggregation::uiText( option ), option ) );
}

View File

@ -19,11 +19,10 @@
#include "RimContourMapProjection.h"
#include "RiaOpenMPTools.h"
#include "RiaWeightedGeometricMeanCalculator.h"
#include "RiaWeightedHarmonicMeanCalculator.h"
#include "RiaWeightedMeanCalculator.h"
#include "RigCellGeometryTools.h"
#include "RigContourMapCalculator.h"
#include "RigContourMapGrid.h"
#include "RimCase.h"
@ -50,21 +49,21 @@ namespace caf
template <>
void RimContourMapProjection::ResultAggregation::setUp()
{
addItem( RimContourMapProjection::RESULTS_OIL_COLUMN, "OIL_COLUMN", "Oil Column" );
addItem( RimContourMapProjection::RESULTS_GAS_COLUMN, "GAS_COLUMN", "Gas Column" );
addItem( RimContourMapProjection::RESULTS_HC_COLUMN, "HC_COLUMN", "Hydrocarbon Column" );
addItem( RigContourMapCalculator::RESULTS_OIL_COLUMN, "OIL_COLUMN", "Oil Column" );
addItem( RigContourMapCalculator::RESULTS_GAS_COLUMN, "GAS_COLUMN", "Gas Column" );
addItem( RigContourMapCalculator::RESULTS_HC_COLUMN, "HC_COLUMN", "Hydrocarbon Column" );
addItem( RimContourMapProjection::RESULTS_MEAN_VALUE, "MEAN_VALUE", "Arithmetic Mean" );
addItem( RimContourMapProjection::RESULTS_HARM_VALUE, "HARM_VALUE", "Harmonic Mean" );
addItem( RimContourMapProjection::RESULTS_GEOM_VALUE, "GEOM_VALUE", "Geometric Mean" );
addItem( RimContourMapProjection::RESULTS_VOLUME_SUM, "VOLUME_SUM", "Volume Weighted Sum" );
addItem( RimContourMapProjection::RESULTS_SUM, "SUM", "Sum" );
addItem( RigContourMapCalculator::RESULTS_MEAN_VALUE, "MEAN_VALUE", "Arithmetic Mean" );
addItem( RigContourMapCalculator::RESULTS_HARM_VALUE, "HARM_VALUE", "Harmonic Mean" );
addItem( RigContourMapCalculator::RESULTS_GEOM_VALUE, "GEOM_VALUE", "Geometric Mean" );
addItem( RigContourMapCalculator::RESULTS_VOLUME_SUM, "VOLUME_SUM", "Volume Weighted Sum" );
addItem( RigContourMapCalculator::RESULTS_SUM, "SUM", "Sum" );
addItem( RimContourMapProjection::RESULTS_TOP_VALUE, "TOP_VALUE", "Top Value" );
addItem( RimContourMapProjection::RESULTS_MIN_VALUE, "MIN_VALUE", "Min Value" );
addItem( RimContourMapProjection::RESULTS_MAX_VALUE, "MAX_VALUE", "Max Value" );
addItem( RigContourMapCalculator::RESULTS_TOP_VALUE, "TOP_VALUE", "Top Value" );
addItem( RigContourMapCalculator::RESULTS_MIN_VALUE, "MIN_VALUE", "Min Value" );
addItem( RigContourMapCalculator::RESULTS_MAX_VALUE, "MAX_VALUE", "Max Value" );
setDefault( RimContourMapProjection::RESULTS_MEAN_VALUE );
setDefault( RigContourMapCalculator::RESULTS_MEAN_VALUE );
}
} // namespace caf
CAF_PDM_ABSTRACT_SOURCE_INIT( RimContourMapProjection, "RimContourMapProjection" );
@ -115,7 +114,12 @@ void RimContourMapProjection::generateResultsIfNecessary( int timeStep )
clearResults();
clearTimeStepRange();
if ( gridMappingNeedsUpdating() ) m_projected3dGridIndices = generateGridMapping();
m_cellGridIdxVisibility = getCellVisibility();
if ( gridMappingNeedsUpdating() )
{
m_projected3dGridIndices = RigContourMapCalculator::generateGridMapping( *this, *m_contourMapGrid );
}
progress.setProgress( 20 );
m_mapCellVisibility = getMapCellVisibility();
progress.setProgress( 30 );
@ -332,8 +336,7 @@ cvf::Vec2ui RimContourMapProjection::numberOfVerticesIJ() const
//--------------------------------------------------------------------------------------------------
bool RimContourMapProjection::isColumnResult() const
{
return m_resultAggregation() == RESULTS_OIL_COLUMN || m_resultAggregation() == RESULTS_GAS_COLUMN ||
m_resultAggregation() == RESULTS_HC_COLUMN;
return RigContourMapCalculator::isColumnResult( m_resultAggregation() );
}
//--------------------------------------------------------------------------------------------------
@ -437,130 +440,7 @@ size_t RimContourMapProjection::gridResultIndex( size_t globalCellIdx ) const
double RimContourMapProjection::calculateValueInMapCell( uint i, uint j, const std::vector<double>& gridCellValues ) const
{
const std::vector<std::pair<size_t, double>>& matchingCells = cellsAtIJ( i, j );
if ( !matchingCells.empty() )
{
switch ( m_resultAggregation() )
{
case RESULTS_TOP_VALUE:
{
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[gridResultIndex( cellIdx )];
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
return cellValue;
}
}
return std::numeric_limits<double>::infinity();
}
case RESULTS_MEAN_VALUE:
{
RiaWeightedMeanCalculator<double> calculator;
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[gridResultIndex( cellIdx )];
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
calculator.addValueAndWeight( cellValue, weight );
}
}
if ( calculator.validAggregatedWeight() )
{
return calculator.weightedMean();
}
return std::numeric_limits<double>::infinity();
}
case RESULTS_GEOM_VALUE:
{
RiaWeightedGeometricMeanCalculator calculator;
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[gridResultIndex( cellIdx )];
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
if ( cellValue < 1.0e-8 )
{
return 0.0;
}
calculator.addValueAndWeight( cellValue, weight );
}
}
if ( calculator.validAggregatedWeight() )
{
return calculator.weightedMean();
}
return std::numeric_limits<double>::infinity();
}
case RESULTS_HARM_VALUE:
{
RiaWeightedHarmonicMeanCalculator calculator;
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[gridResultIndex( cellIdx )];
if ( std::fabs( cellValue ) < 1.0e-8 )
{
return 0.0;
}
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
calculator.addValueAndWeight( cellValue, weight );
}
}
if ( calculator.validAggregatedWeight() )
{
return calculator.weightedMean();
}
return std::numeric_limits<double>::infinity();
}
case RESULTS_MAX_VALUE:
{
double maxValue = -std::numeric_limits<double>::infinity();
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[gridResultIndex( cellIdx )];
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
maxValue = std::max( maxValue, cellValue );
}
}
if ( maxValue == -std::numeric_limits<double>::infinity() )
{
maxValue = std::numeric_limits<double>::infinity();
}
return maxValue;
}
case RESULTS_MIN_VALUE:
{
double minValue = std::numeric_limits<double>::infinity();
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[gridResultIndex( cellIdx )];
minValue = std::min( minValue, cellValue );
}
return minValue;
}
case RESULTS_VOLUME_SUM:
case RESULTS_SUM:
case RESULTS_OIL_COLUMN:
case RESULTS_GAS_COLUMN:
case RESULTS_HC_COLUMN:
{
double sum = 0.0;
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[gridResultIndex( cellIdx )];
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
sum += cellValue * weight;
}
}
return sum;
}
default:
CVF_TIGHT_ASSERT( false );
}
}
return std::numeric_limits<double>::infinity();
return RigContourMapCalculator::calculateValueInMapCell( *this, matchingCells, gridCellValues, m_resultAggregation() );
}
//--------------------------------------------------------------------------------------------------
@ -727,44 +607,6 @@ bool RimContourMapProjection::mapCellVisibilityNeedsUpdating()
return !( mapCellVisiblity == m_mapCellVisibility );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<std::pair<size_t, double>>> RimContourMapProjection::generateGridMapping()
{
m_cellGridIdxVisibility = getCellVisibility();
int nCells = numberOfCells();
std::vector<std::vector<std::pair<size_t, double>>> projected3dGridIndices( nCells );
std::vector<double> weightingResultValues = retrieveParameterWeights();
if ( isStraightSummationResult() )
{
#pragma omp parallel for
for ( int index = 0; index < nCells; ++index )
{
cvf::Vec2ui ij = m_contourMapGrid->ijFromCellIndex( index );
cvf::Vec2d globalPos = m_contourMapGrid->cellCenterPosition( ij.x(), ij.y() ) + m_contourMapGrid->origin2d();
projected3dGridIndices[index] = cellRayIntersectionAndResults( globalPos, weightingResultValues );
}
}
else
{
#pragma omp parallel for
for ( int index = 0; index < nCells; ++index )
{
cvf::Vec2ui ij = m_contourMapGrid->ijFromCellIndex( index );
cvf::Vec2d globalPos = m_contourMapGrid->cellCenterPosition( ij.x(), ij.y() ) + m_contourMapGrid->origin2d();
projected3dGridIndices[index] = cellOverlapVolumesAndResults( globalPos, weightingResultValues );
}
}
return projected3dGridIndices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -1123,131 +965,12 @@ double RimContourMapProjection::sumTriangleAreas( const std::vector<cvf::Vec4d>&
return sumArea;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimContourMapProjection::CellIndexAndResult>
RimContourMapProjection::cellOverlapVolumesAndResults( const cvf::Vec2d& globalPos2d, const std::vector<double>& weightingResultValues ) const
{
const cvf::BoundingBox& expandedBoundingBox = m_contourMapGrid->expandedBoundingBox();
cvf::Vec3d top2dElementCentroid( globalPos2d, expandedBoundingBox.max().z() );
cvf::Vec3d bottom2dElementCentroid( globalPos2d, expandedBoundingBox.min().z() );
cvf::Vec3d planarDiagonalVector( 0.5 * sampleSpacing(), 0.5 * sampleSpacing(), 0.0 );
cvf::Vec3d topNECorner = top2dElementCentroid + planarDiagonalVector;
cvf::Vec3d bottomSWCorner = bottom2dElementCentroid - planarDiagonalVector;
cvf::BoundingBox bbox2dElement( bottomSWCorner, topNECorner );
std::vector<std::pair<size_t, double>> matchingVisibleCellsAndWeight;
// Bounding box has been expanded, so 2d element may be outside actual 3d grid
if ( !bbox2dElement.intersects( m_contourMapGrid->originalBoundingBox() ) )
{
return matchingVisibleCellsAndWeight;
}
std::vector<size_t> allCellIndices = findIntersectingCells( bbox2dElement );
std::vector<std::vector<size_t>> kLayerCellIndexVector;
kLayerCellIndexVector.resize( kLayers() );
if ( kLayerCellIndexVector.empty() )
{
return matchingVisibleCellsAndWeight;
}
for ( size_t globalCellIdx : allCellIndices )
{
if ( ( *m_cellGridIdxVisibility )[globalCellIdx] )
{
kLayerCellIndexVector[kLayer( globalCellIdx )].push_back( globalCellIdx );
}
}
for ( const auto& kLayerIndices : kLayerCellIndexVector )
{
for ( size_t globalCellIdx : kLayerIndices )
{
double overlapVolume = calculateOverlapVolume( globalCellIdx, bbox2dElement );
if ( overlapVolume > 0.0 )
{
double weight = overlapVolume * getParameterWeightForCell( gridResultIndex( globalCellIdx ), weightingResultValues );
if ( weight > 0.0 )
{
matchingVisibleCellsAndWeight.push_back( std::make_pair( globalCellIdx, weight ) );
}
}
}
}
return matchingVisibleCellsAndWeight;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimContourMapProjection::CellIndexAndResult>
RimContourMapProjection::cellRayIntersectionAndResults( const cvf::Vec2d& globalPos2d, const std::vector<double>& weightingResultValues ) const
{
std::vector<std::pair<size_t, double>> matchingVisibleCellsAndWeight;
const cvf::BoundingBox& expandedBoundingBox = m_contourMapGrid->expandedBoundingBox();
cvf::Vec3d highestPoint( globalPos2d, expandedBoundingBox.max().z() );
cvf::Vec3d lowestPoint( globalPos2d, expandedBoundingBox.min().z() );
// Bounding box has been expanded, so ray may be outside actual 3d grid
if ( !m_contourMapGrid->originalBoundingBox().contains( highestPoint ) )
{
return matchingVisibleCellsAndWeight;
}
cvf::BoundingBox rayBBox;
rayBBox.add( highestPoint );
rayBBox.add( lowestPoint );
std::vector<size_t> allCellIndices = findIntersectingCells( rayBBox );
std::map<size_t, std::vector<size_t>> kLayerIndexMap;
for ( size_t globalCellIdx : allCellIndices )
{
if ( ( *m_cellGridIdxVisibility )[globalCellIdx] )
{
kLayerIndexMap[kLayer( globalCellIdx )].push_back( globalCellIdx );
}
}
for ( const auto& kLayerIndexPair : kLayerIndexMap )
{
double weightSumThisKLayer = 0.0;
std::vector<std::pair<size_t, double>> cellsAndWeightsThisLayer;
for ( size_t globalCellIdx : kLayerIndexPair.second )
{
double lengthInCell = calculateRayLengthInCell( globalCellIdx, highestPoint, lowestPoint );
if ( lengthInCell > 0.0 )
{
cellsAndWeightsThisLayer.push_back( std::make_pair( globalCellIdx, lengthInCell ) );
weightSumThisKLayer += lengthInCell;
}
}
for ( auto& cellWeightPair : cellsAndWeightsThisLayer )
{
cellWeightPair.second /= weightSumThisKLayer;
matchingVisibleCellsAndWeight.push_back( cellWeightPair );
}
}
return matchingVisibleCellsAndWeight;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimContourMapProjection::isMeanResult() const
{
return m_resultAggregation() == RESULTS_MEAN_VALUE || m_resultAggregation() == RESULTS_HARM_VALUE ||
m_resultAggregation() == RESULTS_GEOM_VALUE;
return RigContourMapCalculator::isMeanResult( m_resultAggregation() );
}
//--------------------------------------------------------------------------------------------------
@ -1255,16 +978,7 @@ bool RimContourMapProjection::isMeanResult() const
//--------------------------------------------------------------------------------------------------
bool RimContourMapProjection::isStraightSummationResult() const
{
return isStraightSummationResult( m_resultAggregation() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimContourMapProjection::isStraightSummationResult( ResultAggregationEnum aggregationType )
{
return aggregationType == RESULTS_OIL_COLUMN || aggregationType == RESULTS_GAS_COLUMN || aggregationType == RESULTS_HC_COLUMN ||
aggregationType == RESULTS_SUM;
return RigContourMapCalculator::isStraightSummationResult( m_resultAggregation() );
}
//--------------------------------------------------------------------------------------------------
@ -1416,8 +1130,8 @@ void RimContourMapProjection::fieldChangedByUi( const caf::PdmFieldHandle* chang
{
if ( changedField == &m_resultAggregation )
{
ResultAggregation previousAggregation = static_cast<ResultAggregationEnum>( oldValue.toInt() );
if ( isStraightSummationResult( previousAggregation ) != isStraightSummationResult() )
ResultAggregation previousAggregation = static_cast<RigContourMapCalculator::ResultAggregationEnum>( oldValue.toInt() );
if ( RigContourMapCalculator::isStraightSummationResult( previousAggregation ) != isStraightSummationResult() )
{
clearGridMapping();
}

View File

@ -20,6 +20,7 @@
#include "RimCheckableNamedObject.h"
#include "RigContourMapCalculator.h"
#include "RigContourPolygonsTools.h"
#include "cafPdmField.h"
@ -44,21 +45,7 @@ class RimContourMapProjection : public RimCheckableNamedObject
public:
using CellIndexAndResult = std::pair<size_t, double>;
enum ResultAggregationEnum
{
RESULTS_TOP_VALUE,
RESULTS_MEAN_VALUE,
RESULTS_GEOM_VALUE,
RESULTS_HARM_VALUE,
RESULTS_MIN_VALUE,
RESULTS_MAX_VALUE,
RESULTS_VOLUME_SUM,
RESULTS_SUM,
RESULTS_OIL_COLUMN,
RESULTS_GAS_COLUMN,
RESULTS_HC_COLUMN
};
using ResultAggregation = caf::AppEnum<ResultAggregationEnum>;
using ResultAggregation = caf::AppEnum<RigContourMapCalculator::ResultAggregationEnum>;
using ContourPolygons = std::vector<RigContourPolygonsTools::ContourPolygon>;
RimContourMapProjection();
@ -95,6 +82,8 @@ public:
cvf::Vec2ui numberOfVerticesIJ() const;
bool isColumnResult() const;
bool isMeanResult() const;
bool isStraightSummationResult() const;
double valueAtVertex( uint i, uint j ) const;
@ -114,14 +103,11 @@ public:
virtual RimRegularLegendConfig* legendConfig() const = 0;
virtual void updateLegend() = 0;
protected:
// Protected virtual methods to be overridden by Eclipse and Geo-mechanical contour map implementations
virtual void updateGridInformation() = 0;
// Use this function to get the result index into grid cell results. The index will differ if we have active cells
virtual size_t gridResultIndex( size_t globalCellIdx ) const;
virtual std::vector<double> retrieveParameterWeights() = 0;
virtual std::vector<double> generateResults( int timeStep ) = 0;
virtual bool resultVariableChanged() const = 0;
virtual void clearResultVariable() = 0;
virtual RimGridView* baseView() const = 0;
virtual size_t kLayer( size_t globalCellIdx ) const = 0;
virtual size_t kLayers() const = 0;
virtual std::vector<size_t> findIntersectingCells( const cvf::BoundingBox& bbox ) const = 0;
@ -129,8 +115,15 @@ protected:
virtual double calculateRayLengthInCell( size_t globalCellIdx, const cvf::Vec3d& highestPoint, const cvf::Vec3d& lowestPoint ) const = 0;
virtual double getParameterWeightForCell( size_t globalCellIdx, const std::vector<double>& parameterWeights ) const = 0;
// Use this function to get the result index into grid cell results. The index will differ if we have active cells
virtual size_t gridResultIndex( size_t globalCellIdx ) const;
virtual cvf::ref<cvf::UByteArray> getCellVisibility() const;
protected:
// Protected virtual methods to be overridden by Eclipse and Geo-mechanical contour map implementations
virtual void updateGridInformation() = 0;
virtual std::vector<double> generateResults( int timeStep ) = 0;
virtual bool resultVariableChanged() const = 0;
virtual void clearResultVariable() = 0;
virtual RimGridView* baseView() const = 0;
double calculateValueInMapCell( uint i, uint j, const std::vector<double>& gridCellValues ) const;
@ -149,10 +142,10 @@ protected:
virtual std::pair<double, double> minmaxValuesAllTimeSteps();
virtual cvf::ref<cvf::UByteArray> getCellVisibility() const;
virtual std::vector<bool> getMapCellVisibility();
bool mapCellVisibilityNeedsUpdating();
std::vector<std::vector<std::pair<size_t, double>>> generateGridMapping();
static std::vector<std::vector<std::pair<size_t, double>>> generateGridMapping( RimContourMapProjection& contourMapProjection,
const RigContourMapGrid& contourMapGrid );
void generateVertexResults();
void generateTrianglesWithVertexValues();
@ -160,15 +153,6 @@ protected:
static double sumTriangleAreas( const std::vector<cvf::Vec4d>& triangles );
std::vector<CellIndexAndResult> cellOverlapVolumesAndResults( const cvf::Vec2d& globalPos2d,
const std::vector<double>& weightingResultValues ) const;
std::vector<CellIndexAndResult> cellRayIntersectionAndResults( const cvf::Vec2d& globalPos2d,
const std::vector<double>& weightingResultValues ) const;
bool isMeanResult() const;
bool isStraightSummationResult() const;
static bool isStraightSummationResult( ResultAggregationEnum aggregationType );
double interpolateValue( const cvf::Vec2d& gridPosition2d ) const;
double valueInCell( uint i, uint j ) const;
bool hasResultInCell( uint i, uint j ) const;

View File

@ -22,6 +22,7 @@
#include "RigCaseCellResultsData.h"
#include "RigCell.h"
#include "RigCellGeometryTools.h"
#include "RigContourMapCalculator.h"
#include "RigContourMapGrid.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseResultAddress.h"
@ -115,8 +116,7 @@ void RimEclipseContourMapProjection::updateLegend()
legendConfig()->setAutomaticRanges( minValAllTimeSteps, maxValAllTimeSteps, minVal, maxVal );
if ( m_resultAggregation() == RESULTS_OIL_COLUMN || m_resultAggregation() == RESULTS_GAS_COLUMN ||
m_resultAggregation() == RESULTS_HC_COLUMN )
if ( isColumnResult() )
{
legendConfig()->setTitle( QString( "Map Projection\n%1" ).arg( m_resultAggregation().uiText() ) );
}
@ -188,12 +188,14 @@ std::vector<double> RimEclipseContourMapProjection::generateResults( int timeSte
gridCellResult->ensureKnownResultLoaded( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PORO" ) );
gridCellResult->ensureKnownResultLoaded( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "NTG" ) );
gridCellResult->ensureKnownResultLoaded( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "DZ" ) );
if ( m_resultAggregation == RESULTS_OIL_COLUMN || m_resultAggregation == RESULTS_HC_COLUMN )
if ( m_resultAggregation == RigContourMapCalculator::RESULTS_OIL_COLUMN ||
m_resultAggregation == RigContourMapCalculator::RESULTS_HC_COLUMN )
{
gridCellResult->ensureKnownResultLoaded(
RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() ) );
}
if ( m_resultAggregation == RESULTS_GAS_COLUMN || m_resultAggregation == RESULTS_HC_COLUMN )
if ( m_resultAggregation == RigContourMapCalculator::RESULTS_GAS_COLUMN ||
m_resultAggregation == RigContourMapCalculator::RESULTS_HC_COLUMN )
{
gridCellResult->ensureKnownResultLoaded(
RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() ) );
@ -284,7 +286,7 @@ std::vector<double> RimEclipseContourMapProjection::calculateColumnResult( Resul
std::vector<double> resultValues( poroResults.size(), 0.0 );
if ( resultAggregation == RESULTS_OIL_COLUMN || resultAggregation == RESULTS_HC_COLUMN )
if ( resultAggregation == RigContourMapCalculator::RESULTS_OIL_COLUMN || resultAggregation == RigContourMapCalculator::RESULTS_HC_COLUMN )
{
const std::vector<double>& soilResults =
resultData->cellScalarResults( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() ),
@ -295,7 +297,7 @@ std::vector<double> RimEclipseContourMapProjection::calculateColumnResult( Resul
}
}
if ( resultAggregation == RESULTS_GAS_COLUMN || resultAggregation == RESULTS_HC_COLUMN )
if ( resultAggregation == RigContourMapCalculator::RESULTS_GAS_COLUMN || resultAggregation == RigContourMapCalculator::RESULTS_HC_COLUMN )
{
bool hasGasResult =
resultData->hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() ) );

View File

@ -104,6 +104,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RigWellTargetCandidatesGenerator.h
${CMAKE_CURRENT_LIST_DIR}/RigContourMapGrid.h
${CMAKE_CURRENT_LIST_DIR}/RigContourPolygonsTools.h
${CMAKE_CURRENT_LIST_DIR}/RigContourMapCalculator.h
)
set(SOURCE_GROUP_SOURCE_FILES
@ -206,6 +207,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RigWellTargetCandidatesGenerator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigContourMapGrid.cpp
${CMAKE_CURRENT_LIST_DIR}/RigContourPolygonsTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RigContourMapCalculator.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})

View File

@ -0,0 +1,410 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- 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 "RigContourMapCalculator.h"
#include "RiaWeightedGeometricMeanCalculator.h"
#include "RiaWeightedHarmonicMeanCalculator.h"
#include "RiaWeightedMeanCalculator.h"
#include "RigContourMapGrid.h"
#include "RimCase.h"
#include "RimContourMapProjection.h"
#include <algorithm>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigContourMapCalculator::calculateValueInMapCell( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues,
ResultAggregationEnum resultAggregation )
{
if ( matchingCells.empty() ) return std::numeric_limits<double>::infinity();
switch ( resultAggregation )
{
case RESULTS_TOP_VALUE:
return calculateTopValue( contourMapProjection, matchingCells, gridCellValues );
case RESULTS_MEAN_VALUE:
return calculateMeanValue( contourMapProjection, matchingCells, gridCellValues );
case RESULTS_GEOM_VALUE:
return calculateGeometricMeanValue( contourMapProjection, matchingCells, gridCellValues );
case RESULTS_HARM_VALUE:
return calculateHarmonicMeanValue( contourMapProjection, matchingCells, gridCellValues );
case RESULTS_MAX_VALUE:
return calculateMaxValue( contourMapProjection, matchingCells, gridCellValues );
case RESULTS_MIN_VALUE:
return calculateMinValue( contourMapProjection, matchingCells, gridCellValues );
case RESULTS_VOLUME_SUM:
case RESULTS_SUM:
case RESULTS_OIL_COLUMN:
case RESULTS_GAS_COLUMN:
case RESULTS_HC_COLUMN:
return calculateSum( contourMapProjection, matchingCells, gridCellValues );
default:
{
CVF_TIGHT_ASSERT( false );
return std::numeric_limits<double>::infinity();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigContourMapCalculator::calculateTopValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues )
{
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )];
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
return cellValue;
}
}
return std::numeric_limits<double>::infinity();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigContourMapCalculator::calculateMeanValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues )
{
RiaWeightedMeanCalculator<double> calculator;
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )];
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
calculator.addValueAndWeight( cellValue, weight );
}
}
if ( calculator.validAggregatedWeight() )
{
return calculator.weightedMean();
}
return std::numeric_limits<double>::infinity();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigContourMapCalculator::calculateGeometricMeanValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues )
{
RiaWeightedGeometricMeanCalculator calculator;
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )];
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
if ( cellValue < 1.0e-8 )
{
return 0.0;
}
calculator.addValueAndWeight( cellValue, weight );
}
}
if ( calculator.validAggregatedWeight() )
{
return calculator.weightedMean();
}
return std::numeric_limits<double>::infinity();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigContourMapCalculator::calculateHarmonicMeanValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues )
{
RiaWeightedHarmonicMeanCalculator calculator;
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )];
if ( std::fabs( cellValue ) < 1.0e-8 )
{
return 0.0;
}
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
calculator.addValueAndWeight( cellValue, weight );
}
}
if ( calculator.validAggregatedWeight() )
{
return calculator.weightedMean();
}
return std::numeric_limits<double>::infinity();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigContourMapCalculator::calculateMaxValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues )
{
double maxValue = -std::numeric_limits<double>::infinity();
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )];
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
maxValue = std::max( maxValue, cellValue );
}
}
if ( maxValue == -std::numeric_limits<double>::infinity() )
{
maxValue = std::numeric_limits<double>::infinity();
}
return maxValue;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigContourMapCalculator::calculateMinValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues )
{
double minValue = std::numeric_limits<double>::infinity();
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )];
minValue = std::min( minValue, cellValue );
}
return minValue;
}
double RigContourMapCalculator::calculateSum( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues )
{
double sum = 0.0;
for ( auto [cellIdx, weight] : matchingCells )
{
double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )];
if ( std::abs( cellValue ) != std::numeric_limits<double>::infinity() )
{
sum += cellValue * weight;
}
}
return sum;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<std::pair<size_t, double>>>
RigContourMapCalculator::generateGridMapping( RimContourMapProjection& contourMapProjection, const RigContourMapGrid& contourMapGrid )
{
int nCells = contourMapGrid.numberOfCells();
std::vector<std::vector<std::pair<size_t, double>>> projected3dGridIndices( nCells );
std::vector<double> weightingResultValues = contourMapProjection.retrieveParameterWeights();
if ( contourMapProjection.isStraightSummationResult() )
{
#pragma omp parallel for
for ( int index = 0; index < nCells; ++index )
{
cvf::Vec2ui ij = contourMapGrid.ijFromCellIndex( index );
cvf::Vec2d globalPos = contourMapGrid.cellCenterPosition( ij.x(), ij.y() ) + contourMapGrid.origin2d();
projected3dGridIndices[index] =
cellRayIntersectionAndResults( contourMapProjection, contourMapGrid, globalPos, weightingResultValues );
}
}
else
{
#pragma omp parallel for
for ( int index = 0; index < nCells; ++index )
{
cvf::Vec2ui ij = contourMapGrid.ijFromCellIndex( index );
cvf::Vec2d globalPos = contourMapGrid.cellCenterPosition( ij.x(), ij.y() ) + contourMapGrid.origin2d();
projected3dGridIndices[index] =
cellOverlapVolumesAndResults( contourMapProjection, contourMapGrid, globalPos, weightingResultValues );
}
}
return projected3dGridIndices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RigContourMapCalculator::CellIndexAndResult>
RigContourMapCalculator::cellOverlapVolumesAndResults( const RimContourMapProjection& contourMapProjection,
const RigContourMapGrid& contourMapGrid,
const cvf::Vec2d& globalPos2d,
const std::vector<double>& weightingResultValues )
{
const cvf::BoundingBox& expandedBoundingBox = contourMapGrid.expandedBoundingBox();
cvf::Vec3d top2dElementCentroid( globalPos2d, expandedBoundingBox.max().z() );
cvf::Vec3d bottom2dElementCentroid( globalPos2d, expandedBoundingBox.min().z() );
cvf::Vec3d planarDiagonalVector( 0.5 * contourMapGrid.sampleSpacing(), 0.5 * contourMapGrid.sampleSpacing(), 0.0 );
cvf::Vec3d topNECorner = top2dElementCentroid + planarDiagonalVector;
cvf::Vec3d bottomSWCorner = bottom2dElementCentroid - planarDiagonalVector;
cvf::BoundingBox bbox2dElement( bottomSWCorner, topNECorner );
std::vector<std::pair<size_t, double>> matchingVisibleCellsAndWeight;
// Bounding box has been expanded, so 2d element may be outside actual 3d grid
if ( !bbox2dElement.intersects( contourMapGrid.originalBoundingBox() ) )
{
return matchingVisibleCellsAndWeight;
}
std::vector<size_t> allCellIndices = contourMapProjection.findIntersectingCells( bbox2dElement );
std::vector<std::vector<size_t>> kLayerCellIndexVector;
kLayerCellIndexVector.resize( contourMapProjection.kLayers() );
if ( kLayerCellIndexVector.empty() )
{
return matchingVisibleCellsAndWeight;
}
auto cellGridIdxVisibility = contourMapProjection.getCellVisibility();
for ( size_t globalCellIdx : allCellIndices )
{
if ( ( *cellGridIdxVisibility )[globalCellIdx] )
{
kLayerCellIndexVector[contourMapProjection.kLayer( globalCellIdx )].push_back( globalCellIdx );
}
}
for ( const auto& kLayerIndices : kLayerCellIndexVector )
{
for ( size_t globalCellIdx : kLayerIndices )
{
double overlapVolume = contourMapProjection.calculateOverlapVolume( globalCellIdx, bbox2dElement );
if ( overlapVolume > 0.0 )
{
double weight =
overlapVolume * contourMapProjection.getParameterWeightForCell( contourMapProjection.gridResultIndex( globalCellIdx ),
weightingResultValues );
if ( weight > 0.0 )
{
matchingVisibleCellsAndWeight.push_back( std::make_pair( globalCellIdx, weight ) );
}
}
}
}
return matchingVisibleCellsAndWeight;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RigContourMapCalculator::CellIndexAndResult>
RigContourMapCalculator::cellRayIntersectionAndResults( const RimContourMapProjection& contourMapProjection,
const RigContourMapGrid& contourMapGrid,
const cvf::Vec2d& globalPos2d,
const std::vector<double>& weightingResultValues )
{
std::vector<std::pair<size_t, double>> matchingVisibleCellsAndWeight;
const cvf::BoundingBox& expandedBoundingBox = contourMapGrid.expandedBoundingBox();
cvf::Vec3d highestPoint( globalPos2d, expandedBoundingBox.max().z() );
cvf::Vec3d lowestPoint( globalPos2d, expandedBoundingBox.min().z() );
// Bounding box has been expanded, so ray may be outside actual 3d grid
if ( !contourMapGrid.originalBoundingBox().contains( highestPoint ) )
{
return matchingVisibleCellsAndWeight;
}
cvf::BoundingBox rayBBox;
rayBBox.add( highestPoint );
rayBBox.add( lowestPoint );
std::vector<size_t> allCellIndices = contourMapProjection.findIntersectingCells( rayBBox );
std::map<size_t, std::vector<size_t>> kLayerIndexMap;
auto cellGridIdxVisibility = contourMapProjection.getCellVisibility();
for ( size_t globalCellIdx : allCellIndices )
{
if ( ( *cellGridIdxVisibility )[globalCellIdx] )
{
kLayerIndexMap[contourMapProjection.kLayer( globalCellIdx )].push_back( globalCellIdx );
}
}
for ( const auto& kLayerIndexPair : kLayerIndexMap )
{
double weightSumThisKLayer = 0.0;
std::vector<std::pair<size_t, double>> cellsAndWeightsThisLayer;
for ( size_t globalCellIdx : kLayerIndexPair.second )
{
double lengthInCell = contourMapProjection.calculateRayLengthInCell( globalCellIdx, highestPoint, lowestPoint );
if ( lengthInCell > 0.0 )
{
cellsAndWeightsThisLayer.push_back( std::make_pair( globalCellIdx, lengthInCell ) );
weightSumThisKLayer += lengthInCell;
}
}
for ( auto& cellWeightPair : cellsAndWeightsThisLayer )
{
cellWeightPair.second /= weightSumThisKLayer;
matchingVisibleCellsAndWeight.push_back( cellWeightPair );
}
}
return matchingVisibleCellsAndWeight;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigContourMapCalculator::isColumnResult( ResultAggregationEnum aggregationType )
{
return aggregationType == RESULTS_OIL_COLUMN || aggregationType == RESULTS_GAS_COLUMN || aggregationType == RESULTS_HC_COLUMN;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigContourMapCalculator::isMeanResult( ResultAggregationEnum aggregationType )
{
return aggregationType == RESULTS_MEAN_VALUE || aggregationType == RESULTS_HARM_VALUE || aggregationType == RESULTS_GEOM_VALUE;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigContourMapCalculator::isStraightSummationResult( ResultAggregationEnum aggregationType )
{
return aggregationType == RESULTS_OIL_COLUMN || aggregationType == RESULTS_GAS_COLUMN || aggregationType == RESULTS_HC_COLUMN ||
aggregationType == RESULTS_SUM;
}

View File

@ -0,0 +1,98 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- 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 "cvfVector2.h"
#include <utility>
#include <vector>
class RigContourMapGrid;
class RimContourMapProjection;
//==================================================================================================
///
///
//==================================================================================================
class RigContourMapCalculator
{
public:
using CellIndexAndResult = std::pair<size_t, double>;
enum ResultAggregationEnum
{
RESULTS_TOP_VALUE,
RESULTS_MEAN_VALUE,
RESULTS_GEOM_VALUE,
RESULTS_HARM_VALUE,
RESULTS_MIN_VALUE,
RESULTS_MAX_VALUE,
RESULTS_VOLUME_SUM,
RESULTS_SUM,
RESULTS_OIL_COLUMN,
RESULTS_GAS_COLUMN,
RESULTS_HC_COLUMN
};
static std::vector<std::vector<std::pair<size_t, double>>> generateGridMapping( RimContourMapProjection& contourMapProjection,
const RigContourMapGrid& contourMapGrid );
static double calculateValueInMapCell( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues,
ResultAggregationEnum resultAggregation );
static std::vector<CellIndexAndResult> cellOverlapVolumesAndResults( const RimContourMapProjection& contourMapProjection,
const RigContourMapGrid& contourMapGrid,
const cvf::Vec2d& globalPos2d,
const std::vector<double>& weightingResultValues );
static std::vector<CellIndexAndResult> cellRayIntersectionAndResults( const RimContourMapProjection& contourMapProjection,
const RigContourMapGrid& contourMapGrid,
const cvf::Vec2d& globalPos2d,
const std::vector<double>& weightingResultValues );
static bool isColumnResult( ResultAggregationEnum aggregationType );
static bool isMeanResult( ResultAggregationEnum aggregationType );
static bool isStraightSummationResult( ResultAggregationEnum aggregationType );
private:
static double calculateTopValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues );
static double calculateMeanValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues );
static double calculateGeometricMeanValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues );
static double calculateHarmonicMeanValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues );
static double calculateMaxValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues );
static double calculateMinValue( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues );
static double calculateSum( const RimContourMapProjection& contourMapProjection,
const std::vector<std::pair<size_t, double>>& matchingCells,
const std::vector<double>& gridCellValues );
};