From 2f6b2e57f55b71388aea9638bee3e14870106e81 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 10 Feb 2023 12:39:13 +0100 Subject: [PATCH] Add support for radial grids * Update radial grid operations in submodule * Optionally display cell center and cell corners when clicking on cell * Add support for import of radial grids * Modify node coordinates to match host cell --- .../FileInterface/CMakeLists_files.cmake | 2 + .../FileInterface/RifOpmGridTools.cpp | 402 ++++++++++++++++++ .../FileInterface/RifOpmGridTools.h | 60 +++ .../FileInterface/RifReaderEclipseOutput.cpp | 3 + .../FileInterface/RifReaderEclipseOutput.h | 7 - .../RimMultipleEclipseResults.cpp | 24 +- .../RimMultipleEclipseResults.h | 6 + .../UnitTests/opm-summary-Test.cpp | 31 ++ .../UserInterface/RiuResultTextBuilder.cpp | 85 +++- .../UserInterface/RiuResultTextBuilder.h | 8 +- ThirdParty/custom-opm-common/opm-common | 2 +- 11 files changed, 611 insertions(+), 19 deletions(-) create mode 100644 ApplicationLibCode/FileInterface/RifOpmGridTools.cpp create mode 100644 ApplicationLibCode/FileInterface/RifOpmGridTools.h diff --git a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake index 8d55119700..158452a9d3 100644 --- a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake +++ b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake @@ -77,6 +77,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RifRftSegment.h ${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader.h ${CMAKE_CURRENT_LIST_DIR}/RifReaderPressureDepthData.h + ${CMAKE_CURRENT_LIST_DIR}/RifOpmGridTools.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -155,6 +156,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RifRftSegment.cpp ${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader.cpp ${CMAKE_CURRENT_LIST_DIR}/RifReaderPressureDepthData.cpp + ${CMAKE_CURRENT_LIST_DIR}/RifOpmGridTools.cpp ) list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) diff --git a/ApplicationLibCode/FileInterface/RifOpmGridTools.cpp b/ApplicationLibCode/FileInterface/RifOpmGridTools.cpp new file mode 100644 index 0000000000..704626a416 --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifOpmGridTools.cpp @@ -0,0 +1,402 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- 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 "RifOpmGridTools.h" + +#include "RiaLogging.h" +#include "RiaWeightedMeanCalculator.h" + +#include "RifReaderEclipseOutput.h" + +#include "RigMainGrid.h" + +#include "cvfGeometryTools.h" + +#include "opm/io/eclipse/EGrid.hpp" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifOpmGridTools::importCoordinatesForRadialGrid( const std::string& gridFilePath, RigMainGrid* riMainGrid ) +{ + CAF_ASSERT( riMainGrid ); + + try + { + bool isRadialGridPresent = false; + + { + // Open the file and only check "GRIDHEAD" to be able to do an early return if no radial grids are present + + Opm::EclIO::EclFile gridFile( gridFilePath ); + auto arrays = gridFile.getList(); + + int index = 0; + for ( const auto& [name, arrayType, arraySize] : arrays ) + { + if ( name == "GRIDHEAD" ) + { + auto gridhead = gridFile.get( index ); + if ( gridhead.size() > 26 && gridhead[26] > 0 ) + { + isRadialGridPresent = true; + break; + } + } + index++; + } + } + + if ( !isRadialGridPresent ) return; + + Opm::EclIO::EGrid opmMainGrid( gridFilePath ); + + if ( opmMainGrid.is_radial() ) + { + transferCoordinates( opmMainGrid, opmMainGrid, riMainGrid, riMainGrid ); + } + + auto lgrNames = opmMainGrid.list_of_lgrs(); + for ( const auto& lgrName : lgrNames ) + { + Opm::EclIO::EGrid opmLgrGrid( gridFilePath, lgrName ); + + if ( opmLgrGrid.is_radial() ) + { + for ( size_t i = 0; i < riMainGrid->gridCount(); i++ ) + { + auto riLgrGrid = riMainGrid->gridByIndex( i ); + if ( riLgrGrid->gridName() == lgrName ) + { + transferCoordinates( opmMainGrid, opmLgrGrid, riMainGrid, riLgrGrid ); + } + } + } + } + } + catch ( ... ) + { + RiaLogging::warning( QString( "Failed to open grid case for import of radial coordinates : %1" ) + .arg( QString::fromStdString( gridFilePath ) ) ); + } +} + +//-------------------------------------------------------------------------------------------------- +// +// A radial grid is defined by a center point and a set of cylindrical coordinates. The coordinates at the +// outer edge of the grid are defined as a circle, and nodes do not match the geometry of the host cell. +// Adjust the coordinates for these cells to make sure the grid is continuous +// +// Cylindrical coordinates from file gives grid cell with a radial grid in center +// ------------- +// | /---- \ | +// | / - \ | +// || | | || +// | \ - / | +// | \-----/ | +// ------------- + +// +// Adjusted coordinates to match the grid geometry of host cell. The coordinates for the inner nodes are +// unchanged. +// ------------- +// ||---------|| +// || - || +// || | | || +// || - || +// ||---------|| +// ------------- + +// 1. If the node is at the outer edge of the radial grid, find the host cell +// 2. Find the closest point on the pillars of the host cell +// 3. Find the closest point on this pillar, and use this point as the adjusted coordinate for the node +// +//-------------------------------------------------------------------------------------------------- +void RifOpmGridTools::transferCoordinates( Opm::EclIO::EGrid& opmMainGrid, + Opm::EclIO::EGrid& opmGrid, + RigMainGrid* riMainGrid, + RigGridBase* riGrid ) +{ + size_t cellCount = opmGrid.totalNumberOfCells(); + if ( cellCount != riGrid->cellCount() ) return; + + // Read out the corner coordinates from the EGRID file using radial coordinates. + // Prefix OPM structures with _opm_and ResInsight structures with _ri_ + + // Compute the center of the LGR radial grid cells for each K layer + std::map> radialGridCenterTopLayerOpm = + computeXyCenterForTopOfCells( opmMainGrid, opmGrid, riGrid ); + + std::array opmX{}; + std::array opmY{}; + std::array opmZ{}; + + const auto hostCellGlobalIndices = opmGrid.hostCellsGlobalIndex(); + const size_t* cellMappingECLRi = RifReaderEclipseOutput::eclipseCellIndexMapping(); + const auto gridDimension = opmGrid.dimension(); + auto& riNodes = riMainGrid->nodes(); + + std::vector snapToCoordinatesFromMainGrid; + + for ( size_t opmCellIndex = 0; opmCellIndex < cellCount; opmCellIndex++ ) + { + opmGrid.getCellCorners( opmCellIndex, opmX, opmY, opmZ ); + + // Each cell has 8 nodes, use reservoir cell index and multiply to find first node index for cell + auto riNodeStartIndex = riGrid->reservoirCellIndex( opmCellIndex ) * 8; + auto ijkCell = opmGrid.ijk_from_global_index( opmCellIndex ); + + double xCenterCoordOpm = 0.0; + double yCenterCoordOpm = 0.0; + + if ( radialGridCenterTopLayerOpm.count( ijkCell[2] ) > 0 ) + { + const auto& [xCenter, yCenter] = radialGridCenterTopLayerOpm[ijkCell[2]]; + xCenterCoordOpm = xCenter; + yCenterCoordOpm = yCenter; + } + + for ( size_t opmNodeIndex = 0; opmNodeIndex < 8; opmNodeIndex++ ) + { + size_t riNodeIndex = riNodeStartIndex + cellMappingECLRi[opmNodeIndex]; + + // The radial grid is specified with (0,0) as center, add grid center to get correct global coordinates + auto& riNode = riNodes[riNodeIndex]; + riNode.x() = opmX[opmNodeIndex] + xCenterCoordOpm; + riNode.y() = opmY[opmNodeIndex] + yCenterCoordOpm; + riNode.z() = -opmZ[opmNodeIndex]; + + // First grid dimension is radius, check if cell has are at the outer-most slice + if ( !hostCellGlobalIndices.empty() && ( gridDimension[0] - 1 == ijkCell[0] ) ) + { + std::array cellRadius{}; + std::array cellTheta{}; + std::array cellZ{}; + opmGrid.getRadialCellCorners( ijkCell, cellRadius, cellTheta, cellZ ); + + double maxRadius = *std::max_element( cellRadius.begin(), cellRadius.end() ); + + // Check if the radius is at the outer surface of the radial grid + // Adjust the outer nodes to match the corner pillars of the host cell + const double epsilon = 0.15; + if ( fabs( maxRadius - cellRadius[opmNodeIndex] ) < epsilon * cellRadius[opmNodeIndex] ) + { + const auto hostCellIndex = hostCellGlobalIndices[opmCellIndex]; + + double closestPillarDistance = std::numeric_limits::max(); + int closestPillarIndex = -1; + + const auto cylinderCoordX = opmX[opmNodeIndex] + xCenterCoordOpm; + const auto cylinderCoordY = opmY[opmNodeIndex] + yCenterCoordOpm; + const auto cylinderCoordZ = opmZ[opmNodeIndex]; + + const cvf::Vec3d coordinateOnCylinder = cvf::Vec3d( cylinderCoordX, cylinderCoordY, cylinderCoordZ ); + + const auto candidates = computeSnapToCoordinates( opmMainGrid, opmGrid, hostCellIndex, opmCellIndex ); + for ( int pillarIndex = 0; pillarIndex < static_cast( candidates.size() ); pillarIndex++ ) + { + for ( const auto& c : candidates[pillarIndex] ) + { + double distance = coordinateOnCylinder.pointDistance( c ); + if ( distance < closestPillarDistance ) + { + closestPillarDistance = distance; + closestPillarIndex = pillarIndex; + } + } + } + + if ( closestPillarDistance < std::numeric_limits::max() ) + { + const auto& pillarCordinates = candidates[closestPillarIndex]; + + int layerCount = pillarCordinates.size() / 2; + int layerIndexInMainGridCell = ijkCell[2] % layerCount; + int localNodeIndex = opmNodeIndex % 8; + + cvf::Vec3d closestPillarCoord; + if ( localNodeIndex < 4 ) + { + // Top of cell + int pillarCoordIndex = layerIndexInMainGridCell * 2; + closestPillarCoord = pillarCordinates[pillarCoordIndex]; + } + else + { + // Bottom of cell + int pillarCoordIndex = layerIndexInMainGridCell * 2 + 1; + closestPillarCoord = pillarCordinates[pillarCoordIndex]; + } + + riNode.x() = closestPillarCoord.x(); + riNode.y() = closestPillarCoord.y(); + riNode.z() = -closestPillarCoord.z(); + } + } + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map> RifOpmGridTools::computeXyCenterForTopOfCells( Opm::EclIO::EGrid& opmMainGrid, + Opm::EclIO::EGrid& opmGrid, + RigGridBase* riGrid ) +{ + if ( !riGrid || riGrid->isMainGrid() ) return {}; + + size_t cellCount = opmGrid.totalNumberOfCells(); + if ( cellCount != riGrid->cellCount() ) return {}; + + // Read out the corner coordinates from the EGRID file using radial coordinates. + // Prefix OPM structures with _opm_and ResInsight structures with _ri_ + + // Compute the center of the LGR radial grid cells for each K layer + std::map> radialGridCenterTopLayerOpm; + + { + std::array opmX{}; + std::array opmY{}; + std::array opmZ{}; + + std::map>> xyCenterPerLayer; + + auto hostCellGlobalIndices = opmGrid.hostCellsGlobalIndex(); + + for ( size_t cIdx = 0; cIdx < cellCount; cIdx++ ) + { + auto mainGridCellIndex = hostCellGlobalIndices[cIdx]; + opmMainGrid.getCellCorners( mainGridCellIndex, opmX, opmY, opmZ ); + + auto ijkLocalGrid = opmGrid.ijk_from_global_index( cIdx ); + auto layer = ijkLocalGrid[2]; + + // Four corners for top + for ( size_t i = 4; i < 8; i++ ) + { + auto& xyCoords = xyCenterPerLayer[layer]; + xyCoords.emplace_back( opmX[i], opmY[i] ); + } + } + + for ( const auto& [k, xyCoords] : xyCenterPerLayer ) + { + RiaWeightedMeanCalculator xCoord; + RiaWeightedMeanCalculator yCoord; + + for ( const auto& [x, y] : xyCoords ) + { + xCoord.addValueAndWeight( x, 1.0 ); + yCoord.addValueAndWeight( y, 1.0 ); + } + + radialGridCenterTopLayerOpm[k] = { xCoord.weightedMean(), yCoord.weightedMean() }; + } + } + + return radialGridCenterTopLayerOpm; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RifOpmGridTools::computeSnapToCoordinates( Opm::EclIO::EGrid& opmMainGrid, + Opm::EclIO::EGrid& opmGrid, + int mainGridCellIndex, + int lgrCellIndex ) +{ + auto hostCellIndices = opmGrid.hostCellsGlobalIndex(); + auto lgrIjk = opmGrid.ijk_from_global_index( lgrCellIndex ); + + std::vector zDistanceAlongPillar; + + for ( int gridCellIndex = 0; gridCellIndex < opmGrid.totalNumberOfCells(); gridCellIndex++ ) + { + if ( hostCellIndices[gridCellIndex] == mainGridCellIndex ) + { + auto ijk = opmGrid.ijk_from_global_index( gridCellIndex ); + + // Find all LGR cells for the same IJ column + if ( ijk[0] == lgrIjk[0] && ijk[1] == lgrIjk[1] ) + { + std::array cellX{}; + std::array cellY{}; + std::array cellZ{}; + + opmGrid.getCellCorners( gridCellIndex, cellX, cellY, cellZ ); + + // Get top and bottom of one pillar + zDistanceAlongPillar.push_back( cellZ[0] ); + zDistanceAlongPillar.push_back( cellZ[4] ); + } + } + } + + if ( zDistanceAlongPillar.size() < 2 ) return {}; + + std::sort( zDistanceAlongPillar.begin(), zDistanceAlongPillar.end() ); + + auto normalize = []( const std::vector& values ) -> std::vector { + if ( values.size() < 2 ) return {}; + + std::vector normalizedValues; + + double firstValue = values.front(); + double lastValue = values.back(); + double range = lastValue - firstValue; + + // Normalize values to range [0..1] + for ( const auto& value : values ) + { + normalizedValues.emplace_back( ( value - firstValue ) / range ); + } + + return normalizedValues; + }; + + auto normalizedZValues = normalize( zDistanceAlongPillar ); + + std::vector> allCoords; + std::array hostCellX{}; + std::array hostCellY{}; + std::array hostCellZ{}; + + opmMainGrid.getCellCorners( mainGridCellIndex, hostCellX, hostCellY, hostCellZ ); + + for ( int pillarIndex = 0; pillarIndex < 4; pillarIndex++ ) + { + std::vector pillarCoords; + + const cvf::Vec3d p1( hostCellX[0 + pillarIndex], hostCellY[0 + pillarIndex], hostCellZ[0 + pillarIndex] ); + const cvf::Vec3d p2( hostCellX[4 + pillarIndex], hostCellY[4 + pillarIndex], hostCellZ[4 + pillarIndex] ); + + for ( auto t : normalizedZValues ) + { + cvf::Vec3d pillarCoord = p1 * ( 1.0 - t ) + t * p2; + pillarCoords.push_back( pillarCoord ); + } + + allCoords.push_back( pillarCoords ); + } + + return allCoords; +} diff --git a/ApplicationLibCode/FileInterface/RifOpmGridTools.h b/ApplicationLibCode/FileInterface/RifOpmGridTools.h new file mode 100644 index 0000000000..3f903e2efa --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifOpmGridTools.h @@ -0,0 +1,60 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- 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 "cvfVector3.h" + +#include +#include +#include + +namespace Opm +{ +namespace EclIO +{ + class EGrid; +} +} // namespace Opm + +class RigMainGrid; +class RigGridBase; + +//================================================================================================== +/// +//================================================================================================== +class RifOpmGridTools +{ +public: + // If the grid is radial, the coordinates are imported and adjusted to fit the host cells + static void importCoordinatesForRadialGrid( const std::string& gridFilePath, RigMainGrid* mainGrid ); + +private: + static void transferCoordinates( Opm::EclIO::EGrid& opmMainGrid, + Opm::EclIO::EGrid& opmGrid, + RigMainGrid* riMainGrid, + RigGridBase* riGrid ); + + static std::map> + computeXyCenterForTopOfCells( Opm::EclIO::EGrid& opmMainGrid, Opm::EclIO::EGrid& opmGrid, RigGridBase* riGrid ); + + static std::vector> computeSnapToCoordinates( Opm::EclIO::EGrid& opmMainGrid, + Opm::EclIO::EGrid& opmGrid, + int mainGridCellIndex, + int lgrCellIndex ); +}; diff --git a/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.cpp b/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.cpp index 00126931ce..edea05b7ab 100644 --- a/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.cpp +++ b/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.cpp @@ -29,6 +29,7 @@ #include "RifEclipseInputFileTools.h" #include "RifEclipseOutputFileTools.h" #include "RifHdf5ReaderInterface.h" +#include "RifOpmGridTools.h" #include "RifReaderSettings.h" #ifdef USE_HDF5 @@ -414,6 +415,8 @@ bool RifReaderEclipseOutput::open( const QString& fileName, RigEclipseCaseData* { auto task = progress.task( "Transferring grid geometry", 10 ); if ( !transferGeometry( mainEclGrid, eclipseCase ) ) return false; + + RifOpmGridTools::importCoordinatesForRadialGrid( fileName.toStdString(), eclipseCase->mainGrid() ); } { diff --git a/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.h b/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.h index c819bfd723..f788d2b9b0 100644 --- a/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.h +++ b/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.h @@ -76,14 +76,7 @@ public: std::vector allTimeSteps() const; static bool transferGeometry( const ecl_grid_type* mainEclGrid, RigEclipseCaseData* eclipseCase ); - static bool exportGrid( const QString& gridFileName, - RigEclipseCaseData* eclipseCase, - const cvf::Vec3st& min, - const cvf::Vec3st& max, - const cvf::Vec3st& refinement ); - static void transferCoarseningInfo( const ecl_grid_type* eclGrid, RigGridBase* grid ); - static void importEquilData( const QString& deckFileName, const QString& includeStatementAbsolutePathPrefix, RigEclipseCaseData* eclipseCase ); diff --git a/ApplicationLibCode/ProjectDataModel/RimMultipleEclipseResults.cpp b/ApplicationLibCode/ProjectDataModel/RimMultipleEclipseResults.cpp index 52fa3ede42..8e5f3fe5ee 100644 --- a/ApplicationLibCode/ProjectDataModel/RimMultipleEclipseResults.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimMultipleEclipseResults.cpp @@ -21,6 +21,7 @@ #include "RimEclipseCellColors.h" #include "RimEclipseView.h" +#include "cafPdmUiCheckBoxEditor.h" #include "cafPdmUiTreeSelectionEditor.h" CAF_PDM_SOURCE_INIT( RimMultipleEclipseResults, "RimMultipleEclipseResults" ); @@ -32,9 +33,14 @@ RimMultipleEclipseResults::RimMultipleEclipseResults() { CAF_PDM_InitObject( "Multiple Result Info", ":/TextAnnotation16x16.png" ); + CAF_PDM_InitField( &m_showCenterCoordinates, "showCenterCoordinates", false, "Show Center Coordinates" ); + caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_showCenterCoordinates ); + + CAF_PDM_InitField( &m_showCornerCoordinates, "showCornerCoordinates", false, "Show Corner Coordinates" ); + caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_showCornerCoordinates ); + CAF_PDM_InitFieldNoDefault( &m_selectedKeywords, "SelectedProperties", "Properties" ); m_selectedKeywords.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::TOP ); - m_selectedKeywords.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); } @@ -74,6 +80,22 @@ std::vector RimMultipleEclipseResults::additionalResult return resultAddresses; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimMultipleEclipseResults::showCenterCoordinates() const +{ + return m_showCenterCoordinates; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimMultipleEclipseResults::showCornerCoordinates() const +{ + return m_showCornerCoordinates; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/RimMultipleEclipseResults.h b/ApplicationLibCode/ProjectDataModel/RimMultipleEclipseResults.h index 1cf2497dcb..8dafa24140 100644 --- a/ApplicationLibCode/ProjectDataModel/RimMultipleEclipseResults.h +++ b/ApplicationLibCode/ProjectDataModel/RimMultipleEclipseResults.h @@ -40,10 +40,16 @@ public: std::vector additionalResultAddresses() const; + bool showCenterCoordinates() const; + bool showCornerCoordinates() const; + private: QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override; private: + caf::PdmField m_showCornerCoordinates; + caf::PdmField m_showCenterCoordinates; + caf::PdmField> m_selectedKeywords; caf::PdmPointer m_eclipseView; }; diff --git a/ApplicationLibCode/UnitTests/opm-summary-Test.cpp b/ApplicationLibCode/UnitTests/opm-summary-Test.cpp index 448c267c34..5c9b6ab0a6 100644 --- a/ApplicationLibCode/UnitTests/opm-summary-Test.cpp +++ b/ApplicationLibCode/UnitTests/opm-summary-Test.cpp @@ -10,6 +10,7 @@ // Disable warning from external library to make sure treat warnings as error works #pragma warning( disable : 4267 ) #endif +#include "opm/io/eclipse/EGrid.hpp" #include "opm/io/eclipse/ERft.hpp" #include "opm/io/eclipse/ESmry.hpp" #include "opm/io/eclipse/ExtESmry.hpp" @@ -293,3 +294,33 @@ TEST( OpmSummaryTests, OpmComputeSegmentTopology ) } } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( OpmSummaryTests, DISABLED_ReadOpmRadialGrid ) +{ + { + QString filePath = "e:/models/from_equinor_sftp/2021.10.1-Radial-testcase/global-radial/GLOBAL-RADIAL.EGRID"; + + Opm::EclIO::EGrid eGrid( filePath.toStdString() ); + + auto dims = eGrid.dimension(); + + size_t cellCount = dims[0] * dims[1] * dims[2]; + + std::array X{}; + std::array Y{}; + std::array Z{}; + + for ( size_t cidx = 0; cidx < cellCount; cidx++ ) + { + eGrid.getCellCorners( cidx, X, Y, Z ); + + for ( size_t i = 0; i < 8; i++ ) + { + std::cout << X[i] << " " << Y[i] << " " << Z[i] << "\n"; + } + } + } +} diff --git a/ApplicationLibCode/UserInterface/RiuResultTextBuilder.cpp b/ApplicationLibCode/UserInterface/RiuResultTextBuilder.cpp index e53eb56d7e..8c5f8a5fda 100644 --- a/ApplicationLibCode/UserInterface/RiuResultTextBuilder.cpp +++ b/ApplicationLibCode/UserInterface/RiuResultTextBuilder.cpp @@ -39,6 +39,7 @@ #include "RimExtrudedCurveIntersection.h" #include "RimFormationNames.h" #include "RimIntersectionResultDefinition.h" +#include "RimMultipleEclipseResults.h" #include "RimRegularLegendConfig.h" #include "RimReservoirCellResultsStorage.h" #include "RimViewLinker.h" @@ -195,7 +196,7 @@ QString RiuResultTextBuilder::mainResultText() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString RiuResultTextBuilder::geometrySelectionText( QString itemSeparator ) +QString RiuResultTextBuilder::geometrySelectionText( const QString& itemSeparator ) { QString text; @@ -234,6 +235,8 @@ QString RiuResultTextBuilder::geometrySelectionText( QString itemSeparator ) size_t globalCellIndex = grid->reservoirCellIndex( m_cellIndex ); text += QString( "Global Cell Index : %4" ).arg( globalCellIndex ) + itemSeparator; + + text += coordinatesText( grid, globalCellIndex, itemSeparator ); } } @@ -251,10 +254,8 @@ QString RiuResultTextBuilder::geometrySelectionText( QString itemSeparator ) if ( !t.isZero() ) { cvf::Vec3d intPt = m_intersectionPointInDisplay.getTransformedPoint( t ); - formattedText = QString( "Intersection point : [E: %1, N: %2, Depth: %3]" ) - .arg( intPt.x(), 5, 'f', 2 ) - .arg( intPt.y(), 5, 'f', 2 ) - .arg( -intPt.z(), 5, 'f', 2 ); + formattedText = + createTextFromDomainCoordinate( "Intersection point : [E: %1, N: %2, Depth: %3]", intPt ); text += formattedText; } } @@ -265,10 +266,8 @@ QString RiuResultTextBuilder::geometrySelectionText( QString itemSeparator ) cvf::ref transForm = m_displayCoordView->displayCoordTransform(); cvf::Vec3d domainCoord = transForm->translateToDomainCoord( m_intersectionPointInDisplay ); - formattedText = QString( "Intersection point : [E: %1, N: %2, Depth: %3]" ) - .arg( domainCoord.x(), 5, 'f', 2 ) - .arg( domainCoord.y(), 5, 'f', 2 ) - .arg( -domainCoord.z(), 5, 'f', 2 ); + formattedText = + createTextFromDomainCoordinate( "Intersection point : [E: %1, N: %2, Depth: %3]", domainCoord ); text += formattedText; } } @@ -279,6 +278,74 @@ QString RiuResultTextBuilder::geometrySelectionText( QString itemSeparator ) return text; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiuResultTextBuilder::coordinatesText( const RigGridBase* grid, size_t globalCellIndex, const QString& itemSeparator ) +{ + QString text; + + bool showCenter = false; + bool showCorner = false; + + if ( m_eclipseView ) + { + std::vector additionalResultSettings; + m_eclipseView->descendantsOfType( additionalResultSettings ); + if ( !additionalResultSettings.empty() ) + { + showCenter = additionalResultSettings[0]->showCenterCoordinates(); + showCorner = additionalResultSettings[0]->showCornerCoordinates(); + } + } + + if ( showCenter ) + { + auto mainGrid = grid->mainGrid(); + auto cell = mainGrid->cell( globalCellIndex ); + const auto center = cell.center(); + + text += createTextFromDomainCoordinate( "Cell Center : [%1, %2, %3]", center ) + itemSeparator; + } + + if ( showCorner ) + { + auto mainGrid = grid->mainGrid(); + auto cell = mainGrid->cell( globalCellIndex ); + auto indices = cell.cornerIndices(); + + text += QString( "Cell Corners" ) + itemSeparator; + + const std::vector> riNodeOrder{ { 0, "i- j- k+" }, + { 1, "i+ j- k+" }, + { 2, "i+ j+ k+" }, + { 3, "i- j+ k+" }, + { 4, "i- j- k-" }, + { 5, "i+ j- k-" }, + { 6, "i+ j+ k-" }, + { 7, "i- j+ k-" } }; + + for ( int i = 0; i < 8; i++ ) + { + const auto& [nodeIndex, nodeText] = riNodeOrder[i]; + auto v = mainGrid->nodes()[indices[nodeIndex]]; + + text += createTextFromDomainCoordinate( QString::fromStdString( nodeText ) + " : [%1, %2, %3]" + itemSeparator, + v ); + } + } + + return text; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiuResultTextBuilder::createTextFromDomainCoordinate( const QString& formatString, const cvf::Vec3d& domainCoord ) +{ + return formatString.arg( domainCoord.x(), 5, 'f', 2 ).arg( domainCoord.y(), 5, 'f', 2 ).arg( -domainCoord.z(), 5, 'f', 2 ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/UserInterface/RiuResultTextBuilder.h b/ApplicationLibCode/UserInterface/RiuResultTextBuilder.h index 69469d1790..209d3a9c66 100644 --- a/ApplicationLibCode/UserInterface/RiuResultTextBuilder.h +++ b/ApplicationLibCode/UserInterface/RiuResultTextBuilder.h @@ -20,6 +20,7 @@ #pragma once #include "cafPdmPointer.h" + #include "cvfStructGrid.h" #include @@ -30,6 +31,7 @@ class Rim2dIntersectionView; class RigEclipseCaseData; class RimEclipseResultDefinition; class RimGridView; +class RigGridBase; class QString; @@ -62,7 +64,7 @@ public: QString mainResultText(); - QString geometrySelectionText( QString itemSeparator ); + QString geometrySelectionText( const QString& itemSeparator ); private: void appendDetails( QString& text, const QString& details ); @@ -90,6 +92,10 @@ private: std::pair resultTextFromLinkedViews() const; + QString coordinatesText( const RigGridBase* grid, size_t globalCellIndex, const QString& itemSeparator ); + + static QString createTextFromDomainCoordinate( const QString& formatString, const cvf::Vec3d& domainCoord ); + private: caf::PdmPointer m_displayCoordView; caf::PdmPointer m_eclipseView; diff --git a/ThirdParty/custom-opm-common/opm-common b/ThirdParty/custom-opm-common/opm-common index aa8e9c1f84..c548d4ea43 160000 --- a/ThirdParty/custom-opm-common/opm-common +++ b/ThirdParty/custom-opm-common/opm-common @@ -1 +1 @@ -Subproject commit aa8e9c1f84a8ccfe829c3a89295c442e95bb2a09 +Subproject commit c548d4ea4319adee307bba5ddd8d68bb1f44d421