diff --git a/docs/ert/reference/configuration/keywords.rst b/docs/ert/reference/configuration/keywords.rst index b06bfcd8fa0..e461e2acbb6 100644 --- a/docs/ert/reference/configuration/keywords.rst +++ b/docs/ert/reference/configuration/keywords.rst @@ -40,9 +40,6 @@ Keyword name Required :ref:`GRID <grid>` NO Provide an ECLIPSE grid for the reservoir model :ref:`HISTORY_SOURCE <history_source>` NO REFCASE_HISTORY Source used for historical values :ref:`HOOK_WORKFLOW <hook_workflow>` NO Install a workflow to be run automatically -:ref:`IES_DEC_STEPLENGTH <ies_dec_steplength>` NO 2.5 Gauss-Newton steplength decline -:ref:`IES_MAX_STEPLENGTH <ies_max_steplength>` NO 0.6 Gauss-Newton maximum steplength -:ref:`IES_MIN_STEPLENGTH <ies_min_steplength>` NO 0.3 Gauss-Newton minimum steplength :ref:`INCLUDE <include>` NO Include contents from another ert config :ref:`INSTALL_JOB <install_job>` NO Install a job for use in a forward model :ref:`INVERSION <inversion_algorithm>` NO Set inversion method for analysis module @@ -1421,11 +1418,11 @@ ANALYSIS_SET_VAR The analysis modules can have internal state, like e.g. truncation cutoff values. These can be manipulated from the config file using the -ANALYSIS_SET_VAR keyword for either the `STD_ENKF` or `IES_ENKF` module. +ANALYSIS_SET_VAR keyword for the `STD_ENKF` module. :: - ANALYSIS_SET_VAR <STD_ENKF|IES_ENKF> ENKF_TRUNCATION 0.98 + ANALYSIS_SET_VAR STD_ENKF ENKF_TRUNCATION 0.98 @@ -1435,111 +1432,32 @@ INVERSION The analysis modules can specify inversion algorithm used. These can be manipulated from the config file using the -ANALYSIS_SET_VAR keyword for either the `STD_ENKF` or `IES_ENKF` module. +ANALYSIS_SET_VAR keyword for the `STD_ENKF` module. **STD_ENKF** .. list-table:: Inversion Algorithms for Ensemble Smoother - :widths: 50 50 50 50 + :widths: 50 50 50 :header-rows: 1 * - Description - INVERSION - - IES_INVERSION (deprecated) - Note * - Exact inversion with diagonal R=I - EXACT - - 0 - * - Subspace inversion with exact R - SUBSPACE_EXACT_R / SUBSPACE - - 1 - Preferred name: SUBSPACE * - Subspace inversion using R=EE' - SUBSPACE_EE_R - - 2 - Deprecated, maps to: SUBSPACE * - Subspace inversion using E - SUBSPACE_RE - - 3 - Deprecated, maps to: SUBSPACE -**IES_ENKF** - - -.. list-table:: Inversion Algorithms for IES - :widths: 50 50 50 50 - :header-rows: 1 - - * - Description - - INVERSION - - IES_INVERSION (deprecated) - - Note - * - Exact inversion with diagonal R=I - - EXACT / DIRECT - - 0 - - Preferred name: DIRECT - * - Subspace inversion with exact R - - SUBSPACE_EXACT_R / SUBSPACE_EXACT - - 1 - - Preferred name: SUBSPACE_EXACT - * - Subspace inversion using R=EE' - - SUBSPACE_EE_R / SUBSPACE_PROJECTED - - 2 - - Preferred name: SUBSPACE_PROJECTED - * - Subspace inversion using E - - SUBSPACE_RE - - 3 - - Deprecated, maps to: SUBSPACE_PROJECTED - -Setting the inversion method -:: - - -- Example for the `STD_ENKF` module - ANALYSIS_SET_VAR STD_ENKF INVERSION DIRECT - - -IES_MAX_STEPLENGTH -^^^^^^^^^^^^^^^^^^ -.. _ies_max_steplength: - -The analysis modules can specify the Gauss-Newton maximum steplength -for the ``IES_ENKF`` module only. -This is default set to ``0.60``, valid values in range ``[0.1, 1.00]`` - -:: - - ANALYSIS_SET_VAR IES_ENKF IES_MAX_STEPLENGTH 0.6 - - -IES_MIN_STEPLENGTH -^^^^^^^^^^^^^^^^^^ -.. _ies_min_steplength: - -The analysis modules can specify the Gauss-Newton minimum steplength -for the ``IES_ENKF`` module only. -This is default set to ``0.30``, valid values in range ``[0.1, 1.00]`` - -:: - - ANALYSIS_SET_VAR IES_ENKF IES_MIN_STEPLENGTH 0.3 - - -IES_DEC_STEPLENGTH -^^^^^^^^^^^^^^^^^^ -.. _ies_dec_steplength: - -The analysis modules can specify the Gauss-Newton steplength decline -for the ``IES_ENKF`` module only. -This is default set to ``2.5``, valid values in range ``[1.1, 10.0]`` - -:: - - ANALYSIS_SET_VAR IES_ENKF IES_DEC_STEPLENGTH 2.5 - - LOCALIZATION ^^^^^^^^^^^^ .. _localization: @@ -1615,8 +1533,7 @@ al. 1979). :: - -- Example for the `IES_ENKF` module - ANALYSIS_SET_VAR IES_ENKF ENKF_TRUNCATION 0.98 + ANALYSIS_SET_VAR STD_ENKF ENKF_TRUNCATION 0.98 The default value of ENKF_TRUNCATION is 0.98. If ensemble collapse is a big problem, a smaller value should be used (e.g 0.90 or smaller). However, this diff --git a/docs/ert/reference/running_ert.rst b/docs/ert/reference/running_ert.rst index fc84d980260..c423dc63b85 100644 --- a/docs/ert/reference/running_ert.rst +++ b/docs/ert/reference/running_ert.rst @@ -43,15 +43,6 @@ Ensemble Smoother :prog: ert :path: ensemble_smoother -Iterative Ensemble Smoother -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. argparse:: - :module: ert.__main__ - :func: get_ert_parser - :prog: ert - :path: iterative_ensemble_smoother - ES MDA ~~~~~~ diff --git a/docs/ert/theory/ensemble_based_methods.rst b/docs/ert/theory/ensemble_based_methods.rst index 26075283c3d..9b04b3cf162 100644 --- a/docs/ert/theory/ensemble_based_methods.rst +++ b/docs/ert/theory/ensemble_based_methods.rst @@ -384,11 +384,6 @@ In plain English, the ES MDA consists of several consecutive smoother updates wi error bars. The ES MDA with one iteration is identical to the Ensemble smoother. -Iterative ensemble smoother - Ensemble subspace version -------------------------------------------------------- - -The algorithm implemented is described in the article `Efficient Implementation of an Iterative Ensemble Smoother for Data Assimilation and Reservoir History Matching <https://www.frontiersin.org/articles/10.3389/fams.2019.00047/full>`_. - Kalman posterior properties --------------------------- diff --git a/src/ert/__main__.py b/src/ert/__main__.py index 6b5155ecbb7..ed66fd288d7 100755 --- a/src/ert/__main__.py +++ b/src/ert/__main__.py @@ -28,7 +28,6 @@ ENSEMBLE_EXPERIMENT_MODE, ENSEMBLE_SMOOTHER_MODE, ES_MDA_MODE, - ITERATIVE_ENSEMBLE_SMOOTHER_MODE, TEST_RUN_MODE, WORKFLOW_MODE, ) @@ -421,73 +420,6 @@ def get_ert_parser(parser: ArgumentParser | None = None) -> ArgumentParser: help="Name of the experiment", ) - # iterative_ensemble_smoother_parser - iterative_ensemble_smoother_description = ( - "Run experiments in cli while performing updates" - " on the parameters using the iterative ensemble smoother algorithm." - ) - iterative_ensemble_smoother_parser = subparsers.add_parser( - ITERATIVE_ENSEMBLE_SMOOTHER_MODE, - description=iterative_ensemble_smoother_description, - help=iterative_ensemble_smoother_description, - ) - iterative_ensemble_smoother_parser.add_argument( - "--current-case", - type=valid_name, - default="default", - action=DeprecatedAction, - alternative_option="--current-ensemble", - dest="current_ensemble", - help="Deprecated: This argument is deprecated and will be " - "removed in future versions. Use --current-ensemble instead.", - ) - iterative_ensemble_smoother_parser.add_argument( - "--current-ensemble", - type=valid_name, - default="default", - help="Name of the ensemble where the results for the experiment " - "using the prior parameters will be stored.", - ) - iterative_ensemble_smoother_parser.add_argument( - "--target-case", - type=valid_name_format, - default="iter-%d", - action=DeprecatedAction, - dest="target_ensemble", - alternative_option="--target--ensemble", - help="Deprecated: This argument is deprecated and will be " - "removed in future versions. Use --target-ensemble instead.", - ) - iterative_ensemble_smoother_parser.add_argument( - "--target-ensemble", - type=valid_name_format, - default="iter-%d", - help="The iterative ensemble smoother creates multiple ensembles for the different " - "iterations. The ensemble names will follow the specified format. " - "For example, 'Target ensemble format: iter_%%d' will generate " - "ensembles with the names iter_0, iter_1, iter_2, iter_3, ....", - ) - iterative_ensemble_smoother_parser.add_argument( - "--realizations", - type=valid_realizations, - help="These are the realizations that will be used to perform experiments." - "For example, if 'Number of realizations:50 and active realizations are 0-9', " - "then only realizations 0,1,2,3,...,9 will be used to perform experiments " - "while realizations 10,11, 12,...,49 will be excluded.", - ) - iterative_ensemble_smoother_parser.add_argument( - "--num-iterations", - type=valid_num_iterations, - required=False, - help="The number of iterations to run.", - ) - iterative_ensemble_smoother_parser.add_argument( - "--experiment-name", - type=str, - default="ies", - help="Name of the experiment", - ) - # es_mda_parser es_mda_description = f"Run '{ES_MDA_MODE}' in cli" es_mda_parser = subparsers.add_parser( @@ -574,7 +506,6 @@ def get_ert_parser(parser: ArgumentParser | None = None) -> ArgumentParser: test_run_parser, ensemble_experiment_parser, ensemble_smoother_parser, - iterative_ensemble_smoother_parser, es_mda_parser, workflow_parser, ]: diff --git a/src/ert/analysis/__init__.py b/src/ert/analysis/__init__.py index 2b6d8350cde..e3f2ba698f8 100644 --- a/src/ert/analysis/__init__.py +++ b/src/ert/analysis/__init__.py @@ -1,6 +1,5 @@ from ._es_update import ( ErtAnalysisError, - iterative_smoother_update, smoother_update, ) from .event import ( @@ -26,6 +25,5 @@ "ObservationAndResponseSnapshot", "ObservationStatus", "SmootherSnapshot", - "iterative_smoother_update", "smoother_update", ] diff --git a/src/ert/analysis/_es_update.py b/src/ert/analysis/_es_update.py index 44a10ea63e8..e32d3d4a827 100644 --- a/src/ert/analysis/_es_update.py +++ b/src/ert/analysis/_es_update.py @@ -22,7 +22,7 @@ from ert.config import GenKwConfig from ..config.analysis_config import ObservationGroups, UpdateSettings -from ..config.analysis_module import BaseSettings, ESSettings, IESSettings +from ..config.analysis_module import ESSettings from . import misfit_preprocessor from .event import ( AnalysisCompleteEvent, @@ -629,123 +629,6 @@ def correlation_callback( ) -def analysis_IES( - parameters: Iterable[str], - observations: Iterable[str], - rng: np.random.Generator, - analysis_config: IESSettings, - alpha: float, - std_cutoff: float, - smoother_snapshot: SmootherSnapshot, - ens_mask: npt.NDArray[np.bool_], - source_ensemble: Ensemble, - target_ensemble: Ensemble, - sies_smoother: ies.SIES | None, - progress_callback: Callable[[AnalysisEvent], None], - auto_scale_observations: list[ObservationGroups], - sies_step_length: Callable[[int], float], - initial_mask: npt.NDArray[np.bool_], -) -> ies.SIES: - iens_active_index = np.flatnonzero(ens_mask) - # Pick out realizations that were among the initials that are still living - # Example: initial_mask=[1,1,1,0,1], ens_mask=[0,1,1,0,1] - # Then the result is [0,1,1,1] - # This is needed for the SIES library - masking_of_initial_parameters = ens_mask[initial_mask] - - progress_callback(AnalysisStatusEvent(msg="Loading observations and responses..")) - - ( - S, - ( - observation_values, - observation_errors, - update_snapshot, - ), - ) = _load_observations_and_responses( - source_ensemble, - alpha, - std_cutoff, - 1.0, - iens_active_index, - observations, - auto_scale_observations, - progress_callback, - ) - - smoother_snapshot.update_step_snapshots = update_snapshot - if len(observation_values) == 0: - msg = "No active observations for update step" - progress_callback( - AnalysisErrorEvent( - error_msg=msg, - data=DataSection( - header=smoother_snapshot.header, - data=smoother_snapshot.csv, - extra=smoother_snapshot.extra, - ), - ) - ) - raise ErtAnalysisError(msg) - - # if the algorithm object is not passed, initialize it - if sies_smoother is None: - # The sies smoother must be initialized with the full parameter ensemble - # Get relevant active realizations - parameter_ensemble_active = _all_parameters(source_ensemble, iens_active_index) - sies_smoother = ies.SIES( - parameters=parameter_ensemble_active, - covariance=observation_errors**2, - observations=observation_values, - seed=rng, - inversion=analysis_config.inversion, - truncation=analysis_config.enkf_truncation, - ) - - # Keep track of iterations to calculate step-lengths - sies_smoother.iteration = 1 - - # Calculate step-lengths to scale SIES iteration - step_length = sies_step_length(sies_smoother.iteration) - - # Propose a transition matrix using only active realizations - proposed_W = sies_smoother.propose_W_masked( - S, ensemble_mask=masking_of_initial_parameters, step_length=step_length - ) - - # Store transition matrix for later use on sies object - sies_smoother.W[:, masking_of_initial_parameters] = proposed_W - - for param_group in parameters: - param_ensemble_array = _load_param_ensemble_array( - source_ensemble, param_group, iens_active_index - ) - param_ensemble_array += ( - param_ensemble_array @ sies_smoother.W / np.sqrt(len(iens_active_index) - 1) - ) - - progress_callback(AnalysisStatusEvent(msg=f"Storing data for {param_group}..")) - _save_param_ensemble_array_to_disk( - target_ensemble, param_ensemble_array, param_group, iens_active_index - ) - - _copy_unupdated_parameters( - list(source_ensemble.experiment.parameter_configuration.keys()), - parameters, - iens_active_index, - source_ensemble, - target_ensemble, - ) - - assert sies_smoother is not None, "sies_smoother should be initialized" - - # Increment the iteration number - sies_smoother.iteration += 1 - - # Return the sies smoother so it may be iterated over - return sies_smoother - - def _create_smoother_snapshot( prior_name: str, posterior_name: str, @@ -768,7 +651,7 @@ def smoother_update( observations: Iterable[str], parameters: Iterable[str], update_settings: UpdateSettings, - es_settings: BaseSettings, + es_settings: ESSettings, rng: np.random.Generator | None = None, progress_callback: Callable[[AnalysisEvent], None] | None = None, global_scaling: float = 1.0, @@ -778,8 +661,6 @@ def smoother_update( if rng is None: rng = np.random.default_rng() - assert isinstance(es_settings, ESSettings) - ens_mask = prior_storage.get_realization_mask_with_responses() smoother_snapshot = _create_smoother_snapshot( @@ -827,73 +708,3 @@ def smoother_update( ) ) return smoother_snapshot - - -def iterative_smoother_update( - prior_storage: Ensemble, - posterior_storage: Ensemble, - sies_smoother: ies.SIES | None, - parameters: Iterable[str], - observations: Iterable[str], - update_settings: UpdateSettings, - analysis_config: IESSettings, - sies_step_length: Callable[[int], float], - initial_mask: npt.NDArray[np.bool_], - rng: np.random.Generator | None = None, - progress_callback: Callable[[AnalysisEvent], None] | None = None, - global_scaling: float = 1.0, -) -> tuple[SmootherSnapshot, ies.SIES]: - if not progress_callback: - progress_callback = noop_progress_callback - if rng is None: - rng = np.random.default_rng() - - ens_mask = prior_storage.get_realization_mask_with_responses() - - smoother_snapshot = _create_smoother_snapshot( - prior_storage.name, - posterior_storage.name, - update_settings, - global_scaling, - ) - - try: - sies_smoother = analysis_IES( - parameters=parameters, - observations=observations, - rng=rng, - analysis_config=analysis_config, - alpha=update_settings.alpha, - std_cutoff=update_settings.std_cutoff, - smoother_snapshot=smoother_snapshot, - ens_mask=ens_mask, - source_ensemble=prior_storage, - target_ensemble=posterior_storage, - sies_smoother=sies_smoother, - progress_callback=progress_callback, - auto_scale_observations=update_settings.auto_scale_observations, - sies_step_length=sies_step_length, - initial_mask=initial_mask, - ) - except Exception as e: - progress_callback( - AnalysisErrorEvent( - error_msg=str(e), - data=DataSection( - header=smoother_snapshot.header, - data=smoother_snapshot.csv, - extra=smoother_snapshot.extra, - ), - ) - ) - raise e - progress_callback( - AnalysisCompleteEvent( - data=DataSection( - header=smoother_snapshot.header, - data=smoother_snapshot.csv, - extra=smoother_snapshot.extra, - ) - ) - ) - return smoother_snapshot, sies_smoother diff --git a/src/ert/cli/main.py b/src/ert/cli/main.py index 7552851de7a..4568681c636 100644 --- a/src/ert/cli/main.py +++ b/src/ert/cli/main.py @@ -18,7 +18,6 @@ ENSEMBLE_EXPERIMENT_MODE, ENSEMBLE_SMOOTHER_MODE, ES_MDA_MODE, - ITERATIVE_ENSEMBLE_SMOOTHER_MODE, TEST_RUN_MODE, WORKFLOW_MODE, ) @@ -68,7 +67,6 @@ def run_cli(args: Namespace, plugin_manager: ErtPluginManager | None = None) -> if args.mode in { ENSEMBLE_SMOOTHER_MODE, ES_MDA_MODE, - ITERATIVE_ENSEMBLE_SMOOTHER_MODE, }: if not ert_config.ensemble_config.parameter_configs: raise ErtCliError( diff --git a/src/ert/config/__init__.py b/src/ert/config/__init__.py index cda975a3960..e9fe183e210 100644 --- a/src/ert/config/__init__.py +++ b/src/ert/config/__init__.py @@ -1,5 +1,5 @@ from .analysis_config import AnalysisConfig -from .analysis_module import AnalysisModule, ESSettings, IESSettings +from .analysis_module import AnalysisModule, ESSettings from .capture_validation import capture_validation from .design_matrix import DesignMatrix from .ensemble_config import EnsembleConfig @@ -24,7 +24,6 @@ from .observations import EnkfObs from .parameter_config import ParameterConfig from .parsing import ( - AnalysisMode, ConfigValidationError, ConfigWarning, ErrorInfo, @@ -43,7 +42,6 @@ __all__ = [ "AnalysisConfig", - "AnalysisMode", "AnalysisModule", "CancelPluginException", "ConfigValidationError", @@ -69,7 +67,6 @@ "GenDataConfig", "GenKwConfig", "HookRuntime", - "IESSettings", "InvalidResponseFile", "ModelConfig", "ObservationType", diff --git a/src/ert/config/analysis_config.py b/src/ert/config/analysis_config.py index c76adfa9541..70a938e7449 100644 --- a/src/ert/config/analysis_config.py +++ b/src/ert/config/analysis_config.py @@ -9,10 +9,9 @@ from pydantic import PositiveFloat, ValidationError -from .analysis_module import ESSettings, IESSettings +from .analysis_module import ESSettings from .design_matrix import DesignMatrix from .parsing import ( - AnalysisMode, ConfigDict, ConfigKeys, ConfigValidationError, @@ -21,7 +20,6 @@ logger = logging.getLogger(__name__) -DEFAULT_ANALYSIS_MODE = AnalysisMode.ENSEMBLE_SMOOTHER ObservationGroups = list[str] @@ -37,7 +35,6 @@ class AnalysisConfig: minimum_required_realizations: int = 0 update_log_path: str | Path = "update_log" es_module: ESSettings = field(default_factory=ESSettings) - ies_module: IESSettings = field(default_factory=IESSettings) observation_settings: UpdateSettings = field(default_factory=UpdateSettings) num_iterations: int = 1 design_matrix: DesignMatrix | None = None @@ -82,7 +79,7 @@ def from_dict(cls, config_dict: ConfigDict) -> AnalysisConfig: design_matrix_config_lists = config_dict.get(ConfigKeys.DESIGN_MATRIX, []) - options: dict[str, dict[str, Any]] = {"STD_ENKF": {}, "IES_ENKF": {}} + options: dict[str, dict[str, Any]] = {"STD_ENKF": {}} observation_settings: dict[str, Any] = { "alpha": config_dict.get(ConfigKeys.ENKF_ALPHA, 3.0), "std_cutoff": config_dict.get(ConfigKeys.STD_CUTOFF, 1e-6), @@ -95,13 +92,7 @@ def from_dict(cls, config_dict: ConfigDict) -> AnalysisConfig: **dict.fromkeys(["SUBSPACE_EXACT_R", "1"], "subspace"), **dict.fromkeys(["SUBSPACE_EE_R", "2"], "subspace"), **dict.fromkeys(["SUBSPACE_RE", "3"], "subspace"), - }, - "IES_ENKF": { - **dict.fromkeys(["EXACT", "0"], "direct"), - **dict.fromkeys(["SUBSPACE_EXACT_R", "1"], "subspace_exact"), - **dict.fromkeys(["SUBSPACE_EE_R", "2"], "subspace_projected"), - **dict.fromkeys(["SUBSPACE_RE", "3"], "subspace_projected"), - }, + } } deprecated_keys = ["ENKF_NCOMP", "ENKF_SUBSPACE_DIMENSION"] deprecated_inversion_keys = ["USE_EE", "USE_GE"] @@ -109,6 +100,12 @@ def from_dict(cls, config_dict: ConfigDict) -> AnalysisConfig: all_errors = [] for module_name, var_name, value in analysis_set_var: + if module_name == "IES_ENKF": + ConfigWarning.warn( + f"{module_name} has been removed and has no effect, valid options are:\n" + "ANALYSIS_SET_VAR STD_ENKF ..." + ) + continue if module_name == "OBSERVATIONS": if var_name == "AUTO_SCALE": observation_settings["auto_scale_observations"].append( @@ -136,19 +133,13 @@ def from_dict(cls, config_dict: ConfigDict) -> AnalysisConfig: ) ) continue - if var_name in {"INVERSION", "IES_INVERSION"}: + if var_name in {"INVERSION"}: if value in inversion_str_map[module_name]: new_value = inversion_str_map[module_name][value] - if var_name == "IES_INVERSION": - ConfigWarning.warn( - "IES_INVERSION is deprecated, please use INVERSION instead:\n" - f"ANALYSIS_SET_VAR {module_name} INVERSION {new_value.upper()}" - ) - else: - ConfigWarning.warn( - f"Using {value} is deprecated, use:\n" - f"ANALYSIS_SET_VAR {module_name} INVERSION {new_value.upper()}" - ) + ConfigWarning.warn( + f"Using {value} is deprecated, use:\n" + f"ANALYSIS_SET_VAR {module_name} INVERSION {new_value.upper()}" + ) value = new_value var_name = "inversion" @@ -174,7 +165,6 @@ def from_dict(cls, config_dict: ConfigDict) -> AnalysisConfig: try: es_settings = ESSettings(**options["STD_ENKF"]) - ies_settings = IESSettings(**options["IES_ENKF"]) obs_settings = UpdateSettings(**observation_settings) except ValidationError as err: for error in err.errors(): @@ -200,7 +190,6 @@ def from_dict(cls, config_dict: ConfigDict) -> AnalysisConfig: update_log_path=config_dict.get(ConfigKeys.UPDATE_LOG_PATH, "update_log"), observation_settings=obs_settings, es_module=es_settings, - ies_module=ies_settings, design_matrix=design_matrix, ) return config @@ -226,9 +215,6 @@ def __eq__(self, other: object) -> bool: if self.observation_settings != other.observation_settings: return False - if self.ies_module != other.ies_module: - return False - if self.es_module != other.es_module: return False diff --git a/src/ert/config/analysis_module.py b/src/ert/config/analysis_module.py index d565f1345e6..e42e282f9ef 100644 --- a/src/ert/config/analysis_module.py +++ b/src/ert/config/analysis_module.py @@ -9,22 +9,10 @@ logger = logging.getLogger(__name__) -DEFAULT_IES_MAX_STEPLENGTH = 0.60 -DEFAULT_IES_MIN_STEPLENGTH = 0.30 -DEFAULT_IES_DEC_STEPLENGTH = 2.50 DEFAULT_ENKF_TRUNCATION = 0.98 DEFAULT_LOCALIZATION = False -class BaseSettings(BaseModel): - enkf_truncation: Annotated[ - float, - Field(gt=0.0, le=1.0, title="Singular value truncation"), - ] = DEFAULT_ENKF_TRUNCATION - - model_config = ConfigDict(extra="forbid", validate_assignment=True) - - def _lower(v: str) -> str: return v.lower() @@ -43,25 +31,12 @@ def _lower(v: str) -> str: """ -InversionTypeIES = Annotated[ - Literal["direct", "subspace_exact", "subspace_projected"], BeforeValidator(_lower) -] -ies_description = """ - The type of inversion used in the algorithm. Every inversion method - scales the variables. The options are: - - * `direct`: - Solve directly, which involves inverting a matrix - of shape (num_observations, num_observations). - * `subspace_exact` : - Use the Woodbury lemma to invert a matrix of - size (ensemble_size, ensemble_size). - * `subspace_projected` : - Invert by projecting the covariance onto S. - """ - - -class ESSettings(BaseSettings): +class ESSettings(BaseModel): + model_config = ConfigDict(extra="forbid", validate_assignment=True) + enkf_truncation: Annotated[ + float, + Field(gt=0.0, le=1.0, title="Singular value truncation"), + ] = DEFAULT_ENKF_TRUNCATION inversion: Annotated[ InversionTypeES, Field(title="Inversion algorithm", description=es_description) ] = "exact" @@ -88,26 +63,4 @@ def correlation_threshold(self, ensemble_size: int) -> float: return self.localization_correlation_threshold -class IESSettings(BaseSettings): - """A good start is max steplength of 0.6, min steplength of 0.3, and decline of 2.5", - A steplength of 1.0 and one iteration results in ES update""" - - inversion: Annotated[ - InversionTypeIES, - Field(title="Inversion algorithm", description=ies_description), - ] = "subspace_exact" - ies_max_steplength: Annotated[ - float, - Field(ge=0.1, le=1.0, title="Gauss–Newton maximum steplength"), - ] = DEFAULT_IES_MAX_STEPLENGTH - ies_min_steplength: Annotated[ - float, - Field(ge=0.1, le=1.0, title="Gauss–Newton minimum steplength"), - ] = DEFAULT_IES_MIN_STEPLENGTH - ies_dec_steplength: Annotated[ - float, - Field(ge=1.1, le=10.0, title="Gauss–Newton steplength decline"), - ] = DEFAULT_IES_DEC_STEPLENGTH - - -AnalysisModule = ESSettings | IESSettings +AnalysisModule = ESSettings diff --git a/src/ert/config/parsing/__init__.py b/src/ert/config/parsing/__init__.py index 6ac0114fe67..63d993073cc 100644 --- a/src/ert/config/parsing/__init__.py +++ b/src/ert/config/parsing/__init__.py @@ -1,4 +1,3 @@ -from .analysis_mode import AnalysisMode from .config_dict import ConfigDict from .config_errors import ConfigValidationError, ConfigWarning from .config_keywords import ConfigKeys @@ -19,7 +18,6 @@ from .workflow_schema import init_workflow_schema __all__ = [ - "AnalysisMode", "ConfigDict", "ConfigKeys", "ConfigValidationError", diff --git a/src/ert/config/parsing/analysis_mode.py b/src/ert/config/parsing/analysis_mode.py deleted file mode 100644 index e88a97a25a5..00000000000 --- a/src/ert/config/parsing/analysis_mode.py +++ /dev/null @@ -1,6 +0,0 @@ -from enum import StrEnum - - -class AnalysisMode(StrEnum): - ITERATED_ENSEMBLE_SMOOTHER = "IES_ENKF" - ENSEMBLE_SMOOTHER = "STD_ENKF" diff --git a/src/ert/gui/ertwidgets/analysismodulevariablespanel.py b/src/ert/gui/ertwidgets/analysismodulevariablespanel.py index 0bd78746f0c..87cbbc8a32b 100644 --- a/src/ert/gui/ertwidgets/analysismodulevariablespanel.py +++ b/src/ert/gui/ertwidgets/analysismodulevariablespanel.py @@ -19,9 +19,7 @@ from ert.config.analysis_module import ( AnalysisModule, - IESSettings, InversionTypeES, - InversionTypeIES, ) @@ -37,43 +35,8 @@ def __init__(self, analysis_module: AnalysisModule, ensemble_size: int): self.blockSignals(True) - layout.addRow( - QLabel( - "AnalysisModule: STD_ENKF" - if type(analysis_module) != IESSettings - else "AnalysisModule: IES_ENKF" - ) - ) + layout.addRow(QLabel("AnalysisModule: STD_ENKF")) layout.addRow(self.create_horizontal_line()) - - if isinstance(analysis_module, IESSettings): - for variable_name in ( - name for name in analysis_module.model_fields if "steplength" in name - ): - metadata = analysis_module.model_fields[variable_name] - layout.addRow( - metadata.title, - self.createDoubleSpinBox( - variable_name, - analysis_module.__getattribute__(variable_name), - 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, - ), - ) - - lab = QLabel(analysis_module.__doc__) - lab.setStyleSheet("font-style: italic; font-size: 10pt; font-weight: 300") - layout.addRow(lab) - - layout.addRow(self.create_horizontal_line()) - layout.addRow(QLabel("Inversion Algorithm")) dropdown = QComboBox(self) options = analysis_module.model_fields["inversion"] @@ -99,53 +62,48 @@ def __init__(self, analysis_module: AnalysisModule, ensemble_size: int): self.truncation_spinner.setEnabled(False) layout.addRow("Singular value truncation", self.truncation_spinner) - if not isinstance(analysis_module, IESSettings): - layout.addRow(self.create_horizontal_line()) - layout.addRow(QLabel("[EXPERIMENTAL]")) - - localization_frame = QFrame() - localization_frame.setLayout(QHBoxLayout()) - lf_layout = cast(QLayout, localization_frame.layout()) - lf_layout.setContentsMargins(0, 0, 0, 0) - - metadata = analysis_module.model_fields[ - "localization_correlation_threshold" - ] - local_checkbox = QCheckBox(metadata.title) - local_checkbox.setObjectName("localization") - local_checkbox.clicked.connect( - partial( - self.valueChanged, - "localization", - bool, - local_checkbox, - ) - ) - var_name = "localization_correlation_threshold" - metadata = analysis_module.model_fields[var_name] - self.local_spinner = self.createDoubleSpinBox( - var_name, - analysis_module.correlation_threshold(ensemble_size), - 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, + layout.addRow(self.create_horizontal_line()) + layout.addRow(QLabel("[EXPERIMENTAL]")) + + localization_frame = QFrame() + localization_frame.setLayout(QHBoxLayout()) + lf_layout = cast(QLayout, localization_frame.layout()) + lf_layout.setContentsMargins(0, 0, 0, 0) + + metadata = analysis_module.model_fields["localization_correlation_threshold"] + local_checkbox = QCheckBox(metadata.title) + local_checkbox.setObjectName("localization") + local_checkbox.clicked.connect( + partial( + self.valueChanged, + "localization", + bool, + local_checkbox, ) - self.local_spinner.setObjectName("localization_threshold") - self.local_spinner.setEnabled(local_checkbox.isChecked()) + ) + var_name = "localization_correlation_threshold" + metadata = analysis_module.model_fields[var_name] + self.local_spinner = self.createDoubleSpinBox( + var_name, + analysis_module.correlation_threshold(ensemble_size), + 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_threshold") + self.local_spinner.setEnabled(local_checkbox.isChecked()) - lf_layout.addWidget(local_checkbox) - lf_layout.addWidget(self.local_spinner) - layout.addRow(localization_frame) + lf_layout.addWidget(local_checkbox) + lf_layout.addWidget(self.local_spinner) + layout.addRow(localization_frame) - local_checkbox.stateChanged.connect(self.local_spinner.setEnabled) - local_checkbox.setChecked(analysis_module.localization) + local_checkbox.stateChanged.connect(self.local_spinner.setEnabled) + local_checkbox.setChecked(analysis_module.localization) self.setLayout(layout) self.blockSignals(False) - def update_inversion_algorithm( - self, text: InversionTypeES | InversionTypeIES - ) -> None: + def update_inversion_algorithm(self, text: InversionTypeES) -> None: self.truncation_spinner.setEnabled( not any(val in text.lower() for val in ["direct", "exact"]) ) diff --git a/src/ert/gui/simulation/experiment_panel.py b/src/ert/gui/simulation/experiment_panel.py index 3de30c78a4d..25a22ab8722 100644 --- a/src/ert/gui/simulation/experiment_panel.py +++ b/src/ert/gui/simulation/experiment_panel.py @@ -42,7 +42,6 @@ from .ensemble_smoother_panel import EnsembleSmootherPanel from .evaluate_ensemble_panel import EvaluateEnsemblePanel from .experiment_config_panel import ExperimentConfigPanel -from .iterated_ensemble_smoother_panel import IteratedEnsembleSmootherPanel from .manual_update_panel import ManualUpdatePanel from .multiple_data_assimilation_panel import MultipleDataAssimilationPanel from .run_dialog import RunDialog @@ -168,12 +167,6 @@ def __init__( EnsembleSmootherPanel(analysis_config, run_path, notifier, ensemble_size), experiment_type_valid, ) - self.addExperimentConfigPanel( - IteratedEnsembleSmootherPanel( - analysis_config, run_path, notifier, ensemble_size - ), - experiment_type_valid, - ) self.addExperimentConfigPanel( ManualUpdatePanel(ensemble_size, run_path, notifier, analysis_config), experiment_type_valid, diff --git a/src/ert/gui/simulation/iterated_ensemble_smoother_panel.py b/src/ert/gui/simulation/iterated_ensemble_smoother_panel.py deleted file mode 100644 index 9d4e1138cb4..00000000000 --- a/src/ert/gui/simulation/iterated_ensemble_smoother_panel.py +++ /dev/null @@ -1,147 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import TYPE_CHECKING - -from qtpy.QtCore import Slot -from qtpy.QtWidgets import QFormLayout, QLabel, QSpinBox - -from ert.gui.ertnotifier import ErtNotifier -from ert.gui.ertwidgets import ( - ActiveRealizationsModel, - AnalysisModuleEdit, - CopyableLabel, - StringBox, - TargetEnsembleModel, - TextModel, -) -from ert.mode_definitions import ITERATIVE_ENSEMBLE_SMOOTHER_MODE -from ert.run_models import IteratedEnsembleSmoother -from ert.validation import ProperNameFormatArgument, RangeStringArgument -from ert.validation.proper_name_argument import ExperimentValidation - -from .experiment_config_panel import ExperimentConfigPanel - -if TYPE_CHECKING: - from ert.config import AnalysisConfig - - -@dataclass -class Arguments: - mode: str - target_ensemble: str - realizations: str - num_iterations: int - experiment_name: str - - -class IteratedEnsembleSmootherPanel(ExperimentConfigPanel): - def __init__( - self, - analysis_config: AnalysisConfig, - run_path: str, - notifier: ErtNotifier, - ensemble_size: int, - ): - self.notifier = notifier - ExperimentConfigPanel.__init__(self, IteratedEnsembleSmoother) - self.analysis_config = analysis_config - layout = QFormLayout() - self.setObjectName("iterated_ensemble_smoother_panel") - - self._experiment_name_field = StringBox( - TextModel(""), - placeholder_text=self.notifier.storage.get_unique_experiment_name( - ITERATIVE_ENSEMBLE_SMOOTHER_MODE - ), - ) - self._experiment_name_field.setMinimumWidth(250) - self._experiment_name_field.setValidator( - ExperimentValidation(self.notifier.storage) - ) - self._experiment_name_field.setObjectName("experiment_field") - layout.addRow("Experiment name:", self._experiment_name_field) - - runpath_label = CopyableLabel(text=run_path) - layout.addRow("Runpath:", runpath_label) - - number_of_realizations_label = QLabel(f"<b>{ensemble_size}</b>") - layout.addRow(QLabel("Number of realizations:"), number_of_realizations_label) - - # The num_iterations_spinner does not track any external changes (will - # that ever happen?) - self._num_iterations_spinner = QSpinBox() - self._num_iterations_spinner.setMinimum(1) - self._num_iterations_spinner.setMaximum(100) - self._num_iterations_spinner.setValue(4) - - layout.addRow("Number of iterations:", self._num_iterations_spinner) - - self._iterated_target_ensemble_format_model = TargetEnsembleModel( - analysis_config, notifier - ) - self._iterated_target_ensemble_format_field = StringBox( - self._iterated_target_ensemble_format_model, # type: ignore - self._iterated_target_ensemble_format_model.getDefaultValue(), # type: ignore - continuous_update=True, - ) - self._iterated_target_ensemble_format_field.setValidator( - ProperNameFormatArgument() - ) - layout.addRow( - "Target ensemble format:", self._iterated_target_ensemble_format_field - ) - - self._analysis_module_edit = AnalysisModuleEdit( - analysis_config.ies_module, ensemble_size - ) - layout.addRow("Analysis module:", self._analysis_module_edit) - - self._active_realizations_model = ActiveRealizationsModel(ensemble_size) - self._active_realizations_field = StringBox( - self._active_realizations_model, # type: ignore - "config/simulation/active_realizations", - ) - self._active_realizations_field.setValidator(RangeStringArgument(ensemble_size)) - layout.addRow("Active realizations", self._active_realizations_field) - - self._experiment_name_field.getValidationSupport().validationChanged.connect( - self.simulationConfigurationChanged - ) - self._iterated_target_ensemble_format_field.getValidationSupport().validationChanged.connect( - self.simulationConfigurationChanged - ) - self._active_realizations_field.getValidationSupport().validationChanged.connect( - self.simulationConfigurationChanged - ) - self.setLayout(layout) - - self.notifier.ertChanged.connect(self._update_experiment_name_placeholder) - - @Slot(ExperimentConfigPanel) - def experimentTypeChanged(self, w: ExperimentConfigPanel) -> None: - if isinstance(w, IteratedEnsembleSmootherPanel): - self._update_experiment_name_placeholder() - - def _update_experiment_name_placeholder(self) -> None: - self._experiment_name_field.setPlaceholderText( - self.notifier.storage.get_unique_experiment_name( - ITERATIVE_ENSEMBLE_SMOOTHER_MODE - ) - ) - - def isConfigurationValid(self) -> bool: - return ( - self._experiment_name_field.isValid() - and self._iterated_target_ensemble_format_field.isValid() - and self._active_realizations_field.isValid() - ) - - def get_experiment_arguments(self) -> Arguments: - return Arguments( - mode=ITERATIVE_ENSEMBLE_SMOOTHER_MODE, - target_ensemble=self._iterated_target_ensemble_format_model.getValue(), # type: ignore - realizations=self._active_realizations_field.text(), - num_iterations=self._num_iterations_spinner.value(), - experiment_name=self._experiment_name_field.get_text, - ) diff --git a/src/ert/mode_definitions.py b/src/ert/mode_definitions.py index 1ac37931992..8d3327242cf 100644 --- a/src/ert/mode_definitions.py +++ b/src/ert/mode_definitions.py @@ -1,6 +1,5 @@ ENSEMBLE_SMOOTHER_MODE = "ensemble_smoother" ENSEMBLE_EXPERIMENT_MODE = "ensemble_experiment" -ITERATIVE_ENSEMBLE_SMOOTHER_MODE = "iterative_ensemble_smoother" ES_MDA_MODE = "es_mda" TEST_RUN_MODE = "test_run" WORKFLOW_MODE = "workflow" @@ -10,7 +9,6 @@ MODULE_MODE = { "EnsembleSmoother": ENSEMBLE_SMOOTHER_MODE, "EnsembleExperiment": ENSEMBLE_EXPERIMENT_MODE, - "IteratedEnsembleSmoother": ITERATIVE_ENSEMBLE_SMOOTHER_MODE, "MultipleDataAssimilation": ES_MDA_MODE, "SingleTestRun": TEST_RUN_MODE, "EvaluateEnsemble": EVALUATE_ENSEMBLE_MODE, diff --git a/src/ert/run_models/__init__.py b/src/ert/run_models/__init__.py index 4b4f16a9ab3..2970b1d12f2 100644 --- a/src/ert/run_models/__init__.py +++ b/src/ert/run_models/__init__.py @@ -8,7 +8,6 @@ RunModelUpdateBeginEvent, RunModelUpdateEndEvent, ) -from .iterated_ensemble_smoother import IteratedEnsembleSmoother from .model_factory import create_model from .multiple_data_assimilation import MultipleDataAssimilation from .single_test_run import SingleTestRun @@ -18,7 +17,6 @@ "EnsembleExperiment", "EnsembleSmoother", "ErtRunError", - "IteratedEnsembleSmoother", "MultipleDataAssimilation", "RunModelEvent", "RunModelStatusEvent", diff --git a/src/ert/run_models/base_run_model.py b/src/ert/run_models/base_run_model.py index 3778107cf60..168e11b6075 100644 --- a/src/ert/run_models/base_run_model.py +++ b/src/ert/run_models/base_run_model.py @@ -30,7 +30,7 @@ AnalysisEvent, ) from ert.config import HookRuntime, QueueSystem -from ert.config.analysis_module import BaseSettings +from ert.config.analysis_module import ESSettings from ert.config.forward_model_step import ForwardModelStep from ert.config.model_config import ModelConfig from ert.config.workflow import Workflow @@ -738,7 +738,7 @@ def _evaluate_and_postprocess( class UpdateRunModel(BaseRunModel): def __init__( self, - analysis_settings: BaseSettings, + analysis_settings: ESSettings, update_settings: UpdateSettings, storage: Storage, runpath_file: Path, @@ -758,7 +758,7 @@ def __init__( random_seed: int | None, minimum_required_realizations: int, ): - self._analysis_settings: BaseSettings = analysis_settings + self._analysis_settings: ESSettings = analysis_settings self._update_settings: UpdateSettings = update_settings super().__init__( diff --git a/src/ert/run_models/iterated_ensemble_smoother.py b/src/ert/run_models/iterated_ensemble_smoother.py deleted file mode 100644 index 29245dc7ae0..00000000000 --- a/src/ert/run_models/iterated_ensemble_smoother.py +++ /dev/null @@ -1,247 +0,0 @@ -from __future__ import annotations - -import functools -import logging -from pathlib import Path -from queue import SimpleQueue -from typing import TYPE_CHECKING - -import numpy as np -from iterative_ensemble_smoother import steplength_exponential - -from ert.analysis import ErtAnalysisError, iterative_smoother_update -from ert.config import ErtConfig, HookRuntime -from ert.enkf_main import sample_prior -from ert.ensemble_evaluator import EvaluatorServerConfig -from ert.storage import Ensemble, Storage -from ert.trace import tracer - -from ..config.analysis_config import UpdateSettings -from ..config.analysis_module import IESSettings -from ..run_arg import create_run_arguments -from .base_run_model import BaseRunModel, ErtRunError, StatusEvents -from .event import RunModelStatusEvent, RunModelUpdateBeginEvent - -if TYPE_CHECKING: - from uuid import UUID - - import numpy.typing as npt - - from ert.config import QueueConfig - - -logger = logging.getLogger(__name__) - - -class IteratedEnsembleSmoother(BaseRunModel): - def __init__( - self, - target_ensemble: str, - experiment_name: str, - num_retries_per_iter: int, - number_of_iterations: int, - active_realizations: list[bool], - minimum_required_realizations: int, - random_seed: int | None, - config: ErtConfig, - storage: Storage, - queue_config: QueueConfig, - analysis_config: IESSettings, - update_settings: UpdateSettings, - status_queue: SimpleQueue[StatusEvents], - ): - self.analysis_config = analysis_config - self.update_settings = update_settings - - self.sies_step_length = functools.partial( - steplength_exponential, - min_steplength=analysis_config.ies_min_steplength, - max_steplength=analysis_config.ies_max_steplength, - halflife=analysis_config.ies_dec_steplength, - ) - self.target_ensemble_format = target_ensemble - self.experiment_name = experiment_name - - config.analysis_config.num_iterations = number_of_iterations - - super().__init__( - storage, - config.runpath_file, - Path(config.user_config_file), - config.env_vars, - config.env_pr_fm_step, - config.model_config, - queue_config, - config.forward_model_steps, - status_queue, - config.substitutions, - config.ert_templates, - config.hooked_workflows, - active_realizations=active_realizations, - total_iterations=number_of_iterations, - random_seed=random_seed, - minimum_required_realizations=minimum_required_realizations, - ) - self.support_restart = False - - # Initialize sies_smoother to None - # It is initialized later, but kept track of here - self.sies_smoother = None - self.num_retries_per_iter = num_retries_per_iter - - self._design_matrix = config.analysis_config.design_matrix - self._observations = config.observations - self._parameter_configuration = config.ensemble_config.parameter_configuration - self._response_configuration = config.ensemble_config.response_configuration - - @property - def sies_iteration(self) -> int: - """Returns the SIES iteration number, starting at 1.""" - if self.sies_smoother is None: - return 1 - else: - return self.sies_smoother.iteration - - def analyzeStep( - self, - prior_storage: Ensemble, - posterior_storage: Ensemble, - ensemble_id: UUID, - iteration: int, - initial_mask: npt.NDArray[np.bool_], - ) -> None: - self.run_workflows(HookRuntime.PRE_UPDATE, self._storage, prior_storage) - try: - _, self.sies_smoother = iterative_smoother_update( - prior_storage, - posterior_storage, - self.sies_smoother, - parameters=prior_storage.experiment.update_parameters, - observations=prior_storage.experiment.observation_keys, - update_settings=self.update_settings, - analysis_config=self.analysis_config, - sies_step_length=self.sies_step_length, - initial_mask=initial_mask, - rng=self.rng, - progress_callback=functools.partial( - self.send_smoother_event, iteration, ensemble_id - ), - ) - except ErtAnalysisError as e: - raise ErtRunError( - f"Update algorithm failed with the following error: {e}" - ) from e - self.run_workflows(HookRuntime.POST_UPDATE, self._storage, posterior_storage) - - @tracer.start_as_current_span(f"{__name__}.run_experiment") - def run_experiment( - self, evaluator_server_config: EvaluatorServerConfig, restart: bool = False - ) -> None: - self.log_at_startup() - self.restart = restart - self.run_workflows(HookRuntime.PRE_EXPERIMENT) - target_ensemble_format = self.target_ensemble_format - experiment = self._storage.create_experiment( - parameters=self._parameter_configuration, - observations=self._observations, - responses=self._response_configuration, - name=self.experiment_name, - ) - prior = self._storage.create_ensemble( - experiment=experiment, - ensemble_size=self.ensemble_size, - name=target_ensemble_format % 0, - ) - self.set_env_key("_ERT_ENSEMBLE_ID", str(prior.id)) - self.set_env_key("_ERT_EXPERIMENT_ID", str(experiment.id)) - - initial_mask = np.array(self.active_realizations, dtype=bool) - prior_args = create_run_arguments( - self.run_paths, - np.array(self.active_realizations, dtype=bool), - ensemble=prior, - ) - - sample_prior( - prior, - np.where(self.active_realizations)[0], - random_seed=self.random_seed, - ) - - self._evaluate_and_postprocess( - prior_args, - prior, - evaluator_server_config, - ) - - self.run_workflows(HookRuntime.PRE_FIRST_UPDATE, self._storage, prior) - for prior_iter in range(self._total_iterations): - self.send_event( - RunModelUpdateBeginEvent(iteration=prior_iter, run_id=prior.id) - ) - self.send_event( - RunModelStatusEvent( - iteration=prior_iter, - run_id=prior.id, - msg="Creating posterior ensemble..", - ) - ) - - posterior = self._storage.create_ensemble( - experiment, - name=target_ensemble_format % (prior_iter + 1), - ensemble_size=prior.ensemble_size, - iteration=prior_iter + 1, - prior_ensemble=prior, - ) - posterior_args = create_run_arguments( - self.run_paths, - self.active_realizations, - ensemble=posterior, - ) - update_success = False - for _iteration in range(self.num_retries_per_iter): - self.analyzeStep( - prior_storage=prior, - posterior_storage=posterior, - ensemble_id=prior.id, - iteration=prior_iter, - initial_mask=initial_mask, - ) - - # sies iteration starts at 1, we keep iters at 0, - # so we subtract sies to be 0-indexed - analysis_success = prior_iter < (self.sies_iteration - 1) - if analysis_success: - update_success = True - break - self._evaluate_and_postprocess( - prior_args, - prior, - evaluator_server_config, - ) - - if update_success: - self._evaluate_and_postprocess( - posterior_args, - posterior, - evaluator_server_config, - ) - else: - raise ErtRunError( - "Iterated ensemble smoother stopped: " - "maximum number of iteration retries " - f"({self.num_retries_per_iter} retries) reached " - f"for iteration {prior_iter}" - ) - prior = posterior - - self.run_workflows(HookRuntime.POST_EXPERIMENT) - - @classmethod - def name(cls) -> str: - return "Iterated ensemble smoother" - - @classmethod - def description(cls) -> str: - return "Sample parameters → [evaluate → update] several iterations.\nDeprecated algorithm. Prefer ES-MDA." diff --git a/src/ert/run_models/model_factory.py b/src/ert/run_models/model_factory.py index 0cede97e4d2..eb3816b04d6 100644 --- a/src/ert/run_models/model_factory.py +++ b/src/ert/run_models/model_factory.py @@ -13,7 +13,6 @@ ENSEMBLE_SMOOTHER_MODE, ES_MDA_MODE, EVALUATE_ENSEMBLE_MODE, - ITERATIVE_ENSEMBLE_SMOOTHER_MODE, MANUAL_UPDATE_MODE, TEST_RUN_MODE, ) @@ -23,7 +22,6 @@ from .ensemble_experiment import EnsembleExperiment from .ensemble_smoother import EnsembleSmoother from .evaluate_ensemble import EvaluateEnsemble -from .iterated_ensemble_smoother import IteratedEnsembleSmoother from .manual_update import ManualUpdate from .multiple_data_assimilation import MultipleDataAssimilation from .single_test_run import SingleTestRun @@ -67,10 +65,6 @@ def create_model( return _setup_multiple_data_assimilation( config, storage, args, update_settings, status_queue ) - if args.mode == ITERATIVE_ENSEMBLE_SMOOTHER_MODE: - return _setup_iterative_ensemble_smoother( - config, storage, args, update_settings, status_queue - ) if args.mode == MANUAL_UPDATE_MODE: return _setup_manual_update( config, storage, args, update_settings, status_queue @@ -265,34 +259,6 @@ def _setup_multiple_data_assimilation( ) -def _setup_iterative_ensemble_smoother( - config: ErtConfig, - storage: Storage, - args: Namespace, - update_settings: UpdateSettings, - status_queue: SimpleQueue[StatusEvents], -) -> IteratedEnsembleSmoother: - experiment_name = "ies" if args.experiment_name is None else args.experiment_name - active_realizations = _validate_num_realizations(args, config) - return IteratedEnsembleSmoother( - random_seed=config.random_seed, - active_realizations=active_realizations.tolist(), - target_ensemble=_iterative_ensemble_format(args), - number_of_iterations=( - int(args.num_iterations) if args.num_iterations is not None else 4 - ), - minimum_required_realizations=config.analysis_config.minimum_required_realizations, - num_retries_per_iter=4, - experiment_name=experiment_name, - config=config, - storage=storage, - queue_config=config.queue_config, - analysis_config=config.analysis_config.ies_module, - update_settings=update_settings, - status_queue=status_queue, - ) - - def _realizations(args: Namespace, ensemble_size: int) -> npt.NDArray[np.bool_]: if args.realizations is None: return np.ones(ensemble_size, dtype=bool) diff --git a/test-data/ert/snake_oil/snake_oil.ert b/test-data/ert/snake_oil/snake_oil.ert index d871bf1ad62..6b34ea36f36 100644 --- a/test-data/ert/snake_oil/snake_oil.ert +++ b/test-data/ert/snake_oil/snake_oil.ert @@ -4,7 +4,6 @@ NUM_REALIZATIONS 25 QUEUE_OPTION LOCAL MAX_RUNNING 25 -ANALYSIS_SET_VAR IES_ENKF INVERSION SUBSPACE_EXACT ANALYSIS_SET_VAR STD_ENKF INVERSION SUBSPACE DEFINE <STORAGE> storage/<CONFIG_FILE_BASE> diff --git a/tests/ert/ui_tests/cli/test_cli.py b/tests/ert/ui_tests/cli/test_cli.py index 0859197d02f..7100e78496d 100644 --- a/tests/ert/ui_tests/cli/test_cli.py +++ b/tests/ert/ui_tests/cli/test_cli.py @@ -21,7 +21,6 @@ import _ert.threading import ert.shared from _ert.forward_model_runner.client import Client -from ert import LibresFacade from ert.cli.main import ErtCliError from ert.config import ConfigValidationError, ErtConfig from ert.enkf_main import sample_prior @@ -30,7 +29,6 @@ ENSEMBLE_EXPERIMENT_MODE, ENSEMBLE_SMOOTHER_MODE, ES_MDA_MODE, - ITERATIVE_ENSEMBLE_SMOOTHER_MODE, TEST_RUN_MODE, ) from ert.scheduler.job import Job @@ -57,7 +55,6 @@ def test_test_run_on_lsf_configuration_works_with_no_errors(tmp_path): "mode", [ pytest.param(ENSEMBLE_SMOOTHER_MODE), - pytest.param(ITERATIVE_ENSEMBLE_SMOOTHER_MODE), pytest.param(ES_MDA_MODE), ], ) @@ -175,7 +172,6 @@ def test_unopenable_observation_config_fails_gracefully(): "mode", [ pytest.param(ENSEMBLE_SMOOTHER_MODE), - pytest.param(ITERATIVE_ENSEMBLE_SMOOTHER_MODE), pytest.param(ES_MDA_MODE), ], ) @@ -573,11 +569,6 @@ def test_es_mda(snapshot): pytest.param( ENSEMBLE_SMOOTHER_MODE, "target_%d", id=f"{ENSEMBLE_SMOOTHER_MODE}" ), - pytest.param( - ITERATIVE_ENSEMBLE_SMOOTHER_MODE, - "iter-%d", - id=f"{ITERATIVE_ENSEMBLE_SMOOTHER_MODE}", - ), pytest.param(ES_MDA_MODE, "iter-%d", id=f"{ES_MDA_MODE}"), ], ) @@ -616,76 +607,6 @@ def test_cli_test_run(mock_cli_run): thread_start_mock.assert_has_calls([[call(), call()]]) -@pytest.mark.usefixtures("copy_poly_case") -def test_that_running_ies_with_different_steplength_produces_different_result(): - """This is a regression test to make sure that different step-lengths - give different results when running SIES. - """ - - def _run(target, experiment_name): - run_cli( - ITERATIVE_ENSEMBLE_SMOOTHER_MODE, - "--disable-monitoring", - "--target-ensemble", - f"{target}-%d", - "--realizations", - "1,2,4,8", - "poly.ert", - "--num-iterations", - "1", - "--experiment-name", - experiment_name, - ) - facade = LibresFacade.from_config_file("poly.ert") - with open_storage(facade.enspath) as storage: - experiment = storage.get_experiment_by_name(experiment_name) - iter_0_fs = experiment.get_ensemble_by_name(f"{target}-0") - df_iter_0 = iter_0_fs.load_all_gen_kw_data() - iter_1_fs = experiment.get_ensemble_by_name(f"{target}-1") - df_iter_1 = iter_1_fs.load_all_gen_kw_data() - - result = pd.concat( - [df_iter_0, df_iter_1], - keys=["iter-0", "iter-1"], - ) - return result - - # Run SIES with step-lengths defined - with open("poly.ert", mode="a", encoding="utf-8") as fh: - fh.write( - dedent( - """ - RANDOM_SEED 123456 - ANALYSIS_SET_VAR IES_ENKF IES_MAX_STEPLENGTH 0.5 - ANALYSIS_SET_VAR IES_ENKF IES_MIN_STEPLENGTH 0.2 - ANALYSIS_SET_VAR IES_ENKF IES_DEC_STEPLENGTH 2.5 - """ - ) - ) - - result_1 = _run("target_result_1", experiment_name="ies-1") - - # Run SIES with different step-lengths defined - with open("poly.ert", mode="a", encoding="utf-8") as fh: - fh.write( - dedent( - """ - ANALYSIS_SET_VAR IES_ENKF IES_MAX_STEPLENGTH 0.6 - ANALYSIS_SET_VAR IES_ENKF IES_MIN_STEPLENGTH 0.3 - ANALYSIS_SET_VAR IES_ENKF IES_DEC_STEPLENGTH 2.0 - """ - ) - ) - - result_2 = _run("target_result_2", experiment_name="ies-2") - - # Prior should be the same - assert result_1.loc["iter-0"].equals(result_2.loc["iter-0"]) - - # Posterior should be different - assert not np.isclose(result_1.loc["iter-1"], result_2.loc["iter-1"]).all() - - @pytest.mark.usefixtures("copy_poly_case") @pytest.mark.parametrize( "prior_mask,reals_rerun_option", diff --git a/tests/ert/ui_tests/gui/test_main_window.py b/tests/ert/ui_tests/gui/test_main_window.py index 7d51123c6f0..6dd099de325 100644 --- a/tests/ert/ui_tests/gui/test_main_window.py +++ b/tests/ert/ui_tests/gui/test_main_window.py @@ -54,7 +54,6 @@ from ert.run_models import ( EnsembleExperiment, EnsembleSmoother, - IteratedEnsembleSmoother, MultipleDataAssimilation, SingleTestRun, ) @@ -112,7 +111,7 @@ def test_that_the_ui_show_no_errors_and_enables_update_for_poly_example(qapp): with add_gui_log_handler() as log_handler: gui, *_ = ert.gui.main._start_initial_gui_window(args, log_handler) combo_box = get_child(gui, QComboBox, name="experiment_type") - assert combo_box.count() == 7 + assert combo_box.count() == 6 for i in range(combo_box.count()): assert combo_box.model().item(i).isEnabled() @@ -132,7 +131,7 @@ def test_gui_shows_a_warning_and_disables_update_when_there_are_no_observations( with add_gui_log_handler() as log_handler: gui, *_ = ert.gui.main._start_initial_gui_window(args, log_handler) combo_box = get_child(gui, QComboBox, name="experiment_type") - assert combo_box.count() == 7 + assert combo_box.count() == 6 for i in range(3): assert combo_box.model().item(i).isEnabled() @@ -160,7 +159,7 @@ def test_gui_shows_a_warning_and_disables_update_when_parameters_are_missing( with add_gui_log_handler() as log_handler: gui, *_ = ert.gui.main._start_initial_gui_window(args, log_handler) combo_box = get_child(gui, QComboBox, name="experiment_type") - assert combo_box.count() == 7 + assert combo_box.count() == 6 for i in range(3): assert combo_box.model().item(i).isEnabled() @@ -698,7 +697,7 @@ def test_that_es_mda_restart_run_box_is_disabled_when_there_are_no_cases(qtbot): combo_box = get_child(gui, QComboBox, name="experiment_type") qtbot.mouseClick(combo_box, Qt.MouseButton.LeftButton) - assert combo_box.count() == 7 + assert combo_box.count() == 6 combo_box.setCurrentIndex(3) assert combo_box.currentText() == MultipleDataAssimilation.display_name() @@ -757,7 +756,6 @@ def test_validation_of_experiment_names_in_run_models( MultipleDataAssimilation.display_name(), "ES_MDA_panel", ), - (IteratedEnsembleSmoother.display_name(), "iterated_ensemble_smoother_panel"), ) for exp_type, panel_name in experiment_types_to_test: experiment_types.setCurrentText(exp_type) diff --git a/tests/ert/ui_tests/gui/test_missing_parameters_to_update.py b/tests/ert/ui_tests/gui/test_missing_parameters_to_update.py index e8d744924a1..c2cae6dbf5b 100644 --- a/tests/ert/ui_tests/gui/test_missing_parameters_to_update.py +++ b/tests/ert/ui_tests/gui/test_missing_parameters_to_update.py @@ -8,7 +8,6 @@ from ert.run_models import ( EnsembleExperiment, EnsembleSmoother, - IteratedEnsembleSmoother, MultipleDataAssimilation, ) from tests.ert.ui_tests.gui.conftest import get_child, open_gui_with_config @@ -34,10 +33,6 @@ def test_no_updateable_parameters(qtbot): assert not ( simulation_mode_combo.model().item(idx).flags() & Qt.ItemFlag.ItemIsEnabled ) - idx = simulation_mode_combo.findText(IteratedEnsembleSmoother.display_name()) - assert not ( - simulation_mode_combo.model().item(idx).flags() & Qt.ItemFlag.ItemIsEnabled - ) idx = simulation_mode_combo.findText(EnsembleExperiment.display_name()) assert ( simulation_mode_combo.model().item(idx).flags() & Qt.ItemFlag.ItemIsEnabled diff --git a/tests/ert/unit_tests/analysis/test_es_update.py b/tests/ert/unit_tests/analysis/test_es_update.py index 2101a97abca..b8caa78d0d8 100644 --- a/tests/ert/unit_tests/analysis/test_es_update.py +++ b/tests/ert/unit_tests/analysis/test_es_update.py @@ -1,4 +1,3 @@ -import functools from contextlib import ExitStack as does_not_raise from unittest.mock import patch @@ -7,13 +6,11 @@ import pytest import xarray as xr import xtgeo -from iterative_ensemble_smoother import steplength_exponential from tabulate import tabulate from ert.analysis import ( ErtAnalysisError, ObservationStatus, - iterative_smoother_update, smoother_update, ) from ert.analysis._es_update import ( @@ -24,7 +21,7 @@ from ert.analysis.event import AnalysisCompleteEvent, AnalysisErrorEvent from ert.config import Field, GenDataConfig, GenKwConfig from ert.config.analysis_config import UpdateSettings -from ert.config.analysis_module import ESSettings, IESSettings +from ert.config.analysis_module import ESSettings from ert.config.gen_kw_config import TransformFunctionDefinition from ert.field_utils import Shape from ert.storage import open_storage @@ -435,51 +432,26 @@ def test_update_raises_on_singular_matrix(tmp_path): ) -@pytest.mark.parametrize( - "module, expected_gen_kw", - [ - ( - "IES_ENKF", - [ - 0.6038000995616932, - -0.8995579663087738, - -0.650440718033405, - -0.11664520562571357, - 0.14637004546145008, - 0.06369104020984925, - -1.5673340724477953, - 0.2045320804879709, - -0.8182935847537811, - 0.7551499933992224, - ], - ), - ( - "STD_ENKF", - [ - 1.7365584618531105, - -0.819068074727709, - -1.6628460358849138, - -1.269803440396085, - -0.06688718485326725, - 0.5544021609832737, - -2.904293766981197, - 1.6866443742416257, - -1.6783511959093573, - 1.3081213916230614, - ], - ), - ], -) def test_update_snapshot( snake_oil_case_storage, snake_oil_storage, - module, - expected_gen_kw, ): """ Note that this is now a snapshot test, so there is no guarantee that the snapshots are correct, they are just documenting the current behavior. """ + expected_gen_kw = [ + 1.7365584618531105, + -0.819068074727709, + -1.6628460358849138, + -1.269803440396085, + -0.06688718485326725, + 0.5544021609832737, + -2.904293766981197, + 1.6866443742416257, + -1.6783511959093573, + 1.3081213916230614, + ] ert_config = snake_oil_case_storage # Making sure that row scaling with a row scaling factor of 1.0 @@ -498,39 +470,15 @@ def test_update_snapshot( # Make sure we always have the same seed in updates rng = np.random.default_rng(42) - if module == "IES_ENKF": - # Step length defined as a callable on sies-iterations - sies_step_length = functools.partial(steplength_exponential) - - # The sies-smoother is initially optional - sies_smoother = None - - # The initial_mask equals ens_mask on first iteration - initial_mask = prior_ens.get_realization_mask_with_responses() - - # Call an iteration of SIES algorithm. Producing snapshot and SIES obj - iterative_smoother_update( - prior_storage=prior_ens, - posterior_storage=posterior_ens, - sies_smoother=sies_smoother, - observations=experiment.observation_keys, - parameters=list(ert_config.ensemble_config.parameters), - update_settings=UpdateSettings(), - analysis_config=IESSettings(inversion="subspace_exact"), - sies_step_length=sies_step_length, - initial_mask=initial_mask, - rng=rng, - ) - else: - smoother_update( - prior_ens, - posterior_ens, - experiment.observation_keys, - list(ert_config.ensemble_config.parameters), - UpdateSettings(), - ESSettings(inversion="subspace"), - rng=rng, - ) + smoother_update( + prior_ens, + posterior_ens, + experiment.observation_keys, + list(ert_config.ensemble_config.parameters), + UpdateSettings(), + ESSettings(inversion="subspace"), + rng=rng, + ) sim_gen_kw = list( prior_ens.load_parameters("SNAKE_OIL_PARAM", 0)["values"].values.flatten() @@ -645,26 +593,15 @@ def test_smoother_snapshot_alpha( prior_ensemble=prior_storage, ) - # Step length defined as a callable on sies-iterations - sies_step_length = functools.partial(steplength_exponential) - - # The sies-smoother is initially optional - sies_smoother = None - - # The initial_mask equals ens_mask on first iteration - initial_mask = prior_storage.get_realization_mask_with_responses() - with expectation: - result_snapshot, _ = iterative_smoother_update( - prior_storage=prior_storage, - posterior_storage=posterior_storage, - sies_smoother=sies_smoother, + result_snapshot = smoother_update( + prior_storage, + posterior_storage, observations=["OBSERVATION"], parameters=["PARAMETER"], update_settings=UpdateSettings(alpha=alpha), - analysis_config=IESSettings(), - sies_step_length=sies_step_length, - initial_mask=initial_mask, + es_settings=ESSettings(inversion="subspace"), + rng=rng, ) assert result_snapshot.alpha == alpha assert [ diff --git a/tests/ert/unit_tests/cli/test_model_hook_order.py b/tests/ert/unit_tests/cli/test_model_hook_order.py index f6ddbe40fb2..ea2b3872b7a 100644 --- a/tests/ert/unit_tests/cli/test_model_hook_order.py +++ b/tests/ert/unit_tests/cli/test_model_hook_order.py @@ -1,5 +1,5 @@ import uuid -from unittest.mock import ANY, MagicMock, PropertyMock, call, patch +from unittest.mock import ANY, MagicMock, call import pytest @@ -7,11 +7,9 @@ from ert.run_models import ( BaseRunModel, EnsembleSmoother, - IteratedEnsembleSmoother, MultipleDataAssimilation, base_run_model, ensemble_smoother, - iterated_ensemble_smoother, multiple_data_assimilation, ) @@ -97,41 +95,3 @@ def test_hook_call_order_es_mda(monkeypatch): test_class.run_experiment(MagicMock()) assert run_wfs_mock.mock_calls == EXPECTED_CALL_ORDER - - -@pytest.mark.usefixtures("patch_base_run_model") -def test_hook_call_order_iterative_ensemble_smoother(monkeypatch): - """ - The goal of this test is to assert that the hook call order is the same - across different models. - """ - run_wfs_mock = MagicMock() - monkeypatch.setattr(iterated_ensemble_smoother, "sample_prior", MagicMock()) - monkeypatch.setattr(base_run_model, "_seed_sequence", MagicMock(return_value=0)) - monkeypatch.setattr(base_run_model.BaseRunModel, "run_workflows", run_wfs_mock) - - ens_mock = MagicMock() - ens_mock.iteration = 2 - ens_mock.id = uuid.uuid1() - storage_mock = MagicMock() - storage_mock.create_ensemble.return_value = ens_mock - - test_class = IteratedEnsembleSmoother(*[MagicMock()] * 13) - test_class.run_ensemble_evaluator = MagicMock(return_value=[0]) - test_class._storage = storage_mock - # Mock the return values of iterative_smoother_update - # Mock the iteration property of IteratedEnsembleSmoother - with ( - patch( - "ert.run_models.iterated_ensemble_smoother.iterative_smoother_update", - MagicMock(return_value=(MagicMock(), MagicMock())), - ), - patch( - "ert.run_models.iterated_ensemble_smoother.IteratedEnsembleSmoother.sies_iteration", - new_callable=PropertyMock, - ) as mock_iteration, - ): - mock_iteration.return_value = 2 - test_class.run_experiment(MagicMock()) - - assert run_wfs_mock.mock_calls == EXPECTED_CALL_ORDER diff --git a/tests/ert/unit_tests/config/test_analysis_config.py b/tests/ert/unit_tests/config/test_analysis_config.py index 52199b8c940..8794e87656d 100644 --- a/tests/ert/unit_tests/config/test_analysis_config.py +++ b/tests/ert/unit_tests/config/test_analysis_config.py @@ -10,7 +10,6 @@ ConfigValidationError, ErtConfig, ESSettings, - IESSettings, ) from ert.config.parsing import ConfigKeys, ConfigWarning @@ -185,18 +184,6 @@ def test_valid_min_realization(value, expected): ) def test_analysis_config_modules(analysis_config): assert isinstance(analysis_config.es_module, ESSettings) - assert isinstance(analysis_config.ies_module, IESSettings) - - -def test_incorrect_variable_raises_validation_error(): - with pytest.raises( - ConfigValidationError, match="Input should be 'exact' or 'subspace'" - ): - _ = AnalysisConfig.from_dict( - { - ConfigKeys.ANALYSIS_SET_VAR: [["STD_ENKF", "IES_INVERSION", "FOO"]], - } - ) def test_unknown_variable_raises_validation_error(): @@ -302,27 +289,13 @@ def test_num_realizations_0_means_all(): ) -@pytest.mark.parametrize( - "config, expected", - [ - ( - ["STD_ENKF", "INVERSION", "1"], - "Using 1 is deprecated, use:\nANALYSIS_SET_VAR STD_ENKF INVERSION SUBSPACE", - ), - ( - ["STD_ENKF", "IES_INVERSION", "1"], - dedent( - """IES_INVERSION is deprecated, please use INVERSION instead: -ANALYSIS_SET_VAR STD_ENKF INVERSION SUBSPACE""" - ), - ), - ], -) -def test_incorrect_variable_deprecation_warning(config, expected): - with pytest.warns(match=expected): +def test_incorrect_variable_deprecation_warning(): + with pytest.warns( + match="Using 1 is deprecated, use:\nANALYSIS_SET_VAR STD_ENKF INVERSION SUBSPACE" + ): AnalysisConfig.from_dict( { - ConfigKeys.ANALYSIS_SET_VAR: [config], + ConfigKeys.ANALYSIS_SET_VAR: [["STD_ENKF", "INVERSION", "1"]], } ) 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 062aa519bc9..6346282472f 100644 --- a/tests/ert/unit_tests/run_models/test_model_factory.py +++ b/tests/ert/unit_tests/run_models/test_model_factory.py @@ -16,12 +16,10 @@ from ert.mode_definitions import ( ENSEMBLE_SMOOTHER_MODE, ES_MDA_MODE, - ITERATIVE_ENSEMBLE_SMOOTHER_MODE, ) from ert.run_models import ( EnsembleExperiment, EnsembleSmoother, - IteratedEnsembleSmoother, MultipleDataAssimilation, SingleTestRun, model_factory, @@ -33,7 +31,6 @@ "mode", [ pytest.param(ENSEMBLE_SMOOTHER_MODE), - pytest.param(ITERATIVE_ENSEMBLE_SMOOTHER_MODE), pytest.param(ES_MDA_MODE), ], ) @@ -201,28 +198,6 @@ def test_setup_multiple_data_assimilation(storage): assert model.restart_run == False -def test_setup_iterative_ensemble_smoother(poly_case, storage): - model = model_factory._setup_iterative_ensemble_smoother( - ErtConfig.from_file_contents("NUM_REALIZATIONS 100\n"), - storage, - Namespace( - realizations="0-4,7,8", - target_ensemble="test_case_%d", - num_iterations=10, - experiment_name=None, - ), - UpdateSettings(), - queue.SimpleQueue(), - ) - assert isinstance(model, IteratedEnsembleSmoother) - assert model.target_ensemble_format == "test_case_%d" - assert ( - model.active_realizations - == [True] * 5 + [False] * 2 + [True] * 2 + [False] * 91 - ) - assert model._total_iterations == 10 - - @pytest.mark.parametrize( "restart_from_iteration, expected_path", [ @@ -286,7 +261,6 @@ def test_multiple_data_assimilation_restart_paths( [ model_factory._setup_multiple_data_assimilation, model_factory._setup_ensemble_smoother, - model_factory._setup_iterative_ensemble_smoother, ], ) def test_num_realizations_specified_incorrectly_raises(analysis_mode): diff --git a/tests/ert/unit_tests/test_main.py b/tests/ert/unit_tests/test_main.py index 04e86e00b38..3200b79c42c 100644 --- a/tests/ert/unit_tests/test_main.py +++ b/tests/ert/unit_tests/test_main.py @@ -9,7 +9,6 @@ ENSEMBLE_EXPERIMENT_MODE, ENSEMBLE_SMOOTHER_MODE, ES_MDA_MODE, - ITERATIVE_ENSEMBLE_SMOOTHER_MODE, TEST_RUN_MODE, WORKFLOW_MODE, ) @@ -96,20 +95,17 @@ def test_argparse_exec_ensemble_experiment_faulty_realizations(): ) -@pytest.mark.parametrize( - "mode", [ITERATIVE_ENSEMBLE_SMOOTHER_MODE, ENSEMBLE_SMOOTHER_MODE] -) -def test_argparse_exec_smoother_valid_ensemble(mode): +def test_argparse_exec_smoother_valid_ensemble(): parsed = ert_parser( None, [ - mode, + ENSEMBLE_SMOOTHER_MODE, "--target-ensemble", "some_ensemble_%d", "path/to/config.ert", ], ) - assert parsed.mode == mode + assert parsed.mode == ENSEMBLE_SMOOTHER_MODE assert parsed.target_ensemble == "some_ensemble_%d" assert parsed.func.__name__ == "run_cli" @@ -158,23 +154,6 @@ def test_argparse_exec_workflow(): assert parsed.func.__name__ == "run_cli" -def test_argparse_exec_iterative_ensemble_smoother_current_ensemble(): - parsed = ert_parser( - None, - [ - ITERATIVE_ENSEMBLE_SMOOTHER_MODE, - "--current-ensemble", - "test_ensemble", - "--target-ensemble", - "test_ensemble_smoother_%d", - "path/to/config.ert", - ], - ) - assert parsed.mode == ITERATIVE_ENSEMBLE_SMOOTHER_MODE - assert parsed.current_ensemble == "test_ensemble" - assert parsed.func.__name__ == "run_cli" - - @pytest.mark.parametrize( "flag_val,expected_value", [("--verbose", True), (None, False)] )