diff --git a/src/ert/config/analysis_module.py b/src/ert/config/analysis_module.py
index fa09588abc7..5281966a4e0 100644
--- a/src/ert/config/analysis_module.py
+++ b/src/ert/config/analysis_module.py
@@ -86,7 +86,7 @@ def correlation_threshold(self, ensemble_size: int) -> float:
Section 2.3 - Localization in the CHOP problem
"""
if self.localization_correlation_threshold is None:
- return 3 / math.sqrt(ensemble_size)
+ return min(1.0, 3 / math.sqrt(ensemble_size))
return self.localization_correlation_threshold
diff --git a/src/ert/gui/ertwidgets/analysismoduleedit.py b/src/ert/gui/ertwidgets/analysismoduleedit.py
index 82e4258a5c3..990eaee917c 100644
--- a/src/ert/gui/ertwidgets/analysismoduleedit.py
+++ b/src/ert/gui/ertwidgets/analysismoduleedit.py
@@ -1,35 +1,42 @@
from __future__ import annotations
-from typing import TYPE_CHECKING
+from collections import defaultdict
from PyQt6.QtCore import QMargins, Qt
-from PyQt6.QtWidgets import QHBoxLayout, QPushButton, QWidget
+from PyQt6.QtWidgets import (
+ QDialog,
+ QDialogButtonBox,
+ QHBoxLayout,
+ QPushButton,
+ QVBoxLayout,
+ QWidget,
+)
+from ert.config import ESSettings, LocalizationType, ParameterConfig
from ert.gui.icon_utils import load_icon
from .analysismodulevariablespanel import AnalysisModuleVariablesPanel
-from .closabledialog import ClosableDialog
-
-if TYPE_CHECKING:
- from ert.config import AnalysisModule
class AnalysisModuleEdit(QWidget):
def __init__(
self,
- analysis_module: AnalysisModule,
+ es_settings: ESSettings,
+ parameter_config: list[ParameterConfig],
ensemble_size: int,
) -> None:
- self.analysis_module = analysis_module
- self.ensemble_size = ensemble_size
QWidget.__init__(self)
+ self._es_settings: ESSettings = es_settings
+ self._parameter_config: list[ParameterConfig] = parameter_config
+ self._ensemble_size: int = ensemble_size
+
layout = QHBoxLayout()
variables_popup_button = QPushButton("Edit")
variables_popup_button.setObjectName("analysis_variables_popup_button")
variables_popup_button.setIcon(load_icon("edit.svg"))
- variables_popup_button.clicked.connect(self.showVariablesPopup)
+ variables_popup_button.clicked.connect(self._show_update_settings_dialog)
layout.addWidget(variables_popup_button, 0, Qt.AlignmentFlag.AlignLeft)
layout.setContentsMargins(QMargins(0, 0, 0, 0))
@@ -37,13 +44,77 @@ def __init__(
self.setLayout(layout)
- def showVariablesPopup(self) -> None:
- variable_dialog = AnalysisModuleVariablesPanel(
- self.analysis_module, self.ensemble_size
+ @property
+ def parameter_config(self) -> list[ParameterConfig]:
+ return self._parameter_config
+
+ @parameter_config.setter
+ def parameter_config(self, value: list[ParameterConfig]) -> None:
+ self._parameter_config = value
+
+ def _show_update_settings_dialog(self) -> None:
+ dialog = QDialog(self.parent()) # type: ignore
+ dialog.setWindowTitle("Update settings")
+ dialog.setModal(True)
+ dialog.setWindowFlag(Qt.WindowType.CustomizeWindowHint, True)
+ dialog.setWindowFlag(Qt.WindowType.WindowContextHelpButtonHint, False)
+ dialog.setWindowFlag(Qt.WindowType.WindowCloseButtonHint, False)
+
+ layout = QVBoxLayout()
+
+ update_strategies: dict[str, LocalizationType] = defaultdict(
+ lambda: LocalizationType.GLOBAL
+ )
+ for parameter_config in self._parameter_config:
+ if parameter_config.update_strategy:
+ update_strategies[parameter_config.type.upper()] = (
+ parameter_config.update_strategy
+ )
+
+ correlation_threshold = 1.0
+ if self._ensemble_size != 0:
+ correlation_threshold = self._es_settings.correlation_threshold(
+ self._ensemble_size
+ )
+
+ update_settings_dialog = AnalysisModuleVariablesPanel(
+ update_strategies=update_strategies,
+ correlation_threshold=correlation_threshold,
+ enkf_truncation=self._es_settings.enkf_truncation,
)
- dialog = ClosableDialog(
- "Edit variables",
- variable_dialog,
- self.parent(), # type: ignore
+
+ layout.addWidget(update_settings_dialog, stretch=1)
+
+ button_box = QDialogButtonBox(
+ QDialogButtonBox.StandardButton.Save
+ | QDialogButtonBox.StandardButton.Cancel
)
- dialog.exec()
+ save_button = button_box.button(QDialogButtonBox.StandardButton.Save)
+ assert save_button is not None
+ save_button.setAutoDefault(False)
+ cancel_button = button_box.button(QDialogButtonBox.StandardButton.Cancel)
+ assert cancel_button is not None
+ cancel_button.setAutoDefault(False)
+ button_box.accepted.connect(dialog.accept)
+ button_box.rejected.connect(dialog.reject)
+
+ button_layout = QHBoxLayout()
+ button_layout.addStretch()
+ button_layout.addWidget(button_box)
+ layout.addLayout(button_layout)
+
+ dialog.setLayout(layout)
+ dialog.setFixedSize(450, 300)
+
+ if dialog.exec() == QDialog.DialogCode.Accepted:
+ self._es_settings.localization_correlation_threshold = (
+ update_settings_dialog.correlation_threshold
+ )
+ self._es_settings.enkf_truncation = update_settings_dialog.enkf_truncation
+ for name, strategy in update_settings_dialog.update_strategies.items():
+ for parameter_config in self._parameter_config:
+ if (
+ parameter_config.type.upper() == name
+ and parameter_config.update_strategy is not None
+ ):
+ parameter_config.update_strategy = strategy
diff --git a/src/ert/gui/ertwidgets/analysismodulevariablespanel.py b/src/ert/gui/ertwidgets/analysismodulevariablespanel.py
index f7d68a402bf..dc05f1c8c30 100644
--- a/src/ert/gui/ertwidgets/analysismodulevariablespanel.py
+++ b/src/ert/gui/ertwidgets/analysismodulevariablespanel.py
@@ -1,55 +1,157 @@
from __future__ import annotations
-from functools import partial
from typing import cast
from annotated_types import Ge, Gt, Le
+from PyQt6.QtCore import Qt
+from PyQt6.QtGui import QStandardItem, QStandardItemModel
from PyQt6.QtWidgets import (
+ QComboBox,
QDoubleSpinBox,
QFormLayout,
+ QLabel,
QWidget,
)
-from ert.config import AnalysisModule
+from ert.config import AnalysisModule, LocalizationType
+
+
+class _LocalizationTypeModel(QStandardItemModel):
+ def __init__(self, exclude: set[LocalizationType] | None = None) -> None:
+ super().__init__()
+
+ type_set = set(LocalizationType)
+ if exclude is not None:
+ type_set -= exclude
+
+ for localization_type in sorted(type_set, key=lambda lt: lt.name):
+ item = QStandardItem(localization_type.name)
+ item.setData(localization_type, Qt.ItemDataRole.UserRole)
+ self.appendRow(item)
class AnalysisModuleVariablesPanel(QWidget):
- def __init__(self, analysis_module: AnalysisModule, ensemble_size: int) -> None:
+ def __init__(
+ self,
+ update_strategies: dict[str, LocalizationType],
+ correlation_threshold: float,
+ enkf_truncation: float,
+ ) -> None:
QWidget.__init__(self)
- self.analysis_module = analysis_module
- layout = QFormLayout()
+ self._update_strategies = update_strategies
+ self._correlation_threshold = correlation_threshold
+ self._enkf_truncation = enkf_truncation
+ layout = QFormLayout()
self.blockSignals(True)
+ layout.addRow(
+ QLabel("Select the localization method for each parameter type")
+ )
+
+ gen_kw_combobox = QComboBox(self)
+ gen_kw_combobox.setModel(
+ _LocalizationTypeModel(exclude={LocalizationType.DISTANCE})
+ )
+ gen_kw_combobox.setCurrentIndex(
+ self._find_correct_index(gen_kw_combobox, "GEN_KW")
+ )
+ gen_kw_combobox.currentIndexChanged.connect(
+ lambda index: self._update_strategies.__setitem__(
+ "GEN_KW",
+ gen_kw_combobox.itemData(index, Qt.ItemDataRole.UserRole),
+ )
+ )
+ layout.addRow("GEN_KW", gen_kw_combobox)
+
+ field_combobox = QComboBox(self)
+ field_combobox.setModel(_LocalizationTypeModel())
+ field_combobox.setCurrentIndex(
+ self._find_correct_index(field_combobox, "FIELD")
+ )
+ field_combobox.currentIndexChanged.connect(
+ lambda index: self._update_strategies.__setitem__(
+ "FIELD",
+ field_combobox.itemData(index, Qt.ItemDataRole.UserRole),
+ )
+ )
+ layout.addRow("FIELD", field_combobox)
+
+ surface_combobox = QComboBox(self)
+ surface_combobox.setModel(_LocalizationTypeModel())
+ surface_combobox.setCurrentIndex(
+ self._find_correct_index(surface_combobox, "SURFACE")
+ )
+ surface_combobox.currentIndexChanged.connect(
+ lambda index: self._update_strategies.__setitem__(
+ "SURFACE",
+ surface_combobox.itemData(index, Qt.ItemDataRole.UserRole),
+ )
+ )
+ layout.addRow("SURFACE", surface_combobox)
+
+ layout.addRow(QLabel("General settings"))
+
var_name = "enkf_truncation"
metadata = AnalysisModule.model_fields[var_name]
- self.truncation_spinner = self.createDoubleSpinBox(
+ self.truncation_spinner = self._create_double_spinbox(
var_name,
- analysis_module.enkf_truncation,
+ self._enkf_truncation,
cast(float, next(v for v in metadata.metadata if isinstance(v, Gt)).gt)
+ 0.001,
cast(float, next(v for v in metadata.metadata if isinstance(v, Le)).le),
0.01,
)
+ self.truncation_spinner.valueChanged.connect(
+ lambda value: setattr(self, "_enkf_truncation", value)
+ )
+
layout.addRow("Singular value truncation", self.truncation_spinner)
var_name = "localization_correlation_threshold"
metadata = AnalysisModule.model_fields[var_name]
- self.local_spinner = self.createDoubleSpinBox(
+ self.threshold_spinner = self._create_double_spinbox(
var_name,
- analysis_module.correlation_threshold(ensemble_size),
+ self._correlation_threshold,
cast(float, next(v for v in metadata.metadata if isinstance(v, Ge)).ge),
cast(float, next(v for v in metadata.metadata if isinstance(v, Le)).le),
0.1,
)
- self.local_spinner.setObjectName("localization_correlation_threshold")
- layout.addRow("Adaptive localization correlation threshold", self.local_spinner)
+ self.threshold_spinner.setObjectName("localization_correlation_threshold")
+ self.threshold_spinner.valueChanged.connect(
+ lambda value: setattr(self, "_correlation_threshold", value)
+ )
+
+ layout.addRow(
+ "Adaptive localization correlation threshold", self.threshold_spinner
+ )
self.setLayout(layout)
self.blockSignals(False)
- def createDoubleSpinBox(
+ @property
+ def update_strategies(self) -> dict[str, LocalizationType]:
+ return self._update_strategies
+
+ @property
+ def correlation_threshold(self) -> float:
+ return self._correlation_threshold
+
+ @property
+ def enkf_truncation(self) -> float:
+ return self._enkf_truncation
+
+ def _find_correct_index(self, combobox: QComboBox, type_name: str) -> int:
+ if type_name in self._update_strategies:
+ localization_type = self._update_strategies[type_name]
+ if (
+ index := combobox.findData(localization_type, Qt.ItemDataRole.UserRole)
+ ) != -1:
+ return index
+ return combobox.findData(LocalizationType.GLOBAL, Qt.ItemDataRole.UserRole)
+
+ def _create_double_spinbox(
self,
variable_name: str,
variable_value: float,
@@ -61,16 +163,10 @@ def createDoubleSpinBox(
spinner.setDecimals(6)
spinner.setFixedWidth(180)
spinner.setObjectName(variable_name)
-
spinner.setRange(
min_value,
max_value,
)
-
spinner.setSingleStep(step_length)
spinner.setValue(variable_value)
- spinner.valueChanged.connect(partial(self.valueChangedSpinner, variable_name))
return spinner
-
- def valueChangedSpinner(self, name: str, value: float) -> None:
- setattr(self.analysis_module, name, value)
diff --git a/src/ert/gui/experiments/ensemble_smoother_panel.py b/src/ert/gui/experiments/ensemble_smoother_panel.py
index 0d124a22968..72a7c839a33 100644
--- a/src/ert/gui/experiments/ensemble_smoother_panel.py
+++ b/src/ert/gui/experiments/ensemble_smoother_panel.py
@@ -95,14 +95,15 @@ def __init__(
layout.addRow("Ensemble format:", self._ensemble_format_field)
self._analysis_module_edit = AnalysisModuleEdit(
- analysis_config.es_settings,
- sum(
+ es_settings=analysis_config.es_settings,
+ parameter_config=parameter_configuration,
+ ensemble_size=sum(
active_realizations
), # only use active realizations for setting threshold
)
self._analysis_module_edit.setObjectName("ensemble_smoother_edit")
- layout.addRow("Analysis module:", self._analysis_module_edit)
+ layout.addRow("Update settings:", self._analysis_module_edit)
self._active_realizations_field = StringBox(
ActiveRealizationsModel(len(active_realizations)), # type: ignore
"config/experiment/active_realizations",
diff --git a/src/ert/gui/experiments/experiment_panel.py b/src/ert/gui/experiments/experiment_panel.py
index 6b727a9ebc7..9c938847b12 100644
--- a/src/ert/gui/experiments/experiment_panel.py
+++ b/src/ert/gui/experiments/experiment_panel.py
@@ -242,7 +242,12 @@ def __init__(
experiment_type_valid,
)
self.addExperimentConfigPanel(
- ManualUpdatePanel(run_path, notifier, analysis_config),
+ ManualUpdatePanel(
+ run_path,
+ notifier,
+ analysis_config,
+ config.ensemble_config.parameter_configuration,
+ ),
experiment_type_valid,
)
diff --git a/src/ert/gui/experiments/manual_update_panel.py b/src/ert/gui/experiments/manual_update_panel.py
index 56a1b545880..af20c6d4e72 100644
--- a/src/ert/gui/experiments/manual_update_panel.py
+++ b/src/ert/gui/experiments/manual_update_panel.py
@@ -8,7 +8,7 @@
from PyQt6.QtCore import pyqtSlot as Slot
from PyQt6.QtWidgets import QComboBox, QFormLayout, QLabel, QWidget
-from ert.config import AnalysisConfig, ErrorInfo
+from ert.config import AnalysisConfig, ErrorInfo, ParameterConfig
from ert.gui.ertnotifier import ErtNotifier
from ert.gui.ertwidgets import (
ActiveRealizationsModel,
@@ -37,6 +37,7 @@ class Arguments:
target_ensemble: str
ensemble_size: int
experiment_name: str
+ parameter_configuration: list[ParameterConfig]
class ManualUpdatePanel(ExperimentConfigPanel):
@@ -47,9 +48,11 @@ def __init__(
run_path: str,
notifier: ErtNotifier,
analysis_config: AnalysisConfig,
+ parameter_configuration: list[ParameterConfig],
) -> None:
super().__init__(ManualUpdate)
self.setObjectName("Manual_update_panel")
+ self._analysis_config = analysis_config
layout = QFormLayout()
layout.setFormAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
@@ -93,10 +96,15 @@ def show_only_with_response_data_filter(
self._ensemble_format_field.setValidator(ProperNameFormatArgument())
layout.addRow("Ensemble format:", self._ensemble_format_field)
- self._analysis_module_edit = AnalysisModuleEdit(analysis_config.es_settings, 0)
+ self._analysis_module_edit = AnalysisModuleEdit(
+ es_settings=analysis_config.es_settings,
+ parameter_config=parameter_configuration,
+ ensemble_size=0,
+ )
self._analysis_module_edit.setObjectName("ensemble_smoother_edit")
self._analysis_module_edit.setEnabled(False)
- layout.addRow("Analysis module:", self._analysis_module_edit)
+
+ layout.addRow("Update settings:", self._analysis_module_edit)
self._active_realizations_model = ActiveRealizationsModel(0, show_default=False)
self._active_realizations_field = StringBox(
self._active_realizations_model, # type: ignore
@@ -105,6 +113,9 @@ def show_only_with_response_data_filter(
self._active_realizations_field.setObjectName("active_realizations_box")
self._realizations_from_fs()
layout.addRow("Active realizations", self._active_realizations_field)
+ self._active_realizations_field.getValidationSupport().validationChanged.connect(
+ self.experiment_configuration_changed
+ )
self._experiment_name_field = StringBox(
TextModel(""),
@@ -123,20 +134,31 @@ def show_only_with_response_data_filter(
)
)
- self._active_realizations_field.getValidationSupport().validationChanged.connect(
- self.experiment_configuration_changed
- )
self._ensemble_selector.ensemble_populated.connect(self._realizations_from_fs)
self._ensemble_selector.ensemble_populated.connect(
self.experiment_configuration_changed
)
+ self._ensemble_selector.ensemble_populated.connect(
+ self._parameter_configuration_changed
+ )
+
self._ensemble_selector.currentIndexChanged.connect(self._realizations_from_fs)
+ self._ensemble_selector.currentIndexChanged.connect(
+ self._parameter_configuration_changed
+ )
+
self.setLayout(layout)
@property
def selected_update_method(self) -> str:
return self._update_method_dropdown.currentText()
+ def _parameter_configuration_changed(self) -> None:
+ if self._ensemble_selector.selected_ensemble is not None:
+ self._analysis_module_edit.parameter_config = list(
+ self._ensemble_selector.selected_ensemble.experiment.parameter_configuration.values()
+ )
+
@Slot(str)
def _on_update_method_changed(self, new_method: str) -> None:
if new_method == "ES Update":
@@ -164,6 +186,7 @@ def get_experiment_arguments(self) -> Arguments:
target_ensemble=self._ensemble_format_model.getValue(), # type: ignore
ensemble_size=self._ensemble_size,
experiment_name=self._experiment_name_field.get_text,
+ parameter_configuration=self._analysis_module_edit.parameter_config,
)
def _realizations_from_fs(self) -> None:
@@ -193,7 +216,8 @@ def _realizations_from_fs(self) -> None:
active_realizations_size = sum(
self._active_realizations_model.getActiveRealizationsMask()
)
- self._analysis_module_edit.ensemble_size = active_realizations_size
+ self._analysis_module_edit._ensemble_size = active_realizations_size
+
self._analysis_module_edit.setEnabled(bool(active_realizations_size))
except OSError as err:
logger.error(str(err))
diff --git a/src/ert/gui/experiments/multiple_data_assimilation_panel.py b/src/ert/gui/experiments/multiple_data_assimilation_panel.py
index e4ea9f57acb..537c787bb4f 100644
--- a/src/ert/gui/experiments/multiple_data_assimilation_panel.py
+++ b/src/ert/gui/experiments/multiple_data_assimilation_panel.py
@@ -53,6 +53,8 @@
from ert.config import AnalysisConfig
from ert.storage import Ensemble
+
+
logger = logging.getLogger(__name__)
@@ -64,6 +66,7 @@ class Arguments:
weights: str
prior_ensemble_id: str | None # UUID not serializable in json
experiment_name: str
+ parameter_configuration: list[ParameterConfig]
class MultipleDataAssimilationPanel(ExperimentConfigPanel):
@@ -77,6 +80,7 @@ def __init__(
config_num_realization: int,
) -> None:
super().__init__(MultipleDataAssimilation)
+
self.notifier = notifier
self._configured_weights = analysis_config.es_settings.weights
self._weights_source = self._configured_weights
@@ -128,12 +132,14 @@ def __init__(
self._createInputForWeights(layout)
self._analysis_module_edit = AnalysisModuleEdit(
- analysis_config.es_settings,
- sum(
+ es_settings=analysis_config.es_settings,
+ parameter_config=parameter_configuration,
+ ensemble_size=sum(
active_realizations
), # only use active realizations for setting threshold
)
- layout.addRow("Analysis module:", self._analysis_module_edit)
+ layout.addRow("Update settings:", self._analysis_module_edit)
+
self._active_realizations_field = StringBox(
ActiveRealizationsModel(len(active_realizations)), # type: ignore
"config/experiment/active_realizations",
@@ -206,8 +212,15 @@ def get_ensembles_of_ensemble_experiment_type(
layout.addRow("Select prior ensemble:", self._select_prior_ensemble_box)
self._ensemble_selector.ensemble_populated.connect(self.select_prior_toggled)
+ self._ensemble_selector.ensemble_populated.connect(
+ self._parameter_configuration_changed
+ )
self._ensemble_selector.currentIndexChanged.connect(self._realizations_from_fs)
+ self._ensemble_selector.currentIndexChanged.connect(
+ self._parameter_configuration_changed
+ )
self._ensemble_selector.currentIndexChanged.connect(self.update_experiment_name)
+
layout.addRow("Run from prior ensemble:", self._ensemble_selector)
self._experiment_name_field.getValidationSupport().validationChanged.connect(
@@ -256,6 +269,12 @@ def _update_experiment_name_placeholder(self) -> None:
self.notifier.storage.get_unique_experiment_name(ES_MDA_MODE)
)
+ def _parameter_configuration_changed(self) -> None:
+ if self._ensemble_selector.selected_ensemble is not None:
+ self._analysis_module_edit.parameter_config = list(
+ self._ensemble_selector.selected_ensemble.experiment.parameter_configuration.values()
+ )
+
@Slot()
def update_experiment_name(self) -> None:
if not self._experiment_name_field.isEnabled():
@@ -428,6 +447,7 @@ def get_experiment_arguments(self) -> Arguments:
else None
),
experiment_name=self._experiment_name_field.get_text,
+ parameter_configuration=self._analysis_module_edit.parameter_config,
)
def setWeights(self, weights: Any) -> None:
diff --git a/src/ert/run_models/model_factory.py b/src/ert/run_models/model_factory.py
index 203c5999b30..96f09014207 100644
--- a/src/ert/run_models/model_factory.py
+++ b/src/ert/run_models/model_factory.py
@@ -319,6 +319,11 @@ def _setup_manual_update(
ert_templates=config.ert_templates,
shape_registry=config.shape_registry,
experiment_name=args.experiment_name,
+ parameter_configuration=getattr(
+ args,
+ "parameter_configuration",
+ config.ensemble_config.parameter_configuration,
+ ),
)
return ManualUpdate(**runmodel_config.model_dump(), status_queue=status_queue)
@@ -355,6 +360,7 @@ def _setup_manual_update_enif(
ert_templates=config.ert_templates,
shape_registry=config.shape_registry,
experiment_name=args.experiment_name,
+ parameter_configuration=args.parameter_configuration,
)
return ManualUpdateEnIF(**runmodel_config.model_dump(), status_queue=status_queue)
@@ -488,7 +494,11 @@ def _setup_multiple_data_assimilation(
parameter_configs, design_matrix = _merge_parameters(
design_matrix=None if prior_ensemble else config.analysis_config.design_matrix,
- parameter_configs=config.ensemble_config.parameter_configuration,
+ parameter_configs=getattr(
+ args,
+ "parameter_configuration",
+ config.ensemble_config.parameter_configuration,
+ ),
require_updateable_param=True,
)
diff --git a/src/ert/run_models/run_model_configs.py b/src/ert/run_models/run_model_configs.py
index e3807c20bef..dfe0583216e 100644
--- a/src/ert/run_models/run_model_configs.py
+++ b/src/ert/run_models/run_model_configs.py
@@ -304,6 +304,12 @@ class ManualUpdateConfig(UpdateRunModelConfig):
ert_templates: list[tuple[str, str]]
shape_registry: ShapeRegistry | None = None
experiment_name: str
+ parameter_configuration: list[
+ Annotated[
+ (GenKwConfig | SurfaceConfig | FieldConfig | EverestControl),
+ Field(discriminator="type"),
+ ]
+ ]
def to_experiment_config(
self, *, prior_experiment_config: ExperimentConfig
@@ -315,9 +321,9 @@ def to_experiment_config(
"ensemble_id": self.ensemble_id,
"ert_templates": self.ert_templates,
**self._update_experiment_config(),
- "parameter_configuration": prior_experiment_config.get(
- "parameter_configuration", []
- ),
+ "parameter_configuration": [
+ param.model_dump(mode="json") for param in self.parameter_configuration
+ ],
"response_configuration": prior_experiment_config.get(
"response_configuration", []
),
diff --git a/tests/ert/ui_tests/cli/test_run_prior_esmda.py b/tests/ert/ui_tests/cli/test_run_prior_esmda.py
index 8e6ff70dbcd..1e708042e1b 100644
--- a/tests/ert/ui_tests/cli/test_run_prior_esmda.py
+++ b/tests/ert/ui_tests/cli/test_run_prior_esmda.py
@@ -227,6 +227,7 @@ def _build_esmda_run_prior_model(prior_ensemble_id: str):
weights="1,1",
prior_ensemble_id=prior_ensemble_id,
experiment_name="restart-experiment",
+ parameter_configuration=[],
),
SimpleQueue(),
)
diff --git a/tests/ert/ui_tests/gui/test_main_window.py b/tests/ert/ui_tests/gui/test_main_window.py
index e22435f033c..2c013faa178 100644
--- a/tests/ert/ui_tests/gui/test_main_window.py
+++ b/tests/ert/ui_tests/gui/test_main_window.py
@@ -14,7 +14,6 @@
from PyQt6.QtWidgets import (
QCheckBox,
QComboBox,
- QDoubleSpinBox,
QLabel,
QMenuBar,
QMessageBox,
@@ -34,7 +33,6 @@
StringBox,
Suggestor,
)
-from ert.gui.ertwidgets.analysismodulevariablespanel import AnalysisModuleVariablesPanel
from ert.gui.ertwidgets.suggestor._suggestor_message import SuggestorMessage
from ert.gui.experiments import ExperimentPanel, RunDialog
from ert.gui.main import ErtMainWindow, GUILogHandler, _setup_main_window
@@ -490,29 +488,6 @@ def handle_add_dialog():
qtbot.mouseClick(initialize_button, Qt.MouseButton.LeftButton)
-def test_that_truncation_can_be_set_from_gui(qtbot, opened_main_window_poly):
- gui = opened_main_window_poly
-
- sim_mode = get_child(gui, QWidget, name="experiment_type")
- qtbot.keyClick(sim_mode, Qt.Key.Key_Down)
- es_panel = get_child(gui, QWidget, name="ensemble_smoother_panel")
- es_edit = get_child(es_panel, QWidget, name="ensemble_smoother_edit")
-
- # Testing modal dialogs requires some care.
- # https://github.com/pytest-dev/pytest-qt/issues/256
- def handle_analysis_module_panel():
- var_panel = wait_for_child(gui, qtbot, AnalysisModuleVariablesPanel)
- spinner = wait_for_child(var_panel, qtbot, QDoubleSpinBox, "enkf_truncation")
- assert spinner.isEnabled()
-
- var_panel.parent().close()
-
- QTimer.singleShot(500, handle_analysis_module_panel)
- qtbot.mouseClick(
- get_child(es_edit, QPushButton), Qt.MouseButton.LeftButton, delay=1
- )
-
-
def test_that_the_manage_experiments_tool_can_be_used_with_clean_storage(
opened_main_window_poly, qtbot
):
diff --git a/tests/ert/unit_tests/config/test_analysis_module.py b/tests/ert/unit_tests/config/test_analysis_module.py
new file mode 100644
index 00000000000..a352ee39b97
--- /dev/null
+++ b/tests/ert/unit_tests/config/test_analysis_module.py
@@ -0,0 +1,24 @@
+import math
+
+import pytest
+
+from ert.config.analysis_module import ESSettings
+
+
+@pytest.mark.parametrize(
+ ("settings", "ensemble_size", "expected_threshold"),
+ [
+ (ESSettings(), 4, 1.0),
+ (ESSettings(), 8, 1.0),
+ (ESSettings(), 9, 1.0),
+ (ESSettings(), 36, 0.5),
+ (ESSettings(), 200, 3 / math.sqrt(200)),
+ (ESSettings(localization_correlation_threshold=0.2), 9, 0.2),
+ ],
+)
+def test_that_correlation_threshold_uses_default_or_custom_value(
+ settings, ensemble_size, expected_threshold
+):
+ assert settings.correlation_threshold(ensemble_size) == pytest.approx(
+ expected_threshold
+ )
diff --git a/tests/ert/unit_tests/gui/ertwidgets/test_analysismoduleedit.py b/tests/ert/unit_tests/gui/ertwidgets/test_analysismoduleedit.py
new file mode 100644
index 00000000000..7edfb54bb62
--- /dev/null
+++ b/tests/ert/unit_tests/gui/ertwidgets/test_analysismoduleedit.py
@@ -0,0 +1,161 @@
+import pytest
+from PyQt6.QtCore import Qt, QTimer
+from PyQt6.QtWidgets import QApplication, QDialog, QPushButton
+from pytestqt.qtbot import QtBot
+
+from ert.config import ESSettings, GenKwConfig, LocalizationType
+from ert.gui.ertwidgets.analysismoduleedit import AnalysisModuleEdit
+from ert.gui.ertwidgets.analysismodulevariablespanel import AnalysisModuleVariablesPanel
+
+
+def test_that_click_opens_the_correct_dialog(qtbot: QtBot):
+ widget = AnalysisModuleEdit(
+ es_settings=ESSettings(), parameter_config=[], ensemble_size=10
+ )
+ qtbot.addWidget(widget)
+
+ def inspect_and_close_dialog() -> None:
+ dialog = QApplication.activeModalWidget()
+ assert dialog is not None
+ assert isinstance(dialog, QDialog)
+
+ panel = dialog.findChild(AnalysisModuleVariablesPanel)
+ assert panel is not None
+ dialog.reject()
+
+ QTimer.singleShot(0, inspect_and_close_dialog)
+
+ button = widget.findChild(QPushButton)
+ assert button is not None
+ qtbot.mouseClick(button, Qt.MouseButton.LeftButton)
+
+
+def test_that_settings_are_updated_correctly(qtbot: QtBot):
+ es_settings = ESSettings()
+ es_settings.localization_correlation_threshold = 0.5
+ es_settings.enkf_truncation = 0.2
+ ensemble_size = 10
+ parameter = GenKwConfig(
+ name="name",
+ distribution={"name": "uniform", "min": 0, "max": 1},
+ update_strategy=LocalizationType.GLOBAL,
+ )
+ parameter_config = [parameter]
+
+ widget = AnalysisModuleEdit(
+ es_settings=es_settings,
+ parameter_config=parameter_config,
+ ensemble_size=ensemble_size,
+ )
+ qtbot.addWidget(widget)
+
+ def inspect_and_accept_dialog() -> None:
+
+ dialog = QApplication.activeModalWidget()
+ assert dialog is not None
+ assert isinstance(dialog, QDialog)
+
+ panel = dialog.findChild(AnalysisModuleVariablesPanel)
+ assert panel is not None
+
+ # Update settings in the panel
+ panel._correlation_threshold = 0.7
+ panel._enkf_truncation = 0.3
+ panel._update_strategies["GEN_KW"] = LocalizationType.ADAPTIVE
+
+ dialog.accept()
+
+ QTimer.singleShot(0, inspect_and_accept_dialog)
+
+ button = widget.findChild(QPushButton)
+ assert button is not None
+ qtbot.mouseClick(button, Qt.MouseButton.LeftButton)
+
+ # After the dialog is accepted, check that the settings are updated
+ assert pytest.approx(es_settings.localization_correlation_threshold) == 0.7
+ assert pytest.approx(es_settings.enkf_truncation) == 0.3
+ assert widget._parameter_config[0].update_strategy == LocalizationType.ADAPTIVE
+
+
+def test_that_only_gen_kw_parameters_with_update_strategy_are_updated(qtbot: QtBot):
+ parameter_without_strategy = GenKwConfig(
+ name="without_strategy",
+ distribution={"name": "uniform", "min": 0, "max": 1},
+ update_strategy=None,
+ )
+ parameter_with_strategy = GenKwConfig(
+ name="with_strategy",
+ distribution={"name": "uniform", "min": 0, "max": 1},
+ update_strategy=LocalizationType.GLOBAL,
+ )
+
+ widget = AnalysisModuleEdit(
+ es_settings=ESSettings(),
+ parameter_config=[parameter_without_strategy, parameter_with_strategy],
+ ensemble_size=10,
+ )
+ qtbot.addWidget(widget)
+
+ def select_adaptive_strategy_and_accept_dialog() -> None:
+ dialog = QApplication.activeModalWidget()
+ assert isinstance(dialog, QDialog)
+
+ panel = dialog.findChild(AnalysisModuleVariablesPanel)
+ assert panel is not None
+ panel._update_strategies["GEN_KW"] = LocalizationType.ADAPTIVE
+ dialog.accept()
+
+ QTimer.singleShot(0, select_adaptive_strategy_and_accept_dialog)
+
+ button = widget.findChild(QPushButton)
+ assert button is not None
+ qtbot.mouseClick(button, Qt.MouseButton.LeftButton)
+
+ assert parameter_without_strategy.update_strategy is None
+ assert parameter_with_strategy.update_strategy == LocalizationType.ADAPTIVE
+
+
+def test_that_settings_are_not_updated_on_cancel(qtbot: QtBot):
+ es_settings = ESSettings()
+ es_settings.localization_correlation_threshold = 0.5
+ es_settings.enkf_truncation = 0.2
+ ensemble_size = 10
+ parameter = GenKwConfig(
+ name="name",
+ distribution={"name": "uniform", "min": 0, "max": 1},
+ update_strategy=LocalizationType.GLOBAL,
+ )
+ parameter_config = [parameter]
+
+ widget = AnalysisModuleEdit(
+ es_settings=es_settings,
+ parameter_config=parameter_config,
+ ensemble_size=ensemble_size,
+ )
+ qtbot.addWidget(widget)
+
+ def inspect_and_reject_dialog() -> None:
+ dialog = QApplication.activeModalWidget()
+ assert dialog is not None
+ assert isinstance(dialog, QDialog)
+
+ panel = dialog.findChild(AnalysisModuleVariablesPanel)
+ assert panel is not None
+
+ # Update settings in the panel
+ panel._correlation_threshold = 0.7
+ panel._enkf_truncation = 0.3
+ panel._update_strategies["GEN_KW"] = LocalizationType.ADAPTIVE
+
+ dialog.reject()
+
+ QTimer.singleShot(0, inspect_and_reject_dialog)
+
+ button = widget.findChild(QPushButton)
+ assert button is not None
+ qtbot.mouseClick(button, Qt.MouseButton.LeftButton)
+
+ # After the dialog is rejected, check that the settings are not updated
+ assert pytest.approx(es_settings.localization_correlation_threshold) == 0.5
+ assert pytest.approx(es_settings.enkf_truncation) == 0.2
+ assert widget._parameter_config[0].update_strategy == LocalizationType.GLOBAL
diff --git a/tests/ert/unit_tests/gui/ertwidgets/test_analysispanel.py b/tests/ert/unit_tests/gui/ertwidgets/test_analysispanel.py
new file mode 100644
index 00000000000..db41dfb17be
--- /dev/null
+++ b/tests/ert/unit_tests/gui/ertwidgets/test_analysispanel.py
@@ -0,0 +1,142 @@
+import math
+
+import pytest
+from PyQt6.QtWidgets import QComboBox, QDoubleSpinBox
+from pytestqt.qtbot import QtBot
+
+from ert.config import ESSettings, LocalizationType
+from ert.gui.ertwidgets.analysismodulevariablespanel import AnalysisModuleVariablesPanel
+
+
+def test_that_empty_update_strategies_are_set_to_global(qtbot: QtBot):
+ settings = ESSettings()
+ settings.localization_correlation_threshold = 0.5
+ settings.enkf_truncation = 0.2
+ update_strategies = {}
+
+ widget = AnalysisModuleVariablesPanel(
+ update_strategies=update_strategies,
+ correlation_threshold=0.5,
+ enkf_truncation=0.2,
+ )
+
+ qtbot.addWidget(widget)
+
+ comboboxes = widget.findChildren(QComboBox)
+ assert len(comboboxes) == 3
+
+ for combobox in comboboxes:
+ if (
+ combobox.objectName() == "GEN_KW"
+ or combobox.objectName() == "SURFACE"
+ or combobox.objectName() == "FIELD"
+ ):
+ assert combobox.currentData() == LocalizationType.GLOBAL
+
+
+def test_that_the_panel_initializes_with_correct_values(qtbot: QtBot):
+ settings = ESSettings()
+ settings.localization_correlation_threshold = 0.5
+ settings.enkf_truncation = 0.2
+ update_strategies = {
+ "GEN_KW": LocalizationType.GLOBAL,
+ "SURFACE": LocalizationType.DISTANCE,
+ "FIELD": LocalizationType.ADAPTIVE,
+ }
+
+ widget = AnalysisModuleVariablesPanel(
+ update_strategies=update_strategies,
+ correlation_threshold=0.5,
+ enkf_truncation=0.2,
+ )
+
+ qtbot.addWidget(widget)
+
+ correlation_spinner = widget.findChild(
+ QDoubleSpinBox, name="localization_correlation_threshold"
+ )
+ truncation_spinner = widget.findChild(QDoubleSpinBox, name="enkf_truncation")
+
+ assert math.isclose(
+ correlation_spinner.value(), settings.localization_correlation_threshold
+ )
+ assert math.isclose(truncation_spinner.value(), settings.enkf_truncation)
+
+ comboboxes = widget.findChildren(QComboBox)
+ assert len(comboboxes) == 3
+
+ for combobox in comboboxes:
+ if combobox.objectName() == "GEN_KW":
+ assert combobox.currentData() == LocalizationType.GLOBAL
+ elif combobox.objectName() == "SURFACE":
+ assert combobox.currentData() == LocalizationType.DISTANCE
+ elif combobox.objectName() == "FIELD":
+ assert combobox.currentData() == LocalizationType.ADAPTIVE
+
+
+@pytest.mark.parametrize(
+ ("object_name", "property_name", "changed_value"),
+ [
+ ("localization_correlation_threshold", "correlation_threshold", 0.7),
+ ("enkf_truncation", "enkf_truncation", 0.4),
+ ],
+)
+def test_that_changing_numeric_control_updates_corresponding_property(
+ qtbot: QtBot,
+ object_name: str,
+ property_name: str,
+ changed_value: float,
+) -> None:
+ widget = AnalysisModuleVariablesPanel(
+ update_strategies={},
+ correlation_threshold=0.5,
+ enkf_truncation=0.2,
+ )
+ qtbot.addWidget(widget)
+
+ spinner = widget.findChild(QDoubleSpinBox, name=object_name)
+
+ assert spinner is not None
+ spinner.setValue(changed_value)
+ assert math.isclose(getattr(widget, property_name), changed_value)
+
+
+@pytest.mark.parametrize(
+ ("parameter_type", "initial_strategy", "changed_strategy"),
+ [
+ ("GEN_KW", LocalizationType.GLOBAL, LocalizationType.ADAPTIVE),
+ ("FIELD", LocalizationType.ADAPTIVE, LocalizationType.DISTANCE),
+ ("SURFACE", LocalizationType.DISTANCE, LocalizationType.GLOBAL),
+ ],
+)
+def test_that_changing_localization_control_updates_parameter_strategy_property(
+ qtbot: QtBot,
+ parameter_type: str,
+ initial_strategy: LocalizationType,
+ changed_strategy: LocalizationType,
+) -> None:
+ update_strategies = {
+ "GEN_KW": LocalizationType.GLOBAL,
+ "FIELD": LocalizationType.ADAPTIVE,
+ "SURFACE": LocalizationType.DISTANCE,
+ }
+ widget = AnalysisModuleVariablesPanel(
+ update_strategies=update_strategies,
+ correlation_threshold=0.5,
+ enkf_truncation=0.2,
+ )
+ qtbot.addWidget(widget)
+
+ matching_comboboxes = [
+ combobox
+ for combobox in widget.findChildren(QComboBox)
+ if combobox.currentData() == initial_strategy
+ ]
+ assert len(matching_comboboxes) == 1
+
+ combobox = matching_comboboxes[0]
+ changed_index = combobox.findData(changed_strategy)
+ assert changed_index != -1
+ combobox.setCurrentIndex(changed_index)
+
+ assert widget.update_strategies[parameter_type] == changed_strategy
diff --git a/tests/ert/unit_tests/gui/experiments/test_manual_update.py b/tests/ert/unit_tests/gui/experiments/test_manual_update.py
index d705afdd484..7f6d0d940cd 100644
--- a/tests/ert/unit_tests/gui/experiments/test_manual_update.py
+++ b/tests/ert/unit_tests/gui/experiments/test_manual_update.py
@@ -53,6 +53,7 @@ def test_that_active_realizations_selector_validates_with_ensemble_size_from_pri
analysis_config=AnalysisConfig(minimum_required_realizations=1),
run_path="",
notifier=notifier,
+ parameter_configuration=[],
)
qtbot.addWidget(panel)
@@ -120,6 +121,7 @@ def test_that_manual_update_ensemble_selector_only_shows_ensembles_with_data(
analysis_config=AnalysisConfig(minimum_required_realizations=1),
run_path="",
notifier=notifier,
+ parameter_configuration=[],
)
qtbot.addWidget(panel)
ensemble_selector = panel.findChild(EnsembleSelector)
@@ -154,6 +156,7 @@ def test_that_panel_does_not_crash_when_no_realization_has_parameters(
analysis_config=AnalysisConfig(minimum_required_realizations=1),
run_path="",
notifier=notifier,
+ parameter_configuration=[],
)
qtbot.addWidget(panel)
@@ -188,6 +191,7 @@ def test_that_empty_experiment_name_field_defaults_to_manual_update_of_mock_ense
analysis_config=AnalysisConfig(minimum_required_realizations=1),
run_path="",
notifier=notifier,
+ parameter_configuration=[],
)
qtbot.addWidget(panel)
@@ -211,6 +215,7 @@ def test_that_experiment_name_field_is_used_in_experiment_arguments(
analysis_config=AnalysisConfig(minimum_required_realizations=1),
run_path="",
notifier=notifier,
+ parameter_configuration=[],
)
qtbot.addWidget(panel)
diff --git a/tests/ert/unit_tests/gui/experiments/test_multiple_data_assimilation_panel.py b/tests/ert/unit_tests/gui/experiments/test_multiple_data_assimilation_panel.py
index 00cddc3d215..ab679abf383 100644
--- a/tests/ert/unit_tests/gui/experiments/test_multiple_data_assimilation_panel.py
+++ b/tests/ert/unit_tests/gui/experiments/test_multiple_data_assimilation_panel.py
@@ -1,4 +1,3 @@
-import math
from dataclasses import dataclass
from unittest.mock import MagicMock
@@ -231,7 +230,7 @@ def _open_and_capture_threshold(panel, qtbot):
def inspect_and_close_dialog() -> None:
nonlocal captured_value
dialog = QApplication.activeModalWidget()
- if isinstance(dialog, QDialog) and dialog.windowTitle() == "Edit variables":
+ if isinstance(dialog, QDialog) and dialog.windowTitle() == "Update settings":
spinner = dialog.findChild(
QDoubleSpinBox, name="localization_correlation_threshold"
)
@@ -248,39 +247,6 @@ def inspect_and_close_dialog() -> None:
return captured_value
-@pytest.mark.parametrize(
- ("active_realizations", "expected_threshold"),
- [
- ([True], 1.0),
- ([True, False, True, True, True, True, True, True], 1),
- (
- [False, True, True] * 5,
- 3 / math.sqrt(10),
- ),
- ([True, False] * 200, 3 / math.sqrt(200)),
- ],
-)
-def test_that_analysis_module_edit_threshold_matches_expected_from_ensemble_size_via_ui(
- qtbot: QtBot, active_realizations, expected_threshold
-) -> None:
- notifier = ErtNotifier()
- notifier._storage = MockStorage()
-
- panel = MultipleDataAssimilationPanel(
- analysis_config=AnalysisConfig(minimum_required_realizations=1),
- parameter_configuration=EnsembleConfig().parameter_configuration,
- run_path="",
- notifier=notifier,
- active_realizations=active_realizations,
- config_num_realization=len(active_realizations),
- )
- qtbot.addWidget(panel)
-
- observed_threshold = _open_and_capture_threshold(panel, qtbot)
-
- assert observed_threshold == pytest.approx(expected_threshold)
-
-
@dataclass(frozen=True)
class EnsInfo:
ensemble_id: str
diff --git a/tests/ert/unit_tests/gui/run_analysis/test_analysispanel.py b/tests/ert/unit_tests/gui/run_analysis/test_analysispanel.py
deleted file mode 100644
index 647362bbe2c..00000000000
--- a/tests/ert/unit_tests/gui/run_analysis/test_analysispanel.py
+++ /dev/null
@@ -1,45 +0,0 @@
-import math
-
-import pytest
-from PyQt6.QtWidgets import QDoubleSpinBox
-from pytestqt.qtbot import QtBot
-
-from ert.config import ESSettings
-from ert.gui.ertwidgets.analysismodulevariablespanel import AnalysisModuleVariablesPanel
-
-
-@pytest.mark.parametrize(
- ("ensemble_size", "expected"),
- [
- (1, 1),
- (8, 1),
- (9, 3 / math.sqrt(9)),
- (200, 3 / math.sqrt(200)),
- ],
-)
-def test_that_default_localization_threshold_depends_on_ensemble_size(
- qtbot: QtBot, ensemble_size, expected
-):
- settings = ESSettings()
- widget = AnalysisModuleVariablesPanel(settings, ensemble_size)
- qtbot.addWidget(widget)
-
- spinner = widget.findChild(
- QDoubleSpinBox, name="localization_correlation_threshold"
- )
- assert spinner.value() == pytest.approx(expected)
-
-
-@pytest.mark.parametrize("set_value", [0.0, 0.2, 0.5, 1.0])
-def test_that_setting_localization_threshold_updates_analysis_settings(
- qtbot: QtBot, set_value
-):
- settings = ESSettings()
- widget = AnalysisModuleVariablesPanel(settings, 123)
- qtbot.addWidget(widget)
-
- spinner = widget.findChild(
- QDoubleSpinBox, name="localization_correlation_threshold"
- )
- spinner.setValue(set_value)
- assert spinner.value() == settings.localization_correlation_threshold == set_value
diff --git a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/heat_equationconfig.ert/config.json b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/heat_equationconfig.ert/config.json
index c2a6328ff4a..c7ef3ff50ee 100644
--- a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/heat_equationconfig.ert/config.json
+++ b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/heat_equationconfig.ert/config.json
@@ -200,66 +200,7 @@
},
"experiment_name": "es-mda",
"design_matrix": null,
- "parameter_configuration": [
- {
- "type": "gen_kw",
- "name": "t",
- "forward_init": false,
- "update_strategy": "adaptive",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 0.5,
- "max": 1.5
- },
- "group": "INIT_TEMP_SCALE",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "x",
- "forward_init": false,
- "update_strategy": "adaptive",
- "dimensionality": 1,
- "distribution": {
- "name": "normal",
- "mean": 0.8,
- "std": 0.1
- },
- "group": "CORR_LENGTH",
- "input_source": "sampled"
- },
- {
- "type": "field",
- "name": "COND",
- "forward_init": true,
- "update_strategy": "adaptive",
- "dimensionality": 3,
- "ertbox_params": {
- "nx": 50,
- "ny": 50,
- "nz": 1,
- "axis_orientation": 1,
- "xlength": 50.0,
- "ylength": 50.0,
- "xinc": 1.0,
- "yinc": 1.0,
- "rotation_angle": 0.0,
- "origin": [
- 0.0,
- 0.0
- ]
- },
- "file_format": "bgrdecl",
- "output_transformation": "EXP",
- "input_transformation": "LN",
- "truncation_min": null,
- "truncation_max": null,
- "forward_init_file": "cond.bgrdecl",
- "output_file": "cond.bgrdecl",
- "grid_file": "test-data/ert/heat_equation.config.ert/CASE.EGRID"
- }
- ],
+ "parameter_configuration": [],
"response_configuration": [
{
"type": "summary",
diff --git a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/poly_examplepoly.ert/poly.json b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/poly_examplepoly.ert/poly.json
index 8c3c2753baa..2acbfb9acde 100644
--- a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/poly_examplepoly.ert/poly.json
+++ b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/poly_examplepoly.ert/poly.json
@@ -190,50 +190,7 @@
},
"experiment_name": "es-mda",
"design_matrix": null,
- "parameter_configuration": [
- {
- "type": "gen_kw",
- "name": "a",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 0.0,
- "max": 1.0
- },
- "group": "COEFFS",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "b",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 0.0,
- "max": 2.0
- },
- "group": "COEFFS",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "c",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 0.0,
- "max": 5.0
- },
- "group": "COEFFS",
- "input_source": "sampled"
- }
- ],
+ "parameter_configuration": [],
"response_configuration": [
{
"type": "gen_data",
diff --git a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/snake_oilsnake_oil.ert/snake_oil.json b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/snake_oilsnake_oil.ert/snake_oil.json
index 938f3a48458..633bb30c7c2 100644
--- a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/snake_oilsnake_oil.ert/snake_oil.json
+++ b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_esmda_matches_snapshot/snake_oilsnake_oil.ert/snake_oil.json
@@ -166,148 +166,7 @@
},
"experiment_name": "es-mda",
"design_matrix": null,
- "parameter_configuration": [
- {
- "type": "gen_kw",
- "name": "BPR_555_PERSISTENCE",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 0.1,
- "max": 0.5
- },
- "group": "SNAKE_OIL_PARAM_BPR",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "BPR_138_PERSISTENCE",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 0.2,
- "max": 0.7
- },
- "group": "SNAKE_OIL_PARAM_BPR",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "OP1_PERSISTENCE",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 0.01,
- "max": 0.4
- },
- "group": "SNAKE_OIL_PARAM_OP1",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "OP1_OCTAVES",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 3.0,
- "max": 5.0
- },
- "group": "SNAKE_OIL_PARAM_OP1",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "OP1_DIVERGENCE_SCALE",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 0.25,
- "max": 1.25
- },
- "group": "SNAKE_OIL_PARAM_OP1",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "OP1_OFFSET",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": -0.1,
- "max": 0.1
- },
- "group": "SNAKE_OIL_PARAM_OP1",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "OP2_PERSISTENCE",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 0.1,
- "max": 0.6
- },
- "group": "SNAKE_OIL_PARAM_OP2",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "OP2_OCTAVES",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 5.0,
- "max": 12.0
- },
- "group": "SNAKE_OIL_PARAM_OP2",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "OP2_DIVERGENCE_SCALE",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": 0.5,
- "max": 1.5
- },
- "group": "SNAKE_OIL_PARAM_OP2",
- "input_source": "sampled"
- },
- {
- "type": "gen_kw",
- "name": "OP2_OFFSET",
- "forward_init": false,
- "update_strategy": "global",
- "dimensionality": 1,
- "distribution": {
- "name": "uniform",
- "min": -0.2,
- "max": 0.2
- },
- "group": "SNAKE_OIL_PARAM_OP2",
- "input_source": "sampled"
- }
- ],
+ "parameter_configuration": [],
"response_configuration": [
{
"type": "summary",
diff --git a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/heat_equationconfig.ert/config.json b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/heat_equationconfig.ert/config.json
index 12245d079ad..b24affe7e36 100644
--- a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/heat_equationconfig.ert/config.json
+++ b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/heat_equationconfig.ert/config.json
@@ -233,5 +233,6 @@
}
}
},
- "experiment_name": "my_experiment"
+ "experiment_name": "my_experiment",
+ "parameter_configuration": []
}
diff --git a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/poly_examplepoly.ert/poly.json b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/poly_examplepoly.ert/poly.json
index fd83ddb19da..21c7aeea901 100644
--- a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/poly_examplepoly.ert/poly.json
+++ b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/poly_examplepoly.ert/poly.json
@@ -194,5 +194,6 @@
"shape_registry": {
"shapes": {}
},
- "experiment_name": "my_experiment"
+ "experiment_name": "my_experiment",
+ "parameter_configuration": []
}
diff --git a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/snake_oilsnake_oil.ert/snake_oil.json b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/snake_oilsnake_oil.ert/snake_oil.json
index 35ba3f01148..93c23be4bef 100644
--- a/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/snake_oilsnake_oil.ert/snake_oil.json
+++ b/tests/ert/unit_tests/run_models/snapshots/test_experiment_serialization/test_that_dumped_manual_update_matches_snapshot/snake_oilsnake_oil.ert/snake_oil.json
@@ -187,5 +187,6 @@
"shape_registry": {
"shapes": {}
},
- "experiment_name": "my_experiment"
+ "experiment_name": "my_experiment",
+ "parameter_configuration": []
}
diff --git a/tests/ert/unit_tests/run_models/test_experiment_serialization.py b/tests/ert/unit_tests/run_models/test_experiment_serialization.py
index 84cc4e777a1..be996dfd79e 100644
--- a/tests/ert/unit_tests/run_models/test_experiment_serialization.py
+++ b/tests/ert/unit_tests/run_models/test_experiment_serialization.py
@@ -748,6 +748,7 @@ def test_that_dumped_manual_update_matches_snapshot(
ensemble_id=str(prior.id),
target_ensemble="posterior",
experiment_name="my_experiment",
+ parameter_configuration=[],
),
case=f"{config_dir}.{config_file}",
)
@@ -878,6 +879,7 @@ def test_that_dumped_esmda_matches_snapshot(
weights="4, 2, 1",
prior_ensemble_id=None,
experiment_name="es-mda",
+ parameter_configuration=[],
),
case=f"{config_dir}.{config_file}",
)
diff --git a/tests/ert/unit_tests/run_models/test_manual_update.py b/tests/ert/unit_tests/run_models/test_manual_update.py
index 54f0cd95bb8..8385c8265ca 100644
--- a/tests/ert/unit_tests/run_models/test_manual_update.py
+++ b/tests/ert/unit_tests/run_models/test_manual_update.py
@@ -57,6 +57,7 @@ def test_that_manual_update_from_ensemble_experiment_supports_all_update_modes(
ensemble_id=ensemble_id_to_update,
target_ensemble="updated_ens%d",
experiment_name="my manual update",
+ parameter_configuration=[],
),
status_queue=queue.SimpleQueue(),
)
diff --git a/tests/ert/unit_tests/run_models/test_model_factory.py b/tests/ert/unit_tests/run_models/test_model_factory.py
index 1f774528230..46be412c8c5 100644
--- a/tests/ert/unit_tests/run_models/test_model_factory.py
+++ b/tests/ert/unit_tests/run_models/test_model_factory.py
@@ -72,6 +72,7 @@ def test_that_the_model_warns_when_active_realizations_less_min_realizations(
num_iterations=1,
prior_ensemble_id="",
weights="2,3",
+ parameter_configuration=[],
),
queue.SimpleQueue(),
)
@@ -201,6 +202,7 @@ def test_that_setup_multiple_data_assimilation_uses_the_arguments_from_the_cli(
prior_ensemble_id=None,
experiment_name="My-experiment",
starting_iteration=0,
+ parameter_configuration=[],
),
ObservationSettings(),
queue.SimpleQueue(),
@@ -235,6 +237,7 @@ def test_that_setup_multiple_data_assimilation_uses_config_weights_when_cli_omit
prior_ensemble_id=None,
experiment_name="My-experiment",
starting_iteration=0,
+ parameter_configuration=[],
),
ObservationSettings(),
queue.SimpleQueue(),
@@ -279,6 +282,7 @@ def test_multiple_data_assimilation_restart_paths(
target_ensemble="restart_case_%d",
prior_ensemble_id=str(uuid1()),
experiment_name="just_assimilatin",
+ parameter_configuration=[],
)
monkeypatch.setattr(