Source code for at.plot.specific

"""AT plotting functions"""
from ..lattice import Lattice, Refpts
from ..tracking import internal_lpass
from ..physics import get_optics, Orbit
from .generic import baseplot

# --------- Example 1 --------

# The specific data generating functions do not depend on any graphics-related
# function. So they could be located in any module, for instance
# in lattice/linear.py where the get_optics function is.


# data generating function
[docs] def pldata_beta_disp(ring: Lattice, refpts: Refpts, **kwargs): """Generates data for plotting beta functions and dispersion""" # compute linear optics at the required locations data0, _, data = get_optics(ring, refpts=refpts, **kwargs) # Extract the plot data s_pos = data['s_pos'] betax = data['beta'][:, 0] betaz = data['beta'][:, 1] dispersion = data['dispersion'][:, 0] # Left axis definition left = (r'$\beta$ [m]', s_pos, [betax, betaz], [r'$\beta_x$', r'$\beta_z$']) # Right axis definition right = ('dispersion [m]', s_pos, [dispersion], ['dispersion']) return 'Optical functions', left, right
# Convenience function to make the call simpler
[docs] def plot_beta(ring: Lattice, **kwargs): """Plot beta functions and dispersion Parameters: ring: Lattice description. Keyword Args: dp (float): Momentum deviation. dct (float): Path lengthening. If specified, ``dp`` is ignored and the off-momentum is deduced from the path lengthening. orbit (Orbit): Avoids looking for the closed orbit if is already known ((6,) array) method (Callable): Method for linear optics (see :py:func:`.get_optics`): :py:obj:`~.linear.linopt2`: no longitudinal motion, no H/V coupling, :py:obj:`~.linear.linopt4`: no longitudinal motion, Sagan/Rubin 4D-analysis of coupled motion, :py:obj:`~.linear.linopt6` (default): with or without longitudinal motion, normal mode analysis keep_lattice (bool): Assume no lattice change since the previous tracking. Defaults to :py:obj:`False` XYStep (float): Step size. Default: :py:data:`DConstant.XYStep <.DConstant>` DPStep (float): Momentum step size. Default: :py:data:`DConstant.DPStep <.DConstant>` twiss_in: Initial conditions for transfer line optics. Record array as output by :py:func:`.linopt2`, :py:func:`.linopt6`, or dictionary. s_range: Lattice range of interest, default: unchanged, initially set to the full cell. axes (tuple[Axes, Optional[Axes]): :py:class:`~matplotlib.axes.Axes` for plotting as (primary_axes, secondary_axes). Default: create new axes slices (int): Number of slices. Default: 400 legend (bool): Show a legend on the plot labels (Refpts): display the name of selected elements. Default: :py:obj:`None` block (bool): If :py:obj:`True`, block until the figure is closed. Default: :py:obj:`False` dipole (dict): Dictionary of properties overloading the default properties of dipole representation. See :py:func:`.plot_synopt` for details quadrupole (dict): Same definition as for dipole sextupole (dict): Same definition as for dipole multipole (dict): Same definition as for dipole monitor (dict): Same definition as for dipole """ return baseplot(ring, pldata_beta_disp, **kwargs)
# --------- Example 2 -------- # data generating function
[docs] def pldata_linear(ring: Lattice, refpts: Refpts, *keys, **kwargs): """data extraction function for plotting results of get_optics""" class Lind(object): """helper class for lindata extraction""" lab2 = "xz" lab6 = ("x", "x'", "z", "z'", "l", "\\delta") id6 = "123456" params = dict( beta=(r'$\beta$ [m]', r'$\beta_{0}$', lab2), closed_orbit=('position [m]', r'${0}$', lab6), dispersion=('dispersion [m]', r'$\eta_{0}$', lab6), alpha=(r'$\alpha$', r'$\alpha_{0}$', lab2), mu=(r'Phase advance', r'$\mu_{0}$', lab2), gamma=('Gamma', 'Gamma', None), M=('Transfert', r'$T_{{{0},{1}}}$', id6) ) @classmethod def extract(cls, lindata, key, *idx): def it(v): try: return iter(v) except TypeError: return iter([v]) axis_title, fmt, convert = cls.params[key] indices = list(zip(*(it(i) for i in idx))) print(indices) datay = (lindata[key][(slice(None),) + ic] for ic in indices) labels = (fmt.format(*(convert[i] for i in ic)) for ic in indices) return axis_title, lindata['s_pos'], datay, labels title = kwargs.pop('title', 'Linear optics') data0, _, data = get_optics(ring, refpts=refpts, get_chrom=True, **kwargs) return (title,) + tuple(Lind.extract(data, *key) for key in keys)
# Convenience function to make the call simpler
[docs] def plot_linear(ring: Lattice, *keys, **kwargs): """Plot linear optical functions returned by :py:func:`.get_optics` Parameters: ring: Lattice description. Keyword Args: left: Left axis description as a tuple: (key[, indices[, indices]]) **key**: 'beta', 'closed_orbit',... See :py:func:`.get_optics` **indices**: integer, sequence of integers, or slice The number if sequences of indices is data[key].ndim-1 The number of indices is the number of curves to plot. All sequences must have the same length. Examples: :code:`('beta', [0, 1])`: beta_x, beta_z :code:`('dispersion', 0)`: eta_x :code:`('closed_orbit', [1, 3])`: x', z' :code:`('m44', 2, 2)`: T33 :code:`('m44', [0, 0], [0, 1])`: T11, T12 :code:`('m44', 2, slice(4))`: T31, T32, T33, T34 as a single block :code:`('m44', [2,2,2,2], [0,1,2,3])`: T31, T32, T33, T34 right: Right axis (optional). See ``left`` title (str): Plot title, defaults to "Linear optics" dp (float): Momentum deviation. dct (float): Path lengthening. If specified, ``dp`` is ignored and the off-momentum is deduced from the path lengthening. orbit (Orbit): Avoids looking for the closed orbit if is already known ((6,) array) method (Callable): Method for linear optics (see :py:func:`.get_optics`): :py:obj:`~.linear.linopt2`: no longitudinal motion, no H/V coupling, :py:obj:`~.linear.linopt4`: no longitudinal motion, Sagan/Rubin 4D-analysis of coupled motion, :py:obj:`~.linear.linopt6` (default): with or without longitudinal motion, normal mode analysis keep_lattice (bool): Assume no lattice change since the previous tracking. Defaults to :py:obj:`False` XYStep (float): Step size. Default: :py:data:`DConstant.XYStep <.DConstant>` DPStep (float): Momentum step size. Default: :py:data:`DConstant.DPStep <.DConstant>` twiss_in: Initial conditions for transfer line optics. Record array as output by :py:func:`~.linear.linopt2`, :py:func:`~.linear.linopt6`, or dictionary. s_range: Lattice range of interest, default: unchanged, initially set to the full cell. axes (tuple[Axes, Optional[Axes]): :py:class:`~matplotlib.axes.Axes` for plotting as (primary_axes, secondary_axes). Default: create new axes slices (int): Number of slices. Default: 400 legend (bool): Show a legend on the plot labels (Refpts): display the name of selected elements. Default: :py:obj:`None` block (bool): If :py:obj:`True`, block until the figure is closed. Default: :py:obj:`False` dipole (dict): Dictionary of properties overloading the default properties of dipole representation. See :py:func:`.plot_synopt` for details quadrupole (dict): Same definition as for dipole sextupole (dict): Same definition as for dipole multipole (dict): Same definition as for dipole monitor (dict): Same definition as for dipole """ return baseplot(ring, pldata_linear, *keys, **kwargs)
# --------- Example 3 -------- # Here the data generating function is embedded in the convenience function
[docs] def plot_trajectory(ring: Lattice, r_in, nturns: int = 1, **kwargs): """Plot a particle's trajectory Parameters: ring: Lattice object r_in: (6,n) array: input coordinates of n particles nturns: Number of turns Keyword Args: keep_lattice (bool): Assume no lattice change since the previous tracking. Defaults to :py:obj:`False` s_range: Lattice range of interest, default: unchanged, initially set to the full cell. axes (tuple[Axes, Optional[Axes]): :py:class:`~matplotlib.axes.Axes` for plotting as (primary_axes, secondary_axes). Default: create new axes slices (int): Number of slices. Default: 400 legend (bool): Show a legend on the plot block (bool): If :py:obj:`True`, block until the figure is closed. Default: :py:obj:`False` dipole (dict): Dictionary of properties overloading the default properties of dipole representation. See :py:func:`.plot_synopt` for details quadrupole (dict): Same definition as for dipole sextupole (dict): Same definition as for dipole multipole (dict): Same definition as for dipole monitor (dict): Same definition as for dipole """ # noinspection PyShadowingNames def pldata_trajectory(ring, refpts, r_in, nturns=1, **kwargs): r_out = internal_lpass(ring, r_in, refpts=refpts, nturns=nturns, **kwargs) s_pos = ring.get_s_pos(refpts) particles = range(r_out.shape[1]) xx = [r_out[0, i, :, :] for i in particles] zz = [r_out[2, i, :, :] for i in particles] xlabels = [r'$x_{0}$'.format(i) for i in particles] zlabels = [r'$z_{0}$'.format(i) for i in particles] left = ('position [m]', s_pos, xx+zz, xlabels+zlabels) return 'Trajectory', left return baseplot(ring, pldata_trajectory, r_in, nturns=nturns, **kwargs)
Lattice.plot_beta = plot_beta Lattice.plot_trajectory = plot_trajectory