Source code for finesse.analysis.actions.random

"""Random collection of Actions that do no warrant a separate module."""

from ...parameter import Parameter
from .base import Action, convert_str_to_parameter
from finesse.solutions import BaseSolution

import logging

LOGGER = logging.getLogger(__name__)


[docs]class SaveModelAttrSolution(BaseSolution): """ Attributes ---------- values : dict Dictionary of model attribute values """ pass
[docs]class Plot(Action): def __init__(self, name="abcd"): super().__init__(name) def _requests(self, model, memo, first=True): pass def _do(self, state): raise NotImplementedError()
[docs]class Printer(Action): def __init__(self, *args, name="printer", eval=True): super().__init__(name) self.args = args self._eval = eval def _requests(self, model, memo, first=True): pass def _do(self, state): if self._eval: out = [] for _ in self.args: if hasattr(_, "eval"): out.append(_.eval()) else: out.append(_) print(*out) else: print(*(_ for _ in self.args))
[docs]class PrintModel(Action): """An action that prints the model object being currently used to run actions.""" def __init__(self, name="print_model"): super().__init__(name) def _requests(self, model, memo, first=True): pass def _do(self, state): print(state.model)
[docs]class StoreModelAttr(Action): def __init__(self, *args): super().__init__(self.__class__.__name__) self.args = tuple(a if isinstance(a, str) else a.full_name for a in args) def _requests(self, model, memo, first=True): pass def _do(self, state): sol = SaveModelAttrSolution(self.name) sol.values = {} for _ in self.args: p = state.model.get(_) if hasattr(p, "eval"): sol.values[_] = p.eval() else: sol.values[_] = p return sol
[docs]class PrintModelAttr(Action): """Prints an attribute of the model being currently used. Parameters ---------- *args : (str,) Strings input for the attribute to print eval: bool, optional When `True` symbolic expressions will be evaluated before printing. Defaults to `True`. Examples -------- You can print the current value of parameters and such using: >>> PrintModelAttr("m1.R", "bs.phi") """ def __init__(self, *args, eval=True): super().__init__(self.__class__.__name__) self.args = tuple(a if isinstance(a, str) else a.full_name for a in args) self._eval = eval def _requests(self, model, memo, first=True): pass def _do(self, state): if self._eval: out = [] for _ in self.args: obj = state.model.get(_) if hasattr(obj, "eval"): out.append(f"{_}={obj.eval()}") else: out.append(f"{_}={obj}") print(*out) else: print(*(f"{_}={state.model.get(_)}" for _ in self.args))
[docs]class Change(Action): """Changes a model Parameter to some value during an analysis. Parameters ---------- change_dict : dict, optional Dictionary of parameter:value pairs to change. relative : bool, optional Whether to increment from the parameters current value or not **kwargs Alternative method to specify parameter:value pairs to change Examples -------- A simple change of a parameter between running two `noxaxis` analyses: >>> model = finesse.script.parse("l L1 P=1") >>> model.run('series(noxaxis(), change(L1.P=2), noxaxis())') Or increment from the current value: >>> model.run('series(noxaxis(), change(L1.P=1, relative=True), noxaxis())') """ def __init__(self, change_dict=None, *, relative=False, **kwargs): super().__init__(None) self.change_dict = change_dict self.kwargs = kwargs self.relative = relative @property def change_kwargs(self): kwargs = self.kwargs or {} if self.change_dict: kwargs.update(self.change_dict) return kwargs def _requests(self, model, memo, first=True): for el in self.change_kwargs.keys(): p = convert_str_to_parameter(model, el) if isinstance(p, Parameter): memo["changing_parameters"].append(el) else: raise TypeError( f"{el} is not a name of a Parameter or Component in the model" ) def _do(self, state): for el, val in self.change_kwargs.items(): p = convert_str_to_parameter(state.model, el) if self.relative: p.value += val else: p.value = val
[docs]class Execute(Action): """An action that will execute the function passed to it when it is run. Parameters ---------- do_fn : function A function that takes an AnalysisState, and the name of the Exec action as its only arguments. If this function returns a :class:`BaseSolution` object then it will be added to the simulations solution to return to the user. parameters : list, optional A list of parameters that will be changed by do_fn, if any. name : str The name to give this action. Examples -------- A simple function to execute might use a pattern such as this, which generates a Solution that is returned back to the user. >>> from finesse.solutions import SimpleSolution >>> def my_action(state, name): ... sol = SimpleSolution(name) ... return sol The :class:`SimpleSolution` object is just an object you can store anything you want in. You can extract any state information about the simulation or model and store it here. This allows you to probe and store details that might not be available as a detector, for example. """ def __init__(self, do_fn, parameters=None, name="execute"): super().__init__(name) self.do_fn = do_fn self.parameters = parameters def _do(self, state): sol = self.do_fn(state, self.name) if isinstance(sol, BaseSolution): return sol def _requests(self, model, memo, first=True): if self.parameters is not None: memo["changing_parameters"].extend(self.parameters)
[docs]class UpdateMaps(Action): """Update any maps that might be changing in the simulation.""" def __init__(self, name="update_maps", *args, **kwargs): super().__init__(name) self.args = args self.kwargs = kwargs def _requests(self, model, memo, first=True): return None def _do(self, state): state.sim.update_map_data()
[docs]class LogModelAttribute(Action): def __init__(self, *attrs): super().__init__("print_parmeter") self.attrs = attrs def _requests(self, model, memo, first=True): pass def _do(self, state): LOGGER.info(*(f"{_}={state.model.get(str(_))}" for _ in self.attrs))
[docs]class Scale(Action): """Action for scaling simulation outputs by some fixed amount. Included for compatibility with legacy Finesse code. New users should apply any desired scalings manually from Python. Parameters ---------- detectors : dict A dictionary of `detector name: scaling factor` mappings. """ def __init__(self, scales: dict, **kwargs): super().__init__(None) self.kwargs = kwargs self.scales = scales def _requests(self, model, memo, first=True): pass def _do(self, state): sol = state.previous_solution for det, fac in self.scales.items(): sol._outputs[det][()] *= fac
[docs]class MakeTransparent(Action): """Action to make all provided surfaces transparent. Simply sets the reflectivity to zero and transmitivity to one. Parameters ---------- surfaces : list A list of surface component names to be made transparent. """ def __init__(self, surfaces, name="make transparent"): super().__init__(name) self.surfaces = surfaces def _do(self, state): for name, el in state.sim.model.elements.items(): if name in self.surfaces: el.set_RTL(R=0, T=1) def _requests(self, model, memo, first=True): for name, el in model.elements.items(): if name in self.surfaces: memo["changing_parameters"].extend( [el.R.full_name, el.T.full_name, el.L.full_name] )