Skip to content

Commit 8fc6e0e

Browse files
yngve-skxjules
authored andcommitted
Consider only updateable parameters with enif
After some discussions, it has been decided that we will do this to make EnIF not crash when there are categorical variables. PS: This is theoretically wrong, as parameters may affect responses even if they are not updated. Example of this: Suppose we have one scalar parameter + 200 design matrix parameters, and the response is mainly affected by the design parameters. Now EnIF will overlook this and give a poor update. We should aim to first disregard categoricals, but eventually also somehow include them.
1 parent bd61fdf commit 8fc6e0e

File tree

3 files changed

+82
-7
lines changed

3 files changed

+82
-7
lines changed

src/ert/analysis/_enif_update.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,14 @@ def analysis_EnIF(
160160
Y=S.T,
161161
verbose_level=5,
162162
)
163-
163+
updated_parameters = [
164+
p
165+
for p, config in source_ensemble.experiment.parameter_configuration.items()
166+
if config.update
167+
]
164168
# Learn the precision matrix block-sparse over parameter groups
165169
Prec_u = sp.sparse.csc_matrix((0, 0), dtype=float)
166-
for param_group in parameters:
170+
for param_group in updated_parameters:
167171
config_node = source_ensemble.experiment.parameter_configuration[param_group]
168172
X_local = source_ensemble.load_parameters_numpy(param_group, iens_active_index)
169173
X_local_scaler = StandardScaler()
@@ -215,7 +219,7 @@ def analysis_EnIF(
215219

216220
# Iterate over parameters to store the updated ensemble
217221
parameters_updated = 0
218-
for param_group in parameters:
222+
for param_group in updated_parameters:
219223
log_msg = f"Storing data for {param_group}.."
220224
logger.info(log_msg)
221225
progress_callback(AnalysisStatusEvent(msg=log_msg))
@@ -241,7 +245,7 @@ def analysis_EnIF(
241245
)
242246
_copy_unupdated_parameters(
243247
list(source_ensemble.experiment.parameter_configuration.keys()),
244-
parameters,
248+
updated_parameters,
245249
iens_active_index,
246250
source_ensemble,
247251
target_ensemble,

src/ert/analysis/_update_commons.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,11 +340,12 @@ def _all_parameters(
340340
) -> npt.NDArray[np.float64]:
341341
"""Return all parameters in assimilation problem"""
342342

343-
param_groups = list(ensemble.experiment.parameter_configuration.keys())
344-
343+
groups_to_update = [
344+
k for k, v in ensemble.experiment.parameter_configuration.items() if v.update
345+
]
345346
param_arrays = [
346347
ensemble.load_parameters_numpy(param_group, iens_active_index)
347-
for param_group in param_groups
348+
for param_group in groups_to_update
348349
]
349350

350351
return np.vstack(param_arrays)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import queue
2+
from argparse import Namespace
3+
from pathlib import Path
4+
5+
import polars as pl
6+
import pytest
7+
8+
from ert.config import ErtConfig
9+
from ert.ensemble_evaluator import EvaluatorServerConfig
10+
from ert.mode_definitions import (
11+
ENIF_MODE,
12+
)
13+
from ert.run_models import create_model
14+
from ert.storage import open_storage
15+
from tests.ert.conftest import _create_design_matrix
16+
17+
18+
@pytest.mark.integration_test
19+
def test_that_enif_update_does_not_update_design_matrix_parameters(
20+
copy_case,
21+
):
22+
"""
23+
Runs EnIF on poly.ert with hardcoded parameter "a" values in design matrix,
24+
then expect parameter "a" values to remain unchanged after second run
25+
"""
26+
num_realizations = 10
27+
28+
copy_case("poly_example")
29+
config_file = Path("poly.ert")
30+
31+
_create_design_matrix(
32+
"poly_design.xlsx",
33+
pl.DataFrame(
34+
{
35+
"REAL": list(range(num_realizations)),
36+
"a": [1] * num_realizations, # ["a"].to_list(),
37+
}
38+
),
39+
)
40+
41+
with open(config_file, "a", encoding="utf-8") as fh:
42+
fh.write(f"NUM_REALIZATIONS {num_realizations}\n")
43+
fh.write("RANDOM_SEED 123456789\n")
44+
fh.write("DESIGN_MATRIX poly_design.xlsx\n")
45+
46+
evaluator_server_config = EvaluatorServerConfig()
47+
ert_config_with_dm = ErtConfig.from_file("poly.ert")
48+
49+
enif_with_dm = create_model(
50+
ert_config_with_dm,
51+
args=Namespace(
52+
mode=ENIF_MODE,
53+
experiment_name="enif_with_dm",
54+
target_ensemble="ens_with_dm_%d",
55+
),
56+
status_queue=queue.SimpleQueue(),
57+
)
58+
59+
enif_with_dm.start_simulations_thread(evaluator_server_config)
60+
61+
with open_storage(enif_with_dm.storage_path, mode="r") as storage:
62+
experiment_with_dm = storage.get_experiment_by_name("enif_with_dm")
63+
64+
prior_with_dm = experiment_with_dm.get_ensemble_by_name("ens_with_dm_0")
65+
posterior_with_dm = experiment_with_dm.get_ensemble_by_name("ens_with_dm_1")
66+
67+
prior_with_dm_a = prior_with_dm.load_parameters("a")["a"]
68+
posterior_with_dm_a = posterior_with_dm.load_parameters("a")["a"]
69+
70+
assert posterior_with_dm_a.equals(prior_with_dm_a)

0 commit comments

Comments
 (0)