Skip to content

Commit

Permalink
Add design matrix valudation in ensemble experiment panel
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
xjules committed Oct 17, 2024
1 parent 74e401e commit 56d3330
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 8 deletions.
22 changes: 22 additions & 0 deletions src/ert/enkf_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Mapping, Optional, Union

import orjson
import xarray as xr
from numpy.random import SeedSequence

from .config import (
DesignMatrix,
ExtParamConfig,
Field,
GenKwConfig,
Expand Down Expand Up @@ -148,6 +150,26 @@ def _seed_sequence(seed: Optional[int]) -> int:
return int_seed


def load_prior(
ensemble: Ensemble, active_realizations: Iterable[int], design_matrix: DesignMatrix
) -> None:
assert design_matrix.parameter_configuration is not None
assert (
design_matrix.design_matrix_df is not None
and not design_matrix.design_matrix_df.empty
)
for realization_nr in active_realizations:
row = design_matrix.design_matrix_df.loc[realization_nr]["DESIGN_MATRIX"]
ds = xr.Dataset(
{
"values": ("names", list(row.values)),
"transformed_values": ("names", list(row.values)),
"names": list(row.keys()),
}
)
ensemble.save_parameters("DESIGN_MATRIX", realization_nr, ds)


def sample_prior(
ensemble: Ensemble,
active_realizations: Iterable[int],
Expand Down
9 changes: 8 additions & 1 deletion src/ert/gui/simulation/ensemble_experiment_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from ert.gui.tools.design_matrix.design_matrix_panel import DesignMatrixPanel
from ert.mode_definitions import ENSEMBLE_EXPERIMENT_MODE
from ert.run_models import EnsembleExperiment
from ert.validation import RangeStringArgument
from ert.validation import ActiveRange, RangeStringArgument
from ert.validation.proper_name_argument import ExperimentValidation, ProperNameArgument

from .experiment_config_panel import ExperimentConfigPanel
Expand Down Expand Up @@ -85,6 +85,13 @@ def __init__(

design_matrix = analysis_config.design_matrix
if design_matrix is not None:
if design_matrix.design_matrix_df is None:
design_matrix.read_design_matrix()

if design_matrix.active_realizations:
self._active_realizations_field.setText(
ActiveRange(design_matrix.active_realizations).rangestring
)
show_dm_param_button = QPushButton("Show parameters")
show_dm_param_button.setObjectName("show-dm-parameters")
show_dm_param_button.setMinimumWidth(50)
Expand Down
48 changes: 41 additions & 7 deletions src/ert/run_models/ensemble_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import numpy as np

from ert.enkf_main import sample_prior
from ert.enkf_main import load_prior, sample_prior
from ert.ensemble_evaluator import EvaluatorServerConfig
from ert.storage import Ensemble, Experiment, Storage

Expand Down Expand Up @@ -61,7 +61,34 @@ def run_experiment(
restart: bool = False,
) -> None:
self.log_at_startup()
if not restart:
# sensitivity analysis
if self.ert_config.analysis_config.design_matrix is not None:
if (
self.ert_config.analysis_config.design_matrix.parameter_configuration
is None
):
self.ert_config.analysis_config.design_matrix.read_design_matrix()
assert (
self.ert_config.analysis_config.design_matrix.parameter_configuration
is not None
)
parameters_config = [
self.ert_config.analysis_config.design_matrix.parameter_configuration[
"DESIGN_MATRIX"
]
]
self.experiment = self._storage.create_experiment(
name=self.experiment_name,
parameters=parameters_config,
observations=self.ert_config.observations,
responses=self.ert_config.ensemble_config.response_configuration,
)
self.ensemble = self._storage.create_ensemble(
self.experiment,
name=self.ensemble_name,
ensemble_size=self.ensemble_size,
)
elif not restart:
self.experiment = self._storage.create_experiment(
name=self.experiment_name,
parameters=self.ert_config.ensemble_config.parameter_configuration,
Expand All @@ -87,11 +114,18 @@ def run_experiment(
np.array(self.active_realizations, dtype=bool),
ensemble=self.ensemble,
)
sample_prior(
self.ensemble,
np.where(self.active_realizations)[0],
random_seed=self.random_seed,
)
if self.ert_config.analysis_config.design_matrix is not None:
load_prior(
self.ensemble,
np.where(self.active_realizations)[0],
self.ert_config.analysis_config.design_matrix,
)
else:
sample_prior(
self.ensemble,
np.where(self.active_realizations)[0],
random_seed=self.random_seed,
)

self._evaluate_and_postprocess(
run_args,
Expand Down
93 changes: 93 additions & 0 deletions tests/ert/ui_tests/cli/analysis/test_design_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import os
import stat
from textwrap import dedent

import numpy as np
import pandas as pd
import pytest

from ert.config import ErtConfig
from ert.mode_definitions import ENSEMBLE_EXPERIMENT_MODE
from ert.storage import open_storage
from tests.ert.ui_tests.cli.run_cli import run_cli


@pytest.mark.usefixtures("copy_poly_case")
def test_run_poly_example_with_design_matrix():
design_matrix = "poly_design.xlsx"
num_realizations = 10
a_values = list(range(num_realizations))
design_matrix_df = pd.DataFrame(
{
"REAL": list(range(num_realizations)),
"a": a_values,
}
)
default_sheet_df = pd.DataFrame([["b", 1], ["c", 2]])
with pd.ExcelWriter(design_matrix) as xl_write:
design_matrix_df.to_excel(xl_write, index=False, sheet_name="DesignSheet01")
default_sheet_df.to_excel(
xl_write, index=False, sheet_name="DefaultSheet", header=False
)

with open("poly.ert", "w", encoding="utf-8") as fout:
fout.write(
dedent(
"""\
QUEUE_OPTION LOCAL MAX_RUNNING 10
RUNPATH poly_out/realization-<IENS>/iter-<ITER>
NUM_REALIZATIONS 10
MIN_REALIZATIONS 1
GEN_DATA POLY_RES RESULT_FILE:poly.out
DESIGN_MATRIX poly_design.xlsx DESIGN_SHEET:DesignSheet01 DEFAULT_SHEET:DefaultSheet
INSTALL_JOB poly_eval POLY_EVAL
FORWARD_MODEL poly_eval
"""
)
)

with open("poly_eval.py", "w", encoding="utf-8") as f:
f.write(
dedent(
"""\
#!/usr/bin/env python
import numpy as np
import sys
import json
def _load_coeffs(filename):
with open(filename, encoding="utf-8") as f:
return json.load(f)["DESIGN_MATRIX"]
def _evaluate(coeffs, x):
return coeffs["a"] * x**2 + coeffs["b"] * x + coeffs["c"]
if __name__ == "__main__":
coeffs = _load_coeffs("parameters.json")
output = [_evaluate(coeffs, x) for x in range(10)]
with open("poly.out", "w", encoding="utf-8") as f:
f.write("\\n".join(map(str, output)))
"""
)
)
os.chmod(
"poly_eval.py",
os.stat("poly_eval.py").st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,
)

run_cli(
ENSEMBLE_EXPERIMENT_MODE,
"--disable-monitor",
"poly.ert",
"--experiment-name",
"test-experiment",
)
storage_path = ErtConfig.from_file("poly.ert").ens_path
with open_storage(storage_path) as storage:
experiment = storage.get_experiment_by_name("test-experiment")
params = experiment.get_ensemble_by_name("default").load_parameters(
"DESIGN_MATRIX"
)["values"]
np.testing.assert_array_equal(params[:, 0], a_values)
np.testing.assert_array_equal(params[:, 1], 10 * [1])
np.testing.assert_array_equal(params[:, 2], 10 * [2])

0 comments on commit 56d3330

Please sign in to comment.