///////////////////////////////////////////////////////////////////////////////// // // 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 "RigContourMapProjection.h" #include "RiaStatisticsTools.h" #include "RiaWeightedMeanCalculator.h" #include "RigContourMapCalculator.h" #include "RigContourMapGrid.h" #include "cvfArray.h" #include "cvfGeometryTools.h" #include #include #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigContourMapProjection::RigContourMapProjection( const RigContourMapGrid& contourMapGrid ) : m_contourMapGrid( contourMapGrid ) , m_currentResultTimestep( -1 ) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector>> RigContourMapProjection::generateGridMapping( RigContourMapCalculator::ResultAggregationType resultAggregation, const std::vector& weights ) { m_projected3dGridIndices = RigContourMapCalculator::generateGridMapping( *this, m_contourMapGrid, resultAggregation, weights ); return m_projected3dGridIndices; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::maxValue() const { return maxValue( m_aggregatedResults ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::minValue() const { return minValue( m_aggregatedResults ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::meanValue() const { return sumAllValues() / numberOfValidCells(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::sumAllValues() const { double sum = 0.0; for ( size_t index = 0; index < m_aggregatedResults.size(); ++index ) { if ( m_aggregatedResults[index] != std::numeric_limits::infinity() ) { sum += m_aggregatedResults[index]; } } return sum; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Vec2ui RigContourMapProjection::numberOfElementsIJ() const { return m_contourMapGrid.numberOfElementsIJ(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Vec2ui RigContourMapProjection::numberOfVerticesIJ() const { return m_contourMapGrid.numberOfVerticesIJ(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::valueAtVertex( unsigned int i, unsigned int j ) const { size_t index = m_contourMapGrid.vertexIndexFromIJ( i, j ); if ( index < numberOfVertices() ) { return m_aggregatedVertexResults.at( index ); } return std::numeric_limits::infinity(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- unsigned int RigContourMapProjection::numberOfCells() const { return m_contourMapGrid.numberOfCells(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- unsigned int RigContourMapProjection::numberOfValidCells() const { unsigned int validCount = 0u; for ( unsigned int i = 0; i < numberOfCells(); ++i ) { cvf::Vec2ui ij = m_contourMapGrid.ijFromCellIndex( i ); if ( hasResultInCell( ij.x(), ij.y() ) ) { validCount++; } } return validCount; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RigContourMapProjection::numberOfVertices() const { cvf::Vec2ui gridSize = numberOfVerticesIJ(); return static_cast( gridSize.x() ) * static_cast( gridSize.y() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigContourMapProjection::checkForMapIntersection( const cvf::Vec3d& domainPoint3d, cvf::Vec2d* contourMapPoint, double* valueAtPoint ) const { CVF_TIGHT_ASSERT( contourMapPoint ); CVF_TIGHT_ASSERT( valueAtPoint ); const cvf::Vec3d& minPoint = m_contourMapGrid.expandedBoundingBox().min(); cvf::Vec3d mapPos3d = domainPoint3d - minPoint; cvf::Vec2d mapPos2d( mapPos3d.x(), mapPos3d.y() ); cvf::Vec2d gridorigin( minPoint.x(), minPoint.y() ); double value = interpolateValue( mapPos2d ); if ( value != std::numeric_limits::infinity() ) { *valueAtPoint = value; *contourMapPoint = mapPos2d + gridorigin; return true; } return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Vec3d RigContourMapProjection::origin3d() const { return m_contourMapGrid.expandedBoundingBox().min(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RigContourMapProjection::gridResultIndex( size_t globalCellIdx ) const { return globalCellIdx; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::calculateValueInMapCell( unsigned int i, unsigned int j, const std::vector& gridCellValues, RigContourMapCalculator::ResultAggregationType resultAggregation ) const { const std::vector>& matchingCells = cellsAtIJ( i, j ); return RigContourMapCalculator::calculateValueInMapCell( *this, matchingCells, gridCellValues, resultAggregation ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::maxValue( const std::vector& aggregatedResults ) { double maxV = RiaStatisticsTools::maximumValue( aggregatedResults ); return maxV != -std::numeric_limits::max() ? maxV : -std::numeric_limits::infinity(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::minValue( const std::vector& aggregatedResults ) { double minV = RiaStatisticsTools::minimumValue( aggregatedResults ); return minV != std::numeric_limits::max() ? minV : std::numeric_limits::infinity(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigContourMapProjection::setCellVisibility( cvf::ref cellVisibility ) { m_cellGridIdxVisibility = cellVisibility; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RigContourMapProjection::getCellVisibility() const { return m_cellGridIdxVisibility; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigContourMapProjection::generateVertexResults() { size_t nCells = numberOfCells(); if ( nCells != m_aggregatedResults.size() ) return; size_t nVertices = numberOfVertices(); m_aggregatedVertexResults = std::vector( nVertices, std::numeric_limits::infinity() ); #pragma omp parallel for for ( int index = 0; index < static_cast( nVertices ); ++index ) { cvf::Vec2ui ij = m_contourMapGrid.ijFromVertexIndex( index ); m_aggregatedVertexResults[index] = calculateValueAtVertex( ij.x(), ij.y() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::sumTriangleAreas( const std::vector& triangles ) { double sumArea = 0.0; for ( size_t i = 0; i < triangles.size(); i += 3 ) { cvf::Vec3d v1( triangles[i].x(), triangles[i].y(), triangles[i].z() ); cvf::Vec3d v2( triangles[i + 1].x(), triangles[i + 1].y(), triangles[i + 1].z() ); cvf::Vec3d v3( triangles[i + 2].x(), triangles[i + 2].y(), triangles[i + 2].z() ); double area = 0.5 * ( ( v3 - v1 ) ^ ( v2 - v1 ) ).length(); sumArea += area; } return sumArea; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::interpolateValue( const cvf::Vec2d& gridPos2d ) const { cvf::Vec2ui cellContainingPoint = m_contourMapGrid.ijFromLocalPos( gridPos2d ); cvf::Vec2d cellCenter = m_contourMapGrid.cellCenterPosition( cellContainingPoint.x(), cellContainingPoint.y() ); double sampleSpacing = m_contourMapGrid.sampleSpacing(); std::array x; x[0] = cvf::Vec3d( cellCenter + cvf::Vec2d( -sampleSpacing * 0.5, -sampleSpacing * 0.5 ), 0.0 ); x[1] = cvf::Vec3d( cellCenter + cvf::Vec2d( sampleSpacing * 0.5, -sampleSpacing * 0.5 ), 0.0 ); x[2] = cvf::Vec3d( cellCenter + cvf::Vec2d( sampleSpacing * 0.5, sampleSpacing * 0.5 ), 0.0 ); x[3] = cvf::Vec3d( cellCenter + cvf::Vec2d( -sampleSpacing * 0.5, sampleSpacing * 0.5 ), 0.0 ); cvf::Vec4d baryCentricCoords = cvf::GeometryTools::barycentricCoords( x[0], x[1], x[2], x[3], cvf::Vec3d( gridPos2d, 0.0 ) ); std::array v; v[0] = cellContainingPoint; v[1] = cvf::Vec2ui( cellContainingPoint.x() + 1u, cellContainingPoint.y() ); v[2] = cvf::Vec2ui( cellContainingPoint.x() + 1u, cellContainingPoint.y() + 1u ); v[3] = cvf::Vec2ui( cellContainingPoint.x(), cellContainingPoint.y() + 1u ); std::array vertexValues; double validBarycentricCoordsSum = 0.0; for ( int i = 0; i < 4; ++i ) { double vertexValue = valueAtVertex( v[i].x(), v[i].y() ); if ( vertexValue == std::numeric_limits::infinity() ) { return std::numeric_limits::infinity(); } else { vertexValues[i] = vertexValue; validBarycentricCoordsSum += baryCentricCoords[i]; } } if ( validBarycentricCoordsSum < 1.0e-8 ) { return std::numeric_limits::infinity(); } // Calculate final value double value = 0.0; for ( int i = 0; i < 4; ++i ) { value += baryCentricCoords[i] / validBarycentricCoordsSum * vertexValues[i]; } return value; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::valueInCell( unsigned int i, unsigned int j ) const { size_t index = m_contourMapGrid.cellIndexFromIJ( i, j ); if ( index < numberOfCells() ) { return m_aggregatedResults.at( index ); } return std::numeric_limits::infinity(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigContourMapProjection::hasResultInCell( unsigned int i, unsigned int j ) const { return !cellsAtIJ( i, j ).empty(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigContourMapProjection::calculateValueAtVertex( unsigned int vi, unsigned int vj ) const { std::vector averageIs; std::vector averageJs; if ( vi > 0u ) averageIs.push_back( vi - 1 ); if ( vj > 0u ) averageJs.push_back( vj - 1 ); if ( vi < m_contourMapGrid.mapSize().x() ) averageIs.push_back( vi ); if ( vj < m_contourMapGrid.mapSize().y() ) averageJs.push_back( vj ); RiaWeightedMeanCalculator calc; for ( unsigned int j : averageJs ) { for ( unsigned int i : averageIs ) { if ( hasResultInCell( i, j ) ) { calc.addValueAndWeight( valueInCell( i, j ), 1.0 ); } } } if ( calc.validAggregatedWeight() ) { return calc.weightedMean(); } return std::numeric_limits::infinity(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector> RigContourMapProjection::cellsAtIJ( unsigned int i, unsigned int j ) const { size_t cellIndex = m_contourMapGrid.cellIndexFromIJ( i, j ); if ( cellIndex < m_projected3dGridIndices.size() ) { return m_projected3dGridIndices[cellIndex]; } return std::vector>(); } //-------------------------------------------------------------------------------------------------- /// Vertex positions in local coordinates (add origin2d.x() for UTM x) //-------------------------------------------------------------------------------------------------- std::vector RigContourMapProjection::xVertexPositions() const { return m_contourMapGrid.xVertexPositions(); } //-------------------------------------------------------------------------------------------------- /// Vertex positions in local coordinates (add origin2d.y() for UTM y) //-------------------------------------------------------------------------------------------------- std::vector RigContourMapProjection::yVertexPositions() const { return m_contourMapGrid.yVertexPositions(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::vector& RigContourMapProjection::aggregatedResults() const { return m_aggregatedResults; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::vector& RigContourMapProjection::aggregatedVertexResults() const { return m_aggregatedVertexResults; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::vector>>& RigContourMapProjection::projected3dGridIndices() const { return m_projected3dGridIndices; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigContourMapProjection::clearResults() { m_aggregatedResults.clear(); m_aggregatedVertexResults.clear(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigContourMapProjection::clearGridMapping() { m_projected3dGridIndices.clear(); }