diff --git a/src/ert/gui/simulation/evaluate_ensemble_panel.py b/src/ert/gui/simulation/evaluate_ensemble_panel.py index 44d7400c4ef..a81b40ad15c 100644 --- a/src/ert/gui/simulation/evaluate_ensemble_panel.py +++ b/src/ert/gui/simulation/evaluate_ensemble_panel.py @@ -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 EnsembleRealizationsArgument @dataclass @@ -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 = EnsembleRealizationsArgument( + 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) @@ -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: @@ -80,7 +81,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() missing_responses = ~ensemble.get_realization_mask_with_responses() failures = ~ensemble.get_realization_mask_without_failure() diff --git a/src/ert/gui/simulation/manual_update_panel.py b/src/ert/gui/simulation/manual_update_panel.py index b96f75db15f..4a7d2a93be5 100644 --- a/src/ert/gui/simulation/manual_update_panel.py +++ b/src/ert/gui/simulation/manual_update_panel.py @@ -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 EnsembleRealizationsArgument, ProperNameFormatArgument @dataclass @@ -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 = EnsembleRealizationsArgument( + 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 ) @@ -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: @@ -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) diff --git a/src/ert/validation/__init__.py b/src/ert/validation/__init__.py index b503bea56cc..7b8ffa7cc01 100644 --- a/src/ert/validation/__init__.py +++ b/src/ert/validation/__init__.py @@ -1,5 +1,6 @@ from .active_range import ActiveRange from .argument_definition import ArgumentDefinition +from .ensemble_realizations_argument import EnsembleRealizationsArgument from .integer_argument import IntegerArgument from .number_list_string_argument import NumberListStringArgument from .proper_name_argument import ProperNameArgument @@ -12,6 +13,7 @@ __all__ = [ "ActiveRange", "ArgumentDefinition", + "EnsembleRealizationsArgument", "IntegerArgument", "NumberListStringArgument", "ProperNameArgument", diff --git a/src/ert/validation/ensemble_realizations_argument.py b/src/ert/validation/ensemble_realizations_argument.py new file mode 100644 index 00000000000..4220b00b65f --- /dev/null +++ b/src/ert/validation/ensemble_realizations_argument.py @@ -0,0 +1,49 @@ +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 EnsembleRealizationsArgument(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 = [] + initialized_realization_ids = self.__ensemble.is_initalized() + for realization in attempted_realizations: + if not realization in initialized_realization_ids: + invalid_realizations.append(realization) + + if invalid_realizations: + validation_status.setFailed() + validation_status.addToMessage( + EnsembleRealizationsArgument.UNINITIALIZED_REALIZATIONS_SPECIFIED + % str(invalid_realizations) + ) + return validation_status + + validation_status.setValue(token) + return validation_status