Merge pull request #6522 from lechevaa/fix_hybrid_newton_python_tests

Fix hybrid newton python tests imports
This commit is contained in:
Arne Morten Kvarving authored and GitHub committed 2025-10-09 15:02:51 +02:00
commit 92cf91082b
8 files changed
+66 -49

No files matched your search

+4
View File
@@ -525,6 +525,10 @@ if(MPI_FOUND)
include (${CMAKE_CURRENT_SOURCE_DIR}/parallelUnitTests.cmake)
endif()
if(OPM_ENABLE_PYTHON)
include (${CMAKE_CURRENT_SOURCE_DIR}/pythonIntegrationTests.cmake)
endif()
include(OpmBashCompletion)
if (NOT BUILD_FLOW)
File renamed without changes.
File renamed without changes.
@@ -4,12 +4,11 @@ from pathlib import Path
import numpy as np
import subprocess
from utils import Dense, Sequential
from utils import collect_input_features, compute_output_vars, write_config, extract_newtit_from_file, extract_unrst_variables
from utils import (ABSOLUTE_CASES, RELATIVE_CASES, FEATURE_ENGINEERING_CASES, SCALING_CASES, MULTI_MODEL_CASES, ZERO_NEWTON_CASES, ALL_CASES)
import tensorflow as tf
from kerasify import export_model
from utils import ABSOLUTE_CASES, RELATIVE_CASES, FEATURE_ENGINEERING_CASES, SCALING_CASES, MULTI_MODEL_CASES, ZERO_NEWTON_CASES, ALL_CASES
from opm.ml.ml_tools.kerasify import export_model
class TestHybridNewton(unittest.TestCase):
@classmethod
@@ -24,27 +23,28 @@ class TestHybridNewton(unittest.TestCase):
cls.times = []
baseline_cmd = [
"flow",
os.environ.get("FLOW_BINARY", default="flow"),
str(cls.data_dir / cls.deck_file),
"--output-extra-convergence-info=steps,iterations",
"--newton-min-iterations=0",
"--output-dir=.",
"--full-time-step-initially=true",
]
print("Running baseline simulation...")
subprocess.run(baseline_cmd, cwd=cls.data_dir, stdout=subprocess.DEVNULL, check=True)
print("Running baseline simulation... ")
subprocess.run(baseline_cmd, stdout=subprocess.DEVNULL, check=True)
# Extract Newton iterations
cls.baseline_iters = extract_newtit_from_file(cls.data_dir / Path(cls.deck_file).stem)
cls.baseline_iters = extract_newtit_from_file(Path('.') / Path(cls.deck_file).stem)
print(f"Baseline Newton iterations: {cls.baseline_iters}")
# Extract fluid state from UNRST for all timesteps
cls.unrst, cls.times = extract_unrst_variables(cls.data_dir, cls.deck_file)
cls.unrst, cls.times = extract_unrst_variables(".", cls.deck_file)
cls.rd_init["PERMX"] = [10**2] * len(cls.unrst["PRESSURE"][0])
cls.n_cells = len(cls.unrst["PRESSURE"][0])
def _run_cases(self, cases):
models_dir = self.data_dir / "models"
models_dir = Path('.') / "models"
os.makedirs(models_dir, exist_ok=True)
for case in cases:
@@ -89,9 +89,8 @@ class TestHybridNewton(unittest.TestCase):
input_flat = input_flat.reshape(-1)
output_flat = output_flat.reshape(-1)
model = tf.keras.Sequential([
tf.keras.Input(shape=(input_flat.shape[0],)),
tf.keras.layers.Dense(output_flat.shape[0], use_bias=True)
model = Sequential([
Dense(input_dim=input_flat.shape[0], output_dim=output_flat.shape[0])
])
model.layers[0].set_weights([np.zeros((input_flat.shape[0], output_flat.shape[0])), output_flat])
apply_time = self.times[start_idx]
@@ -126,21 +125,22 @@ class TestHybridNewton(unittest.TestCase):
def _run_hybrid_newton_test(self, json_path):
"""Run hybrid Newton via subprocess and extract Newton iterations."""
cmd = [
"flow",
os.environ.get("FLOW_BINARY", default="flow"),
str(self.data_dir / self.deck_file),
f"--hy-ne-config-file={json_path}",
"--use-hy-ne=true",
"--output-extra-convergence-info=steps,iterations",
"--newton-min-iterations=0",
"--output-dir=.",
"--full-time-step-initially=true"
]
print(f"Running hybrid Newton simulation with config {json_path}...")
subprocess.run(cmd, cwd=self.data_dir,
subprocess.run(cmd,
stdout=subprocess.DEVNULL,
check=True)
hybrid_iters = extract_newtit_from_file(self.data_dir / Path(self.deck_file).stem)
hybrid_iters = extract_newtit_from_file(Path('.') / Path(self.deck_file).stem)
return hybrid_iters
def test_absolute_cases(self):
@@ -160,42 +160,12 @@ class TestHybridNewton(unittest.TestCase):
def test_zero_newton_cases(self):
hybrid_iters = self._run_cases(ZERO_NEWTON_CASES)
# Length must match (failed newton convergence otherwise)
assert len(hybrid_iters) == len(self.baseline_iters), (
f"Hybrid iterations length {len(hybrid_iters)} "
f"does not match baseline length {len(self.baseline_iters)}"
)
# First two must be 0
assert hybrid_iters[0] == 0, f"Expected hybrid_iters[0] == 0, got {hybrid_iters[0]}"
assert hybrid_iters[1] == 0, f"Expected hybrid_iters[1] == 0, got {hybrid_iters[1]}"
# Hybrid must not exceed baseline
for i, (h, b) in enumerate(zip(hybrid_iters, self.baseline_iters)):
assert h <= b, (
f"Hybrid iterations exceeded baseline at index {i}: "
f"got {h}, expected <= {b}"
)
print(f"Hybrid Newton iterations all_features: {hybrid_iters}")
def test_all_cases(self):
hybrid_iters = self._run_cases(ALL_CASES)
# Length must match (failed newton convergence otherwise)
assert len(hybrid_iters) == len(self.baseline_iters), (
f"Hybrid iterations length {len(hybrid_iters)} "
f"does not match baseline length {len(self.baseline_iters)}"
)
print(f"Hybrid Newton iterations all_cases: {hybrid_iters}")
# First two must be 0
assert hybrid_iters[0] == 0, f"Expected hybrid_iters[0] == 0, got {hybrid_iters[0]}"
assert hybrid_iters[1] == 0, f"Expected hybrid_iters[1] == 0, got {hybrid_iters[1]}"
# Hybrid must not exceed baseline
for i, (h, b) in enumerate(zip(hybrid_iters, self.baseline_iters)):
assert h <= b, (
f"Hybrid iterations exceeded baseline at index {i}: "
f"got {h}, expected <= {b}"
)
if __name__ == "__main__":
unittest.main()
@@ -5,6 +5,27 @@ from pathlib import Path
from opm.io.ecl import ERst, ESmry
# Avoid tensorflow dependency but maintain compability with kerasify export_model method
class Dense:
def __init__(self, input_dim, output_dim, activation='linear'):
self.weights = np.zeros((input_dim, output_dim), dtype=np.float32)
self.biases = np.zeros((output_dim,), dtype=np.float32)
self.activation = activation
def set_weights(self, w_b):
self.weights = w_b[0].astype(np.float32)
self.biases = w_b[1].astype(np.float32)
def get_weights(self):
return [self.weights, self.biases]
def get_config(self):
return {'activation': self.activation}
class Sequential:
def __init__(self, layers):
self.layers = layers
def extract_unrst_variables(data_dir, deck_file):
"""
@@ -220,7 +241,7 @@ def compute_output_vars(output_features, start_idx, end_idx, unrst, rd_init, fea
return np.stack(output_data), scaling_params
def extract_newtit_from_file(filename: str | Path) -> list[int]:
def extract_newtit_from_file(filename):
"""
Parse an INFOSTEP file and return the values of the 'NewtIt' column.
+22
View File
@@ -0,0 +1,22 @@
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/tests/integration/HybridNewton)
add_test(NAME
HybridNewton
COMMAND
${Python3_EXECUTABLE}
-m unittest discover
${PROJECT_SOURCE_DIR}/python/integration_tests/ml/hybrid_newton
WORKING_DIRECTORY
${PROJECT_BINARY_DIR}/tests/integration/HybridNewton
)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.22)
set(modifications
"PYTHONPATH=path_list_append:${opm-common_DIR}/python"
"PYTHONPATH=path_list_append:${CMAKE_CURRENT_BINARY_DIR}/python"
"FLOW_BINARY=set:$<TARGET_FILE:flow>"
)
set_tests_properties(HybridNewton PROPERTIES
ENVIRONMENT_MODIFICATION
"${modifications}"
)
endif()