diff --git a/test-data/ert/heat_equation/cond_0.bgrdecl b/test-data/ert/heat_equation/cond_0.bgrdecl new file mode 100644 index 00000000000..9235e9b352f Binary files /dev/null and b/test-data/ert/heat_equation/cond_0.bgrdecl differ diff --git a/test-data/ert/heat_equation/cond_1.bgrdecl b/test-data/ert/heat_equation/cond_1.bgrdecl new file mode 100644 index 00000000000..b9e235986e9 Binary files /dev/null and b/test-data/ert/heat_equation/cond_1.bgrdecl differ diff --git a/test-data/ert/heat_equation/cond_2.bgrdecl b/test-data/ert/heat_equation/cond_2.bgrdecl new file mode 100644 index 00000000000..6e0f8e71f30 Binary files /dev/null and b/test-data/ert/heat_equation/cond_2.bgrdecl differ diff --git a/test-data/ert/heat_equation/cond_3.bgrdecl b/test-data/ert/heat_equation/cond_3.bgrdecl new file mode 100644 index 00000000000..dcde3a34d89 Binary files /dev/null and b/test-data/ert/heat_equation/cond_3.bgrdecl differ diff --git a/test-data/ert/heat_equation/cond_4.bgrdecl b/test-data/ert/heat_equation/cond_4.bgrdecl new file mode 100644 index 00000000000..1f80e65287c Binary files /dev/null and b/test-data/ert/heat_equation/cond_4.bgrdecl differ diff --git a/test-data/ert/heat_equation/cond_5.bgrdecl b/test-data/ert/heat_equation/cond_5.bgrdecl new file mode 100644 index 00000000000..d3f40bdffc4 Binary files /dev/null and b/test-data/ert/heat_equation/cond_5.bgrdecl differ diff --git a/test-data/ert/heat_equation/cond_6.bgrdecl b/test-data/ert/heat_equation/cond_6.bgrdecl new file mode 100644 index 00000000000..0f7d78025ae Binary files /dev/null and b/test-data/ert/heat_equation/cond_6.bgrdecl differ diff --git a/test-data/ert/heat_equation/cond_7.bgrdecl b/test-data/ert/heat_equation/cond_7.bgrdecl new file mode 100644 index 00000000000..cdbc36de82e Binary files /dev/null and b/test-data/ert/heat_equation/cond_7.bgrdecl differ diff --git a/test-data/ert/heat_equation/cond_8.bgrdecl b/test-data/ert/heat_equation/cond_8.bgrdecl new file mode 100644 index 00000000000..8d4a3bf231d Binary files /dev/null and b/test-data/ert/heat_equation/cond_8.bgrdecl differ diff --git a/test-data/ert/heat_equation/cond_9.bgrdecl b/test-data/ert/heat_equation/cond_9.bgrdecl new file mode 100644 index 00000000000..9eea003c553 Binary files /dev/null and b/test-data/ert/heat_equation/cond_9.bgrdecl differ diff --git a/test-data/ert/heat_equation/config_forward_init_false.ert b/test-data/ert/heat_equation/config_forward_init_false.ert new file mode 100644 index 00000000000..8c3521c0805 --- /dev/null +++ b/test-data/ert/heat_equation/config_forward_init_false.ert @@ -0,0 +1,26 @@ +-- By default, NumPy utilizes multiple threads, which is beneficial for parallelizable computations. +-- However, the heat equation implementation in this case does not benefit from parallel execution within a single realization. +-- When ERT runs multiple realizations, each one by default uses multiple threads for NumPy operations, +-- leading to resource contention and slower overall execution. +-- Setting these thread counts to 1 ensures each realization uses minimal resources, +-- allowing more realizations to run concurrently and significantly speeding up the entire experiment. +SETENV MKL_NUM_THREADS 1 +SETENV NUMEXPR_NUM_THREADS 1 +SETENV OMP_NUM_THREADS 1 + +QUEUE_SYSTEM LOCAL +QUEUE_OPTION LOCAL MAX_RUNNING 10 + +RANDOM_SEED 11223344 + +NUM_REALIZATIONS 10 +GRID CASE.EGRID + +OBS_CONFIG observations + +FIELD COND PARAMETER cond.bgrdecl INIT_FILES:cond_%d.bgrdecl FORWARD_INIT:False + +GEN_DATA MY_RESPONSE RESULT_FILE:gen_data_%d.out REPORT_STEPS:10,71,132,193,255,316,377,438 INPUT_FORMAT:ASCII + +INSTALL_JOB heat_equation HEAT_EQUATION +SIMULATION_JOB heat_equation diff --git a/test-data/ert/heat_equation/generate_files.py b/test-data/ert/heat_equation/generate_files.py index 0f0ebab271b..769ceefe82e 100644 --- a/test-data/ert/heat_equation/generate_files.py +++ b/test-data/ert/heat_equation/generate_files.py @@ -8,6 +8,7 @@ import numpy as np import numpy.typing as npt import pandas as pd +import resfo import xtgeo from definition import Coordinate, obs_coordinates, obs_times from heat_equation import heat_equation, sample_prior_conductivity @@ -71,6 +72,24 @@ def make_observations( return d +def generate_priors(): + """Generates and saves 10 random conductivity field realizations. + + Uses a prior sampling function to create conductivity fields, + then saves each field to a separate .bgrdecl file in ECLIPSE format + using Fortran-style ordering. Used for testing when FORWARD_INIT + is disabled. + """ + + rng = np.random.default_rng() + for i in range(10): + cond = sample_prior_conductivity(ensemble_size=1, nx=nx, rng=rng) + resfo.write( + f"cond_{i}.bgrdecl", + [("COND ", cond.flatten(order="F").astype(np.float32))], + ) + + if __name__ == "__main__": create_egrid_file() @@ -122,3 +141,5 @@ def make_observations( with open(f"obs_{obs_time}.txt", "w", encoding="utf-8") as fobs: df = d.iloc[d.index.get_level_values("k") == obs_time] fobs.write(df.sort_index().to_csv(header=False, index=False, sep=" ")) + + generate_priors() diff --git a/tests/ert/conftest.py b/tests/ert/conftest.py index 59f4b62b868..7e021f083cf 100644 --- a/tests/ert/conftest.py +++ b/tests/ert/conftest.py @@ -202,6 +202,13 @@ def copy_snake_oil_case(copy_case): fh.write("QUEUE_OPTION LOCAL MAX_RUNNING 12\n") +@pytest.fixture() +def copy_heat_equation(copy_case): + copy_case("heat_equation") + with open("config.ert", "a", encoding="utf-8") as fh: + fh.write("QUEUE_OPTION LOCAL MAX_RUNNING 12\n") + + @pytest.fixture( name="copy_snake_oil_case_storage", params=[ diff --git a/tests/ert/ui_tests/cli/test_field_parameter.py b/tests/ert/ui_tests/cli/test_field_parameter.py index f849b66f009..4f55ec739a8 100644 --- a/tests/ert/ui_tests/cli/test_field_parameter.py +++ b/tests/ert/ui_tests/cli/test_field_parameter.py @@ -7,6 +7,7 @@ import numpy as np import numpy.testing import polars as pl +import pytest import resfo import xtgeo @@ -332,3 +333,42 @@ def test_field_param_update_using_heat_equation_zero_var_params_and_adaptive_loc ) # Check that generalized variance is reduced by update step. assert np.trace(prior_covariance) > np.trace(posterior_covariance) + + +@pytest.mark.usefixtures("copy_heat_equation") +def test_foward_init_false(): + config = ErtConfig.from_file("config_forward_init_false.ert") + run_cli( + ENSEMBLE_SMOOTHER_MODE, + "--disable-monitor", + "config_forward_init_false.ert", + "--experiment-name", + "es-test", + ) + + with open_storage(config.ens_path) as storage: + experiment = storage.get_experiment_by_name("es-test") + prior = experiment.get_ensemble_by_name("iter-0") + posterior = experiment.get_ensemble_by_name("iter-1") + + param_config = config.ensemble_config.parameter_configs["COND"] + + prior_result = prior.load_parameters("COND")["values"] + prior_covariance = np.cov( + prior_result.values.reshape( + prior.ensemble_size, param_config.nx * param_config.ny * param_config.nz + ), + rowvar=False, + ) + + posterior_result = posterior.load_parameters("COND")["values"] + posterior_covariance = np.cov( + posterior_result.values.reshape( + posterior.ensemble_size, + param_config.nx * param_config.ny * param_config.nz, + ), + rowvar=False, + ) + + # Check that generalized variance is reduced by update step. + assert np.trace(prior_covariance) > np.trace(posterior_covariance)