mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
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
This commit is contained in:
parent
4615d0b524
commit
b3a56a9353
@ -77,6 +77,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RifRftSegment.h
|
${CMAKE_CURRENT_LIST_DIR}/RifRftSegment.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader.h
|
${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RifReaderPressureDepthData.h
|
${CMAKE_CURRENT_LIST_DIR}/RifReaderPressureDepthData.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RifOpmGridTools.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCE_GROUP_SOURCE_FILES
|
set(SOURCE_GROUP_SOURCE_FILES
|
||||||
@ -155,6 +156,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RifRftSegment.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RifRftSegment.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RifReaderPressureDepthData.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RifReaderPressureDepthData.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RifOpmGridTools.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||||
|
402
ApplicationLibCode/FileInterface/RifOpmGridTools.cpp
Normal file
402
ApplicationLibCode/FileInterface/RifOpmGridTools.cpp
Normal file
@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// 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 <algorithm>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
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<int>( 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<int, std::pair<double, double>> radialGridCenterTopLayerOpm =
|
||||||
|
computeXyCenterForTopOfCells( opmMainGrid, opmGrid, riGrid );
|
||||||
|
|
||||||
|
std::array<double, 8> opmX{};
|
||||||
|
std::array<double, 8> opmY{};
|
||||||
|
std::array<double, 8> opmZ{};
|
||||||
|
|
||||||
|
const auto hostCellGlobalIndices = opmGrid.hostCellsGlobalIndex();
|
||||||
|
const size_t* cellMappingECLRi = RifReaderEclipseOutput::eclipseCellIndexMapping();
|
||||||
|
const auto gridDimension = opmGrid.dimension();
|
||||||
|
auto& riNodes = riMainGrid->nodes();
|
||||||
|
|
||||||
|
std::vector<cvf::Vec3d> 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<double, 8> cellRadius{};
|
||||||
|
std::array<double, 8> cellTheta{};
|
||||||
|
std::array<double, 8> 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<double>::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<int>( 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<double>::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<int, std::pair<double, double>> 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<int, std::pair<double, double>> radialGridCenterTopLayerOpm;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::array<double, 8> opmX{};
|
||||||
|
std::array<double, 8> opmY{};
|
||||||
|
std::array<double, 8> opmZ{};
|
||||||
|
|
||||||
|
std::map<int, std::vector<std::pair<double, double>>> 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<double> xCoord;
|
||||||
|
RiaWeightedMeanCalculator<double> 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<std::vector<cvf::Vec3d>> 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<double> 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<double, 8> cellX{};
|
||||||
|
std::array<double, 8> cellY{};
|
||||||
|
std::array<double, 8> 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<double>& values ) -> std::vector<double> {
|
||||||
|
if ( values.size() < 2 ) return {};
|
||||||
|
|
||||||
|
std::vector<double> 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<std::vector<cvf::Vec3d>> allCoords;
|
||||||
|
std::array<double, 8> hostCellX{};
|
||||||
|
std::array<double, 8> hostCellY{};
|
||||||
|
std::array<double, 8> hostCellZ{};
|
||||||
|
|
||||||
|
opmMainGrid.getCellCorners( mainGridCellIndex, hostCellX, hostCellY, hostCellZ );
|
||||||
|
|
||||||
|
for ( int pillarIndex = 0; pillarIndex < 4; pillarIndex++ )
|
||||||
|
{
|
||||||
|
std::vector<cvf::Vec3d> 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;
|
||||||
|
}
|
60
ApplicationLibCode/FileInterface/RifOpmGridTools.h
Normal file
60
ApplicationLibCode/FileInterface/RifOpmGridTools.h
Normal file
@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cvfVector3.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
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<int, std::pair<double, double>>
|
||||||
|
computeXyCenterForTopOfCells( Opm::EclIO::EGrid& opmMainGrid, Opm::EclIO::EGrid& opmGrid, RigGridBase* riGrid );
|
||||||
|
|
||||||
|
static std::vector<std::vector<cvf::Vec3d>> computeSnapToCoordinates( Opm::EclIO::EGrid& opmMainGrid,
|
||||||
|
Opm::EclIO::EGrid& opmGrid,
|
||||||
|
int mainGridCellIndex,
|
||||||
|
int lgrCellIndex );
|
||||||
|
};
|
@ -29,6 +29,7 @@
|
|||||||
#include "RifEclipseInputFileTools.h"
|
#include "RifEclipseInputFileTools.h"
|
||||||
#include "RifEclipseOutputFileTools.h"
|
#include "RifEclipseOutputFileTools.h"
|
||||||
#include "RifHdf5ReaderInterface.h"
|
#include "RifHdf5ReaderInterface.h"
|
||||||
|
#include "RifOpmGridTools.h"
|
||||||
#include "RifReaderSettings.h"
|
#include "RifReaderSettings.h"
|
||||||
|
|
||||||
#ifdef USE_HDF5
|
#ifdef USE_HDF5
|
||||||
@ -414,6 +415,8 @@ bool RifReaderEclipseOutput::open( const QString& fileName, RigEclipseCaseData*
|
|||||||
{
|
{
|
||||||
auto task = progress.task( "Transferring grid geometry", 10 );
|
auto task = progress.task( "Transferring grid geometry", 10 );
|
||||||
if ( !transferGeometry( mainEclGrid, eclipseCase ) ) return false;
|
if ( !transferGeometry( mainEclGrid, eclipseCase ) ) return false;
|
||||||
|
|
||||||
|
RifOpmGridTools::importCoordinatesForRadialGrid( fileName.toStdString(), eclipseCase->mainGrid() );
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -76,14 +76,7 @@ public:
|
|||||||
std::vector<QDateTime> allTimeSteps() const;
|
std::vector<QDateTime> allTimeSteps() const;
|
||||||
|
|
||||||
static bool transferGeometry( const ecl_grid_type* mainEclGrid, RigEclipseCaseData* eclipseCase );
|
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 transferCoarseningInfo( const ecl_grid_type* eclGrid, RigGridBase* grid );
|
||||||
|
|
||||||
static void importEquilData( const QString& deckFileName,
|
static void importEquilData( const QString& deckFileName,
|
||||||
const QString& includeStatementAbsolutePathPrefix,
|
const QString& includeStatementAbsolutePathPrefix,
|
||||||
RigEclipseCaseData* eclipseCase );
|
RigEclipseCaseData* eclipseCase );
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "RimEclipseCellColors.h"
|
#include "RimEclipseCellColors.h"
|
||||||
#include "RimEclipseView.h"
|
#include "RimEclipseView.h"
|
||||||
|
|
||||||
|
#include "cafPdmUiCheckBoxEditor.h"
|
||||||
#include "cafPdmUiTreeSelectionEditor.h"
|
#include "cafPdmUiTreeSelectionEditor.h"
|
||||||
|
|
||||||
CAF_PDM_SOURCE_INIT( RimMultipleEclipseResults, "RimMultipleEclipseResults" );
|
CAF_PDM_SOURCE_INIT( RimMultipleEclipseResults, "RimMultipleEclipseResults" );
|
||||||
@ -32,9 +33,14 @@ RimMultipleEclipseResults::RimMultipleEclipseResults()
|
|||||||
{
|
{
|
||||||
CAF_PDM_InitObject( "Multiple Result Info", ":/TextAnnotation16x16.png" );
|
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" );
|
CAF_PDM_InitFieldNoDefault( &m_selectedKeywords, "SelectedProperties", "Properties" );
|
||||||
m_selectedKeywords.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::TOP );
|
m_selectedKeywords.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::TOP );
|
||||||
|
|
||||||
m_selectedKeywords.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
|
m_selectedKeywords.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +80,22 @@ std::vector<RigEclipseResultAddress> RimMultipleEclipseResults::additionalResult
|
|||||||
return resultAddresses;
|
return resultAddresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimMultipleEclipseResults::showCenterCoordinates() const
|
||||||
|
{
|
||||||
|
return m_showCenterCoordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimMultipleEclipseResults::showCornerCoordinates() const
|
||||||
|
{
|
||||||
|
return m_showCornerCoordinates;
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
@ -40,10 +40,16 @@ public:
|
|||||||
|
|
||||||
std::vector<RigEclipseResultAddress> additionalResultAddresses() const;
|
std::vector<RigEclipseResultAddress> additionalResultAddresses() const;
|
||||||
|
|
||||||
|
bool showCenterCoordinates() const;
|
||||||
|
bool showCornerCoordinates() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
|
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
caf::PdmField<bool> m_showCornerCoordinates;
|
||||||
|
caf::PdmField<bool> m_showCenterCoordinates;
|
||||||
|
|
||||||
caf::PdmField<std::vector<QString>> m_selectedKeywords;
|
caf::PdmField<std::vector<QString>> m_selectedKeywords;
|
||||||
caf::PdmPointer<RimEclipseView> m_eclipseView;
|
caf::PdmPointer<RimEclipseView> m_eclipseView;
|
||||||
};
|
};
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
// Disable warning from external library to make sure treat warnings as error works
|
// Disable warning from external library to make sure treat warnings as error works
|
||||||
#pragma warning( disable : 4267 )
|
#pragma warning( disable : 4267 )
|
||||||
#endif
|
#endif
|
||||||
|
#include "opm/io/eclipse/EGrid.hpp"
|
||||||
#include "opm/io/eclipse/ERft.hpp"
|
#include "opm/io/eclipse/ERft.hpp"
|
||||||
#include "opm/io/eclipse/ESmry.hpp"
|
#include "opm/io/eclipse/ESmry.hpp"
|
||||||
#include "opm/io/eclipse/ExtESmry.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<double, 8> X{};
|
||||||
|
std::array<double, 8> Y{};
|
||||||
|
std::array<double, 8> 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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "RimExtrudedCurveIntersection.h"
|
#include "RimExtrudedCurveIntersection.h"
|
||||||
#include "RimFormationNames.h"
|
#include "RimFormationNames.h"
|
||||||
#include "RimIntersectionResultDefinition.h"
|
#include "RimIntersectionResultDefinition.h"
|
||||||
|
#include "RimMultipleEclipseResults.h"
|
||||||
#include "RimRegularLegendConfig.h"
|
#include "RimRegularLegendConfig.h"
|
||||||
#include "RimReservoirCellResultsStorage.h"
|
#include "RimReservoirCellResultsStorage.h"
|
||||||
#include "RimViewLinker.h"
|
#include "RimViewLinker.h"
|
||||||
@ -195,7 +196,7 @@ QString RiuResultTextBuilder::mainResultText()
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
QString RiuResultTextBuilder::geometrySelectionText( QString itemSeparator )
|
QString RiuResultTextBuilder::geometrySelectionText( const QString& itemSeparator )
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
|
|
||||||
@ -234,6 +235,8 @@ QString RiuResultTextBuilder::geometrySelectionText( QString itemSeparator )
|
|||||||
|
|
||||||
size_t globalCellIndex = grid->reservoirCellIndex( m_cellIndex );
|
size_t globalCellIndex = grid->reservoirCellIndex( m_cellIndex );
|
||||||
text += QString( "Global Cell Index : %4" ).arg( globalCellIndex ) + itemSeparator;
|
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() )
|
if ( !t.isZero() )
|
||||||
{
|
{
|
||||||
cvf::Vec3d intPt = m_intersectionPointInDisplay.getTransformedPoint( t );
|
cvf::Vec3d intPt = m_intersectionPointInDisplay.getTransformedPoint( t );
|
||||||
formattedText = QString( "Intersection point : [E: %1, N: %2, Depth: %3]" )
|
formattedText =
|
||||||
.arg( intPt.x(), 5, 'f', 2 )
|
createTextFromDomainCoordinate( "Intersection point : [E: %1, N: %2, Depth: %3]", intPt );
|
||||||
.arg( intPt.y(), 5, 'f', 2 )
|
|
||||||
.arg( -intPt.z(), 5, 'f', 2 );
|
|
||||||
text += formattedText;
|
text += formattedText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,10 +266,8 @@ QString RiuResultTextBuilder::geometrySelectionText( QString itemSeparator )
|
|||||||
cvf::ref<caf::DisplayCoordTransform> transForm = m_displayCoordView->displayCoordTransform();
|
cvf::ref<caf::DisplayCoordTransform> transForm = m_displayCoordView->displayCoordTransform();
|
||||||
cvf::Vec3d domainCoord = transForm->translateToDomainCoord( m_intersectionPointInDisplay );
|
cvf::Vec3d domainCoord = transForm->translateToDomainCoord( m_intersectionPointInDisplay );
|
||||||
|
|
||||||
formattedText = QString( "Intersection point : [E: %1, N: %2, Depth: %3]" )
|
formattedText =
|
||||||
.arg( domainCoord.x(), 5, 'f', 2 )
|
createTextFromDomainCoordinate( "Intersection point : [E: %1, N: %2, Depth: %3]", domainCoord );
|
||||||
.arg( domainCoord.y(), 5, 'f', 2 )
|
|
||||||
.arg( -domainCoord.z(), 5, 'f', 2 );
|
|
||||||
text += formattedText;
|
text += formattedText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,6 +278,74 @@ QString RiuResultTextBuilder::geometrySelectionText( QString itemSeparator )
|
|||||||
return text;
|
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<RimMultipleEclipseResults*> 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<std::pair<int, std::string>> 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 );
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "cafPdmPointer.h"
|
#include "cafPdmPointer.h"
|
||||||
|
|
||||||
#include "cvfStructGrid.h"
|
#include "cvfStructGrid.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -30,6 +31,7 @@ class Rim2dIntersectionView;
|
|||||||
class RigEclipseCaseData;
|
class RigEclipseCaseData;
|
||||||
class RimEclipseResultDefinition;
|
class RimEclipseResultDefinition;
|
||||||
class RimGridView;
|
class RimGridView;
|
||||||
|
class RigGridBase;
|
||||||
|
|
||||||
class QString;
|
class QString;
|
||||||
|
|
||||||
@ -62,7 +64,7 @@ public:
|
|||||||
|
|
||||||
QString mainResultText();
|
QString mainResultText();
|
||||||
|
|
||||||
QString geometrySelectionText( QString itemSeparator );
|
QString geometrySelectionText( const QString& itemSeparator );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void appendDetails( QString& text, const QString& details );
|
void appendDetails( QString& text, const QString& details );
|
||||||
@ -90,6 +92,10 @@ private:
|
|||||||
|
|
||||||
std::pair<bool, QStringList> resultTextFromLinkedViews() const;
|
std::pair<bool, QStringList> resultTextFromLinkedViews() const;
|
||||||
|
|
||||||
|
QString coordinatesText( const RigGridBase* grid, size_t globalCellIndex, const QString& itemSeparator );
|
||||||
|
|
||||||
|
static QString createTextFromDomainCoordinate( const QString& formatString, const cvf::Vec3d& domainCoord );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
caf::PdmPointer<RimGridView> m_displayCoordView;
|
caf::PdmPointer<RimGridView> m_displayCoordView;
|
||||||
caf::PdmPointer<RimEclipseView> m_eclipseView;
|
caf::PdmPointer<RimEclipseView> m_eclipseView;
|
||||||
|
2
ThirdParty/custom-opm-common/opm-common
vendored
2
ThirdParty/custom-opm-common/opm-common
vendored
@ -1 +1 @@
|
|||||||
Subproject commit aa8e9c1f84a8ccfe829c3a89295c442e95bb2a09
|
Subproject commit c548d4ea4319adee307bba5ddd8d68bb1f44d421
|
Loading…
Reference in New Issue
Block a user