Skip to content

Commit

Permalink
Add validation for uninitialized ensembles in manual update and evaluate
Browse files Browse the repository at this point in the history
experiment

This commit adds validation for the realizations specified by the user
when trying to run `manual_update` or `evaluate_experiment`. The
validator checks the selected ensemble if the specified realization(s)
exists. If not, the field becomes red and a warning is displayed.
The commit also disables the realization field until an ensemble is
selected.
  • Loading branch information
jonathan-eq committed Oct 17, 2024
1 parent 74e401e commit 134593d
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 10 deletions.
10 changes: 6 additions & 4 deletions src/ert/gui/simulation/evaluate_ensemble_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from ert.gui.simulation.experiment_config_panel import ExperimentConfigPanel
from ert.mode_definitions import EVALUATE_ENSEMBLE_MODE
from ert.run_models.evaluate_ensemble import EvaluateEnsemble
from ert.validation import RangeStringArgument
from ert.validation import RealizationsInEnsembleArgument


@dataclass
Expand Down Expand Up @@ -47,9 +47,10 @@ def __init__(self, ensemble_size: int, run_path: str, notifier: ErtNotifier):
ActiveRealizationsModel(ensemble_size, show_default=False), # type: ignore
"config/simulation/active_realizations",
)
self._active_realizations_field.setValidator(
RangeStringArgument(ensemble_size),
self._realizations_validator = RealizationsInEnsembleArgument(
self._ensemble_selector.selected_ensemble, max_value=ensemble_size
)
self._active_realizations_field.setValidator(self._realizations_validator)
self._realizations_from_fs()
layout.addRow("Active realizations", self._active_realizations_field)

Expand All @@ -68,7 +69,7 @@ def isConfigurationValid(self) -> bool:
return (
self._active_realizations_field.isValid()
and self._ensemble_selector.currentIndex() != -1
and bool(self._active_realizations_field.text())
and self._active_realizations_field.isValid()
)

def get_experiment_arguments(self) -> Arguments:
Expand All @@ -80,6 +81,7 @@ def get_experiment_arguments(self) -> Arguments:

def _realizations_from_fs(self) -> None:
ensemble = self._ensemble_selector.selected_ensemble
self._active_realizations_field.setEnabled(ensemble is not None)
if ensemble:
parameters = ensemble.get_realization_mask_with_parameters()
missing_responses = ~ensemble.get_realization_mask_with_responses()
Expand Down
14 changes: 8 additions & 6 deletions src/ert/gui/simulation/manual_update_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from ert.gui.simulation.experiment_config_panel import ExperimentConfigPanel
from ert.mode_definitions import MANUAL_UPDATE_MODE
from ert.run_models.manual_update import ManualUpdate
from ert.validation import ProperNameFormatArgument, RangeStringArgument
from ert.validation import ProperNameFormatArgument, RealizationsInEnsembleArgument


@dataclass
Expand Down Expand Up @@ -72,14 +72,13 @@ def __init__(
ActiveRealizationsModel(ensemble_size, show_default=False), # type: ignore
"config/simulation/active_realizations",
)
self._active_realizations_field.setValidator(
RangeStringArgument(ensemble_size),
self._realizations_validator = RealizationsInEnsembleArgument(
self._ensemble_selector.selected_ensemble, max_value=ensemble_size
)
self._active_realizations_field.setValidator(self._realizations_validator)
self._realizations_from_fs()
layout.addRow("Active realizations", self._active_realizations_field)

self.setLayout(layout)

self._active_realizations_field.getValidationSupport().validationChanged.connect(
self.simulationConfigurationChanged
)
Expand All @@ -88,12 +87,13 @@ def __init__(
self.simulationConfigurationChanged
)
self._ensemble_selector.currentIndexChanged.connect(self._realizations_from_fs)
self.setLayout(layout)

def isConfigurationValid(self) -> bool:
return (
self._active_realizations_field.isValid()
and self._ensemble_selector.currentIndex() != -1
and bool(self._active_realizations_field.text())
and self._active_realizations_field.isValid()
)

def get_experiment_arguments(self) -> Arguments:
Expand All @@ -106,7 +106,9 @@ def get_experiment_arguments(self) -> Arguments:

def _realizations_from_fs(self) -> None:
ensemble = self._ensemble_selector.selected_ensemble
self._active_realizations_field.setEnabled(ensemble is not None)
if ensemble:
self._realizations_validator.set_ensemble(ensemble)
parameters = ensemble.get_realization_mask_with_parameters()
responses = ensemble.get_realization_mask_with_responses()
mask = np.logical_and(parameters, responses)
Expand Down
1 change: 1 addition & 0 deletions src/ert/run_models/base_run_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ def send_smoother_event(
)
)
elif isinstance(event, AnalysisErrorEvent):
print("FOUND ME")
self.send_event(
RunModelErrorEvent(
iteration=iteration,
Expand Down
2 changes: 2 additions & 0 deletions src/ert/storage/local_ensemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,8 @@ def save_cross_correlations(

@lru_cache # noqa: B019
def load_responses(self, key: str, realizations: Tuple[int]) -> polars.DataFrame:
print(f"{realizations=}")
print(f"{key=}")
"""Load responses for key and realizations into xarray Dataset.
For each given realization, response data is loaded from the NetCDF
Expand Down
2 changes: 2 additions & 0 deletions src/ert/validation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .proper_name_format_argument import ProperNameFormatArgument
from .range_string_argument import RangeStringArgument
from .rangestring import mask_to_rangestring, rangestring_to_list, rangestring_to_mask
from .realizations_in_ensemble_argument import RealizationsInEnsembleArgument
from .runpath_argument import RunPathArgument
from .validation_status import ValidationStatus

Expand All @@ -17,6 +18,7 @@
"ProperNameArgument",
"ProperNameFormatArgument",
"RangeStringArgument",
"RealizationsInEnsembleArgument",
"RunPathArgument",
"ValidationStatus",
"mask_to_rangestring",
Expand Down
51 changes: 51 additions & 0 deletions src/ert/validation/realizations_in_ensemble_argument.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from typing import TYPE_CHECKING, Optional

from .range_string_argument import RangeStringArgument
from .rangestring import rangestring_to_list
from .validation_status import ValidationStatus

if TYPE_CHECKING:
from ert.storage import Ensemble


class RealizationsInEnsembleArgument(RangeStringArgument):
UNINITIALIZED_REALIZATIONS_SPECIFIED = (
"The specified realization(s) %s are not found in selected ensemble."
)

def __init__(
self, ensemble: "Ensemble", max_value: Optional[int], **kwargs: bool
) -> None:
super().__init__(max_value, **kwargs)
self.__ensemble = ensemble

def set_ensemble(self, ensemble: "Ensemble") -> None:
self.__ensemble = ensemble

def validate(self, token: str) -> ValidationStatus:
if not token:
return ValidationStatus()

validation_status = super().validate(token)
if not validation_status:
return validation_status
attempted_realizations = rangestring_to_list(token)

invalid_realizations = []
for realization in attempted_realizations:
if not self._validate_selected_realization_exist(realization):
invalid_realizations.append(realization)

if invalid_realizations:
validation_status.setFailed()
validation_status.addToMessage(
RealizationsInEnsembleArgument.UNINITIALIZED_REALIZATIONS_SPECIFIED
% str(invalid_realizations)
)
return validation_status

validation_status.setValue(token)
return validation_status

def _validate_selected_realization_exist(self, realization: int):

Check failure on line 50 in src/ert/validation/realizations_in_ensemble_argument.py

View workflow job for this annotation

GitHub Actions / type-checking (3.12)

Function is missing a return type annotation
return self.__ensemble._responses_exist_for_realization(realization)

0 comments on commit 134593d

Please sign in to comment.