diff --git a/bluemira/equilibria/optimisation/problem/_breakdown.py b/bluemira/equilibria/optimisation/problem/_breakdown.py index d8486e33e9..2a33b42e47 100644 --- a/bluemira/equilibria/optimisation/problem/_breakdown.py +++ b/bluemira/equilibria/optimisation/problem/_breakdown.py @@ -223,7 +223,15 @@ def __init__( max_currents = np.atleast_1d(max_currents) self.bounds = (-max_currents / self.scale, max_currents / self.scale) - def optimise(self, x0=None, *, fixed_coils=True): + def optimise( + self, + x0=None, + *, + fixed_coils: bool = True, + keep_history: bool = False, + check_constraints: bool = False, + verbose: bool = False, + ): """ Solve the optimisation problem. """ @@ -246,6 +254,9 @@ def optimise(self, x0=None, *, fixed_coils=True): bounds=self.bounds, eq_constraints=eq_constraints, ineq_constraints=ineq_constraints, + keep_history=keep_history, + check_constraints=check_constraints, + check_constraints_warn=verbose, ) opt_currents = opt_result.x diff --git a/bluemira/equilibria/optimisation/problem/_nested_position.py b/bluemira/equilibria/optimisation/problem/_nested_position.py index bad7a15053..fdfca3758d 100644 --- a/bluemira/equilibria/optimisation/problem/_nested_position.py +++ b/bluemira/equilibria/optimisation/problem/_nested_position.py @@ -194,6 +194,8 @@ def __init__( initial_currents=None, *, debug: bool = False, + keep_history: bool = True, + check_constraints: bool = True, ): self.coilset = coilset self.position_mapper = position_mapper @@ -214,6 +216,9 @@ def __init__( opt_dimension = self.position_mapper.dimension self.bounds = (np.zeros(opt_dimension), np.ones(opt_dimension)) + self.keep_history = keep_history + self.check_constraints = check_constraints + @staticmethod def _run_reporting(itern, max_fom, verbose): """ @@ -248,7 +253,10 @@ def _run_diagnostics( debug[entry].append([lcfs, value]) def sub_opt_objective( - self, vector: npt.NDArray[np.float64], *, verbose: bool = False + self, + vector: npt.NDArray[np.float64], + *, + verbose: bool = False, ) -> float: """Run the sub-optimisations and return the largest figure of merit.""" pos_map = self.position_mapper.to_xz_dict(vector) @@ -262,7 +270,12 @@ def sub_opt_objective( for sub_opt_prob in self.sub_opt_problems: sub_opt_prob.coilset.set_optimisation_state(coil_position_map=pos_map) - result = sub_opt_prob.optimise(x0=self.initial_currents, fixed_coils=False) + result = sub_opt_prob.optimise( + x0=self.initial_currents, + fixed_coils=False, + keep_history=self.keep_history, + check_constraints=self.check_constraints, + ) self._run_diagnostics(self.debug, sub_opt_prob, result) fom_values.append(result.f_x) @@ -275,7 +288,10 @@ def objective( self, vector: npt.NDArray[np.float64], *, verbose: bool = False ) -> float: """The objective function of the parent optimisation.""" - return self.sub_opt_objective(vector, verbose=verbose) + return self.sub_opt_objective( + vector, + verbose=verbose, + ) def _get_initial_vector(self) -> npt.NDArray[np.float64]: """ @@ -287,7 +303,12 @@ def _get_initial_vector(self) -> npt.NDArray[np.float64]: return self.position_mapper.to_L(cs_opt_state.xs, cs_opt_state.zs) def optimise( - self, x0: npt.NDArray | None = None, *, verbose: bool = False + self, + x0: npt.NDArray | None = None, + *, + verbose: bool = False, + keep_history: bool = False, + check_constraints: bool = False, ) -> CoilsetOptimiserResult: """ Run the PulsedNestedPositionCOP @@ -304,6 +325,8 @@ def optimise( coilset: Optimised CoilSet """ + keep_history = keep_history or self.keep_history + check_constraints = check_constraints or self.check_constraints if x0 is None: x0 = self._get_initial_vector() @@ -318,12 +341,15 @@ def optimise( bounds=self.bounds, eq_constraints=eq_constraints, ineq_constraints=ineq_constraints, + keep_history=keep_history, + check_constraints=check_constraints, + check_constraints_warn=verbose, ) optimal_positions = opt_result.x # Call the objective one last time, makes sure the coilset state # is set to the optimum - self.sub_opt_objective(optimal_positions) + self.sub_opt_objective(optimal_positions, verbose=verbose) # Clean up state of Equilibrium objects for sub_opt in self.sub_opt_problems: diff --git a/bluemira/equilibria/optimisation/problem/_tikhonov.py b/bluemira/equilibria/optimisation/problem/_tikhonov.py index bdb3428022..4dbb9aca21 100644 --- a/bluemira/equilibria/optimisation/problem/_tikhonov.py +++ b/bluemira/equilibria/optimisation/problem/_tikhonov.py @@ -86,7 +86,15 @@ def __init__( ) self._constraints = [] if constraints is None else constraints - def optimise(self, x0=None, *, fixed_coils=True) -> CoilsetOptimiserResult: + def optimise( + self, + x0=None, + *, + fixed_coils=True, + keep_history: bool = False, + check_constraints: bool = False, + verbose: bool = False, + ) -> CoilsetOptimiserResult: """ Solve the optimisation problem @@ -129,6 +137,9 @@ def optimise(self, x0=None, *, fixed_coils=True) -> CoilsetOptimiserResult: opt_parameters=self.opt_parameters, eq_constraints=eq_constraints, ineq_constraints=ineq_constraints, + keep_history=keep_history, + check_constraints=check_constraints, + check_constraints_warn=verbose, ) opt_currents = opt_result.x diff --git a/bluemira/equilibria/run.py b/bluemira/equilibria/run.py index b143875a50..533d9a4b36 100644 --- a/bluemira/equilibria/run.py +++ b/bluemira/equilibria/run.py @@ -282,7 +282,9 @@ def _get_psi_premag(self): bluemira_warn("Premagnetisation not calculated") return np.inf - def run_premagnetisation(self): + def run_premagnetisation( + self, *, keep_history: bool = False, check_constraints: bool = False + ): """Run the breakdown optimisation problem. Raises @@ -323,7 +325,11 @@ def run_premagnetisation(self): opt_conditions=self.bd_settings.opt_conditions, constraints=constraints, ) - result = problem.optimise(fixed_coils=False) + result = problem.optimise( + fixed_coils=False, + keep_history=keep_history, + check_constraints=check_constraints, + ) breakdown.set_breakdown_point(*strategy.breakdown_point) psi_premag = breakdown.breakdown_psi @@ -383,6 +389,8 @@ def run_reference_equilibrium(self): relaxation=self.eq_settings.relaxation, fixed_coils=True, plot=False, + keep_history=True, + check_constraints=True, ) program() @@ -631,7 +639,13 @@ def _prepare_coilset(self, coilset: CoilSet) -> CoilSet: ) return coilset - def optimise(self, *, verbose: bool = False) -> CoilSet: + def optimise( + self, + *, + verbose: bool = False, + keep_history: bool = False, + check_constraints: bool = False, + ) -> CoilSet: """ Optimise the coil positions for the start and end of the current flat-top. """ @@ -649,7 +663,11 @@ def optimise(self, *, verbose: bool = False) -> CoilSet: self.pos_settings.opt_conditions, constraints=None, ) - result = pos_opt_problem.optimise(verbose=verbose) + result = pos_opt_problem.optimise( + verbose=verbose, + keep_history=keep_history, + check_constraints=check_constraints, + ) optimised_coilset = self._consolidate_coilset(result.coilset, sub_opt_problems) self.converge_and_snapshot(sub_opt_problems) diff --git a/bluemira/equilibria/solve.py b/bluemira/equilibria/solve.py index 4404226a7c..d6298b51c1 100644 --- a/bluemira/equilibria/solve.py +++ b/bluemira/equilibria/solve.py @@ -468,6 +468,8 @@ def __init__( gif: bool = False, figure_folder: str | None = None, plot_name: str = "default_0", + keep_history: bool = False, + check_constraints: bool = False, ): self.eq = eq self.coilset = self.eq.coilset @@ -482,7 +484,8 @@ def __init__( " ConvergenceCriterion." ) self.fixed_coils = fixed_coils - + self.keep_history = keep_history + self.check_constraints = check_constraints self.relaxation = relaxation self.maxiter = maxiter self.plot_flag = plot or (gif and not plot) @@ -501,7 +504,11 @@ def __init__( def _optimise_coilset(self): self.result = None try: - self.result = self.opt_prob.optimise(fixed_coils=self.fixed_coils) + self.result = self.opt_prob.optimise( + fixed_coils=self.fixed_coils, + keep_history=self.keep_history, + check_constraints=self.check_constraints, + ) self.coilset = self.result.coilset except OptimisationError: self.coilset = self.store[-1]