Source code for lightwin.optimisation.design_space.constraint

"""Define :class:`Constraint`, which stores a constraint.

It saves it's name, limits, and methods to evaluate if it is violated or not.

"""

import logging
import math
from dataclasses import dataclass

import numpy as np

from lightwin.beam_calculation.simulation_output.simulation_output import (
    SimulationOutput,
)
from lightwin.optimisation.design_space.design_space_parameter import (
    DesignSpaceParameter,
)
from lightwin.util.typing import CONSTRAINTS


[docs] @dataclass class Constraint(DesignSpaceParameter): """A single constraint. For now, it can only be a synchronous phase limits. By convention, all calculations are done in rad, and phases are always printed in deg. """
[docs] def __post_init__(self): """Convert values in deg for output if it is angle.""" logging.critical("Dirty patch, phi_s is hard-coded") if self.name not in CONSTRAINTS: raise ValueError("phi_s constraint hard-coded!!") logging.warning("Constraint not tested.") # in particular: phi_s is hard-coded in get_value!! super().__post_init__() self._to_deg = False self._to_numpy = False if "phi" not in self.name: return for lim in self.limits: if lim < -math.pi or lim > math.pi: logging.error( f"Phase limits are expected to be in [-pi, +pi]. {lim = }" )
@property def kwargs(self) -> dict[str, bool]: """Return the `kwargs` to send a `get` method.""" _kwargs = { "to_deg": self._to_deg, "to_numpy": self._to_numpy, "elt": self.element_name, } return _kwargs @property def n_constraints(self) -> int: """Return number of embedded constraints in this object. A lower + and upper bound count as two constraints. """ return np.where(~np.isnan(np.array(self.limits)))[0].shape[0]
[docs] def get_value(self, simulation_output: SimulationOutput) -> float: """Get from the `SimulationOutput` the quantity called `self.name`. Currently bugged. When trying too access ``phi_s``, we get the value stored in ``SimulationOutput.elts`` instead of the one in ``SetOfCavitySettings``. So we end up with the ``phi_s`` from the broken linac instead of the ones in the cavity settings we just tried. """ for key, value in simulation_output.set_of_cavity_settings.items(): if key.name == self.element_name: return value.phi_s raise ValueError("phi_s not found") return simulation_output.get(self.name, **self.kwargs)
[docs] def evaluate( self, simulation_output: SimulationOutput ) -> tuple[float, float]: """Check if constraint is respected. They should be < 0. """ value = self.get_value(simulation_output) const = (self.limits[0] - value, value - self.limits[1]) return const