#14223 Calculate geometry grid properties when creating grid from python API

Compute the depth related geometry properties (DEPTH, DX, DY, DZ, TOPS, BOTTOM) in RimCornerPointCase::createFromCoordinatesArray and replaceGridFromCoordinatesArray, matching the behavior when importing a grid from file. The computation is guarded by the same autoComputeDepthRelatedProperties preference used by the file importers.
This commit is contained in:
Kristian Bendiksen
2026-06-15 15:29:33 +02:00
parent c4a8f38b65
commit 8c17130714
4 changed files with 90 additions and 1 deletions
@@ -21,6 +21,7 @@
#include "RiaApplication.h"
#include "RiaDefines.h"
#include "RiaLogging.h"
#include "RiaPreferencesGrid.h"
#include "RiaQStringFormatter.h"
#include "RifInputPropertyLoader.h"
@@ -108,6 +109,7 @@ std::expected<RimCornerPointCase*, QString> RimCornerPointCase::createFromCoordi
buildGrid( *cornerPointCase->eclipseCaseData(), nx, ny, nz, coord, zcorn, actnum );
cornerPointCase->computeCachedData();
computeDepthRelatedResults( *cornerPointCase );
return cornerPointCase;
}
@@ -142,6 +144,7 @@ std::expected<void, QString> RimCornerPointCase::replaceGridFromCoordinatesArray
buildGrid( *cornerPointCase.eclipseCaseData(), nx, ny, nz, coord, zcorn, actnum );
cornerPointCase.computeCachedData();
computeDepthRelatedResults( cornerPointCase );
return {};
}
@@ -369,6 +372,19 @@ void RimCornerPointCase::createActnumResult( RigEclipseCaseData& eclipseCaseData
std::fill( ( *modifiableData )[0].begin(), ( *modifiableData )[0].end(), 1.0 );
}
//--------------------------------------------------------------------------------------------------
/// Compute the depth related geometry properties (DEPTH, DX, DY, DZ, TOPS, BOTTOM), matching the
/// behavior when a grid is imported from file.
//--------------------------------------------------------------------------------------------------
void RimCornerPointCase::computeDepthRelatedResults( RimCornerPointCase& cornerPointCase )
{
if ( RiaPreferencesGrid::current()->autoComputeDepthRelatedProperties() )
{
cornerPointCase.results( RiaDefines::PorosityModelType::MATRIX_MODEL )->computeDepthRelatedResults();
cornerPointCase.results( RiaDefines::PorosityModelType::FRACTURE_MODEL )->computeDepthRelatedResults();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -71,6 +71,8 @@ protected:
static void createActnumResult( RigEclipseCaseData& eclipseCaseData );
static void computeDepthRelatedResults( RimCornerPointCase& cornerPointCase );
static std::array<cvf::Vec3d, 8> getCorners( const RigMainGrid& grid,
const std::vector<float>& coord,
const std::vector<float>& zcorn,
@@ -37,4 +37,9 @@ nx = grid.dimensions.ncol
ny = grid.dimensions.nrow
nz = grid.dimensions.nlay
project.create_corner_point_grid(name, nx, ny, nz, coord, zcorn, actnum)
case = project.create_corner_point_grid(name, nx, ny, nz, coord, zcorn, actnum)
# Geometry properties (DEPTH, DX, DY, DZ, TOPS, BOTTOM) are computed automatically
print("Static properties: ", case.available_properties("STATIC_NATIVE"))
depth = case.active_cell_property("STATIC_NATIVE", "DEPTH", 0)
print("DEPTH min/max: ", min(depth), max(depth))
@@ -2,9 +2,13 @@ import sys
import os
import math
import pytest
sys.path.insert(1, os.path.join(sys.path[0], "../../"))
import dataroot
GEOMETRY_PROPERTIES = ["DEPTH", "DX", "DY", "DZ", "TOPS", "BOTTOM"]
def test_export_corner_point_grid_basic(rips_instance, initialize_test):
"""Test the export_corner_point_grid method with a simple created grid"""
@@ -58,6 +62,10 @@ def test_export_corner_point_grid_basic(rips_instance, initialize_test):
assert len(actnum_values) == active_count
assert all(v == 1.0 for v in actnum_values)
# Geometry properties should be computed automatically (issue #14223)
for prop in GEOMETRY_PROPERTIES:
assert prop in case.available_properties("STATIC_NATIVE")
# Test our export function
exported_zcorn, exported_coord, exported_actnum, export_nx, export_ny, export_nz = (
case.export_corner_point_grid()
@@ -144,6 +152,58 @@ def test_create_corner_point_grid_with_inactive_cells(rips_instance, initialize_
assert sum(1 for x in exported_actnum if x > 0) == expected_active
def test_create_corner_point_grid_geometry_properties(rips_instance, initialize_test):
"""Geometry properties (DEPTH, DX, DY, DZ, TOPS, BOTTOM) are computed automatically
when creating a grid from the python API, as when importing a grid from file (issue #14223)."""
# 2x2x2 grid of 100 m cubic cells in two layers: 1000-1100 and 1100-1200
nx, ny, nz = 2, 2, 2
coord = []
for j in range(ny + 1):
for i in range(nx + 1):
x = i * 100.0
y = j * 100.0
coord.extend([x, y, 1000.0])
coord.extend([x, y, 1200.0])
# ZCORN uses the Eclipse layout: for each layer, the 4*nx*ny top corner depths
# followed by the 4*nx*ny bottom corner depths.
zcorn = []
for k in range(nz):
top_depth = 1000.0 + k * 100.0
zcorn.extend([top_depth] * (4 * nx * ny))
zcorn.extend([top_depth + 100.0] * (4 * nx * ny))
actnum = [1] * (nx * ny * nz)
case = rips_instance.project.create_corner_point_grid(
"GeometryPropertiesGrid", nx, ny, nz, coord, zcorn, actnum
)
for prop in GEOMETRY_PROPERTIES:
assert prop in case.available_properties("STATIC_NATIVE")
active_count = case.cell_count().active_cell_count
values = {
prop: case.active_cell_property("STATIC_NATIVE", prop, 0)
for prop in GEOMETRY_PROPERTIES
}
for prop in GEOMETRY_PROPERTIES:
assert len(values[prop]) == active_count
# Active cell index order follows the cell index order (i fastest, k slowest),
# so the first 4 cells are in layer k=0 and the last 4 in layer k=1.
for active_index in range(active_count):
k = active_index // (nx * ny)
assert values["DX"][active_index] == pytest.approx(100.0)
assert values["DY"][active_index] == pytest.approx(100.0)
assert values["DZ"][active_index] == pytest.approx(100.0)
assert values["TOPS"][active_index] == pytest.approx(1000.0 + k * 100.0)
assert values["BOTTOM"][active_index] == pytest.approx(1100.0 + k * 100.0)
assert values["DEPTH"][active_index] == pytest.approx(1050.0 + k * 100.0)
def test_export_corner_point_grid_return_types(rips_instance, initialize_test):
"""Test that export_corner_point_grid returns the correct types"""
@@ -352,6 +412,12 @@ def test_replace_corner_point_grid_basic(rips_instance, initialize_test):
assert new_cell_count.reservoir_cell_count == nx_new * ny_new * nz_new
assert new_cell_count.reservoir_cell_count == 27 # 3x3x3
# Geometry properties should be re-computed for the replaced grid (issue #14223)
for prop in GEOMETRY_PROPERTIES:
assert prop in case.available_properties("STATIC_NATIVE")
prop_values = case.active_cell_property("STATIC_NATIVE", prop, 0)
assert len(prop_values) == new_cell_count.active_cell_count
# ACTNUM should be re-created for the replaced grid (issue #14109)
assert "ACTNUM" in case.available_properties("STATIC_NATIVE")
actnum_values = case.active_cell_property("STATIC_NATIVE", "ACTNUM", 0)