Skip to content

Commit 467863e

Browse files
committed
Add design matrix valudation in ensemble experiment panel
- Prefil active realization box with realizations from design matrix - Use design_matrix parameters in ensemble experiment - add test run cli with design matrix and poly example
1 parent 74e401e commit 467863e

File tree

4 files changed

+165
-8
lines changed

4 files changed

+165
-8
lines changed

src/ert/enkf_main.py

+22
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Mapping, Optional, Union
1010

1111
import orjson
12+
import xarray as xr
1213
from numpy.random import SeedSequence
1314

1415
from .config import (
16+
DesignMatrix,
1517
ExtParamConfig,
1618
Field,
1719
GenKwConfig,
@@ -148,6 +150,26 @@ def _seed_sequence(seed: Optional[int]) -> int:
148150
return int_seed
149151

150152

153+
def load_prior(
154+
ensemble: Ensemble, active_realizations: Iterable[int], design_matrix: DesignMatrix
155+
) -> None:
156+
assert design_matrix.parameter_configuration is not None
157+
assert (
158+
design_matrix.design_matrix_df is not None
159+
and not design_matrix.design_matrix_df.empty
160+
)
161+
for realization_nr in active_realizations:
162+
row = design_matrix.design_matrix_df.loc[realization_nr]["DESIGN_MATRIX"]
163+
ds = xr.Dataset(
164+
{
165+
"values": ("names", list(row.values)),
166+
"transformed_values": ("names", list(row.values)),
167+
"names": list(row.keys()),
168+
}
169+
)
170+
ensemble.save_parameters("DESIGN_MATRIX", realization_nr, ds)
171+
172+
151173
def sample_prior(
152174
ensemble: Ensemble,
153175
active_realizations: Iterable[int],

src/ert/gui/simulation/ensemble_experiment_panel.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from ert.gui.tools.design_matrix.design_matrix_panel import DesignMatrixPanel
1616
from ert.mode_definitions import ENSEMBLE_EXPERIMENT_MODE
1717
from ert.run_models import EnsembleExperiment
18-
from ert.validation import RangeStringArgument
18+
from ert.validation import ActiveRange, RangeStringArgument
1919
from ert.validation.proper_name_argument import ExperimentValidation, ProperNameArgument
2020

2121
from .experiment_config_panel import ExperimentConfigPanel
@@ -85,6 +85,13 @@ def __init__(
8585

8686
design_matrix = analysis_config.design_matrix
8787
if design_matrix is not None:
88+
if design_matrix.design_matrix_df is None:
89+
design_matrix.read_design_matrix()
90+
91+
if design_matrix.active_realizations:
92+
self._active_realizations_field.setText(
93+
ActiveRange(design_matrix.active_realizations).rangestring
94+
)
8895
show_dm_param_button = QPushButton("Show parameters")
8996
show_dm_param_button.setObjectName("show-dm-parameters")
9097
show_dm_param_button.setMinimumWidth(50)

src/ert/run_models/ensemble_experiment.py

+42-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import numpy as np
88

9-
from ert.enkf_main import sample_prior
9+
from ert.enkf_main import load_prior, sample_prior
1010
from ert.ensemble_evaluator import EvaluatorServerConfig
1111
from ert.storage import Ensemble, Experiment, Storage
1212

@@ -61,7 +61,35 @@ def run_experiment(
6161
restart: bool = False,
6262
) -> None:
6363
self.log_at_startup()
64-
if not restart:
64+
# If design matrix is present, we substitute the experiment parameters
65+
# with those in the design matrix
66+
if self.ert_config.analysis_config.design_matrix is not None:
67+
if (
68+
self.ert_config.analysis_config.design_matrix.parameter_configuration
69+
is None
70+
):
71+
self.ert_config.analysis_config.design_matrix.read_design_matrix()
72+
assert (
73+
self.ert_config.analysis_config.design_matrix.parameter_configuration
74+
is not None
75+
)
76+
parameters_config = [
77+
self.ert_config.analysis_config.design_matrix.parameter_configuration[
78+
"DESIGN_MATRIX"
79+
]
80+
]
81+
self.experiment = self._storage.create_experiment(
82+
name=self.experiment_name,
83+
parameters=parameters_config,
84+
observations=self.ert_config.observations,
85+
responses=self.ert_config.ensemble_config.response_configuration,
86+
)
87+
self.ensemble = self._storage.create_ensemble(
88+
self.experiment,
89+
name=self.ensemble_name,
90+
ensemble_size=self.ensemble_size,
91+
)
92+
elif not restart:
6593
self.experiment = self._storage.create_experiment(
6694
name=self.experiment_name,
6795
parameters=self.ert_config.ensemble_config.parameter_configuration,
@@ -87,11 +115,18 @@ def run_experiment(
87115
np.array(self.active_realizations, dtype=bool),
88116
ensemble=self.ensemble,
89117
)
90-
sample_prior(
91-
self.ensemble,
92-
np.where(self.active_realizations)[0],
93-
random_seed=self.random_seed,
94-
)
118+
if self.ert_config.analysis_config.design_matrix is not None:
119+
load_prior(
120+
self.ensemble,
121+
np.where(self.active_realizations)[0],
122+
self.ert_config.analysis_config.design_matrix,
123+
)
124+
else:
125+
sample_prior(
126+
self.ensemble,
127+
np.where(self.active_realizations)[0],
128+
random_seed=self.random_seed,
129+
)
95130

96131
self._evaluate_and_postprocess(
97132
run_args,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import os
2+
import stat
3+
from textwrap import dedent
4+
5+
import numpy as np
6+
import pandas as pd
7+
import pytest
8+
9+
from ert.config import ErtConfig
10+
from ert.mode_definitions import ENSEMBLE_EXPERIMENT_MODE
11+
from ert.storage import open_storage
12+
from tests.ert.ui_tests.cli.run_cli import run_cli
13+
14+
15+
@pytest.mark.usefixtures("copy_poly_case")
16+
def test_run_poly_example_with_design_matrix():
17+
design_matrix = "poly_design.xlsx"
18+
num_realizations = 10
19+
a_values = list(range(num_realizations))
20+
design_matrix_df = pd.DataFrame(
21+
{
22+
"REAL": list(range(num_realizations)),
23+
"a": a_values,
24+
}
25+
)
26+
default_sheet_df = pd.DataFrame([["b", 1], ["c", 2]])
27+
with pd.ExcelWriter(design_matrix) as xl_write:
28+
design_matrix_df.to_excel(xl_write, index=False, sheet_name="DesignSheet01")
29+
default_sheet_df.to_excel(
30+
xl_write, index=False, sheet_name="DefaultSheet", header=False
31+
)
32+
33+
with open("poly.ert", "w", encoding="utf-8") as fout:
34+
fout.write(
35+
dedent(
36+
"""\
37+
QUEUE_OPTION LOCAL MAX_RUNNING 10
38+
RUNPATH poly_out/realization-<IENS>/iter-<ITER>
39+
NUM_REALIZATIONS 10
40+
MIN_REALIZATIONS 1
41+
GEN_DATA POLY_RES RESULT_FILE:poly.out
42+
DESIGN_MATRIX poly_design.xlsx DESIGN_SHEET:DesignSheet01 DEFAULT_SHEET:DefaultSheet
43+
INSTALL_JOB poly_eval POLY_EVAL
44+
FORWARD_MODEL poly_eval
45+
"""
46+
)
47+
)
48+
49+
with open("poly_eval.py", "w", encoding="utf-8") as f:
50+
f.write(
51+
dedent(
52+
"""\
53+
#!/usr/bin/env python
54+
import numpy as np
55+
import sys
56+
import json
57+
58+
def _load_coeffs(filename):
59+
with open(filename, encoding="utf-8") as f:
60+
return json.load(f)["DESIGN_MATRIX"]
61+
62+
def _evaluate(coeffs, x):
63+
return coeffs["a"] * x**2 + coeffs["b"] * x + coeffs["c"]
64+
65+
if __name__ == "__main__":
66+
coeffs = _load_coeffs("parameters.json")
67+
output = [_evaluate(coeffs, x) for x in range(10)]
68+
with open("poly.out", "w", encoding="utf-8") as f:
69+
f.write("\\n".join(map(str, output)))
70+
"""
71+
)
72+
)
73+
os.chmod(
74+
"poly_eval.py",
75+
os.stat("poly_eval.py").st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,
76+
)
77+
78+
run_cli(
79+
ENSEMBLE_EXPERIMENT_MODE,
80+
"--disable-monitor",
81+
"poly.ert",
82+
"--experiment-name",
83+
"test-experiment",
84+
)
85+
storage_path = ErtConfig.from_file("poly.ert").ens_path
86+
with open_storage(storage_path) as storage:
87+
experiment = storage.get_experiment_by_name("test-experiment")
88+
params = experiment.get_ensemble_by_name("default").load_parameters(
89+
"DESIGN_MATRIX"
90+
)["values"]
91+
np.testing.assert_array_equal(params[:, 0], a_values)
92+
np.testing.assert_array_equal(params[:, 1], 10 * [1])
93+
np.testing.assert_array_equal(params[:, 2], 10 * [2])

0 commit comments

Comments
 (0)