From 293e19d8200a37bb47206b0076a5b2a8ca0baf85 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Thu, 17 Oct 2024 14:29:59 +0200 Subject: [PATCH] Refactor: make contour map calculation easier to reuse. --- .../RimGeoMechContourMapProjection.cpp | 12 +- .../RimContourMapProjection.cpp | 336 ++------------ .../RimContourMapProjection.h | 60 +-- .../RimEclipseContourMapProjection.cpp | 14 +- .../ReservoirDataModel/CMakeLists_files.cmake | 2 + .../RigContourMapCalculator.cpp | 410 ++++++++++++++++++ .../RigContourMapCalculator.h | 98 +++++ 7 files changed, 574 insertions(+), 358 deletions(-) create mode 100644 ApplicationLibCode/ReservoirDataModel/RigContourMapCalculator.cpp create mode 100644 ApplicationLibCode/ReservoirDataModel/RigContourMapCalculator.h diff --git a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechContourMapProjection.cpp b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechContourMapProjection.cpp index f848136237..8821377cd1 100644 --- a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechContourMapProjection.cpp +++ b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechContourMapProjection.cpp @@ -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 RimGeoMechContourMapProjection::calculateValueOpti if ( fieldNeedingOptions == &m_resultAggregation ) { - std::vector validOptions = - { RESULTS_TOP_VALUE, RESULTS_MEAN_VALUE, RESULTS_GEOM_VALUE, RESULTS_HARM_VALUE, RESULTS_MIN_VALUE, RESULTS_MAX_VALUE, RESULTS_SUM }; + std::vector 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 ) ); } diff --git a/ApplicationLibCode/ProjectDataModel/RimContourMapProjection.cpp b/ApplicationLibCode/ProjectDataModel/RimContourMapProjection.cpp index 8a514febf0..d95a581789 100644 --- a/ApplicationLibCode/ProjectDataModel/RimContourMapProjection.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimContourMapProjection.cpp @@ -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& gridCellValues ) const { const std::vector>& 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::infinity() ) - { - return cellValue; - } - } - return std::numeric_limits::infinity(); - } - case RESULTS_MEAN_VALUE: - { - RiaWeightedMeanCalculator calculator; - for ( auto [cellIdx, weight] : matchingCells ) - { - double cellValue = gridCellValues[gridResultIndex( cellIdx )]; - if ( std::abs( cellValue ) != std::numeric_limits::infinity() ) - { - calculator.addValueAndWeight( cellValue, weight ); - } - } - if ( calculator.validAggregatedWeight() ) - { - return calculator.weightedMean(); - } - return std::numeric_limits::infinity(); - } - case RESULTS_GEOM_VALUE: - { - RiaWeightedGeometricMeanCalculator calculator; - for ( auto [cellIdx, weight] : matchingCells ) - { - double cellValue = gridCellValues[gridResultIndex( cellIdx )]; - if ( std::abs( cellValue ) != std::numeric_limits::infinity() ) - { - if ( cellValue < 1.0e-8 ) - { - return 0.0; - } - calculator.addValueAndWeight( cellValue, weight ); - } - } - if ( calculator.validAggregatedWeight() ) - { - return calculator.weightedMean(); - } - return std::numeric_limits::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::infinity() ) - { - calculator.addValueAndWeight( cellValue, weight ); - } - } - if ( calculator.validAggregatedWeight() ) - { - return calculator.weightedMean(); - } - return std::numeric_limits::infinity(); - } - case RESULTS_MAX_VALUE: - { - double maxValue = -std::numeric_limits::infinity(); - for ( auto [cellIdx, weight] : matchingCells ) - { - double cellValue = gridCellValues[gridResultIndex( cellIdx )]; - if ( std::abs( cellValue ) != std::numeric_limits::infinity() ) - { - maxValue = std::max( maxValue, cellValue ); - } - } - if ( maxValue == -std::numeric_limits::infinity() ) - { - maxValue = std::numeric_limits::infinity(); - } - return maxValue; - } - case RESULTS_MIN_VALUE: - { - double minValue = std::numeric_limits::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::infinity() ) - { - sum += cellValue * weight; - } - } - return sum; - } - default: - CVF_TIGHT_ASSERT( false ); - } - } - return std::numeric_limits::infinity(); + return RigContourMapCalculator::calculateValueInMapCell( *this, matchingCells, gridCellValues, m_resultAggregation() ); } //-------------------------------------------------------------------------------------------------- @@ -727,44 +607,6 @@ bool RimContourMapProjection::mapCellVisibilityNeedsUpdating() return !( mapCellVisiblity == m_mapCellVisibility ); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector>> RimContourMapProjection::generateGridMapping() -{ - m_cellGridIdxVisibility = getCellVisibility(); - - int nCells = numberOfCells(); - std::vector>> projected3dGridIndices( nCells ); - - std::vector 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& return sumArea; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector - RimContourMapProjection::cellOverlapVolumesAndResults( const cvf::Vec2d& globalPos2d, const std::vector& 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> 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 allCellIndices = findIntersectingCells( bbox2dElement ); - - std::vector> 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::cellRayIntersectionAndResults( const cvf::Vec2d& globalPos2d, const std::vector& weightingResultValues ) const -{ - std::vector> 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 allCellIndices = findIntersectingCells( rayBBox ); - - std::map> 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> 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( oldValue.toInt() ); - if ( isStraightSummationResult( previousAggregation ) != isStraightSummationResult() ) + ResultAggregation previousAggregation = static_cast( oldValue.toInt() ); + if ( RigContourMapCalculator::isStraightSummationResult( previousAggregation ) != isStraightSummationResult() ) { clearGridMapping(); } diff --git a/ApplicationLibCode/ProjectDataModel/RimContourMapProjection.h b/ApplicationLibCode/ProjectDataModel/RimContourMapProjection.h index 08ae48c18b..9ecc867255 100644 --- a/ApplicationLibCode/ProjectDataModel/RimContourMapProjection.h +++ b/ApplicationLibCode/ProjectDataModel/RimContourMapProjection.h @@ -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; - 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; + using ResultAggregation = caf::AppEnum; using ContourPolygons = std::vector; 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; - virtual std::vector retrieveParameterWeights() = 0; - virtual std::vector generateResults( int timeStep ) = 0; - virtual bool resultVariableChanged() const = 0; - virtual void clearResultVariable() = 0; - virtual RimGridView* baseView() 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 std::vector retrieveParameterWeights() = 0; + virtual size_t kLayer( size_t globalCellIdx ) const = 0; virtual size_t kLayers() const = 0; virtual std::vector 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& 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 getCellVisibility() const; + +protected: + // Protected virtual methods to be overridden by Eclipse and Geo-mechanical contour map implementations + virtual void updateGridInformation() = 0; + virtual std::vector 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& gridCellValues ) const; @@ -149,10 +142,10 @@ protected: virtual std::pair minmaxValuesAllTimeSteps(); - virtual cvf::ref getCellVisibility() const; - virtual std::vector getMapCellVisibility(); - bool mapCellVisibilityNeedsUpdating(); - std::vector>> generateGridMapping(); + virtual std::vector getMapCellVisibility(); + bool mapCellVisibilityNeedsUpdating(); + static std::vector>> generateGridMapping( RimContourMapProjection& contourMapProjection, + const RigContourMapGrid& contourMapGrid ); void generateVertexResults(); void generateTrianglesWithVertexValues(); @@ -160,15 +153,6 @@ protected: static double sumTriangleAreas( const std::vector& triangles ); - std::vector cellOverlapVolumesAndResults( const cvf::Vec2d& globalPos2d, - const std::vector& weightingResultValues ) const; - std::vector cellRayIntersectionAndResults( const cvf::Vec2d& globalPos2d, - const std::vector& 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; diff --git a/ApplicationLibCode/ProjectDataModel/RimEclipseContourMapProjection.cpp b/ApplicationLibCode/ProjectDataModel/RimEclipseContourMapProjection.cpp index a88a854a3e..71d76103c8 100644 --- a/ApplicationLibCode/ProjectDataModel/RimEclipseContourMapProjection.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimEclipseContourMapProjection.cpp @@ -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 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 RimEclipseContourMapProjection::calculateColumnResult( Resul std::vector 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& soilResults = resultData->cellScalarResults( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() ), @@ -295,7 +297,7 @@ std::vector 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() ) ); diff --git a/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake index 8e9b8bd8cd..fa554796a4 100644 --- a/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake @@ -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}) diff --git a/ApplicationLibCode/ReservoirDataModel/RigContourMapCalculator.cpp b/ApplicationLibCode/ReservoirDataModel/RigContourMapCalculator.cpp new file mode 100644 index 0000000000..d7a55db529 --- /dev/null +++ b/ApplicationLibCode/ReservoirDataModel/RigContourMapCalculator.cpp @@ -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 +// 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 + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigContourMapCalculator::calculateValueInMapCell( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues, + ResultAggregationEnum resultAggregation ) +{ + if ( matchingCells.empty() ) return std::numeric_limits::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::infinity(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigContourMapCalculator::calculateTopValue( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues ) +{ + for ( auto [cellIdx, weight] : matchingCells ) + { + double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )]; + if ( std::abs( cellValue ) != std::numeric_limits::infinity() ) + { + return cellValue; + } + } + return std::numeric_limits::infinity(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigContourMapCalculator::calculateMeanValue( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues ) +{ + RiaWeightedMeanCalculator calculator; + for ( auto [cellIdx, weight] : matchingCells ) + { + double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )]; + if ( std::abs( cellValue ) != std::numeric_limits::infinity() ) + { + calculator.addValueAndWeight( cellValue, weight ); + } + } + if ( calculator.validAggregatedWeight() ) + { + return calculator.weightedMean(); + } + return std::numeric_limits::infinity(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigContourMapCalculator::calculateGeometricMeanValue( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues ) +{ + RiaWeightedGeometricMeanCalculator calculator; + for ( auto [cellIdx, weight] : matchingCells ) + { + double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )]; + if ( std::abs( cellValue ) != std::numeric_limits::infinity() ) + { + if ( cellValue < 1.0e-8 ) + { + return 0.0; + } + calculator.addValueAndWeight( cellValue, weight ); + } + } + if ( calculator.validAggregatedWeight() ) + { + return calculator.weightedMean(); + } + return std::numeric_limits::infinity(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigContourMapCalculator::calculateHarmonicMeanValue( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& 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::infinity() ) + { + calculator.addValueAndWeight( cellValue, weight ); + } + } + if ( calculator.validAggregatedWeight() ) + { + return calculator.weightedMean(); + } + return std::numeric_limits::infinity(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigContourMapCalculator::calculateMaxValue( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues ) +{ + double maxValue = -std::numeric_limits::infinity(); + for ( auto [cellIdx, weight] : matchingCells ) + { + double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )]; + if ( std::abs( cellValue ) != std::numeric_limits::infinity() ) + { + maxValue = std::max( maxValue, cellValue ); + } + } + if ( maxValue == -std::numeric_limits::infinity() ) + { + maxValue = std::numeric_limits::infinity(); + } + return maxValue; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigContourMapCalculator::calculateMinValue( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues ) +{ + double minValue = std::numeric_limits::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>& matchingCells, + const std::vector& gridCellValues ) +{ + double sum = 0.0; + for ( auto [cellIdx, weight] : matchingCells ) + { + double cellValue = gridCellValues[contourMapProjection.gridResultIndex( cellIdx )]; + if ( std::abs( cellValue ) != std::numeric_limits::infinity() ) + { + sum += cellValue * weight; + } + } + return sum; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector>> + RigContourMapCalculator::generateGridMapping( RimContourMapProjection& contourMapProjection, const RigContourMapGrid& contourMapGrid ) +{ + int nCells = contourMapGrid.numberOfCells(); + std::vector>> projected3dGridIndices( nCells ); + + std::vector 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::cellOverlapVolumesAndResults( const RimContourMapProjection& contourMapProjection, + const RigContourMapGrid& contourMapGrid, + const cvf::Vec2d& globalPos2d, + const std::vector& 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> matchingVisibleCellsAndWeight; + + // Bounding box has been expanded, so 2d element may be outside actual 3d grid + if ( !bbox2dElement.intersects( contourMapGrid.originalBoundingBox() ) ) + { + return matchingVisibleCellsAndWeight; + } + + std::vector allCellIndices = contourMapProjection.findIntersectingCells( bbox2dElement ); + + std::vector> 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::cellRayIntersectionAndResults( const RimContourMapProjection& contourMapProjection, + const RigContourMapGrid& contourMapGrid, + const cvf::Vec2d& globalPos2d, + const std::vector& weightingResultValues ) +{ + std::vector> 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 allCellIndices = contourMapProjection.findIntersectingCells( rayBBox ); + + std::map> 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> 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; +} diff --git a/ApplicationLibCode/ReservoirDataModel/RigContourMapCalculator.h b/ApplicationLibCode/ReservoirDataModel/RigContourMapCalculator.h new file mode 100644 index 0000000000..19257c1f56 --- /dev/null +++ b/ApplicationLibCode/ReservoirDataModel/RigContourMapCalculator.h @@ -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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfVector2.h" + +#include +#include + +class RigContourMapGrid; +class RimContourMapProjection; + +//================================================================================================== +/// +/// +//================================================================================================== +class RigContourMapCalculator +{ +public: + using CellIndexAndResult = std::pair; + + 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>> generateGridMapping( RimContourMapProjection& contourMapProjection, + const RigContourMapGrid& contourMapGrid ); + + static double calculateValueInMapCell( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues, + ResultAggregationEnum resultAggregation ); + + static std::vector cellOverlapVolumesAndResults( const RimContourMapProjection& contourMapProjection, + const RigContourMapGrid& contourMapGrid, + const cvf::Vec2d& globalPos2d, + const std::vector& weightingResultValues ); + + static std::vector cellRayIntersectionAndResults( const RimContourMapProjection& contourMapProjection, + const RigContourMapGrid& contourMapGrid, + const cvf::Vec2d& globalPos2d, + const std::vector& 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>& matchingCells, + const std::vector& gridCellValues ); + static double calculateMeanValue( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues ); + + static double calculateGeometricMeanValue( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues ); + static double calculateHarmonicMeanValue( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues ); + static double calculateMaxValue( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues ); + static double calculateMinValue( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues ); + static double calculateSum( const RimContourMapProjection& contourMapProjection, + const std::vector>& matchingCells, + const std::vector& gridCellValues ); +};