Source code for pyhdtoolkit.cpymadtools.matching

"""
.. _cpymadtools-matching:

Matching Routines
-----------------

Module with functions to perform ``MAD-X`` matchings
through a `~cpymad.madx.Madx` object.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from loguru import logger

from pyhdtoolkit.cpymadtools.lhc import get_lhc_tune_and_chroma_knobs

if TYPE_CHECKING:
    from collections.abc import Sequence

    from cpymad.madx import Madx

# ----- Workhorse ----- #


[docs] def match_tunes_and_chromaticities( madx: Madx, /, accelerator: str | None = None, sequence: str | None = None, q1_target: float | None = None, q2_target: float | None = None, dq1_target: float | None = None, dq2_target: float | None = None, varied_knobs: Sequence[str] | None = None, telescopic_squeeze: bool = True, run3: bool = False, step: float = 1e-7, calls: int = 100, tolerance: float = 1e-21, ) -> None: """ .. versionadded:: 0.8.0 Provided with an active `~cpymad.madx.Madx` object, will run relevant commands to match tunes and/or chromaticities. As target values are given, the function expects knob names to be provided, which are then used and varied by ``MAD-X`` to match the targets. This is a convenient wrapper around the ``MATCH`` command in the ``MAD-X`` process. For usage details, see the `MAD-X manual <http://madx.web.cern.ch/madx/releases/last-rel/madxuguide.pdf>`_. One can find examples of this function in the :ref:`lattice plotting <demo-accelerator-lattice>`, the :ref:`rigid waist shift <demo-rigid-waist-shift>` and the :ref:`phase space <demo-phase-space>` example galleries. Important --------- If only target tune values are provided, then tune matching is performed with the provided knobs. If only target chromaticity values are provided, then chromaticity matching is performed with the provided knobs. Otherwise if targets are provided for both, then both are matched in a single call with the provided knobs. Note ---- If one wishes to perform different matching calls for each, then it is recommended to call this function as many times as necessary, with the appropriate targets, or simply the wrappers provided in this module. For instance, in some cases and machines some prefer to do a tune matching followed by a chromaticity matching, then followed by a combined matching. In this case one could call this function three times, or use each wrapper once (first tunes, then chromaticities, then this function). Refer to the :func:`match_tunes` and :func:`match_chromaticities` functions. Hint ---- When acting on either the ``LHC`` or ``HLLHC`` machines, the accelerator name can be provided and the vary knobs will be automatically set accordingly to the provided targets, based on the machine's default knobs. Note that in this case only the relevant knobs are set, so if tune targets only are provided, then tune knobs only will be used, and vice versa. If explicit knobs are provided, these will always take precedence. On any other machine the knobs should be provided explicitly, always. Parameters ---------- madx : cpymad.madx.Madx An instanciated `~cpymad.madx.Madx` object. accelerator : str, optional Name of the accelerator, used to determmine knobs if *variables* is not given. Automatic determination will only work for the ``LHC`` and ``HLLHC`` (accepted case insensitively). Defaults to `None`, in which case the knobs must be provided explicitly through ``varied_knobs``. sequence : str, optional Name of the sequence to perform the matching for. Defaults to `None`, in which case the currently active sequence will be used for the matching. q1_target : float, optional Horizontal tune to match to. Defaults to `None`, in which case it will not be a target and will be excluded from the matching. q2_target : float, optional Vertical tune to match to. Defaults to `None`, in which case it will not be a target and will be excluded from the matching. dq1_target : float, optional Horizontal chromaticity to match to. Defaults to `None`, in which case it will not be a target and will be excluded from the matching. dq2_target : float, optional Vertical chromaticity to match to. Defaults to `None`, in which case it will not be a target and will be excluded from the matching. varied_knobs : Sequence[str], optional The variables names to ``VARY`` in the ``MAD-X`` ``MATCH`` routine. An example input could be ``["kqf", "ksd", "kqf", "kqd"]`` as they are common names used for quadrupole and sextupole strengths (focusing / defocusing) in most examples. This parameter is optional if the accelerator is provided as ``LHC`` or ``HLLHC``, but must be provided otherwise. Defaults to `None`. telescopic_squeeze : bool ``LHC`` specific. If set to `True`, uses the ``(HL)LHC`` knobs for Telescopic Squeeze configuration. Defaults to `True` since `v0.9.0`. run3 : bool ``LHC`` specific. If set to `True`, uses the ``LHC`` Run 3 `*_op` knobs. Defaults to `False`. step : float Step size to use when varying knobs. Defaults to :math:`10^{-7}`. calls : int Max number of varying calls to perform. Defaults to 100. tolerance : float Tolerance for successfull matching. Defaults to :math:`10^{-21}`. Examples -------- Matching a dummy lattice (not ``LHC`` or ``HLLHC``): .. code-block:: python matching.match_tunes_and_chromaticities( madx, None, # this is not LHC or HLLHC sequence="CAS3", q1_target=6.335, q2_target=6.29, dq1_target=100, dq2_target=100, varied_knobs=["kqf", "kqd", "ksf", "ksd"], ) Note that since the `accelerator` and `sequence` parameters default to `None`, they can be omitted. In this case the sequence currently in use will be used for the matching, and `varied_knobs` must be provided: .. code-block:: python matching.match_tunes_and_chromaticities( madx, q1_target=6.335, q2_target=6.29, dq1_target=100, dq2_target=100, varied_knobs=["kqf", "kqd", "ksf", "ksd"], ) Matching the ``lhcb1`` sequence of the ``LHC`` lattice and letting the function determine the knobs automatically: .. code-block:: python matching.match_tunes_and_chromaticities( madx, "lhc", # will find the knobs automatically sequence="lhcb1", q1_target=62.31, q2_target=60.32, dq1_target=2.0, dq2_target=2.0, run3=True, # influences the knobs definition ) """ if accelerator and not varied_knobs: # Assume valid accelerator, which checked in function below logger.trace(f"Getting knobs from default {accelerator.upper()} values") lhc_knobs = get_lhc_tune_and_chroma_knobs( accelerator=accelerator, beam=int(sequence[-1]), telescopic_squeeze=telescopic_squeeze, run3=run3 ) tune_knobs, chroma_knobs = lhc_knobs[:2], lhc_knobs[2:] # first two, last two def match(*args, **kwargs): """Create matching commands for kwarg targets, varying the given args.""" logger.debug(f"Executing matching commands, using sequence '{sequence}'") madx.command.match() logger.trace(f"Targets are given as {kwargs}") madx.command.global_(sequence=sequence, **kwargs) for variable_name in args: logger.trace(f"Creating vary command for knob '{variable_name}'") madx.command.vary(name=variable_name, step=step) madx.command.lmdif(calls=calls, tolerance=tolerance) madx.command.endmatch() logger.trace("Performing routine TWISS") madx.command.twiss() # prevents errors if the user forgets to TWISS before querying tables # Case of a combined matching: both tune and chroma targets have been provided if q1_target is not None and q2_target is not None and dq1_target is not None and dq2_target is not None: logger.debug( f"Doing combined matching to Qx={q1_target}, Qy={q2_target}, " f"dqx={dq1_target}, dqy={dq2_target} for sequence '{sequence}'" ) varied_knobs = varied_knobs or lhc_knobs # if accelerator was given we've extracted this already logger.trace(f"Vary knobs sent are {varied_knobs}") match(*varied_knobs, q1=q1_target, q2=q2_target, dq1=dq1_target, dq2=dq2_target) # Case of a tune matching: ony tune targets have been provided (see also 'match_tunes' wrapper) elif q1_target is not None and q2_target is not None: logger.debug(f"Matching tunes to Qx={q1_target}, Qy={q2_target} for sequence '{sequence}'") tune_knobs = varied_knobs or tune_knobs # if accelerator was given we've extracted this already logger.trace(f"Vary knobs sent are {tune_knobs}") match(*tune_knobs, q1=q1_target, q2=q2_target) # sent varied_knobs should be tune knobs # Case of a chrom matching: ony chroma targets have been provided (see also 'match_chromaticities' wrapper) elif dq1_target is not None and dq2_target is not None: logger.debug(f"Matching chromaticities to dq1={dq1_target}, dq2={dq2_target} for sequence {sequence}") chroma_knobs = varied_knobs or chroma_knobs # if accelerator was given we've extracted this already logger.trace(f"Vary knobs sent are {chroma_knobs}") match(*chroma_knobs, dq1=dq1_target, dq2=dq2_target) # sent varied_knobs should be chromaticity knobs
# ----- Convenient Wrappers ----- #
[docs] def match_tunes( madx: Madx, /, accelerator: str | None = None, sequence: str | None = None, q1_target: float | None = None, q2_target: float | None = None, varied_knobs: Sequence[str] | None = None, telescopic_squeeze: bool = True, run3: bool = False, step: float = 1e-7, calls: int = 100, tolerance: float = 1e-21, ): """ .. versionadded:: 0.17.0 Provided with an active `~cpymad.madx.Madx` object, will run relevant commands to match tunes to the desired target values. Note ---- This is a wrapper around the `~.match_tunes_and_chromaticities` function. Refer to its documentation for usage details. Parameters ---------- madx : cpymad.madx.Madx An instanciated `~cpymad.madx.Madx` object. accelerator : str, optional Name of the accelerator, used to determmine knobs if *variables* is not given. Automatic determination will only work for the ``LHC`` and ``HLLHC`` (accepted case insensitively). Defaults to `None`, in which case the knobs must be provided explicitly through ``varied_knobs``. sequence : str, optional Name of the sequence to perform the matching for. Defaults to `None`, in which case the currently active sequence will be used for the matching. q1_target : float, optional Horizontal tune to match to. Defaults to `None`, in which case it will not be a target and will be excluded from the matching. q2_target : float, optional Vertical tune to match to. Defaults to `None`, in which case it will not be a target and will be excluded from the matching. varied_knobs : Sequence[str], optional The variables names to ``VARY`` in the ``MAD-X`` ``MATCH`` routine. An example input could be ``["kqf", "ksd", "kqf", "kqd"]`` as they are common names used for quadrupole and sextupole strengths (focusing / defocusing) in most examples. This parameter is optional if the accelerator is provided as ``LHC`` or ``HLLHC``, but must be provided otherwise. Defaults to `None`. telescopic_squeeze : bool ``LHC`` specific. If set to `True`, uses the ``(HL)LHC`` knobs for Telescopic Squeeze configuration. Defaults to `True` since `v0.9.0`. run3 : bool ``LHC`` specific. If set to `True`, uses the ``LHC`` Run 3 `*_op` knobs. Defaults to `False`. step : float Step size to use when varying knobs. Defaults to :math:`10^{-7}`. calls : int Max number of varying calls to perform. Defaults to 100. tolerance : float Tolerance for successfull matching. Defaults to :math:`10^{-21}`. Examples -------- Matching a dummy lattice (not ``LHC`` or ``HLLHC``): .. code-block:: python matching.match_tunes( madx, None, # this is not LHC or HLLHC sequence="CAS3", q1_target=6.335, q2_target=6.29, varied_knobs=["kqf", "kqd"], # only tune knobs ) Note that since the `accelerator` and `sequence` parameters default to `None`, they can be omitted. In this case the sequence currently in use will be used for the matching, and `varied_knobs` must be provided: .. code-block:: python matching.match_tunes_and_chromaticities( madx, q1_target=6.335, q2_target=6.29, varied_knobs=["kqf", "kqd"], # only tune knobs ) Matching the ``lhcb1`` sequence of the ``LHC`` lattice and letting the function determine the knobs automatically: .. code-block:: python matching.match_tunes( madx, "lhc", # will find the knobs automatically sequence="lhcb1", q1_target=62.31, q2_target=60.32, ) """ match_tunes_and_chromaticities( madx, accelerator=accelerator, sequence=sequence, q1_target=q1_target, q2_target=q2_target, dq1_target=None, dq2_target=None, varied_knobs=varied_knobs, telescopic_squeeze=telescopic_squeeze, run3=run3, step=step, calls=calls, tolerance=tolerance, )
[docs] def match_chromaticities( madx: Madx, /, accelerator: str | None = None, sequence: str | None = None, dq1_target: float | None = None, dq2_target: float | None = None, varied_knobs: Sequence[str] | None = None, telescopic_squeeze: bool = True, run3: bool = False, step: float = 1e-7, calls: int = 100, tolerance: float = 1e-21, ): """ .. versionadded:: 0.17.0 Provided with an active `~cpymad.madx.Madx` object, will run relevant commands to match chromaticities to the desired target values. Note ---- This is a wrapper around the `~.match_tunes_and_chromaticities` function. Refer to its documentation for usage details. Parameters ---------- madx : cpymad.madx.Madx An instanciated `~cpymad.madx.Madx` object. accelerator : str, optional Name of the accelerator, used to determmine knobs if *variables* is not given. Automatic determination will only work for the ``LHC`` and ``HLLHC`` (accepted case insensitively). Defaults to `None`, in which case the knobs must be provided explicitly through ``varied_knobs``. sequence : str, optional Name of the sequence to perform the matching for. Defaults to `None`, in which case the currently active sequence will be used for the matching. dq1_target : float, optional Horizontal chromaticity to match to. Defaults to `None`, in which case it will not be a target and will be excluded from the matching. dq2_target : float, optional Vertical chromaticity to match to. Defaults to `None`, in which case it will not be a target and will be excluded from the matching. varied_knobs : Sequence[str], optional The variables names to ``VARY`` in the ``MAD-X`` ``MATCH`` routine. An example input could be ``["kqf", "ksd", "kqf", "kqd"]`` as they are common names used for quadrupole and sextupole strengths (focusing / defocusing) in most examples. This parameter is optional if the accelerator is provided as ``LHC`` or ``HLLHC``, but must be provided otherwise. Defaults to `None`. telescopic_squeeze : bool ``LHC`` specific. If set to `True`, uses the ``(HL)LHC`` knobs for Telescopic Squeeze configuration. Defaults to `True` since `v0.9.0`. run3 : bool ``LHC`` specific. If set to `True`, uses the ``LHC`` Run 3 `*_op` knobs. Defaults to `False`. step : float Step size to use when varying knobs. Defaults to :math:`10^{-7}`. calls : int Max number of varying calls to perform. Defaults to 100. tolerance : float Tolerance for successfull matching. Defaults to :math:`10^{-21}`. Examples -------- Matching a dummy lattice (not ``LHC`` or ``HLLHC``): .. code-block:: python matching.match_chromaticities( madx, None, # this is not LHC or HLLHC sequence="CAS3", dq1_target=100, dq2_target=100, varied_knobs=["ksf", "ksd"], # only chroma knobs ) Note that since the `accelerator` and `sequence` parameters default to `None`, they can be omitted. In this case the sequence currently in use will be used for the matching, and `varied_knobs` must be provided: .. code-block:: python matching.match_tunes_and_chromaticities( madx, dq1_target=100, dq2_target=100, varied_knobs=["ksf", "ksd"], # only chroma knobs ) Matching the ``lhcb1`` sequence of the ``LHC`` lattice and letting the function determine the knobs automatically: .. code-block:: python matching.match_chromaticities( madx, "lhc", # will find the knobs automatically sequence="lhcb1", dq1_target=2.0, dq2_target=2.0, ) """ match_tunes_and_chromaticities( madx, accelerator=accelerator, sequence=sequence, q1_target=None, q2_target=None, dq1_target=dq1_target, dq2_target=dq2_target, varied_knobs=varied_knobs, telescopic_squeeze=telescopic_squeeze, run3=run3, step=step, calls=calls, tolerance=tolerance, )