From cce101c9fcf222e0d9293affe4bc0b813d3a7d59 Mon Sep 17 00:00:00 2001 From: Peter Verveer Date: Fri, 31 Jan 2025 08:40:16 +0000 Subject: [PATCH 1/7] Remove tabular optimization output --- src/ert/run_models/everest_run_model.py | 88 +------------------------ 1 file changed, 2 insertions(+), 86 deletions(-) diff --git a/src/ert/run_models/everest_run_model.py b/src/ert/run_models/everest_run_model.py index 3e4818d5ec9..101a7a4cbe7 100644 --- a/src/ert/run_models/everest_run_model.py +++ b/src/ert/run_models/everest_run_model.py @@ -210,92 +210,8 @@ def run_experiment( self._exit_code = EverestExitCode.COMPLETED def _create_optimizer(self) -> BasicOptimizer: - RESULT_COLUMNS = { - "result_id": "ID", - "batch_id": "Batch", - "functions.weighted_objective": "Total-Objective", - "linear_constraints.violations": "IC-violation", - "nonlinear_constraints.violations": "OC-violation", - "functions.objectives": "Objective", - "functions.constraints": "Constraint", - "evaluations.variables": "Control", - "linear_constraints.values": "IC-diff", - "nonlinear_constraints.values": "OC-diff", - "functions.scaled_objectives": "Scaled-Objective", - "functions.scaled_constraints": "Scaled-Constraint", - "evaluations.scaled_variables": "Scaled-Control", - "nonlinear_constraints.scaled_values": "Scaled-OC-diff", - "nonlinear_constraints.scaled_violations": "Scaled-OC-violation", - } - GRADIENT_COLUMNS = { - "result_id": "ID", - "batch_id": "Batch", - "gradients.weighted_objective": "Total-Gradient", - "gradients.objectives": "Grad-objective", - "gradients.constraints": "Grad-constraint", - } - SIMULATION_COLUMNS = { - "result_id": "ID", - "batch_id": "Batch", - "realization": "Realization", - "evaluations.evaluation_ids": "Simulation", - "evaluations.variables": "Control", - "evaluations.objectives": "Objective", - "evaluations.constraints": "Constraint", - "evaluations.scaled_variables": "Scaled-Control", - "evaluations.scaled_objectives": "Scaled-Objective", - "evaluations.scaled_constraints": "Scaled-Constraint", - } - PERTURBATIONS_COLUMNS = { - "result_id": "ID", - "batch_id": "Batch", - "realization": "Realization", - "evaluations.perturbed_evaluation_ids": "Simulation", - "evaluations.perturbed_variables": "Control", - "evaluations.perturbed_objectives": "Objective", - "evaluations.perturbed_constraints": "Constraint", - "evaluations.scaled_perturbed_variables": "Scaled-Control", - "evaluations.scaled_perturbed_objectives": "Scaled-Objective", - "evaluations.scaled_perturbed_constraints": "Scaled-Constraint", - } - MIN_HEADER_LEN = 3 - - # Initialize the optimizer with output tables. `min_header_len` is set - # to ensure that all tables have the same number of header lines, - # simplifying code that reads them as fixed width tables. `maximize` is - # set because ropt reports minimization results, while everest wants - # maximization results, necessitating a conversion step. - ropt_output_folder = Path(self._everest_config.optimization_output_dir) - optimizer = ( - BasicOptimizer( - enopt_config=self._ropt_config, evaluator=self._forward_model_evaluator - ) - .add_table( - columns=RESULT_COLUMNS, - path=ropt_output_folder / "results.txt", - min_header_len=MIN_HEADER_LEN, - maximize=True, - ) - .add_table( - columns=GRADIENT_COLUMNS, - path=ropt_output_folder / "gradients.txt", - table_type="gradients", - min_header_len=MIN_HEADER_LEN, - maximize=True, - ) - .add_table( - columns=SIMULATION_COLUMNS, - path=ropt_output_folder / "simulations.txt", - min_header_len=MIN_HEADER_LEN, - maximize=True, - ) - .add_table( - columns=PERTURBATIONS_COLUMNS, - path=ropt_output_folder / "perturbations.txt", - table_type="gradients", - min_header_len=MIN_HEADER_LEN, - maximize=True, - ) + optimizer = BasicOptimizer( + enopt_config=self._ropt_config, evaluator=self._forward_model_evaluator ) # Before each batch evaluation we check if we should abort: From 0ca046df42cf28189ca3226ef8481e4ed0271b47 Mon Sep 17 00:00:00 2001 From: Peter Verveer Date: Fri, 31 Jan 2025 08:40:47 +0000 Subject: [PATCH 2/7] Enable simulator cache --- src/everest/config/simulator_config.py | 8 ++------ tests/everest/test_simulator_cache.py | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/everest/config/simulator_config.py b/src/everest/config/simulator_config.py index 7797dbd46a9..9d277e7f2a6 100644 --- a/src/everest/config/simulator_config.py +++ b/src/everest/config/simulator_config.py @@ -79,17 +79,13 @@ class SimulatorConfig(BaseModel, extra="forbid"): # type: ignore If not specified, a default value of 1 will be used.""", ) enable_cache: bool = Field( - default=False, + default=True, description="""Enable forward model result caching. If enabled, objective and constraint function results are cached for each realization. If the optimizer requests an evaluation that has already been done before, these cached values will be re-used without - running the forward model again. - - This option is disabled by default, since it will not be necessary for - the most common use of a standard optimization with a continuous - optimizer.""", + running the forward model again.""", ) @field_validator("queue_system", mode="before") diff --git a/tests/everest/test_simulator_cache.py b/tests/everest/test_simulator_cache.py index 32bfa592cba..26c9b64abdf 100644 --- a/tests/everest/test_simulator_cache.py +++ b/tests/everest/test_simulator_cache.py @@ -19,7 +19,6 @@ def new_call(*args): config = EverestConfig.load_file("config_minimal.yml") config_dict = config.model_dump(exclude_none=True) - config_dict["simulator"] = {"enable_cache": True} config = EverestConfig.model_validate(config_dict) run_model = EverestRunModel.create(config) From b935f10e5f79a55fff1a26a624f475306351de87 Mon Sep 17 00:00:00 2001 From: Peter Verveer Date: Fri, 31 Jan 2025 09:05:40 +0000 Subject: [PATCH 3/7] Remove some unnecessary data from storage --- src/everest/api/everest_data_api.py | 30 ------------------- src/everest/everest_storage.py | 26 ++-------------- .../config_advanced.yml/snapshot.json | 16 ---------- .../config_minimal.yml/snapshot.json | 12 -------- .../config_multiobj.yml/snapshot.json | 12 -------- tests/everest/test_api_snapshots.py | 8 ----- 6 files changed, 3 insertions(+), 101 deletions(-) diff --git a/src/everest/api/everest_data_api.py b/src/everest/api/everest_data_api.py index d6b47519bca..e3a51a6bdd0 100644 --- a/src/everest/api/everest_data_api.py +++ b/src/everest/api/everest_data_api.py @@ -3,7 +3,6 @@ import polars import polars as pl -from ropt.enums import ConstraintType from ert.storage import open_storage from everest.config import EverestConfig @@ -53,35 +52,6 @@ def output_constraint_names(self): else [] ) - def input_constraint(self, control): - # Note: This function is weird, its existence is probably not well-justified - # consider removing! - initial_values = self._ever_storage.data.controls - control_spec = initial_values.filter( - pl.col("control_name") == control - ).to_dicts()[0] - return { - "min": control_spec.get("lower_bounds"), - "max": control_spec.get("upper_bounds"), - } - - def output_constraint(self, constraint): - """ - :return: a dictionary with two keys: "type" and "right_hand_side". - "type" has three options: - ["lower_bound", "upper_bound", "target"] - "right_hand_side" is a constant real number that indicates - the constraint bound/target. - """ - - constraint_dict = self._ever_storage.data.nonlinear_constraints.filter( - polars.col("constraint_name") == constraint - ).to_dicts()[0] - return { - "type": ConstraintType(constraint_dict["constraint_type"]).name.lower(), - "right_hand_side": constraint_dict["constraint_rhs_value"], - } - @property def realizations(self): return sorted( diff --git a/src/everest/everest_storage.py b/src/everest/everest_storage.py index 87595c48d63..f643cdcef0d 100644 --- a/src/everest/everest_storage.py +++ b/src/everest/everest_storage.py @@ -6,11 +6,7 @@ import traceback from dataclasses import dataclass, field from pathlib import Path -from typing import ( - Any, - TypedDict, - cast, -) +from typing import Any, TypedDict, cast import numpy as np import polars @@ -389,18 +385,10 @@ def _format_control_names(control_names): "control_name": polars.Series( _format_control_names(config.variables.names), dtype=polars.String ), - "initial_value": polars.Series( - config.variables.initial_values, dtype=polars.Float64 - ), - "lower_bounds": polars.Series( - config.variables.lower_bounds, dtype=polars.Float64 - ), - "upper_bounds": polars.Series( - config.variables.upper_bounds, dtype=polars.Float64 - ), } ) - + # TODO: The weight and normalization keys are only used by the everest api, + # with everviz. They should be removed in the long run. self.data.objective_functions = polars.DataFrame( { "objective_name": config.objectives.names, @@ -418,11 +406,6 @@ def _format_control_names(control_names): self.data.nonlinear_constraints = polars.DataFrame( { "constraint_name": config.nonlinear_constraints.names, - "normalization": [ - 1.0 / s for s in config.nonlinear_constraints.scales - ], # Q: Is this correct? - "constraint_rhs_value": config.nonlinear_constraints.rhs_values, - "constraint_type": config.nonlinear_constraints.types, } ) @@ -431,9 +414,6 @@ def _format_control_names(control_names): "realization": polars.Series( config.realizations.names, dtype=polars.UInt32 ), - "weight": polars.Series( - config.realizations.weights, dtype=polars.Float64 - ), } ) diff --git a/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_advanced.yml/snapshot.json b/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_advanced.yml/snapshot.json index 3d7e4636061..f333faaf641 100644 --- a/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_advanced.yml/snapshot.json +++ b/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_advanced.yml/snapshot.json @@ -312,18 +312,6 @@ "value": 0.2172204 } ], - "input_constraint('point_x-0')": { - "max": 1.0, - "min": -1.0 - }, - "input_constraint('point_x-1')": { - "max": 1.0, - "min": -1.0 - }, - "input_constraint('point_x-2')": { - "max": 1.0, - "min": -1.0 - }, "objective_function_names": [ "distance" ], @@ -446,10 +434,6 @@ }, "total_objective": -1.52561897 }, - "output_constraint('x-0_coord')": { - "right_hand_side": 0.1, - "type": "ge" - }, "output_constraint_names": [ "x-0_coord" ], diff --git a/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_minimal.yml/snapshot.json b/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_minimal.yml/snapshot.json index fc3f92607ad..0523d94c811 100644 --- a/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_minimal.yml/snapshot.json +++ b/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_minimal.yml/snapshot.json @@ -80,18 +80,6 @@ "value": 0.79933798 } ], - "input_constraint('point_x')": { - "max": 1.0, - "min": -1.0 - }, - "input_constraint('point_y')": { - "max": 1.0, - "min": -1.0 - }, - "input_constraint('point_z')": { - "max": 1.0, - "min": -1.0 - }, "objective_function_names": [ "distance" ], diff --git a/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_multiobj.yml/snapshot.json b/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_multiobj.yml/snapshot.json index 36809dae68a..7f2c9e71518 100644 --- a/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_multiobj.yml/snapshot.json +++ b/tests/everest/snapshots/test_api_snapshots/test_api_snapshots/config_multiobj.yml/snapshot.json @@ -98,18 +98,6 @@ "value": 1.0044895 } ], - "input_constraint('point_x')": { - "max": 1.0, - "min": -1.0 - }, - "input_constraint('point_y')": { - "max": 1.0, - "min": -1.0 - }, - "input_constraint('point_z')": { - "max": 1.0, - "min": -1.0 - }, "objective_function_names": [ "distance_p", "distance_q" diff --git a/tests/everest/test_api_snapshots.py b/tests/everest/test_api_snapshots.py index 28a73356dbe..8718c7f2990 100644 --- a/tests/everest/test_api_snapshots.py +++ b/tests/everest/test_api_snapshots.py @@ -39,14 +39,6 @@ def make_api_snapshot(api) -> dict[str, Any]: "single_objective_values": api.single_objective_values, "gradient_values": api.gradient_values, "objective_values": api.objective_values, - **{ - f"input_constraint('{control}')": api.input_constraint(control) - for control in api.control_names - }, - **{ - f"output_constraint('{constraint}')": api.output_constraint(constraint) - for constraint in api.output_constraint_names - }, } return api_json From 66b724ea8c9d363280222daf8716c74a7347579f Mon Sep 17 00:00:00 2001 From: Peter Verveer Date: Fri, 31 Jan 2025 09:13:45 +0000 Subject: [PATCH 4/7] Introduce formatted_control_names method --- src/everest/config/everest_config.py | 14 ++++++++++++++ src/everest/config/utils.py | 16 +--------------- src/everest/optimizer/everest2ropt.py | 16 +++++++++------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/everest/config/everest_config.py b/src/everest/config/everest_config.py index 587fab7ee02..4f0df35f9af 100644 --- a/src/everest/config/everest_config.py +++ b/src/everest/config/everest_config.py @@ -621,6 +621,20 @@ def control_names(self): controls = self.controls or [] return [control.name for control in controls] + @property + def formatted_control_names(self) -> list[str]: + names = [] + for control in self.controls: + for variable in control.variables: + if isinstance(variable, ControlVariableGuessListConfig): + for index in range(1, len(variable.initial_guess) + 1): + names.append(f"{control.name}_{variable.name}-{index}") + elif variable.index is not None: + names.append(f"{control.name}_{variable.name}-{variable.index}") + else: + names.append(f"{control.name}_{variable.name}") + return names + @property def objective_names(self) -> list[str]: return [objective.name for objective in self.objective_functions] diff --git a/src/everest/config/utils.py b/src/everest/config/utils.py index ee7088b71f2..06b5875e88b 100644 --- a/src/everest/config/utils.py +++ b/src/everest/config/utils.py @@ -1,4 +1,4 @@ -from collections.abc import Generator, Iterator +from collections.abc import Generator from typing import Any from .control_config import ControlConfig @@ -129,17 +129,3 @@ def _inject_defaults( ]: if var_dict.get(key) is None: var_dict[key] = getattr(control, key) - - -def control_tuples( - controls: list[ControlConfig], -) -> Iterator[tuple[str, str, int] | tuple[str, str]]: - for control in controls: - for variable in control.variables: - if isinstance(variable, ControlVariableGuessListConfig): - for index in range(1, len(variable.initial_guess) + 1): - yield (control.name, variable.name, index) - elif variable.index is not None: - yield (control.name, variable.name, variable.index) - else: - yield (control.name, variable.name) diff --git a/src/everest/optimizer/everest2ropt.py b/src/everest/optimizer/everest2ropt.py index 62b458fa9ce..5b90c69b2a0 100644 --- a/src/everest/optimizer/everest2ropt.py +++ b/src/everest/optimizer/everest2ropt.py @@ -14,12 +14,11 @@ OptimizationConfig, OutputConstraintConfig, ) -from everest.config.utils import FlattenedControls, control_tuples +from everest.config.utils import FlattenedControls from everest.strings import EVEREST -def _parse_controls(ever_controls: list[ControlConfig], ropt_config): - controls = FlattenedControls(ever_controls) +def _parse_controls(controls: FlattenedControls, ropt_config): control_types = [ None if type_ is None else VariableType[type_.upper()] for type_ in controls.types @@ -141,7 +140,7 @@ def _parse_objectives(objective_functions: list[ObjectiveFunctionConfig], ropt_c def _parse_input_constraints( - controls: list[ControlConfig], + controls: FlattenedControls, input_constraints: list[InputConstraintConfig] | None, ropt_config, ): @@ -150,13 +149,14 @@ def _parse_input_constraints( # TODO: Issue #9816 is intended to address the need for a more general # naming scheme. This code should be revisited once that issue is resolved. + # Ideally the formatted_control_names property of the config is used. formatted_names = [ ( f"{control_name[0]}.{control_name[1]}-{control_name[2]}" if len(control_name) > 2 else f"{control_name[0]}.{control_name[1]}" ) - for control_name in control_tuples(controls) + for control_name in controls.names ] coefficients_matrix = [] @@ -391,10 +391,12 @@ def everest2ropt(ever_config: EverestConfig) -> EnOptConfig: """ ropt_config: dict[str, Any] = {} - _parse_controls(ever_config.controls, ropt_config) + flattened_controls = FlattenedControls(ever_config.controls) + + _parse_controls(flattened_controls, ropt_config) _parse_objectives(ever_config.objective_functions, ropt_config) _parse_input_constraints( - ever_config.controls, ever_config.input_constraints, ropt_config + flattened_controls, ever_config.input_constraints, ropt_config ) _parse_output_constraints(ever_config.output_constraints, ropt_config) _parse_optimization( From fac55ca207a9cf292038520c2eda5be38d3bf2cd Mon Sep 17 00:00:00 2001 From: Peter Verveer Date: Fri, 31 Jan 2025 09:25:01 +0000 Subject: [PATCH 5/7] Update to ropt 0.11 --- pyproject.toml | 4 +- src/ert/run_models/everest_run_model.py | 1 + src/everest/everest_storage.py | 95 +++++++++++++---------- src/everest/optimizer/everest2ropt.py | 55 +++++-------- tests/everest/test_multiobjective.py | 4 +- tests/everest/test_output_constraints.py | 1 - tests/everest/test_ropt_initialization.py | 8 +- 7 files changed, 83 insertions(+), 85 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bbdba3cc627..971a05c0171 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -138,8 +138,8 @@ everest = [ "decorator", "resdata", "colorama", - "ropt[pandas]>=0.1,<0.11", - "ropt-dakota>=0.1,<0.11", + "ropt[pandas]>=0.11,<0.12", + "ropt-dakota>=0.11,<0.12", ] [tool.setuptools] diff --git a/src/ert/run_models/everest_run_model.py b/src/ert/run_models/everest_run_model.py index 101a7a4cbe7..859c15bdb54 100644 --- a/src/ert/run_models/everest_run_model.py +++ b/src/ert/run_models/everest_run_model.py @@ -190,6 +190,7 @@ def run_experiment( self.ever_storage = EverestStorage( output_dir=Path(self._everest_config.optimization_output_dir), ) + self.ever_storage.init(self._everest_config) self.ever_storage.observe_optimizer(optimizer) # Run the optimization: diff --git a/src/everest/everest_storage.py b/src/everest/everest_storage.py index f643cdcef0d..30948a66f70 100644 --- a/src/everest/everest_storage.py +++ b/src/everest/everest_storage.py @@ -350,80 +350,82 @@ def read_from_output_dir(self) -> None: exp = _OptimizerOnlyExperiment(self._output_dir) self.data.read_from_experiment(exp) - def observe_optimizer( - self, - optimizer: BasicOptimizer, - ) -> None: - optimizer.add_observer( - EventType.START_OPTIMIZER_STEP, self._on_start_optimization - ) + def observe_optimizer(self, optimizer: BasicOptimizer) -> None: optimizer.add_observer( EventType.FINISHED_EVALUATION, self._on_batch_evaluation_finished ) optimizer.add_observer( - EventType.FINISHED_OPTIMIZER_STEP, - self._on_optimization_finished, + EventType.FINISHED_OPTIMIZER_STEP, self._on_optimization_finished ) - def _on_start_optimization(self, event: Event) -> None: - def _format_control_names(control_names): - converted_names = [] - for name in control_names: - converted = f"{name[0]}_{name[1]}" - if len(name) > 2: - converted += f"-{name[2]}" - converted_names.append(converted) - - return converted_names - - config = event.config - - # Note: We probably do not have to store - # all of this information, consider removing. + def init(self, everest_config: EverestConfig) -> None: self.data.controls = polars.DataFrame( { "control_name": polars.Series( - _format_control_names(config.variables.names), dtype=polars.String + everest_config.formatted_control_names, dtype=polars.String ), } ) + # TODO: The weight and normalization keys are only used by the everest api, # with everviz. They should be removed in the long run. + weights = np.fromiter( + ( + 1.0 if obj.weight is None else obj.weight + for obj in everest_config.objective_functions + ), + dtype=np.float64, + ) self.data.objective_functions = polars.DataFrame( { - "objective_name": config.objectives.names, - "weight": polars.Series( - config.objectives.weights, dtype=polars.Float64 - ), - "normalization": polars.Series( # Q: Is this correct? - [1.0 / s for s in config.objectives.scales], + "objective_name": everest_config.objective_names, + "weight": polars.Series(weights / sum(weights), dtype=polars.Float64), + "normalization": polars.Series( + [ + 1.0 if obj.normalization is None else obj.normalization + for obj in everest_config.objective_functions + ], dtype=polars.Float64, ), } ) - if config.nonlinear_constraints is not None: + if everest_config.output_constraints is not None: self.data.nonlinear_constraints = polars.DataFrame( { - "constraint_name": config.nonlinear_constraints.names, + "constraint_name": everest_config.constraint_names, } ) + else: + self.data.nonlinear_constraints = None self.data.realization_weights = polars.DataFrame( { "realization": polars.Series( - config.realizations.names, dtype=polars.UInt32 + everest_config.model.realizations, dtype=polars.UInt32 ), } ) def _store_function_results(self, results: FunctionResults) -> _EvaluationResults: + names = { + "variable": self.data.controls["control_name"], + "objective": self.data.objective_functions["objective_name"], + "nonlinear_constraint": ( + self.data.nonlinear_constraints["constraint_name"] + if self.data.nonlinear_constraints is not None + else None + ), + "realization": self.data.realization_weights["realization"], + } + # We could select only objective values, # but we select all to also get the constraint values (if they exist) realization_objectives = polars.from_pandas( results.to_dataframe( "evaluations", select=["objectives", "evaluation_ids"], + names=names, ).reset_index(), ).select( "batch_id", @@ -438,6 +440,7 @@ def _store_function_results(self, results: FunctionResults) -> _EvaluationResult results.to_dataframe( "evaluations", select=["constraints", "evaluation_ids"], + names=names, ).reset_index(), ).select( "batch_id", @@ -452,7 +455,9 @@ def _store_function_results(self, results: FunctionResults) -> _EvaluationResult ) batch_constraints = polars.from_pandas( - results.to_dataframe("functions", select=["constraints"]).reset_index() + results.to_dataframe( + "functions", select=["constraints"], names=names + ).reset_index() ).select("batch_id", "nonlinear_constraint", "constraints") batch_constraints = batch_constraints.rename( @@ -480,12 +485,13 @@ def _store_function_results(self, results: FunctionResults) -> _EvaluationResult results.to_dataframe( "functions", select=["objectives", "weighted_objective"], + names=names, ).reset_index() ).select("batch_id", "objective", "objectives", "weighted_objective") realization_controls = polars.from_pandas( results.to_dataframe( - "evaluations", select=["variables", "evaluation_ids"] + "evaluations", select=["variables", "evaluation_ids"], names=names ).reset_index() ).select( "batch_id", @@ -535,8 +541,19 @@ def _store_function_results(self, results: FunctionResults) -> _EvaluationResult } def _store_gradient_results(self, results: GradientResults) -> _GradientResults: + names = { + "variable": self.data.controls["control_name"], + "objective": self.data.objective_functions["objective_name"], + "nonlinear_constraint": ( + self.data.nonlinear_constraints["constraint_name"] + if self.data.nonlinear_constraints is not None + else None + ), + "realization": self.data.realization_weights["realization"], + } + perturbation_objectives = polars.from_pandas( - results.to_dataframe("evaluations").reset_index() + results.to_dataframe("evaluations", names=names).reset_index() ).select( [ "batch_id", @@ -560,7 +577,7 @@ def _store_gradient_results(self, results: GradientResults) -> _GradientResults: if results.gradients is not None: batch_objective_gradient = polars.from_pandas( - results.to_dataframe("gradients").reset_index() + results.to_dataframe("gradients", names=names).reset_index() ).select( [ "batch_id", @@ -678,7 +695,7 @@ def _on_batch_evaluation_finished(self, event: Event) -> None: logger.debug("Storing batch results dataframes") converted_results = tuple( - convert_to_maximize(result) for result in event.results + convert_to_maximize(result) for result in event.data.get("results", []) ) results: list[FunctionResults | GradientResults] = [] diff --git a/src/everest/optimizer/everest2ropt.py b/src/everest/optimizer/everest2ropt.py index 5b90c69b2a0..1ca8853c709 100644 --- a/src/everest/optimizer/everest2ropt.py +++ b/src/everest/optimizer/everest2ropt.py @@ -6,7 +6,6 @@ from ropt.enums import ConstraintType, PerturbationType, VariableType from everest.config import ( - ControlConfig, EverestConfig, InputConstraintConfig, ModelConfig, @@ -49,7 +48,6 @@ def _parse_controls(controls: FlattenedControls, ropt_config): ] indices = [idx for idx, is_enabled in enumerate(controls.enabled) if is_enabled] ropt_config["variables"] = { - "names": controls.names, "types": None if all(item is None for item in control_types) else control_types, "initial_values": controls.initial_guesses, "lower_bounds": controls.lower_bounds, @@ -57,7 +55,6 @@ def _parse_controls(controls: FlattenedControls, ropt_config): "offsets": offsets, "scales": scales, "indices": indices if indices else None, - "delimiters": "_-", } if "gradients" not in ropt_config: @@ -81,62 +78,55 @@ def _parse_controls(controls: FlattenedControls, ropt_config): ] ropt_config["gradient"]["perturbation_types"] = [ - PerturbationType.SCALED.value - if auto_scale - else PerturbationType[perturbation_type.upper()] - for perturbation_type, auto_scale in zip( - controls.perturbation_types, controls.auto_scales, strict=True - ) + PerturbationType[perturbation_type.upper()] + for perturbation_type in controls.perturbation_types ] def _parse_objectives(objective_functions: list[ObjectiveFunctionConfig], ropt_config): - names: list[str] = [] scales: list[float] = [] auto_scale: list[bool] = [] weights: list[float] = [] - transform_indices: list[int] = [] - transforms: list = [] + function_estimator_indices: list[int] = [] + function_estimators: list = [] for objective in objective_functions: assert isinstance(objective.name, str) - names.append(objective.name) weights.append(objective.weight or 1.0) scales.append(1.0 / (objective.normalization or 1.0)) auto_scale.append(objective.auto_normalize or False) # If any objective specifies an objective type, we have to specify - # function transforms in ropt to implement these types. This is done by - # supplying a list of transforms and for each objective an index into + # function estimators in ropt to implement these types. This is done by + # supplying a list of estimators and for each objective an index into # that list: objective_type = objective.type if objective_type is None: objective_type = "mean" - # Find the transform if it exists: - transform_idx = next( + # Find the estimator if it exists: + function_estimator_idx = next( ( idx - for idx, transform in enumerate(transforms) - if transform["method"] == objective_type + for idx, estimator in enumerate(function_estimators) + if estimator["method"] == objective_type ), None, ) - # If not, make a new transform: - if transform_idx is None: - transform_idx = len(transforms) - transforms.append({"method": objective_type}) - transform_indices.append(transform_idx) + # If not, make a new estimator: + if function_estimator_idx is None: + function_estimator_idx = len(function_estimators) + function_estimators.append({"method": objective_type}) + function_estimator_indices.append(function_estimator_idx) ropt_config["objectives"] = { - "names": names, "weights": weights, "scales": scales, "auto_scale": auto_scale, } - if transforms: + if function_estimators: # Only needed if we specified at least one objective type: - ropt_config["objectives"]["function_transforms"] = transform_indices - ropt_config["function_transforms"] = transforms + ropt_config["objectives"]["function_estimators"] = function_estimator_indices + ropt_config["function_estimators"] = function_estimators def _parse_input_constraints( @@ -197,7 +187,6 @@ def _parse_output_constraints( if not output_constraints: return - names: list[str] = [] rhs_values: list[float] = [] scales: list[float] = [] auto_scale: list[bool] = [] @@ -207,8 +196,6 @@ def _add_output_constraint( rhs_value: float | None, constraint_type: ConstraintType, suffix=None ): if rhs_value is not None: - name = constr.name - names.append(name if suffix is None else f"{name}:{suffix}") rhs_values.append(rhs_value) scales.append(constr.scale if constr.scale is not None else 1.0) auto_scale.append(constr.auto_scale or False) @@ -238,7 +225,6 @@ def _add_output_constraint( ) ropt_config["nonlinear_constraints"] = { - "names": names, "rhs_values": rhs_values, "scales": scales, "auto_scale": auto_scale, @@ -336,9 +322,9 @@ def _parse_optimization( # indices to any realization filters that should be applied. In this # case, we want all objectives and constraints to refer to the same # filter implementing cvar: - objective_count = len(ropt_config["objectives"]["names"]) + objective_count = len(ropt_config["objectives"]["weights"]) constraint_count = len( - ropt_config.get("nonlinear_constraints", {}).get("names", []) + ropt_config.get("nonlinear_constraints", {}).get("rhs_values", []) ) ropt_config["objectives"]["realization_filters"] = objective_count * [0] if constraint_count > 0: @@ -366,7 +352,6 @@ def _parse_model( ever_reals_weights = [1.0 / len(ever_reals)] * len(ever_reals) ropt_config["realizations"] = { - "names": ever_reals, "weights": ever_reals_weights, } min_real_succ = ever_opt.min_realizations_success if ever_opt else None diff --git a/tests/everest/test_multiobjective.py b/tests/everest/test_multiobjective.py index 7ea40f32d02..ee55b925347 100644 --- a/tests/everest/test_multiobjective.py +++ b/tests/everest/test_multiobjective.py @@ -89,10 +89,8 @@ def test_multi_objectives2ropt(copy_mocked_test_data_to_tmp): enopt_config = EnOptConfig.model_validate( everest2ropt(EverestConfig.model_validate(config_dict)) ) - assert len(enopt_config.objectives.names) == 2 - assert enopt_config.objectives.names[1] == ever_objs[1]["name"] + assert len(enopt_config.objectives.weights) == 2 assert enopt_config.objectives.weights[1] == ever_objs[1]["weight"] / norm - assert enopt_config.objectives.names[0] == ever_objs[0]["name"] assert enopt_config.objectives.weights[0] == ever_objs[0]["weight"] / norm assert enopt_config.objectives.scales[0] == ever_objs[0]["normalization"] diff --git a/tests/everest/test_output_constraints.py b/tests/everest/test_output_constraints.py index b7e281a0bc6..1d30f681394 100644 --- a/tests/everest/test_output_constraints.py +++ b/tests/everest/test_output_constraints.py @@ -222,7 +222,6 @@ def test_upper_bound_output_constraint_def(copy_mocked_test_data_to_tmp): } assert expected["scale"] == 1.0 / ropt_conf.nonlinear_constraints.scales[0] - assert expected["name"] == ropt_conf.nonlinear_constraints.names[0] assert expected["rhs_value"] == ropt_conf.nonlinear_constraints.rhs_values[0] assert expected["type"] == ropt_conf.nonlinear_constraints.types[0] diff --git a/tests/everest/test_ropt_initialization.py b/tests/everest/test_ropt_initialization.py index 2eacf5e3fb6..30b2f9b3a74 100644 --- a/tests/everest/test_ropt_initialization.py +++ b/tests/everest/test_ropt_initialization.py @@ -20,8 +20,7 @@ def test_tutorial_everest2ropt(): realizations = ropt_config.realizations - assert len(realizations.names) == 2 - assert realizations.names[0] == 0 + assert len(realizations.weights) == 2 assert realizations.weights[0] == 0.5 @@ -131,17 +130,16 @@ def test_everest2ropt_controls_optimizer_setting(): config = os.path.join(_CONFIG_DIR, "config_full_gradient_info.yml") config = EverestConfig.load_file(config) ropt_config = everest2ropt(config) - assert len(ropt_config.realizations.names) == 15 + assert len(ropt_config.realizations.weights) == 15 assert ropt_config.optimizer.method == "conmin_mfd" assert ropt_config.gradient.number_of_perturbations == 20 - assert ropt_config.realizations.names == tuple(range(15)) def test_everest2ropt_constraints(): config = os.path.join(_CONFIG_DIR, "config_output_constraints.yml") config = EverestConfig.load_file(config) ropt_config = everest2ropt(config) - assert len(ropt_config.nonlinear_constraints.names) == 16 + assert len(ropt_config.nonlinear_constraints.rhs_values) == 16 def test_everest2ropt_backend_options(): From a45fce05e1ef1f05e4faa075e60d46df26fb1650 Mon Sep 17 00:00:00 2001 From: Peter Verveer Date: Fri, 31 Jan 2025 10:24:17 +0000 Subject: [PATCH 6/7] Insert names in everest results using polars --- src/everest/everest_storage.py | 221 ++++++++++++++------------------- 1 file changed, 94 insertions(+), 127 deletions(-) diff --git a/src/everest/everest_storage.py b/src/everest/everest_storage.py index 30948a66f70..6dc4d43c1fb 100644 --- a/src/everest/everest_storage.py +++ b/src/everest/everest_storage.py @@ -324,6 +324,43 @@ def _enforce_dtypes(df: polars.DataFrame) -> polars.DataFrame: return df + def _ropt_to_df( + self, + results: FunctionResults | GradientResults, + field: str, + *, + values: list[str], + select: list, + ) -> polars.DataFrame: + df = polars.from_pandas( + results.to_dataframe(field, select=values).reset_index(), + ).select(select + values) + + # The results from ropt do not contain any names, but indices referring + # to control names, objective names, etc. The corresponding names can be + # retrieved from the everest configuration and were stored in the init + # method. Here we replace the indices with those names: + ropt_to_everest_names = { + "variable": self.data.controls["control_name"], + "objective": self.data.objective_functions["objective_name"], + "nonlinear_constraint": ( + self.data.nonlinear_constraints["constraint_name"] + if self.data.nonlinear_constraints is not None + else None + ), + "realization": self.data.realization_weights["realization"], + } + df = df.with_columns( + polars.col(ropt_name).replace_strict(dict(enumerate(everest_names))) + for ropt_name, everest_names in ropt_to_everest_names.items() + if ropt_name in select + ) + + df = self._rename_ropt_df_columns(df) + df = self._enforce_dtypes(df) + + return df + def write_to_output_dir(self) -> None: exp = _OptimizerOnlyExperiment(self._output_dir) @@ -408,63 +445,28 @@ def init(self, everest_config: EverestConfig) -> None: ) def _store_function_results(self, results: FunctionResults) -> _EvaluationResults: - names = { - "variable": self.data.controls["control_name"], - "objective": self.data.objective_functions["objective_name"], - "nonlinear_constraint": ( - self.data.nonlinear_constraints["constraint_name"] - if self.data.nonlinear_constraints is not None - else None - ), - "realization": self.data.realization_weights["realization"], - } - # We could select only objective values, # but we select all to also get the constraint values (if they exist) - realization_objectives = polars.from_pandas( - results.to_dataframe( - "evaluations", - select=["objectives", "evaluation_ids"], - names=names, - ).reset_index(), - ).select( - "batch_id", - "realization", - "objective", - "objectives", - "evaluation_ids", + realization_objectives = self._ropt_to_df( + results, + "evaluations", + values=["objectives", "evaluation_ids"], + select=["batch_id", "realization", "objective"], ) if results.functions is not None and results.functions.constraints is not None: - realization_constraints = polars.from_pandas( - results.to_dataframe( - "evaluations", - select=["constraints", "evaluation_ids"], - names=names, - ).reset_index(), - ).select( - "batch_id", - "realization", - "evaluation_ids", - "nonlinear_constraint", - "constraints", - ) - - realization_constraints = self._rename_ropt_df_columns( - realization_constraints + realization_constraints = self._ropt_to_df( + results, + "evaluations", + values=["constraints", "evaluation_ids"], + select=["batch_id", "realization", "nonlinear_constraint"], ) - batch_constraints = polars.from_pandas( - results.to_dataframe( - "functions", select=["constraints"], names=names - ).reset_index() - ).select("batch_id", "nonlinear_constraint", "constraints") - - batch_constraints = batch_constraints.rename( - { - "nonlinear_constraint": "constraint_name", - "constraints": "constraint_value", - } + batch_constraints = self._ropt_to_df( + results, + "functions", + values=["constraints"], + select=["batch_id", "nonlinear_constraint"], ) batch_constraints = batch_constraints.pivot( @@ -481,28 +483,19 @@ def _store_function_results(self, results: FunctionResults) -> _EvaluationResult batch_constraints = None realization_constraints = None - batch_objectives = polars.from_pandas( - results.to_dataframe( - "functions", - select=["objectives", "weighted_objective"], - names=names, - ).reset_index() - ).select("batch_id", "objective", "objectives", "weighted_objective") - - realization_controls = polars.from_pandas( - results.to_dataframe( - "evaluations", select=["variables", "evaluation_ids"], names=names - ).reset_index() - ).select( - "batch_id", - "variable", - "realization", - "variables", - "evaluation_ids", + batch_objectives = self._ropt_to_df( + results, + "functions", + values=["objectives", "weighted_objective"], + select=["batch_id", "objective"], ) - realization_controls = self._rename_ropt_df_columns(realization_controls) - realization_controls = self._enforce_dtypes(realization_controls) + realization_controls = self._ropt_to_df( + results, + "evaluations", + values=["variables", "evaluation_ids"], + select=["batch_id", "variable", "realization"], + ) realization_controls = realization_controls.pivot( on="control_name", @@ -510,12 +503,6 @@ def _store_function_results(self, results: FunctionResults) -> _EvaluationResult separator=":", ) - batch_objectives = self._rename_ropt_df_columns(batch_objectives) - batch_objectives = self._enforce_dtypes(batch_objectives) - - realization_objectives = self._rename_ropt_df_columns(realization_objectives) - realization_objectives = self._enforce_dtypes(realization_objectives) - batch_objectives = batch_objectives.pivot( on="objective_name", values=["objective_value"], @@ -541,65 +528,45 @@ def _store_function_results(self, results: FunctionResults) -> _EvaluationResult } def _store_gradient_results(self, results: GradientResults) -> _GradientResults: - names = { - "variable": self.data.controls["control_name"], - "objective": self.data.objective_functions["objective_name"], - "nonlinear_constraint": ( - self.data.nonlinear_constraints["constraint_name"] - if self.data.nonlinear_constraints is not None - else None + have_perturbed_constraints = ( + results.evaluations.perturbed_constraints is not None + ) + perturbation_objectives = self._ropt_to_df( + results, + "evaluations", + values=( + [ + "variables", + "perturbed_variables", + "perturbed_objectives", + "perturbed_evaluation_ids", + ] + + (["perturbed_constraints"] if have_perturbed_constraints else []) + ), + select=( + ["batch_id", "variable", "realization", "perturbation", "objective"] + + (["nonlinear_constraint"] if have_perturbed_constraints else []) ), - "realization": self.data.realization_weights["realization"], - } - - perturbation_objectives = polars.from_pandas( - results.to_dataframe("evaluations", names=names).reset_index() - ).select( - [ - "batch_id", - "variable", - "realization", - "perturbation", - "objective", - "variables", - "perturbed_variables", - "perturbed_objectives", - "perturbed_evaluation_ids", - *( - ["nonlinear_constraint", "perturbed_constraints"] - if results.evaluations.perturbed_constraints is not None - else [] - ), - ] ) - perturbation_objectives = self._rename_ropt_df_columns(perturbation_objectives) - perturbation_objectives = self._enforce_dtypes(perturbation_objectives) if results.gradients is not None: - batch_objective_gradient = polars.from_pandas( - results.to_dataframe("gradients", names=names).reset_index() - ).select( - [ - "batch_id", - "variable", - "objective", - "weighted_objective", - "objectives", - *( - ["nonlinear_constraint", "constraints"] - if results.gradients.constraints is not None - else [] - ), - ] - ) - batch_objective_gradient = self._rename_ropt_df_columns( - batch_objective_gradient + have_constraints = results.gradients.constraints is not None + batch_objective_gradient = self._ropt_to_df( + results, + "gradients", + values=( + ["weighted_objective", "objectives"] + + (["constraints"] if have_constraints else []) + ), + select=( + ["batch_id", "variable", "objective"] + + (["nonlinear_constraint"] if have_constraints else []) + ), ) - batch_objective_gradient = self._enforce_dtypes(batch_objective_gradient) else: batch_objective_gradient = None - if results.evaluations.perturbed_constraints is not None: + if have_perturbed_constraints: perturbation_constraints = ( perturbation_objectives[ "batch_id", From 49dae10e0c1c1c8b919620988aa4bac644126fe2 Mon Sep 17 00:00:00 2001 From: Peter Verveer Date: Wed, 29 Jan 2025 11:18:44 +0000 Subject: [PATCH 7/7] Use a scaler object to re-implement control scaling --- src/ert/run_models/everest_run_model.py | 6 ++-- src/everest/everest_storage.py | 16 ++++++--- src/everest/optimizer/everest2ropt.py | 38 +++++--------------- src/everest/optimizer/transforms.py | 44 +++++++++++++++++++++++ tests/everest/test_ropt_initialization.py | 7 ++-- 5 files changed, 73 insertions(+), 38 deletions(-) create mode 100644 src/everest/optimizer/transforms.py diff --git a/src/ert/run_models/everest_run_model.py b/src/ert/run_models/everest_run_model.py index 859c15bdb54..52b42224bfd 100644 --- a/src/ert/run_models/everest_run_model.py +++ b/src/ert/run_models/everest_run_model.py @@ -31,6 +31,7 @@ from everest.config import ControlConfig, ControlVariableGuessListConfig, EverestConfig from everest.everest_storage import EverestStorage, OptimalResult from everest.optimizer.everest2ropt import everest2ropt +from everest.optimizer.transforms import get_transforms from everest.simulator.everest_to_ert import everest_to_ert_config from everest.strings import EVEREST @@ -96,7 +97,8 @@ def __init__( ) self._everest_config = everest_config - self._ropt_config = everest2ropt(everest_config) + self._transforms = get_transforms(everest_config) + self._ropt_config = everest2ropt(everest_config, transforms=self._transforms) self._sim_callback = simulation_callback self._opt_callback = optimization_callback @@ -191,7 +193,7 @@ def run_experiment( output_dir=Path(self._everest_config.optimization_output_dir), ) self.ever_storage.init(self._everest_config) - self.ever_storage.observe_optimizer(optimizer) + self.ever_storage.observe_optimizer(optimizer, self._transforms) # Run the optimization: optimizer_exit_code = optimizer.run().exit_code diff --git a/src/everest/everest_storage.py b/src/everest/everest_storage.py index 6dc4d43c1fb..a323ed092d3 100644 --- a/src/everest/everest_storage.py +++ b/src/everest/everest_storage.py @@ -5,6 +5,7 @@ import os import traceback from dataclasses import dataclass, field +from functools import partial from pathlib import Path from typing import Any, TypedDict, cast @@ -13,6 +14,7 @@ from ropt.enums import EventType from ropt.plan import BasicOptimizer, Event from ropt.results import FunctionResults, GradientResults, convert_to_maximize +from ropt.transforms import Transforms from everest.config import EverestConfig from everest.strings import EVEREST @@ -387,9 +389,12 @@ def read_from_output_dir(self) -> None: exp = _OptimizerOnlyExperiment(self._output_dir) self.data.read_from_experiment(exp) - def observe_optimizer(self, optimizer: BasicOptimizer) -> None: + def observe_optimizer( + self, optimizer: BasicOptimizer, transforms: Transforms + ) -> None: optimizer.add_observer( - EventType.FINISHED_EVALUATION, self._on_batch_evaluation_finished + EventType.FINISHED_EVALUATION, + partial(self._on_batch_evaluation_finished, transforms=transforms), ) optimizer.add_observer( EventType.FINISHED_OPTIMIZER_STEP, self._on_optimization_finished @@ -658,11 +663,14 @@ def _store_gradient_results(self, results: GradientResults) -> _GradientResults: "perturbation_constraints": perturbation_constraints, } - def _on_batch_evaluation_finished(self, event: Event) -> None: + def _on_batch_evaluation_finished( + self, event: Event, transforms: Transforms + ) -> None: logger.debug("Storing batch results dataframes") converted_results = tuple( - convert_to_maximize(result) for result in event.data.get("results", []) + convert_to_maximize(result).transform_back(transforms) + for result in event.data.get("results", []) ) results: list[FunctionResults | GradientResults] = [] diff --git a/src/everest/optimizer/everest2ropt.py b/src/everest/optimizer/everest2ropt.py index 1ca8853c709..cd1fdc5c013 100644 --- a/src/everest/optimizer/everest2ropt.py +++ b/src/everest/optimizer/everest2ropt.py @@ -2,8 +2,9 @@ import os from typing import Any -from ropt.config.enopt import EnOptConfig +from ropt.config.enopt import EnOptConfig, EnOptContext from ropt.enums import ConstraintType, PerturbationType, VariableType +from ropt.transforms import Transforms from everest.config import ( EverestConfig, @@ -22,38 +23,12 @@ def _parse_controls(controls: FlattenedControls, ropt_config): None if type_ is None else VariableType[type_.upper()] for type_ in controls.types ] - if all(item is None for item in controls.auto_scales): - offsets = None - scales = None - else: - scales = [ - (ub - lb) / (sr[1] - sr[0]) if au else 1.0 - for au, lb, ub, sr in zip( - controls.auto_scales, - controls.lower_bounds, - controls.upper_bounds, - controls.scaled_ranges, - strict=True, - ) - ] - offsets = [ - lb - sr[0] * sc if au else 0.0 - for au, lb, sc, sr in zip( - controls.auto_scales, - controls.lower_bounds, - scales, - controls.scaled_ranges, - strict=True, - ) - ] indices = [idx for idx, is_enabled in enumerate(controls.enabled) if is_enabled] ropt_config["variables"] = { "types": None if all(item is None for item in control_types) else control_types, "initial_values": controls.initial_guesses, "lower_bounds": controls.lower_bounds, "upper_bounds": controls.upper_bounds, - "offsets": offsets, - "scales": scales, "indices": indices if indices else None, } @@ -367,7 +342,9 @@ def _parse_environment( ropt_config["gradient"]["seed"] = random_seed -def everest2ropt(ever_config: EverestConfig) -> EnOptConfig: +def everest2ropt( + ever_config: EverestConfig, transforms: Transforms | None = None +) -> EnOptConfig: """Generate a ropt configuration from an Everest one NOTE: This method is a work in progress. So far only the some of @@ -402,4 +379,7 @@ def everest2ropt(ever_config: EverestConfig) -> EnOptConfig: ropt_config=ropt_config, ) - return EnOptConfig.model_validate(ropt_config) + return EnOptConfig.model_validate( + ropt_config, + context=None if transforms is None else EnOptContext(transforms=transforms), + ) diff --git a/src/everest/optimizer/transforms.py b/src/everest/optimizer/transforms.py new file mode 100644 index 00000000000..1149bcb937f --- /dev/null +++ b/src/everest/optimizer/transforms.py @@ -0,0 +1,44 @@ +from collections.abc import Sequence + +import numpy as np +from ropt.transforms import Transforms, VariableScaler + +from everest.config import EverestConfig +from everest.config.utils import FlattenedControls + + +class ControlScaler(VariableScaler): + def __init__( + self, + lower_bounds: Sequence[float], + upper_bounds: Sequence[float], + scaled_ranges: Sequence[tuple[float, float]], + auto_scales: Sequence[bool], + ) -> None: + scales = [ + (ub - lb) / (sr[1] - sr[0]) if au else 1.0 + for au, lb, ub, sr in zip( + auto_scales, lower_bounds, upper_bounds, scaled_ranges, strict=True + ) + ] + offsets = [ + lb - sr[0] * sc if au else 0.0 + for au, lb, sc, sr in zip( + auto_scales, lower_bounds, scales, scaled_ranges, strict=True + ) + ] + super().__init__(np.array(scales), np.array(offsets)) + + +def get_transforms(ever_config: EverestConfig) -> Transforms: + controls = FlattenedControls(ever_config.controls) + if any(controls.auto_scales): + variable_scaler = ControlScaler( + controls.lower_bounds, + controls.upper_bounds, + controls.scaled_ranges, + controls.auto_scales, + ) + else: + variable_scaler = None + return Transforms(variables=variable_scaler) diff --git a/tests/everest/test_ropt_initialization.py b/tests/everest/test_ropt_initialization.py index 30b2f9b3a74..bc0491fef52 100644 --- a/tests/everest/test_ropt_initialization.py +++ b/tests/everest/test_ropt_initialization.py @@ -8,6 +8,7 @@ from everest.config import EverestConfig from everest.config_file_loader import yaml_file_to_substituted_config_dict from everest.optimizer.everest2ropt import everest2ropt +from everest.optimizer.transforms import get_transforms from tests.everest.utils import relpath _CONFIG_DIR = relpath("test_data/mocked_test_case") @@ -41,7 +42,7 @@ def test_everest2ropt_controls_auto_scale(): controls = config.controls controls[0].auto_scale = True controls[0].scaled_range = [0.3, 0.7] - ropt_config = everest2ropt(config) + ropt_config = everest2ropt(config, transforms=get_transforms(config)) assert numpy.allclose(ropt_config.variables.lower_bounds, 0.3) assert numpy.allclose(ropt_config.variables.upper_bounds, 0.7) @@ -51,7 +52,7 @@ def test_everest2ropt_variables_auto_scale(): controls = config.controls controls[0].variables[1].auto_scale = True controls[0].variables[1].scaled_range = [0.3, 0.7] - ropt_config = everest2ropt(config) + ropt_config = everest2ropt(config, transforms=get_transforms(config)) assert ropt_config.variables.lower_bounds[0] == 0.0 assert ropt_config.variables.upper_bounds[0] == 0.1 assert ropt_config.variables.lower_bounds[1] == 0.3 @@ -115,7 +116,7 @@ def test_everest2ropt_controls_input_constraint_auto_scale(): scaled_coefficients = coefficients * (max_values - min_values) / 0.4 scaled_coefficients[:2, 1] = coefficients[:2, 1] * 2.0 / 0.4 - ropt_config = everest2ropt(config) + ropt_config = everest2ropt(config, transforms=get_transforms(config)) assert numpy.allclose( ropt_config.linear_constraints.coefficients, scaled_coefficients,