From 85b3ff57049b5ad36d2d37e36b3be042948c63ca Mon Sep 17 00:00:00 2001 From: Felix Soubelet <19598248+fsoubelet@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:45:26 +0000 Subject: [PATCH] Changes for 1.1.0 (#99) --- .github/workflows/coverage.yml | 3 + .github/workflows/cron.yml | 3 + .github/workflows/tests.yml | 3 + .gitignore | 4 +- docs/api/cpymadtools.rst | 32 +- docs/quickstart.rst | 2 +- docs/release.rst | 8 + docs/releases/v1.1.0.rst | 36 + examples/demo_acd_tracking_spectra.py | 4 +- examples/demo_aperture.py | 8 +- examples/demo_beam_enveloppe.py | 6 +- examples/demo_ir_errors.py | 11 +- examples/demo_lattice.py | 15 +- examples/demo_lhc_crossing_schemes.py | 4 +- examples/demo_lhc_rigid_waist_shift.py | 22 +- examples/demo_machine_survey.py | 6 +- examples/demo_phase_space.py | 18 +- examples/demo_sbs_plotting.py | 2 +- examples/demo_stats_fitting.py | 14 +- examples/demo_track_spectra.py | 4 +- examples/demo_tune_diagram.py | 2 +- pyhdtoolkit/cpymadtools/__init__.py | 34 +- .../{generators.py => _generators.py} | 0 pyhdtoolkit/cpymadtools/constants.py | 39 +- pyhdtoolkit/cpymadtools/correctors.py | 162 -- pyhdtoolkit/cpymadtools/lhc.py | 1200 ------------- pyhdtoolkit/cpymadtools/lhc/__init__.py | 69 + pyhdtoolkit/cpymadtools/lhc/_coupling.py | 86 + pyhdtoolkit/cpymadtools/lhc/_elements.py | 233 +++ .../cpymadtools/{errors.py => lhc/_errors.py} | 112 +- pyhdtoolkit/cpymadtools/lhc/_misc.py | 202 +++ pyhdtoolkit/cpymadtools/lhc/_powering.py | 412 +++++ pyhdtoolkit/cpymadtools/lhc/_queries.py | 290 ++++ pyhdtoolkit/cpymadtools/lhc/_routines.py | 186 +++ pyhdtoolkit/cpymadtools/lhc/_setup.py | 530 ++++++ pyhdtoolkit/cpymadtools/lhc/_twiss.py | 78 + pyhdtoolkit/cpymadtools/orbit.py | 198 --- pyhdtoolkit/cpymadtools/setup.py | 268 --- pyhdtoolkit/cpymadtools/twiss.py | 62 - pyhdtoolkit/cpymadtools/utils.py | 7 +- pyhdtoolkit/plotting/styles/paper.py | 16 +- pyhdtoolkit/utils/_misc.py | 18 +- pyhdtoolkit/version.py | 2 +- tests/conftest.py | 2 +- tests/inputs/madx/PROTON/opticsfile.22 | 1477 +++++++++++++++++ tests/test_cpymadtools/test_correctors.py | 78 - tests/test_cpymadtools/test_errors.py | 97 -- tests/test_cpymadtools/test_generators.py | 2 +- tests/test_cpymadtools/test_lhc.py | 333 +++- tests/test_cpymadtools/test_matching.py | 2 +- tests/test_cpymadtools/test_orbit.py | 109 -- tests/test_cpymadtools/test_ptc.py | 2 +- tests/test_cpymadtools/test_tune.py | 3 +- tests/test_cpymadtools/test_twiss.py | 30 +- tests/test_plotting/test_lattice.py | 2 +- tests/test_plotting/test_phasespace.py | 2 +- 56 files changed, 4093 insertions(+), 2457 deletions(-) create mode 100644 docs/releases/v1.1.0.rst rename pyhdtoolkit/cpymadtools/{generators.py => _generators.py} (100%) delete mode 100644 pyhdtoolkit/cpymadtools/correctors.py delete mode 100644 pyhdtoolkit/cpymadtools/lhc.py create mode 100644 pyhdtoolkit/cpymadtools/lhc/__init__.py create mode 100644 pyhdtoolkit/cpymadtools/lhc/_coupling.py create mode 100644 pyhdtoolkit/cpymadtools/lhc/_elements.py rename pyhdtoolkit/cpymadtools/{errors.py => lhc/_errors.py} (73%) create mode 100644 pyhdtoolkit/cpymadtools/lhc/_misc.py create mode 100644 pyhdtoolkit/cpymadtools/lhc/_powering.py create mode 100644 pyhdtoolkit/cpymadtools/lhc/_queries.py create mode 100644 pyhdtoolkit/cpymadtools/lhc/_routines.py create mode 100644 pyhdtoolkit/cpymadtools/lhc/_setup.py create mode 100644 pyhdtoolkit/cpymadtools/lhc/_twiss.py delete mode 100644 pyhdtoolkit/cpymadtools/orbit.py delete mode 100644 pyhdtoolkit/cpymadtools/setup.py create mode 100644 tests/inputs/madx/PROTON/opticsfile.22 delete mode 100644 tests/test_cpymadtools/test_correctors.py delete mode 100644 tests/test_cpymadtools/test_errors.py delete mode 100644 tests/test_cpymadtools/test_orbit.py diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 638f1d76..5ff90eff 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -33,6 +33,9 @@ jobs: - name: Install package with test dependencies run: python -m pip install ".[test]" + - name: Get acc-models-lhc + run: git clone https://gitlab.cern.ch/acc-models/acc-models-lhc.git --depth 1 + - name: Run all tests run: make alltests diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 80abc0cf..8cbdaf91 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -41,5 +41,8 @@ jobs: - name: Install package with test dependencies run: python -m pip install ".[test]" + - name: Get acc-models-lhc + run: git clone https://gitlab.cern.ch/acc-models/acc-models-lhc.git --depth 1 + - name: Run Tests run: make alltests diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 99310a81..a35e6018 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -58,5 +58,8 @@ jobs: - name: Install package run: python -m pip install ".[test]" + - name: Get acc-models-lhc + run: git clone https://gitlab.cern.ch/acc-models/acc-models-lhc.git --depth 1 + - name: Run Tests run: make slowtests diff --git a/.gitignore b/.gitignore index f2149997..97f00be8 100644 --- a/.gitignore +++ b/.gitignore @@ -252,4 +252,6 @@ Temporary Items # Sphinx build directory and sphinx-gallery generated documents doc_build/ docs/gallery/ -docs/gen_modules/ \ No newline at end of file +docs/gen_modules/ + +acc-models-lhc/ \ No newline at end of file diff --git a/docs/api/cpymadtools.rst b/docs/api/cpymadtools.rst index fb3a44f5..6dc713e6 100644 --- a/docs/api/cpymadtools.rst +++ b/docs/api/cpymadtools.rst @@ -8,34 +8,46 @@ The ``cpymadtools`` subpackage is a collection of utilities to conveniently hand .. automodule:: pyhdtoolkit.cpymadtools.constants :members: -.. automodule:: pyhdtoolkit.cpymadtools.correctors +.. automodule:: pyhdtoolkit.cpymadtools.coupling :members: -.. automodule:: pyhdtoolkit.cpymadtools.coupling +.. automodule:: pyhdtoolkit.cpymadtools.lhc :members: -.. automodule:: pyhdtoolkit.cpymadtools.errors +.. automodule:: pyhdtoolkit.cpymadtools.lhc._coupling :members: -.. automodule:: pyhdtoolkit.cpymadtools.generators +.. automodule:: pyhdtoolkit.cpymadtools.lhc._elements :members: -.. automodule:: pyhdtoolkit.cpymadtools.lhc +.. automodule:: pyhdtoolkit.cpymadtools.lhc._errors :members: -.. automodule:: pyhdtoolkit.cpymadtools.matching +.. automodule:: pyhdtoolkit.cpymadtools.lhc._misc :members: -.. automodule:: pyhdtoolkit.cpymadtools.orbit +.. automodule:: pyhdtoolkit.cpymadtools.lhc._powering :members: -.. automodule:: pyhdtoolkit.cpymadtools.parameters +.. automodule:: pyhdtoolkit.cpymadtools.lhc._queries :members: -.. automodule:: pyhdtoolkit.cpymadtools.ptc +.. automodule:: pyhdtoolkit.cpymadtools.lhc._routines + :members: + +.. automodule:: pyhdtoolkit.cpymadtools.lhc._setup :members: -.. automodule:: pyhdtoolkit.cpymadtools.setup +.. automodule:: pyhdtoolkit.cpymadtools.lhc._twiss + :members: + +.. automodule:: pyhdtoolkit.cpymadtools.matching + :members: + +.. automodule:: pyhdtoolkit.cpymadtools.parameters + :members: + +.. automodule:: pyhdtoolkit.cpymadtools.ptc :members: .. automodule:: pyhdtoolkit.cpymadtools.track diff --git a/docs/quickstart.rst b/docs/quickstart.rst index ca397f7f..d0037fad 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -93,7 +93,7 @@ Then using the `~pyhdtoolkit.cpymadtools` apis goes as: In the `~pyhdtoolkit.cpymadtools` one will find modules to: * Encompass existing ``MAD-X`` commands, such as for example :ref:`matching ` or :ref:`tracking `; -* Perform useful routines with a clean pythonic interface (for instance :ref:`betatron coupling ` calculation and handling, :ref:`errors assignments ` or :ref:`table querying `); +* Perform useful routines with a clean pythonic interface (for instance :ref:`betatron coupling ` calculation and handling or :ref:`table querying `); * Run :ref:`(HL)LHC ` specific functionality, mostly tailored to my work. One can find many examples of the `~pyhdtoolkit.cpymadtools` apis' use in the :ref:`gallery ` section of this documentation. diff --git a/docs/release.rst b/docs/release.rst index f299d594..021db061 100644 --- a/docs/release.rst +++ b/docs/release.rst @@ -3,6 +3,14 @@ Release Notes The full list of releases can be found in the GitHub repository's `releases page `_. +Version 1.1.0 +------------- + +.. toctree:: + :maxdepth: 2 + + releases/v1.1.0 + Version 1.0.0 ------------- diff --git a/docs/releases/v1.1.0.rst b/docs/releases/v1.1.0.rst new file mode 100644 index 00000000..dc93fad4 --- /dev/null +++ b/docs/releases/v1.1.0.rst @@ -0,0 +1,36 @@ +.. _release_1.1.0: + +1.1.0 +----- + +Release `1.1.0` brings some changes to match the adapted extracted API for `beamopticsanalysis/cpymadtools`. +Code using ``pyhdtoolkit`` will need to be adapted. + +Breaking Changes +~~~~~~~~~~~~~~~~ + +* The `~pyhdtoolkit.cpymadtools.correctors`, `~pyhdtoolkit.cpymadtools.errors`, `~pyhdtoolkit.cpymadtools.orbit` and `~pyhdtoolkit.cpymadtools.setup` modules has been removed and their functionality included in `~pyhdtoolkit.cpymadtools.lhc`, as it was ``LHC``-specific. +* The `~pyhdtoolkit.plotting.generators` module has been made private. + +Bug Fixes +~~~~~~~~~ + +* The `~pyhdtoolkit.cpymadtools.lhc.prepare_lhc_run2` function now properly calls the found sequence file. +* The `~pyhdtoolkit.cpymadtools.utils.get_table_tfs` function now avoids using the `.dframe()` method of tables and converts them to a dict, then to a DataFrame to export. The previous implementation would sometimes crash on certain element names, or in cases of sliced sequences. + +Enhancements +~~~~~~~~~~~~ + +* The `~pyhdtoolkit.cpymadtools.lhc.do_kmodulation` function now accepts ``kwargs`` that will be passed down to the ``TWISS`` call. + +Maintenance +~~~~~~~~~~~ + +* Documentation has been updated for all new APIs. Refer to the gallery for example uses. +* The `~pyhdtoolkit.cpymadtools._generators` being now private, they have been removed from the public API documentation. +* Tests and internal API usehave been adapted. +* Some style parameters in `~pyhdtoolkit.plotting.styles.paper` have been adapted. +* The `~pyhdtoolkit.cpymadtools.lhc` module has been split up into many smaller *private* modules. The functionality of the APIs is unchanged, and they are still exposed at the `~pyhdtoolkit.cpymadtools.lhc` level. + + +See `v1.1.0 release notes on GitHub `_ and the `full changes since v1.0.0 `_. diff --git a/examples/demo_acd_tracking_spectra.py b/examples/demo_acd_tracking_spectra.py index 244350c3..6dda639c 100755 --- a/examples/demo_acd_tracking_spectra.py +++ b/examples/demo_acd_tracking_spectra.py @@ -29,7 +29,7 @@ from pyhdtoolkit.plotting.styles import _SPHINX_GALLERY_PARAMS from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial ############################################################################### @@ -164,6 +164,6 @@ # The use of the following functions, methods, classes and modules is shown # in this example: # -# - `~.cpymadtools.lhc`: `~.lhc.make_lhc_beams`, `~.lhc.re_cycle_sequence`, `~.lhc.make_lhc_thin`, `~.lhc.install_ac_dipole_as_kicker` +# - `~.cpymadtools.lhc`: `~.lhc._setup.make_lhc_beams`, `~.lhc._setup.re_cycle_sequence`, `~.lhc._setup.make_lhc_thin`, `~.lhc._elements.install_ac_dipole_as_kicker` # - `~.cpymadtools.matching`: `~.matching.match_tunes_and_chromaticities` # - `~.cpymadtools.track`: `~.track.track_single_particle` diff --git a/examples/demo_aperture.py b/examples/demo_aperture.py index 8319bc1a..5508a78f 100755 --- a/examples/demo_aperture.py +++ b/examples/demo_aperture.py @@ -19,7 +19,7 @@ from pyhdtoolkit.plotting.styles import _SPHINX_GALLERY_PARAMS from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial ############################################################################### @@ -42,9 +42,7 @@ madx.call("lhc/aper_tol.b1.madx") madx.command.twiss() -madx.command.aperture( - cor=0.002, dp=8.6e-4, halo="{6,6,6,6}", bbeat=1.05, dparx=0.14, dpary=0.14 -) +madx.command.aperture(cor=0.002, dp=8.6e-4, halo="{6,6,6,6}", bbeat=1.05, dparx=0.14, dpary=0.14) ############################################################################### # We can now determine the exact position of the IP5 point and plot the LHC @@ -84,5 +82,5 @@ # The use of the following functions, methods, classes and modules is shown # in this example: # -# - `~.cpymadtools.lhc`: `~.lhc.make_lhc_beams` +# - `~.cpymadtools.lhc`: `~.lhc._setup.make_lhc_beams` # - `~.plotting.aperture`: `~.plotting.aperture.plot_aperture` diff --git a/examples/demo_beam_enveloppe.py b/examples/demo_beam_enveloppe.py index cf12e04e..15e39518 100755 --- a/examples/demo_beam_enveloppe.py +++ b/examples/demo_beam_enveloppe.py @@ -22,7 +22,7 @@ from pyhdtoolkit.plotting.styles import _SPHINX_GALLERY_PARAMS from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial ############################################################################### @@ -159,9 +159,7 @@ title=f"Vertical aperture at {beam_injection.pc_GeV} GeV/c", axis=axes[1], ) -plot_stay_clear( - madx, beam_injection, title=f"Stay-Clear at {beam_injection.pc_GeV} GeV/c", axis=axes[2] -) +plot_stay_clear(madx, beam_injection, title=f"Stay-Clear at {beam_injection.pc_GeV} GeV/c", axis=axes[2]) plt.show() ############################################################################### diff --git a/examples/demo_ir_errors.py b/examples/demo_ir_errors.py index f75246c5..79aefdef 100755 --- a/examples/demo_ir_errors.py +++ b/examples/demo_ir_errors.py @@ -6,7 +6,7 @@ LHC IR Errors Assignments ========================= -This example shows how to use the `~.errors.misalign_lhc_ir_quadrupoles` function +This example shows how to use the `~.lhc.misalign_lhc_ir_quadrupoles` function to assign magnet errors in the Insertion Region magnets of the LHC. .. warning:: @@ -19,11 +19,11 @@ from cpymad.madx import Madx -from pyhdtoolkit.cpymadtools import errors, lhc, matching +from pyhdtoolkit.cpymadtools import lhc, matching from pyhdtoolkit.plotting.styles import _SPHINX_GALLERY_PARAMS from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial ############################################################################### @@ -56,7 +56,7 @@ # Here let's apply systematic horizontal misalignment errors and tilt errors to the # quadrupoles Q1 to Q6 (first to sixth) on both sides of IP1: -errors.misalign_lhc_ir_quadrupoles( +lhc.misalign_lhc_ir_quadrupoles( madx, ips=[1], beam=1, @@ -139,6 +139,5 @@ # The use of the following functions, methods, classes and modules is shown # in this example: # -# - `~.cpymadtools.errors`: `~.errors.misalign_lhc_ir_quadrupoles` -# - `~.cpymadtools.lhc`: `~.lhc.make_lhc_beams` +# - `~.cpymadtools.lhc`: `~.lhc._setup.make_lhc_beams`, `~.lhc._errors.misalign_lhc_ir_quadrupoles` # - `~.cpymadtools.matching`: `~.matching.match_tunes_and_chromaticities` diff --git a/examples/demo_lattice.py b/examples/demo_lattice.py index 688626c7..f37f9b0d 100755 --- a/examples/demo_lattice.py +++ b/examples/demo_lattice.py @@ -16,13 +16,13 @@ from cpymad.madx import Madx -from pyhdtoolkit.cpymadtools import lhc, matching, orbit -from pyhdtoolkit.cpymadtools.generators import LatticeGenerator +from pyhdtoolkit.cpymadtools import lhc, matching +from pyhdtoolkit.cpymadtools._generators import LatticeGenerator from pyhdtoolkit.plotting.lattice import plot_latwiss from pyhdtoolkit.plotting.styles import _SPHINX_GALLERY_PARAMS from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial ############################################################################### @@ -56,9 +56,7 @@ title = rf"Base Lattice, $\mu_{{x, cell}}={mu_x_cell:.3f}, \ \mu_{{y, cell}}={mu_y_cell:.3f}$" plt.figure(figsize=(18, 11)) -plot_latwiss( - madx, title=title, k0l_lim=(-0.15, 0.15), k1l_lim=(-0.08, 0.08), disp_ylim=(-10, 125), lw=3 -) +plot_latwiss(madx, title=title, k0l_lim=(-0.15, 0.15), k1l_lim=(-0.08, 0.08), disp_ylim=(-10, 125), lw=3) plt.tight_layout() plt.show() @@ -80,7 +78,7 @@ lhc.re_cycle_sequence(lhc_madx, sequence="lhcb1", start="IP3") lhc.re_cycle_sequence(lhc_madx, sequence="lhcb2", start="IP3") -orbit_scheme = orbit.setup_lhc_orbit(lhc_madx, scheme="flat") +orbit_scheme = lhc.setup_lhc_orbit(lhc_madx, scheme="flat") lhc.make_lhc_beams(lhc_madx, energy=7000) lhc_madx.command.use(sequence="lhcb1") @@ -179,8 +177,7 @@ # The use of the following functions, methods, classes and modules is shown # in this example: # -# - `~.cpymadtools.lhc`: `~.lhc.make_lhc_beams`, `~.lhc.re_cycle_sequence` +# - `~.cpymadtools.lhc`: `~.lhc._setup.make_lhc_beams`, `~.lhc._setup.re_cycle_sequence`, `~.lhc._setup.setup_lhc_orbit` # - `~.cpymadtools.generators`: `~.generators.LatticeGenerator` # - `~.cpymadtools.matching`: `~.matching.match_tunes_and_chromaticities` -# - `~.cpymadtools.orbit`: `~.orbit.setup_lhc_orbit` # - `~.plotting.lattice`: `~.plotting.lattice.plot_latwiss` diff --git a/examples/demo_lhc_crossing_schemes.py b/examples/demo_lhc_crossing_schemes.py index a0185327..a3e47820 100755 --- a/examples/demo_lhc_crossing_schemes.py +++ b/examples/demo_lhc_crossing_schemes.py @@ -21,7 +21,7 @@ from pyhdtoolkit.plotting.styles import _SPHINX_GALLERY_PARAMS from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial @@ -68,5 +68,5 @@ # The use of the following functions, methods, classes and modules is shown # in this example: # -# - `~.cpymadtools.lhc`: `~.lhc.make_lhc_beams`, `~.lhc.re_cycle_sequence` +# - `~.cpymadtools.lhc`: `~.lhc._setup.make_lhc_beams`, `~.lhc._setup.re_cycle_sequence` # - `~.plotting.crossing`: `~.plotting.crossing.plot_two_lhc_ips_crossings` diff --git a/examples/demo_lhc_rigid_waist_shift.py b/examples/demo_lhc_rigid_waist_shift.py index 1087dc96..0ae2c5c4 100755 --- a/examples/demo_lhc_rigid_waist_shift.py +++ b/examples/demo_lhc_rigid_waist_shift.py @@ -31,7 +31,7 @@ from pyhdtoolkit.plotting.styles import _SPHINX_GALLERY_PARAMS from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial ############################################################################### @@ -184,9 +184,7 @@ lhc.re_cycle_sequence(madx, sequence=f"lhcb1", start=f"MSIA.EXIT.B1") madx.command.use(sequence=f"lhcb1") lhc.make_lhc_thin(madx, sequence=f"lhcb1", slicefactor=4) - lhc.add_markers_around_lhc_ip( - madx, sequence=f"lhcb1", ip=1, n_markers=1000, interval=0.001 - ) + lhc.add_markers_around_lhc_ip(madx, sequence=f"lhcb1", ip=1, n_markers=1000, interval=0.001) madx.command.twiss() initial_twiss = madx.table.twiss.dframe().copy() @@ -287,25 +285,19 @@ # Manipulating the equation to determine the waist yields: # :math:`w = L^{*} - \sqrt{\beta_0 \beta_w - \beta_w^2}` -q1_right_s = twiss_df[twiss_df.name.str.contains(f"mqxa.1r1")].s[ - 0 -] # to calculate from the right Q1 -q1_left_s = twiss_df[twiss_df.name.str.contains(f"mqxa.1l1")].s[ - -1 -] # to calculate from the left Q1 +q1_right_s = twiss_df[twiss_df.name.str.contains(f"mqxa.1r1")].s[0] # to calculate from the right Q1 +q1_left_s = twiss_df[twiss_df.name.str.contains(f"mqxa.1l1")].s[-1] # to calculate from the left Q1 L_star = ip_s - q1_left_s # we calculate from left Q1 # beta0 = twiss_df[twiss_df.name.str.contains(f"mqxa.1r1")].betx[0] # to calculate from the right -beta0 = twiss_df[twiss_df.name.str.contains(f"mqxa.1l1")].betx[ - -1 -] # to calculate from the left +beta0 = twiss_df[twiss_df.name.str.contains(f"mqxa.1l1")].betx[-1] # to calculate from the left betaw = around_ip.betx.min() ############################################################################### # The analytical result (sign will swap depending on if we calculate from left # or right Q1) is then easily calculated. We can then compare this value to the # one found with the markers we previously added, and they are fairly close. -waist = L_star - np.sqrt(beta0 * betaw - betaw**2) +waist = L_star - np.sqrt(beta0 * betaw - betaw ** 2) print(f"Analytical: {waist}") print(f"Markers: {shift}") @@ -316,6 +308,6 @@ # The use of the following functions, methods, classes and modules is shown # in this example: # -# - `~.cpymadtools.lhc`: `~.lhc.make_lhc_beams`, `~.lhc.re_cycle_sequence`, `~.lhc.apply_lhc_rigidity_waist_shift_knob`, `~.lhc.add_markers_around_lhc_ip` +# - `~.cpymadtools.lhc`: `~.lhc._setup.make_lhc_beams`, `~.lhc._setup.re_cycle_sequence`, `~.lhc._powering.apply_lhc_rigidity_waist_shift_knob`, `~.lhc._elements.add_markers_around_lhc_ip` # - `~.cpymadtools.matching`: `~.matching.match_tunes`, `~.matching.match_chromaticities`, `~.matching.match_tunes_and_chromaticities` # - `~.plotting.lattice`: `~.plotting.lattice.plot_latwiss` diff --git a/examples/demo_machine_survey.py b/examples/demo_machine_survey.py index 7d1e963c..09949267 100755 --- a/examples/demo_machine_survey.py +++ b/examples/demo_machine_survey.py @@ -14,12 +14,12 @@ from cpymad.madx import Madx -from pyhdtoolkit.cpymadtools.generators import LatticeGenerator +from pyhdtoolkit.cpymadtools._generators import LatticeGenerator from pyhdtoolkit.plotting.lattice import plot_machine_survey from pyhdtoolkit.plotting.styles import _SPHINX_GALLERY_PARAMS from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial ############################################################################### @@ -59,5 +59,5 @@ # The use of the following functions, methods, classes and modules is shown # in this example: # -# - `~.cpymadtools.generators`: `~.generators.LatticeGenerator`, `~.lhc.re_cycle_sequence` +# - `~.cpymadtools._generators`: `~._generators.LatticeGenerator` # - `~.plotting.lattice`: `~.plotting.lattice.plot_machine_survey` diff --git a/examples/demo_phase_space.py b/examples/demo_phase_space.py index 4f7c00e1..7d5b1024 100755 --- a/examples/demo_phase_space.py +++ b/examples/demo_phase_space.py @@ -19,7 +19,7 @@ from cpymad.madx import Madx -from pyhdtoolkit.cpymadtools.generators import LatticeGenerator +from pyhdtoolkit.cpymadtools._generators import LatticeGenerator from pyhdtoolkit.cpymadtools.matching import match_tunes_and_chromaticities from pyhdtoolkit.cpymadtools.track import track_single_particle from pyhdtoolkit.plotting.phasespace import ( @@ -29,7 +29,7 @@ from pyhdtoolkit.plotting.styles import _SPHINX_GALLERY_PARAMS from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial ############################################################################### @@ -65,9 +65,7 @@ # a particle's coordinates for each turn. for starting_x in initial_x_coordinates: - tracks_df = track_single_particle( - madx, initial_coordinates=(starting_x, 0, 0, 0, 0, 0), nturns=n_turns - ) + tracks_df = track_single_particle(madx, initial_coordinates=(starting_x, 0, 0, 0, 0, 0), nturns=n_turns) x_coords.append(tracks_df["observation_point_1"].x.to_numpy()) y_coords.append(tracks_df["observation_point_1"].y.to_numpy()) px_coords.append(tracks_df["observation_point_1"].px.to_numpy()) @@ -126,9 +124,7 @@ x_coords_sext, px_coords_sext, y_coords_sext, py_coords_sext = [], [], [], [] for starting_x in initial_x_coordinates: - tracks_df = track_single_particle( - madx, initial_coordinates=(starting_x, 0, 0, 0, 0, 0), nturns=n_turns - ) + tracks_df = track_single_particle(madx, initial_coordinates=(starting_x, 0, 0, 0, 0, 0), nturns=n_turns) x_coords_sext.append(tracks_df["observation_point_1"].x.to_numpy()) y_coords_sext.append(tracks_df["observation_point_1"].y.to_numpy()) px_coords_sext.append(tracks_df["observation_point_1"].px.to_numpy()) @@ -138,9 +134,7 @@ # Plotting the new phase space, we can clearly see the resonance's islands! fig, ax = plt.subplots(figsize=(10, 10)) -plot_courant_snyder_phase_space_colored( - madx, x_coords_sext, px_coords_sext, plane="Horizontal" -) +plot_courant_snyder_phase_space_colored(madx, x_coords_sext, px_coords_sext, plane="Horizontal") ax.set_xlim(-15e-3, 15e-3) ax.set_ylim(-15e-3, 15e-3) plt.show() @@ -157,7 +151,7 @@ # The use of the following functions, methods, classes and modules is shown # in this example: # -# - `~.cpymadtools.generators`: `~.generators.LatticeGenerator` +# - `~.cpymadtools._generators`: `~._generators.LatticeGenerator` # - `~.cpymadtools.matching`: `~.matching.match_tunes_and_chromaticities` # - `~.plotting.phasespace`: `~.plotting.phasespace.plot_courant_snyder_phase_space`, `~.plotting.phasespace.plot_courant_snyder_phase_space_colored` # - `~.cpymadtools.track`: `~.track.track_single_particle` diff --git a/examples/demo_sbs_plotting.py b/examples/demo_sbs_plotting.py index 464e7dc1..aaefbb50 100644 --- a/examples/demo_sbs_plotting.py +++ b/examples/demo_sbs_plotting.py @@ -17,7 +17,7 @@ from pyhdtoolkit.plotting.styles import _SPHINX_GALLERY_PARAMS from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial plt.rcParams.update({"text.usetex": True, "legend.fontsize": 16}) # for these specific plots diff --git a/examples/demo_stats_fitting.py b/examples/demo_stats_fitting.py index 0eb66f82..bddee0a9 100755 --- a/examples/demo_stats_fitting.py +++ b/examples/demo_stats_fitting.py @@ -27,7 +27,7 @@ from pyhdtoolkit.plotting.utils import set_arrow_label from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial ############################################################################### @@ -173,11 +173,7 @@ def chi_dist(num: int, meas_used: int) -> np.ndarray: legend=True, ax=ax, ) -param_names = ( - (best_fit_func.shapes + ", loc, scale").split(", ") - if best_fit_func.shapes - else ["loc", "scale"] -) +param_names = (best_fit_func.shapes + ", loc, scale").split(", ") if best_fit_func.shapes else ["loc", "scale"] param_str = ", ".join([f"{k}={v:0.2f}" for k, v in zip(param_names, best_fit_params)]) dist_str = f"{fitting.DISTRIBUTIONS[best_fit_func]}({param_str})" @@ -211,11 +207,7 @@ def chi_dist(num: int, meas_used: int) -> np.ndarray: # with ``loc=0`` and ``scale=1``, so we expect here to find a standard deviation of # one. -factor = ( - np.sqrt(2) - * scipy.special.gamma((degrees_of_freedom + 1) / 2) - / scipy.special.gamma(degrees_of_freedom / 2) -) +factor = np.sqrt(2) * scipy.special.gamma((degrees_of_freedom + 1) / 2) / scipy.special.gamma(degrees_of_freedom / 2) determined_stdev = chi_data.mean() / factor assert np.isclose(determined_stdev, 1, rtol=1e-2) # nice tolerance here too diff --git a/examples/demo_track_spectra.py b/examples/demo_track_spectra.py index 702dd9d7..a2df4166 100755 --- a/examples/demo_track_spectra.py +++ b/examples/demo_track_spectra.py @@ -22,7 +22,7 @@ from pyhdtoolkit.plotting.styles import _SPHINX_GALLERY_PARAMS from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial ############################################################################### @@ -156,5 +156,5 @@ # The use of the following functions, methods, classes and modules is shown # in this example: # -# - `~.cpymadtools.lhc`: `~.lhc.make_lhc_beams`, `~.lhc.re_cycle_sequence` +# - `~.cpymadtools.lhc`: `~.lhc._setup.make_lhc_beams`, `~.lhc._setup.re_cycle_sequence` # - `~.cpymadtools.track`: `~.track.track_single_particle` diff --git a/examples/demo_tune_diagram.py b/examples/demo_tune_diagram.py index fa867f92..77d2b770 100755 --- a/examples/demo_tune_diagram.py +++ b/examples/demo_tune_diagram.py @@ -16,7 +16,7 @@ from pyhdtoolkit.plotting.tune import plot_tune_diagram from pyhdtoolkit.utils import logging -logging.config_logger(level="warning") +logging.config_logger(level="error") plt.rcParams.update(_SPHINX_GALLERY_PARAMS) # for readability of this tutorial ############################################################################### diff --git a/pyhdtoolkit/cpymadtools/__init__.py b/pyhdtoolkit/cpymadtools/__init__.py index 63927082..ff6523bb 100644 --- a/pyhdtoolkit/cpymadtools/__init__.py +++ b/pyhdtoolkit/cpymadtools/__init__.py @@ -1,33 +1,3 @@ -from . import ( - constants, - correctors, - coupling, - errors, - generators, - lhc, - matching, - orbit, - parameters, - ptc, - track, - tune, - twiss, - utils, -) +from . import constants, coupling, lhc, matching, ptc, track, tune, twiss, utils -__all__ = [ - constants, - correctors, - coupling, - errors, - generators, - lhc, - matching, - orbit, - parameters, - ptc, - track, - tune, - twiss, - utils, -] +__all__ = [constants, coupling, lhc, matching, ptc, track, tune, twiss, utils] diff --git a/pyhdtoolkit/cpymadtools/generators.py b/pyhdtoolkit/cpymadtools/_generators.py similarity index 100% rename from pyhdtoolkit/cpymadtools/generators.py rename to pyhdtoolkit/cpymadtools/_generators.py diff --git a/pyhdtoolkit/cpymadtools/constants.py b/pyhdtoolkit/cpymadtools/constants.py index f2d25958..924040b9 100644 --- a/pyhdtoolkit/cpymadtools/constants.py +++ b/pyhdtoolkit/cpymadtools/constants.py @@ -21,6 +21,7 @@ # MQX + maybe F (1/3 in HLLHC) + A (1/3) or B (2) + . + maybe A or B (2) + triplet number (1/2/3) + side (R/L) + IP number (1/2/5/8) LHC_TRIPLETS_REGEX = "^MQXF?[AB].[AB]?[123][RL][1258]" +# This might not be accurate anymore LHC_CROSSING_SCHEMES: Dict[str, Dict[str, float]] = { "flat": {}, "lhc_inj": { @@ -154,34 +155,34 @@ "MQSX1": 0.600 / 0.050, # 0.6 T.m @ 50 mm in IR1&IR5 "MQSX2": 1.360 / 0.017, # 1.36 T @ 17 mm in IR2&IR8 # ------------- # - "MCSX1": 0.050 * 2 / (0.050**2), # 0.050 Tm @ 50 mm in IR1&IR5 - "MCSX2": 0.028 * 2 / (0.017**2), # 0.028 T @ 17 mm in IR2&IR8 + "MCSX1": 0.050 * 2 / (0.050 ** 2), # 0.050 Tm @ 50 mm in IR1&IR5 + "MCSX2": 0.028 * 2 / (0.017 ** 2), # 0.028 T @ 17 mm in IR2&IR8 # ------------- # - "MCSSX1": 0.050 * 2 / (0.050**2), # 0.050 Tm @ 50 mm in IR1&IR5 - "MCSSX2": 0.11 * 2 / (0.017**2), # 0.11 T @ 17 mm in IR2&IR8 + "MCSSX1": 0.050 * 2 / (0.050 ** 2), # 0.050 Tm @ 50 mm in IR1&IR5 + "MCSSX2": 0.11 * 2 / (0.017 ** 2), # 0.11 T @ 17 mm in IR2&IR8 # ------------- # - "MCOX1": 0.030 * 6 / (0.050**3), # 0.030 Tm @ 50 mm in IR1&IR5 - "MCOX2": 0.045 * 6 / (0.017**3), # 0.045 T @ 17 mm in IR2&IR8 + "MCOX1": 0.030 * 6 / (0.050 ** 3), # 0.030 Tm @ 50 mm in IR1&IR5 + "MCOX2": 0.045 * 6 / (0.017 ** 3), # 0.045 T @ 17 mm in IR2&IR8 # ------------- # - "MCOSX1": 0.030 * 6 / (0.050**3), # 0.030 Tm @ 50 mm in IR1&IR5 - "MCOSX2": 0.048 * 6 / (0.017**3), # 0.048 T @ 17 mm in IR2&IR8 + "MCOSX1": 0.030 * 6 / (0.050 ** 3), # 0.030 Tm @ 50 mm in IR1&IR5 + "MCOSX2": 0.048 * 6 / (0.017 ** 3), # 0.048 T @ 17 mm in IR2&IR8 # ------------- # - "MCDX1": 0.030 * 24 / (0.050**4), # 0.030 Tm @ 50 mm in IR1&IR5 + "MCDX1": 0.030 * 24 / (0.050 ** 4), # 0.030 Tm @ 50 mm in IR1&IR5 # ------------- # - "MCDSX1": 0.030 * 24 / (0.050**4), # 0.030 Tm @ 50 mm in IR1&IR5 + "MCDSX1": 0.030 * 24 / (0.050 ** 4), # 0.030 Tm @ 50 mm in IR1&IR5 # ------------- # - "MCTX1": 0.07 * 120 / (0.050**5), # 0.070 Tm @ 50 mm in IR1&IR5 - "MCTX2": 0.01 * 120 / (0.017**5), # 0.010 Tm @ 17 mm in IR1&IR5 + "MCTX1": 0.07 * 120 / (0.050 ** 5), # 0.070 Tm @ 50 mm in IR1&IR5 + "MCTX2": 0.01 * 120 / (0.017 ** 5), # 0.010 Tm @ 17 mm in IR1&IR5 # ------------- # - "MCTSX1": 0.07 * 120 / (0.050**5), # 0.070 Tm @ 50 mm in IR1&IR5 + "MCTSX1": 0.07 * 120 / (0.050 ** 5), # 0.070 Tm @ 50 mm in IR1&IR5 "MQT": 120, # 120 T/m "MQS": 120, # 120 T/m - "MS": 1.280 * 2 / (0.017**2), # 1.28 T @ 17 mm - "MSS": 1.280 * 2 / (0.017**2), # 1.28 T @ 17 mm - "MCS": 0.471 * 2 / (0.017**2), # 0.471 T @ 17 mm - "MCO": 0.040 * 6 / (0.017**3), # 0.04 T @ 17 mm - "MCD": 0.100 * 24 / (0.017**4), # 0.1 T @ 17 mm - "MO": 0.29 * 6 / (0.017**3), # 0.29 T @ 17 mm + "MS": 1.280 * 2 / (0.017 ** 2), # 1.28 T @ 17 mm + "MSS": 1.280 * 2 / (0.017 ** 2), # 1.28 T @ 17 mm + "MCS": 0.471 * 2 / (0.017 ** 2), # 0.471 T @ 17 mm + "MCO": 0.040 * 6 / (0.017 ** 3), # 0.04 T @ 17 mm + "MCD": 0.100 * 24 / (0.017 ** 4), # 0.1 T @ 17 mm + "MO": 0.29 * 6 / (0.017 ** 3), # 0.29 T @ 17 mm } FD_FAMILIES: Set[str] = {"MO", "MS", "MQT"} # Magnets that have F and D families diff --git a/pyhdtoolkit/cpymadtools/correctors.py b/pyhdtoolkit/cpymadtools/correctors.py deleted file mode 100644 index fd624f60..00000000 --- a/pyhdtoolkit/cpymadtools/correctors.py +++ /dev/null @@ -1,162 +0,0 @@ -""" -.. _cpymadtools-correctors: - - -Correctors ----------- - -Module with functions to perform ``MAD-X`` correctors-related operations and manipulations -through a `~cpymad.madx.Madx` object, mainly for LHC and HLLHC machines. -""" -from typing import Dict, List, Sequence - -from cpymad.madx import Madx -from loguru import logger - -from pyhdtoolkit.cpymadtools.constants import ( - LHC_KCD_KNOBS, - LHC_KCO_KNOBS, - LHC_KCOSX_KNOBS, - LHC_KCOX_KNOBS, - LHC_KCS_KNOBS, - LHC_KCSSX_KNOBS, - LHC_KCSX_KNOBS, - LHC_KCTX_KNOBS, - LHC_KO_KNOBS, - LHC_KQS_KNOBS, - LHC_KQSX_KNOBS, - LHC_KQTF_KNOBS, - LHC_KSF_KNOBS, - LHC_KSS_KNOBS, -) - - -def query_triplet_correctors_powering(madx: Madx) -> Dict[str, float]: - """ - .. versionadded:: 0.15.0 - - Queries for the triplet corrector strengths and returns their values as a percentage of - their max powering. This is a port of one of the **corr_value.madx** file's macros. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object with an - active (HL)LHC sequence. - - Returns: - A `dict` with the percentage for each corrector. - - Example: - .. code-block:: python - - >>> triplet_knobs = query_triplet_correctors_powering(madx) - """ - logger.debug("Querying triplets correctors powering") - result: Dict[str, float] = {} - - logger.debug("Querying triplet skew quadrupole correctors (MQSXs) powering") - k_mqsx_max = 1.360 / 0.017 / madx.globals.brho # 1.36 T @ 17mm - result.update({knob: 100 * _knob_value(madx, knob) / k_mqsx_max for knob in LHC_KQSX_KNOBS}) - - logger.debug("Querying triplet sextupole correctors (MCSXs) powering") - k_mcsx_max = 0.028 * 2 / 0.017**2 / madx.globals.brho # 0.028 T @ 17 mm - result.update({knob: 100 * _knob_value(madx, knob) / k_mcsx_max for knob in LHC_KCSX_KNOBS}) - - logger.debug("Querying triplet skew sextupole correctors (MCSSXs) powering") - k_mcssx_max = 0.11 * 2 / 0.017**2 / madx.globals.brho # 0.11 T @ 17 mm - result.update({knob: 100 * _knob_value(madx, knob) / k_mcssx_max for knob in LHC_KCSSX_KNOBS}) - - logger.debug("Querying triplet octupole correctors (MCOXs) powering") - k_mcox_max = 0.045 * 6 / 0.017**3 / madx.globals.brho # 0.045 T @ 17 mm - result.update({knob: 100 * _knob_value(madx, knob) / k_mcox_max for knob in LHC_KCOX_KNOBS}) - - logger.debug("Querying triplet skew octupole correctors (MCOSXs) powering") - k_mcosx_max = 0.048 * 6 / 0.017**3 / madx.globals.brho # 0.048 T @ 17 mm - result.update({knob: 100 * _knob_value(madx, knob) / k_mcosx_max for knob in LHC_KCOSX_KNOBS}) - - logger.debug("Querying triplet decapole correctors (MCTXs) powering") - k_mctx_max = 0.01 * 120 / 0.017**5 / madx.globals.brho # 0.010 T @ 17 mm - result.update({knob: 100 * _knob_value(madx, knob) / k_mctx_max for knob in LHC_KCTX_KNOBS}) - return result - - -def query_arc_correctors_powering(madx: Madx) -> Dict[str, float]: - """ - .. versionadded:: 0.15.0 - - Queries for the arc corrector strengths and returns their values as a percentage of - their max powering. This is a port of one of the **corr_value.madx** file's macros - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object with an - active (HL)LHC sequence. - - Returns: - A `dict` with the percentage for each corrector. - - Example: - .. code-block:: python - - >>> arc_knobs = query_arc_correctors_powering(madx) - """ - logger.debug("Querying triplets correctors powering") - result: Dict[str, float] = {} - - logger.debug("Querying arc tune trim quadrupole correctors (MQTs) powering") - k_mqt_max = 120 / madx.globals.brho # 120 T/m - result.update({knob: 100 * _knob_value(madx, knob) / k_mqt_max for knob in LHC_KQTF_KNOBS}) - - logger.debug("Querying arc short straight sections skew quadrupole correctors (MQSs) powering") - k_mqs_max = 120 / madx.globals.brho # 120 T/m - result.update({knob: 100 * _knob_value(madx, knob) / k_mqs_max for knob in LHC_KQS_KNOBS}) - - logger.debug("Querying arc sextupole correctors (MSs) powering") - k_ms_max = 1.280 * 2 / 0.017**2 / madx.globals.brho # 1.28 T @ 17 mm - result.update({knob: 100 * _knob_value(madx, knob) / k_ms_max for knob in LHC_KSF_KNOBS}) - - logger.debug("Querying arc skew sextupole correctors (MSSs) powering") - k_mss_max = 1.280 * 2 / 0.017**2 / madx.globals.brho # 1.28 T @ 17 mm - result.update({knob: 100 * _knob_value(madx, knob) / k_mss_max for knob in LHC_KSS_KNOBS}) - - logger.debug("Querying arc spool piece (skew) sextupole correctors (MCSs) powering") - k_mcs_max = 0.471 * 2 / 0.017**2 / madx.globals.brho # 0.471 T @ 17 mm - result.update({knob: 100 * _knob_value(madx, knob) / k_mcs_max for knob in LHC_KCS_KNOBS}) - - logger.debug("Querying arc spool piece (skew) octupole correctors (MCOs) powering") - k_mco_max = 0.040 * 6 / 0.017**3 / madx.globals.brho # 0.04 T @ 17 mm - result.update({knob: 100 * _knob_value(madx, knob) / k_mco_max for knob in LHC_KCO_KNOBS}) - - logger.debug("Querying arc spool piece (skew) decapole correctors (MCDs) powering") - k_mcd_max = 0.100 * 24 / 0.017**4 / madx.globals.brho # 0.1 T @ 17 mm - result.update({knob: 100 * _knob_value(madx, knob) / k_mcd_max for knob in LHC_KCD_KNOBS}) - - logger.debug("Querying arc short straight sections octupole correctors (MOs) powering") - k_mo_max = 0.29 * 6 / 0.017**3 / madx.globals.brho # 0.29 T @ 17 mm - result.update({knob: 100 * _knob_value(madx, knob) / k_mo_max for knob in LHC_KO_KNOBS}) - return result - - -# ----- Helpers ----- # - - -def _knob_value(madx: Madx, knob: str) -> float: - """ - Queryies the current value of a given *knob* name in the ``MAD-X`` process, and defaults - to 0 (as ``MAD-X`` does) in case that knob has not been defined in the current process. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - knob (str): the name the knob. - - Returns: - The knob value if it was defined, otherwise 0. - - Example: - .. code-block:: python - - >>> _knob_value(madx, knob="underfined_for_sure") - 0 - """ - try: - return madx.globals[knob] - except KeyError: # cpymad gives a 'Variable not defined: var_name' - return 0 diff --git a/pyhdtoolkit/cpymadtools/lhc.py b/pyhdtoolkit/cpymadtools/lhc.py deleted file mode 100644 index 02fd313b..00000000 --- a/pyhdtoolkit/cpymadtools/lhc.py +++ /dev/null @@ -1,1200 +0,0 @@ -""" -.. _cpymadtools-lhc: - -LHC-Specific Utilities ----------------------- - -Module with functions to perform ``MAD-X`` actions through a `~cpymad.madx.Madx` object, -that are specific to LHC and HLLHC machines. -""" -from typing import Dict, List, Sequence, Tuple, Union - -import numpy as np -import tfs - -from cpymad.madx import Madx -from loguru import logger -from optics_functions.coupling import coupling_via_cmatrix - -from pyhdtoolkit.cpymadtools import twiss -from pyhdtoolkit.cpymadtools.constants import ( - LHC_ANGLE_FLAGS, - LHC_CROSSING_ANGLE_FLAGS, - LHC_EXPERIMENT_STATE_FLAGS, - LHC_IP2_SPECIAL_FLAG, - LHC_IP_OFFSET_FLAGS, - LHC_PARALLEL_SEPARATION_FLAGS, - MONITOR_TWISS_COLUMNS, -) -from pyhdtoolkit.cpymadtools.utils import _get_k_strings -from pyhdtoolkit.optics.ripken import _add_beam_size_to_df - -# ----- Setup Utlites ----- # - - -def make_lhc_beams( - madx: Madx, - energy: float = 7000, - emittance_x: float = 3.75e-6, - emittance_y: float = 3.75e-6, - b4: bool = False, - **kwargs, -) -> None: - """ - .. versionadded:: 0.15.0 - - Defines beams with default configuratons for ``LHCB1`` and ``LHCB2`` sequences. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - energy (float): beam energy, in [GeV]. Defaults to 6500. - emittance_x (float): horizontal emittance in [m]. Will be used to calculate - geometric emittance which is then fed to the ``BEAM`` command. - emittance_y (float): vertical emittance in [m]. Will be used to calculate - geometric emittance which is then fed to the ``BEAM`` command. - b4 (bool): if `True`, will consider one is using ``lhb4`` to do tracking on beam 2, - and will properly set the ``bv`` flag to 1. Defaults to `False`. - **kwargs: Any keyword argument that can be given to the ``MAD-X`` ``BEAM`` command. - - Examples: - - .. code-block:: python - - >>> make_lhc_beams(madx, energy=6800, emittance_x=2.5e-6, emittance_y=3e-6) - - Setting up in a way compatible for tracking of beam 2 (needs to call ``lhcb4`` and set - ``bv`` to 1): - - .. code-block:: python - - >>> make_lhc_beams(madx, energy=6800, emittance_x=2.5e-6, emittance_y=3e-6, b4=True) - """ - logger.debug("Making default beams for 'lhcb1' and 'lhbc2' sequences") - madx.globals["NRJ"] = energy - madx.globals["brho"] = energy * 1e9 / madx.globals.clight - geometric_emit_x = madx.globals["geometric_emit_x"] = emittance_x / (energy / 0.938) - geometric_emit_y = madx.globals["geometric_emit_y"] = emittance_y / (energy / 0.938) - - for beam in (1, 2): - bv = 1 if beam == 1 or b4 is True else -1 - logger.trace(f"Defining beam for sequence 'lhcb{beam:d}'") - madx.command.beam( - sequence=f"lhcb{beam:d}", - particle="proton", - bv=bv, - energy=energy, - npart=1.15e11, - ex=geometric_emit_x, - ey=geometric_emit_y, - sige=4.5e-4, - **kwargs, - ) - - -def make_lhc_thin(madx: Madx, sequence: str, slicefactor: int = 1, **kwargs) -> None: - """ - .. versionadded:: 0.15.0 - - Executes the ``MAKETHIN`` command for the LHC sequence as previously done in ``MAD-X`` macros. - This will use the ``teapot`` style and will enforce ``makedipedge``. - - One can find an exemple use of this function in the :ref:`AC Dipole Tracking ` - and :ref:`Free Tracking ` example galleries. - - Args: - madx (cpymad.madx.Madx): an instantiated `~cpymad.madx.Madx` object. - sequence (str): the sequence to use for the ``MAKETHIN`` command. - slicefactor (int): the slice factor to apply in ``MAKETHIN``, which is a factor - applied to default values for different elements, as did the old macro. Defaults - to 1. - **kwargs: any keyword argument will be transmitted to the ``MAD-X`` ``MAKETHN`` - command, namely ``style`` (will default to ``teapot``) and the ``makedipedge`` - flag (will default to `True`). - - Example: - .. code-block:: python - - >>> make_lhc_thin(madx, sequence="lhcb1", slicefactor=4) - """ - logger.debug(f"Slicing sequence '{sequence}'") - madx.select(flag="makethin", clear=True) - four_slices_patterns = [r"mbx\.", r"mbrb\.", r"mbrc\.", r"mbrs\."] - four_slicefactor_patterns = [ - r"mqwa\.", - r"mqwb\.", - r"mqy\.", - r"mqm\.", - r"mqmc\.", - r"mqml\.", - r"mqtlh\.", - r"mqtli\.", - r"mqt\.", - ] - - logger.trace("Defining slices for general MB and MQ elements") - madx.select(flag="makethin", class_="MB", slice_=2) - madx.select(flag="makethin", class_="MQ", slice_=2 * slicefactor) - - logger.trace("Defining slices for triplets") - madx.select(flag="makethin", class_="mqxa", slice_=16 * slicefactor) - madx.select(flag="makethin", class_="mqxb", slice_=16 * slicefactor) - - logger.trace("Defining slices for various specifc mb elements") - for pattern in four_slices_patterns: - madx.select(flag="makethin", pattern=pattern, slice_=4) - - logger.trace("Defining slices for varous specifc mq elements") - for pattern in four_slicefactor_patterns: - madx.select(flag="makethin", pattern=pattern, slice_=4 * slicefactor) - - madx.use(sequence=sequence) - style = kwargs.get("style", "teapot") - makedipedge = kwargs.get("makedipedge", False) # defaults to False to compensate default TEAPOT style - madx.command.makethin(sequence=sequence, style=style, makedipedge=makedipedge) - - -def re_cycle_sequence(madx: Madx, sequence: str = "lhcb1", start: str = "IP3") -> None: - """ - .. versionadded:: 0.15.0 - - Re-cycles the provided *sequence* from a different starting point, given as *start*. - - One can find an exemple use of this function in the :ref:`AC Dipole Tracking ` - and :ref:`Free Tracking ` example galleries. - - Args: - madx (cpymad.madx.Madx): an instantiated `~cpymad.madx.Madx` object. - sequence (str): the sequence to re-cycle. - start (str): element to start the new cycle from. - - Example: - .. code-block:: python - - >>> lhc.re_cycle_sequence(madx, sequence="lhcb1", start="MSIA.EXIT.B1") - """ - logger.debug(f"Re-cycling sequence '{sequence}' from {start}") - madx.command.seqedit(sequence=sequence) - madx.command.flatten() - madx.command.cycle(start=start) - madx.command.endedit() - - -# ----- Magnets Powering ----- # - - -def apply_lhc_colinearity_knob(madx: Madx, colinearity_knob_value: float = 0, ir: int = None) -> None: - """ - .. versionadded:: 0.15.0 - - Applies the a trim of the LHC colinearity knob. - - .. note:: - If you don't know what this is, you really should not be using this function. - - .. tip:: - The convention, which is also the one I implemented in ``LSA`` for the ``LHC``, is that a - positive value of the colinearity knob results in a powering increase of the ``MQSX`` *right* - of the IP, and a powering decrease of the ``MQSX`` *left* of the IP. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - colinearity_knob_value (float): Units of the colinearity knob to apply. Defaults to 0 so users - don't mess up local IR coupling by mistake. This should be a positive integer, normally between 1 - and 10. - ir (int): The Interaction Region to apply the knob to, should be one of [1, 2, 5, 8]. - Classically 1 or 5. - - Example: - .. code-block:: python - - >>> apply_lhc_colinearity_knob(madx, colinearity_knob_value=5, ir=1) - """ - logger.debug(f"Applying Colinearity knob with a unit setting of {colinearity_knob_value}") - logger.warning("You should re-match tunes & chromaticities after this colinearity knob is applied") - knob_variables = (f"KQSX3.R{ir:d}", f"KQSX3.L{ir:d}") # MQSX IP coupling correctors powering - right_knob, left_knob = knob_variables - - madx.globals[right_knob] = colinearity_knob_value * 1e-4 - logger.trace(f"Set '{right_knob}' to {madx.globals[right_knob]}") - madx.globals[left_knob] = -1 * colinearity_knob_value * 1e-4 - logger.trace(f"Set '{left_knob}' to {madx.globals[left_knob]}") - - -def apply_lhc_colinearity_knob_delta(madx: Madx, colinearity_knob_delta: float = 0, ir: int = None) -> None: - """ - .. versionadded:: 0.21.0 - - This is essentially the same as `.apply_lhc_colinearity_knob`, but instead of a applying fixed powering - value, it applies a delta to the (potentially) existing value. - - .. note:: - If you don't know what this is, you really should not be using this function. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - colinearity_knob_delta (float): Units of the colinearity knob to vary the existing powerings with. - Defaults to 0. - ir (int): The Interaction Region to apply the knob to, should be one of [1, 2, 5, 8]. - Classically 1 or 5. - - Example: - .. code-block:: python - - >>> apply_lhc_colinearity_knob_delta(madx, colinearity_knob_delta=3.5, ir=1) - """ - logger.debug(f"Applying Colinearity knob delta of {colinearity_knob_delta}") - logger.warning("You should re-match tunes & chromaticities after this delta is applied") - knob_variables = (f"KQSX3.R{ir:d}", f"KQSX3.L{ir:d}") # MQSX IP coupling correctors powering - right_knob, left_knob = knob_variables - - logger.debug("Query current knob values") - current_right = madx.eval(right_knob) # ugly, but avoids KeyError if not defined yet - current_left = madx.eval(left_knob) # augly, but avoids KeyError if not defined yet - logger.trace(f"Current right knob value is {current_right}") - logger.trace(f"Current left knob value is {current_left}") - - madx.globals[right_knob] = current_right + colinearity_knob_delta * 1e-4 - logger.trace(f"Set '{right_knob}' to {madx.globals[right_knob]}") - madx.globals[left_knob] = current_left - colinearity_knob_delta * 1e-4 - logger.trace(f"Set '{left_knob}' to {madx.globals[left_knob]}") - - -def apply_lhc_rigidity_waist_shift_knob( - madx: Madx, rigidty_waist_shift_value: float = 0, ir: int = None, side: str = "left" -) -> None: - """ - .. versionadded:: 0.15.0 - - Applies a trim of the LHC rigidity waist shift knob, moving the waist left or right of IP. - The waist shift is achieved by moving all four betatron waists simltaneously: unbalancing - the triplet powering knobs of the left and right-hand sides of the IP. - - .. note:: - If you don't know what this is, you really should not be using this function. - - .. warning:: - Applying the shift will modify your tunes and is likely to flip them, making a subsequent matching - impossible if your lattice has coupling. To avoid this, one should match to tunes split further apart - before applying the waist shift knob, and then match to the desired working point. For instance for - the LHC, matching to (62.27, 60.36) before applying and afterwards rematching to (62.31, 60.32) usually - works well. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - rigidty_waist_shift_value (float): Units of the rigidity waist shift knob (positive values only). - ir (int): The Interaction Region to apply the knob to, should be one of [1, 2, 5, 8]. - Classically 1 or 5. - side (str): Which side of the IP to move the waist to, determines a sign in the calculation. - Defaults to `left`, which means :math:`s_{\\mathrm{waist}} \\lt s_{\\mathrm{ip}}` (and - setting it to `right` would move the waist such that - :math:`s_{\\mathrm{waist}} \\gt s_{\\mathrm{ip}}`). - - Example: - .. code-block:: python - - >>> matching.match_tunes_and_chromaticities(madx, "lhc", "lhcb1", 62.27, 60.36) - >>> apply_lhc_rigidity_waist_shift_knob(madx, rigidty_waist_shift_value=1.5, ir=5) - >>> matching.match_tunes_and_chromaticities(madx, "lhc", "lhcb1", 62.31, 60.32) - """ - logger.debug(f"Applying Rigidity Waist Shift knob with a unit setting of {rigidty_waist_shift_value}") - logger.warning("You should re-match tunes & chromaticities after this rigid waist shift knob is applied") - right_knob, left_knob = f"kqx.r{ir:d}", f"kqx.l{ir:d}" # IP triplet default knob (no trims) - - current_right_knob = madx.globals[right_knob] - current_left_knob = madx.globals[left_knob] - - if side.lower() == "left": - madx.globals[right_knob] = (1 - rigidty_waist_shift_value * 0.005) * current_right_knob - madx.globals[left_knob] = (1 + rigidty_waist_shift_value * 0.005) * current_left_knob - elif side.lower() == "right": - madx.globals[right_knob] = (1 + rigidty_waist_shift_value * 0.005) * current_right_knob - madx.globals[left_knob] = (1 - rigidty_waist_shift_value * 0.005) * current_left_knob - else: - logger.error(f"Given side '{side}' invalid, only 'left' and 'right' are accepted values.") - raise ValueError("Invalid value for parameter 'side'.") - - logger.trace(f"Set '{right_knob}' to {madx.globals[right_knob]}") - logger.trace(f"Set '{left_knob}' to {madx.globals[left_knob]}") - - -def apply_lhc_coupling_knob( - madx: Madx, coupling_knob: float = 0, beam: int = 1, telescopic_squeeze: bool = True -) -> None: - """ - .. versionadded:: 0.15.0 - - Applies a trim of the LHC coupling knob to reach the desired :math:`|C^{-}|` value. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - coupling_knob (float): Desired value for the Cminus, typically a few units of ``1E-3``. - Defaults to 0 so users don't mess up coupling by mistake. - beam (int): beam to apply the knob to. Defaults to beam 1. - telescopic_squeeze (bool): if set to `True`, uses the knobs for Telescopic Squeeze configuration. - Defaults to `True` since `v0.9.0`. - - Example: - .. code-block:: python - - >>> apply_lhc_coupling_knob(madx, coupling_knob=5e-4, beam=1) - """ - # NOTE: for maintainers, no `_op` suffix on ATS coupling knobs, only `_sq` even in Run 3 - logger.debug("Applying coupling knob") - logger.warning("You should re-match tunes & chromaticities after this coupling knob is applied") - suffix = "_sq" if telescopic_squeeze else "" - # NOTE: Only using this knob will give a dqmin very close to coupling_knob - # If one wants to also assign f"CMIS.b{beam:d}{suffix}" the dqmin will be > coupling_knob - knob_name = f"CMRS.b{beam:d}{suffix}" - - logger.trace(f"Knob '{knob_name}' is {madx.globals[knob_name]} before implementation") - madx.globals[knob_name] = coupling_knob - logger.trace(f"Set '{knob_name}' to {madx.globals[knob_name]}") - - -def carry_colinearity_knob_over(madx: Madx, ir: int, to_left: bool = True) -> None: - """ - .. versionadded:: 0.20.0 - - Removes the powering setting on one side of the colinearty knob and applies it to the - other side. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - ir (int): The Interaction Region around which to apply the change, should be - one of [1, 2, 5, 8]. - to_left (bool): If `True`, the magnet right of IP is de-powered of and its powering - is transferred to the magnet left of IP. If `False`, then the opposite happens. - Defaults to `True`. - - Example: - .. code-block:: python - - >>> carry_colinearity_knob_over(madx, ir=5, to_left=True) - """ - side = "left" if to_left else "right" - logger.debug(f"Carrying colinearity knob powering around IP{ir:d} over to the {side} side") - - left_variable, right_variable = f"kqsx3.l{ir:d}", f"kqsx3.r{ir:d}" - left_powering, right_powering = madx.globals[left_variable], madx.globals[right_variable] - logger.trace(f"Current powering values are: '{left_variable}'={left_powering} | '{right_variable}'={left_powering}") - - new_left = left_powering + right_powering if to_left else 0 - new_right = 0 if to_left else left_powering + right_powering - logger.trace(f"New powering values are: '{left_variable}'={new_left} | '{right_variable}'={new_right}") - madx.globals[left_variable] = new_left - madx.globals[right_variable] = new_right - logger.trace("New powerings applied") - - -def power_landau_octupoles(madx: Madx, beam: int, mo_current: float, defective_arc: bool = False) -> None: - """ - .. versionadded:: 0.15.0 - - Powers the Landau octupoles in the (HL)LHC. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - beam (int): beam to use. - mo_current (float): `MO` powering, in [A]. - defective_arc: If set to `True`, the ``KOD`` in Arc 56 are powered for less ``Imax``. - - Example: - .. code-block:: python - - >>> power_landau_octupoles(madx, beam=1, mo_current=350, defect_arc=True) - """ - try: - brho = madx.globals.nrj * 1e9 / madx.globals.clight # clight is MAD-X constant - except AttributeError as madx_error: - logger.exception("The global MAD-X variable 'NRJ' should have been set in the optics files but is not defined.") - raise EnvironmentError("No 'NRJ' variable found in scripts") from madx_error - - logger.debug(f"Powering Landau Octupoles, beam {beam} @ {madx.globals.nrj} GeV with {mo_current} A.") - strength = mo_current / madx.globals.Imax_MO * madx.globals.Kmax_MO / brho - beam = 2 if beam == 4 else beam - - for arc in _all_lhc_arcs(beam): - for fd in "FD": - octupole = f"KO{fd}.{arc}" - logger.trace(f"Powering element '{octupole}' at {strength} Amps") - madx.globals[octupole] = strength - - if defective_arc and (beam == 1): - madx.globals["KOD.A56B1"] = strength * 4.65 / 6 # defective MO group - - -def deactivate_lhc_arc_sextupoles(madx: Madx, beam: int) -> None: - """ - .. versionadded:: 0.15.0 - - Deactivates all arc sextupoles in the (HL)LHC. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - beam (int): beam to use. - - Example: - .. code-block:: python - - >>> deactivate_lhc_arc_sextupoles(madx, beam=1) - """ - # KSF1 and KSD2 - Strong sextupoles of sectors 81/12/45/56 - # KSF2 and KSD1 - Weak sextupoles of sectors 81/12/45/56 - # Rest: Weak sextupoles in sectors 78/23/34/67 - logger.debug(f"Deactivating all arc sextupoles for beam {beam}.") - beam = 2 if beam == 4 else beam - - for arc in _all_lhc_arcs(beam): - for fd in "FD": - for i in (1, 2): - sextupole = f"KS{fd}{i:d}.{arc}" - logger.trace(f"De-powering element '{sextupole}'") - madx.globals[sextupole] = 0.0 - - -def vary_independent_ir_quadrupoles( - madx: Madx, quad_numbers: Sequence[int], ip: int, sides: Sequence[str] = ("r", "l"), beam: int = 1 -) -> None: - """ - .. versionadded:: 0.15.0 - - Sends the ``VARY`` commands for the desired quadrupoles in the IR surrounding the provided *ip*. - The independent quadrupoles for which this is implemented are Q4 to Q13 included. This is useful - to setup some specific matching involving these elements. - - .. important:: - It is necessary to have defined a ``brho`` variable when creating your beams. If one has used - `make_lhc_beams` to create the beams, this has already been done automatically. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - quad_numbers (Sequence[int]): quadrupoles to be varied, by number (aka position from IP). - ip (int): the IP around which to apply the instructions. - sides (Sequence[str]): the sides of IP to act on. Should be `R` for right and `L` for left, - accepts these letters case-insensitively. Defaults to both sides of the IP. - beam (int): the beam for which to apply the instructions. Defaults to 1. - - Example: - .. code-block:: python - - >>> vary_independent_ir_quadrupoles( - ... madx, quad_numbers=[10, 11, 12, 13], ip=1, sides=("r", "l") - ... ) - """ - if ( - ip not in (1, 2, 5, 8) - or any(side.upper() not in ("R", "L") for side in sides) - or any(quad not in (4, 5, 6, 7, 8, 9, 10, 11, 12, 13) for quad in quad_numbers) - ): - logger.error("Either the IP number of the side provided are invalid, not applying any error.") - raise ValueError("Invalid 'quad_numbers', 'ip', 'sides' argument") - - logger.debug(f"Preparing a knob involving quadrupoles {quad_numbers}") - # Each quad has a specific power circuit used for their k1 boundaries - power_circuits: Dict[int, str] = { - 4: "mqy", - 5: "mqml", - 6: "mqml", - 7: "mqm", - 8: "mqml", - 9: "mqm", - 10: "mqml", - 11: "mqtli", - 12: "mqt", - 13: "mqt", - } - for quad in quad_numbers: - circuit = power_circuits[quad] - for side in sides: - logger.trace(f"Sending vary command for Q{quad}{side.upper()}{ip}") - madx.command.vary( - name=f"kq{'t' if quad >= 11 else ''}{'l' if quad == 11 else ''}{quad}.{side}{ip}b{beam}", - step=1e-7, - lower=f"-{circuit}.{'b' if quad == 7 else ''}{quad}{side}{ip}.b{beam}->kmax/brho", - upper=f"+{circuit}.{'b' if quad == 7 else ''}{quad}{side}{ip}.b{beam}->kmax/brho", - ) - - -# ----- Useful Routines ----- # - - -def do_kmodulation( - madx: Madx, ir: int = 1, side: str = "right", steps: int = 100, stepsize: float = 3e-8 -) -> tfs.TfsDataFrame: - r""" - .. versionadded:: 0.20.0 - - Simulates a K-Modulation measurement by varying the powering of Q1 left or - right of the IP, and returning the tune variations resulting from this - modulation. - - .. note:: - At the end of the simulation, the powering of the quadrupole is reset - to the value it had at the time of function call. - - .. tip:: - From these, one can then calculate the :math:`\beta`-functions at the Q1 - and then at the IP, plus the possible waist shift, according to - :cite:t:`Carlier:AccuracyFeasibilityMeasurement2017`. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - ir (int): the IR in which to perform the modulation. Defaults to 1. - side (str): which side of the IP to use the Q1 to perform the modulation. - Should be either ``right`` or ``left``, case-insensitive. Defaults to - ``right``. - steps (int): the number of steps to perform in the modulations, aka the number - of "measurements". Defaults to 100. - stepsize (float): the increment in powering for Q1, in direct values of the - powering variable used in ``MAD-X``. Defaults to 3e-8. - - Returns: - A `~tfs.TfsDataFrame` containing the tune values at each powering step. - - Example: - - .. code-block:: python - - >>> tune_results = do_kmodulation(madx, ir=1, side="right", steps=100, stepsize=3e-8) - """ - element = f"MQXA.1R{ir:d}" if side.lower() == "right" else f"MQXA.1L{ir:d}" - powering_variable = f"KTQX1.R{ir:d}" if side.lower() == "right" else f"KTQX1.L{ir:d}" - - logger.debug(f"Saving current magnet powering for '{element}'") - old_powering = madx.globals[powering_variable] - minval = old_powering - steps / 2 * stepsize - maxval = old_powering + steps / 2 * stepsize - k_powerings = np.linspace(minval, maxval, steps + 1) - results = tfs.TfsDataFrame( - index=k_powerings, - columns=["K", "TUNEX", "ERRTUNEX", "TUNEY", "ERRTUNEY"], - headers={ - "TITLE": "K-Modulation", - "ELEMENT": element, - "VARIABLE": powering_variable, - "STEPS": steps, - "STEP_SIZE": stepsize, - }, - dtype=float, - ) - - logger.debug(f"Modulating quadrupole '{element}'") - for powering in k_powerings: - logger.trace(f"Modulation of '{element}' - Setting '{powering_variable}' to {powering}") - madx.globals[powering_variable] = powering - df = twiss.get_ir_twiss(madx, ir=ir, centre=True, columns=["k1l", "l"]) - results.loc[powering].K = df.loc[element.lower()].k1l / df.loc[element.lower()].l # Store K - results.loc[powering].TUNEX = madx.table.summ.q1[0] # Store Qx - results.loc[powering].TUNEY = madx.table.summ.q2[0] # Store Qy - - logger.debug(f"Resetting '{element}' powering") - madx.globals[powering_variable] = old_powering - - results.index.name = powering_variable - results.ERRTUNEX = 0 # No measurement error from MAD-X - results.ERRTUNEY = 0 # No measurement error from MAD-X - return results - - -def correct_lhc_global_coupling( - madx: Madx, beam: int = 1, telescopic_squeeze: bool = True, calls: int = 100, tolerance: float = 1.0e-21 -) -> None: - """ - .. versionadded:: 0.20.0 - - A littly tricky matching routine to perform a decent global coupling correction using - the ``LHC`` coupling knobs. - - .. important:: - This routine makes use of some matching tricks and uses the ``SUMM`` table's - ``dqmin`` variable for the matching. It should be considered a helpful little - trick, but it is not a perfect solution. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - beam (int): which beam you want to perform the matching for, should be `1` or - `2`. Defaults to `1`. - telescopic_squeeze (bool): If set to `True`, uses the coupling knobs - for Telescopic Squeeze configuration. Defaults to `True`. - calls (int): max number of varying calls to perform when matching. Defaults to 100. - tolerance (float): tolerance for successfull matching. Defaults to :math:`10^{-21}`. - - Example: - .. code-block:: python - - >>> correct_lhc_global_coupling(madx, sequence="lhcb1", telescopic_squeeze=True) - """ - suffix = "_sq" if telescopic_squeeze else "" - sequence = f"lhcb{beam:d}" - logger.debug(f"Attempting to correct global coupling through matching, on sequence '{sequence}'") - - real_knob, imag_knob = f"CMRS.b{beam:d}{suffix}", f"CMIS.b{beam:d}{suffix}" - logger.debug(f"Matching using the coupling knobs '{real_knob}' and '{imag_knob}'") - madx.command.match(chrom=True, sequence=sequence) - madx.command.gweight(dqmin=1, Q1=0) - madx.command.global_(dqmin=0, Q1=62.28) - madx.command.vary(name=real_knob, step=1.0e-8) - madx.command.vary(name=imag_knob, step=1.0e-8) - madx.command.lmdif(calls=calls, tolerance=tolerance) - madx.command.endmatch() - - -# ----- Elements / Markers Installation ----- # - - -def install_ac_dipole_as_kicker( - madx: Madx, - deltaqx: float, - deltaqy: float, - sigma_x: float, - sigma_y: float, - beam: int = 1, - start_turn: int = 100, - ramp_turns: int = 2000, - top_turns: int = 6600, -) -> None: - """ - .. versionadded:: 0.15.0 - - Installs an AC dipole as a kicker element in (HL)LHC beam 1 or 2, for tracking. This function - assumes that you have already defined lhcb1/lhcb2 sequence, made a beam for it (``BEAM`` - command or `~lhc.make_lhc_beams` function), matched to your desired working point and made - a ``TWISS`` call. - - .. important:: - In a real machine, the AC Dipole does impact the orbit as well as the betatron - functions when turned on (:cite:t:`Miyamoto:ACD:2008`, part III). In ``MAD-X`` - however, it cannot be modeled to do both at the same time. This routine introduces - an AC Dipole as a kicker element so that its effect can be seen on particle trajectory - in tracking. It **does not** affect ``TWISS`` functions. - - One can find a full example use of the function for tracking in the - :ref:`AC Dipole Tracking ` example gallery. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - deltaqx (float): the deltaQx (horizontal tune excitation) used by the AC dipole. - deltaqy (float): the deltaQy (vertical tune excitation) used by the AC dipole. - sigma_x (float): the horizontal amplitude to drive the beam to, in bunch sigma. - sigma_y (float): the vertical amplitude to drive the beam to, in bunch sigma. - beam (int): the LHC beam to install the AC Dipole into, either 1 or 2. Defaults to 1. - start_turn (int): the turn at which to start ramping up the AC dipole. Defaults to 100. - ramp_turns (int): the number of turns to use for the ramp-up and the ramp-down of the AC dipole. - This number is important in order to preserve the adiabaticity of the cycle. Defaults to 2000 - as in the LHC. - top_turns (int): the number of turns to drive the beam for. Defaults to 6600 as in the LHC. - - Example: - .. code-block:: python - - >>> lhc.install_ac_dipole_as_kicker( - ... madx, - ... deltaqx=-0.01, # driven horizontal tune to Qxd = 62.31 - 0.01 = 62.30 - ... deltaqy=0.012, # driven vertical tune to Qyd = 60.32 + 0.012 = 60.332 - ... sigma_x=2, # bunch amplitude kick in the horizontal plane - ... sigma_y=2, # bunch amplitude kick in the vertical plane - ... beam=1, # beam for which to install and kick - ... start_turn=100, # when to turn on the AC Dipole - ... ramp_turns=2000, # how many turns to ramp up/down the AC Dipole - ... top_turns=6600, # how many turns to keep the AC Dipole at full kick - ... ) - """ - logger.warning("This AC Dipole is implemented as a kicker and will not affect TWISS functions!") - logger.debug("This routine should be done after 'match', 'twiss' and 'makethin' for the appropriate beam") - - if top_turns > 6600: - logger.warning( - f"Configuring the AC Dipole for {top_turns:d} of driving is fine for MAD-X but is " - "higher than what the device can do in the (HL)LHC! Beware." - ) - ramp1, ramp2 = start_turn, start_turn + ramp_turns - ramp3 = ramp2 + top_turns - ramp4 = ramp3 + ramp_turns - - logger.debug("Retrieving tunes from internal tables") - q1, q2 = madx.table.summ.q1[0], madx.table.summ.q2[0] - logger.trace(f"Retrieved values are q1 = {q1:.5f}, q2 = {q2:.5f}") - q1_dipole, q2_dipole = q1 + deltaqx, q2 + deltaqy - - logger.trace("Querying BETX and BETY at AC Dipole location") - # All below is done as model_creator macros with `.input()` calls - madx.input(f"pbeam = beam%lhcb{beam:d}->pc;") - madx.input(f"betxac = table(twiss, MKQA.6L4.B{beam:d}, BEAM, betx);") - madx.input(f"betyac = table(twiss, MKQA.6L4.B{beam:d}, BEAM, bety);") - - logger.trace("Calculating AC Dipole voltage values") - madx.input(f"voltx = 0.042 * pbeam * ABS({deltaqx}) / SQRT(180.0 * betxac) * {sigma_x}") - madx.input(f"volty = 0.042 * pbeam * ABS({deltaqy}) / SQRT(177.0 * betyac) * {sigma_y}") - - logger.trace("Defining kicker elements for transverse planes") - madx.input( - f"MKACH.6L4.B{beam:d}: hacdipole, l=0, freq:={q1_dipole}, lag=0, volt=voltx, ramp1={ramp1}, " - f"ramp2={ramp2}, ramp3={ramp3}, ramp4={ramp4};" - ) - madx.input( - f"MKACV.6L4.B{beam:d}: vacdipole, l=0, freq:={q2_dipole}, lag=0, volt=volty, ramp1={ramp1}, " - f"ramp2={ramp2}, ramp3={ramp3}, ramp4={ramp4};" - ) - - logger.debug(f"Installing AC Dipole kicker with driven tunes of Qx_D = {q1_dipole:.5f} | Qy_D = {q2_dipole:.5f}") - madx.command.seqedit(sequence=f"lhcb{beam:d}") - madx.command.flatten() - # The kicker version is meant for a thin lattice and is installed a right at MKQA.6L4.B[12] (at=0) - madx.command.install(element=f"MKACH.6L4.B{beam:d}", at=0, from_=f"MKQA.6L4.B{beam:d}") - madx.command.install(element=f"MKACV.6L4.B{beam:d}", at=0, from_=f"MKQA.6L4.B{beam:d}") - madx.command.endedit() - - logger.warning( - f"Sequence LHCB{beam:d} is now re-USEd for changes to take effect. Beware that this will reset it, " - "remove errors etc." - ) - madx.use(sequence=f"lhcb{beam:d}") - - -def install_ac_dipole_as_matrix(madx: Madx, deltaqx: float, deltaqy: float, beam: int = 1) -> None: - """ - .. versionadded:: 0.15.0 - - Installs an AC dipole as a matrix element in (HL)LHC beam 1 or 2, to see its effect on TWISS functions - This function assumes that you have already defined lhcb1/lhcb2 sequence, made a beam for it (``BEAM`` - command or `~lhc.make_lhc_beams` function), matched to your desired working point and made a ``TWISS`` - call. - - This function's use is very similar to that of `~.lhc.install_ac_dipole_as_kicker`. - - .. important:: - In a real machine, the AC Dipole does impact the orbit as well as the betatron - functions when turned on (:cite:t:`Miyamoto:ACD:2008`, part III). In ``MAD-X`` - however, it cannot be modeled to do both at the same time. This routine introduces - an AC Dipole as a matrix element so that its effect can be seen on ``TWISS`` functions. - It **does not** affect tracking. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - deltaqx (float): the deltaQx (horizontal tune excitation) used by the AC dipole. - deltaqy (float): the deltaQy (vertical tune excitation) used by the AC dipole. - beam (int): the LHC beam to install the AC Dipole into, either 1 or 2. Defaults to 1. - - Example: - .. code-block:: python - - >>> install_ac_dipole_as_matrix(madx, deltaqx=-0.01, deltaqy=0.012, beam=1) - """ - logger.warning("This AC Dipole is implemented as a matrix and will not affect particle tracking!") - logger.debug("This routine should be done after 'match', 'twiss' and 'makethin' for the appropriate beam.") - - logger.debug("Retrieving tunes from internal tables") - q1, q2 = madx.table.summ.q1[0], madx.table.summ.q2[0] - logger.trace(f"Retrieved values are q1 = {q1:.5f}, q2 = {q2:.5f}") - q1_dipole, q2_dipole = q1 + deltaqx, q2 + deltaqy - - logger.trace("Querying BETX and BETY at AC Dipole location") - # All below is done as model_creator macros with `.input()` calls - madx.input(f"betxac = table(twiss, MKQA.6L4.B{beam:d}, BEAM, betx);") - madx.input(f"betyac = table(twiss, MKQA.6L4.B{beam:d}, BEAM, bety);") - - logger.trace("Calculating AC Dipole matrix terms") - madx.input(f"hacmap21 = 2 * (cos(2*pi*{q1_dipole}) - cos(2*pi*{q1})) / (betxac * sin(2*pi*{q1}));") - madx.input(f"vacmap43 = 2 * (cos(2*pi*{q2_dipole}) - cos(2*pi*{q2})) / (betyac * sin(2*pi*{q2}));") - - logger.trace("Defining matrix elements for transverse planes") - madx.input(f"hacmap: matrix, l=0, rm21=hacmap21;") - madx.input(f"vacmap: matrix, l=0, rm43=vacmap43;") - - logger.debug(f"Installing AC Dipole matrix with driven tunes of Qx_D = {q1_dipole:.5f} | Qy_D = {q2_dipole:.5f}") - madx.command.seqedit(sequence=f"lhcb{beam:d}") - madx.command.flatten() - # The matrix version is meant for a thick lattice and is installed a little after MKQA.6L4.B[12] - madx.command.install(element="hacmap", at="1.583 / 2", from_=f"MKQA.6L4.B{beam:d}") - madx.command.install(element="vacmap", at="1.583 / 2", from_=f"MKQA.6L4.B{beam:d}") - madx.command.endedit() - - logger.warning( - f"Sequence LHCB{beam:d} is now re-USEd for changes to take effect. Beware that this will reset it, " - "remove errors etc." - ) - madx.use(sequence=f"lhcb{beam:d}") - - -def add_markers_around_lhc_ip(madx: Madx, sequence: str, ip: int, n_markers: int, interval: float) -> None: - """ - .. versionadded:: 1.0.0 - - Adds some simple marker elements left and right of an IP point, to increase the granularity of optics - functions returned from a ``TWISS`` call. - - .. warning:: - You will most likely need to have sliced the sequence before calling this function, - as otherwise there is a risk on getting a negative drift depending on the affected - IP. This would lead to the remote ``MAD-X`` process to crash. - - .. warning:: - After editing the *sequence* to add markers, the ``USE`` command will be run for the changes to apply. - This means the caveats of ``USE`` apply, for instance the erasing of previously defined errors, orbits - corrections etc. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - sequence (str): which sequence to use the routine on. - ip (int): The interaction point around which to add markers. - n_markers (int): how many markers to add on each side of the IP. - interval (float): the distance between markers, in [m]. Giving ``interval=0.05`` will - place a marker every 5cm (starting 5cm away from the IP on each side). - - Example: - .. code-block:: python - - >>> add_markers_around_lhc_ip( - ... madx, sequence=f"lhcb1", ip=1, n_markers=1000, interval=0.001 - ... ) - """ - logger.debug(f"Adding {n_markers:d} markers on each side of IP{ip:d}") - madx.command.seqedit(sequence=sequence) - madx.command.flatten() - for i in range(1, n_markers + 1): - madx.command.install( - element=f"MARKER.LEFT.IP{ip:d}.{i:02d}", class_="MARKER", at=-i * interval, from_=f"IP{ip:d}" - ) - madx.command.install( - element=f"MARKER.RIGHT.IP{ip:d}.{i:02d}", class_="MARKER", at=i * interval, from_=f"IP{ip:d}" - ) - madx.command.flatten() - madx.command.endedit() - logger.warning( - f"Sequence '{sequence}' will be USEd for new markers to be taken in consideration, beware that this will erase errors etc." - ) - madx.use(sequence=sequence) - - -# ----- Output Utilities ----- # - - -def make_sixtrack_output(madx: Madx, energy: int) -> None: - """ - .. versionadded:: 0.15.0 - - Prepare output for a ``SixTrack`` run. Initial implementation credits go to - :user:`Joschua Dilly `. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - energy (float): beam energy, in [GeV]. - - Example: - .. code-block:: python - - >>> make_sixtrack_output(madx, energy=6800) - """ - logger.debug("Preparing outputs for SixTrack") - - logger.debug("Powering RF cavities") - madx.globals["VRF400"] = 8 if energy < 5000 else 16 # is 6 at injection for protons iirc? - madx.globals["LAGRF400.B1"] = 0.5 # cavity phase difference in units of 2pi - madx.globals["LAGRF400.B2"] = 0.0 - - logger.debug("Executing TWISS and SIXTRACK commands") - madx.twiss() # used by sixtrack - madx.sixtrack(cavall=True, radius=0.017) # this value is only ok for HL(LHC) magnet radius - - -# ----- Miscellaneous Utilities ----- # - - -def reset_lhc_bump_flags(madx: Madx) -> None: - """ - .. versionadded:: 0.15.0 - - Resets all LHC IP bump flags to 0. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - - Example: - .. code-block:: python - - >>> reset_lhc_bump_flags(madx) - """ - logger.debug("Resetting all LHC IP bump flags") - ALL_BUMPS = ( - LHC_ANGLE_FLAGS - + LHC_CROSSING_ANGLE_FLAGS - + LHC_EXPERIMENT_STATE_FLAGS - + LHC_IP2_SPECIAL_FLAG - + LHC_IP_OFFSET_FLAGS - + LHC_PARALLEL_SEPARATION_FLAGS - ) - with madx.batch(): - madx.globals.update({bump: 0 for bump in ALL_BUMPS}) - - -def get_lhc_bpms_list(madx: Madx) -> List[str]: - """ - .. versionadded:: 0.16.0 - - Returns the list of monitoring BPMs for the current LHC sequence in use. - The BPMs are queried through a regex in the result of a ``TWISS`` command. - - .. note:: - As this function calls the ``TWISS`` command and requires that ``TWISS`` can - succeed on your sequence. - - Args: - madx (cpymad.madx.Madx): an instantiated cpymad.madx.Madx object. - - Returns: - The `list` of BPM names. - - Example: - .. code-block:: python - - >>> observation_bpms = get_lhc_bpms_list(madx) - """ - twiss_df = twiss.get_twiss_tfs(madx).reset_index() - bpms_df = twiss_df[twiss_df.NAME.str.contains("^bpm.*B[12]$", case=False, regex=True)] - return bpms_df.NAME.tolist() - - -def get_lhc_tune_and_chroma_knobs( - accelerator: str, beam: int = 1, telescopic_squeeze: bool = True, run3: bool = False -) -> Tuple[str, str, str, str]: - """ - .. versionadded:: 0.16.0 - - Gets names of knobs needed to match tunes and chromaticities as a tuple of strings, - for the LHC or HLLHC machines. Initial implementation credits go to - :user:`Joschua Dilly `. - - Args: - accelerator (str): Accelerator either 'LHC' (dQ[xy], dQp[xy] knobs) or 'HLLHC' - (kqt[fd], ks[fd] knobs). - beam (int): Beam to use, for the knob names. Defaults to 1. - telescopic_squeeze (bool): if set to `True`, returns the knobs for Telescopic - Squeeze configuration. Defaults to `True` to reflect run III scenarios. - run3 (bool): if set to `True`, returns the Run 3 `*_op` knobs. Defaults to `False`. - - Returns: - A `tuple` of strings with knobs for ``(qx, qy, dqx, dqy)``. - - Examples: - .. code-block:: python - - >>> get_lhc_tune_and_chroma_knobs("LHC", beam=1, telescopic_squeeze=False) - ('dQx.b1', 'dQy.b1', 'dQpx.b1', 'dQpy.b1') - - .. code-block:: python - - >>> get_lhc_tune_and_chroma_knobs("LHC", beam=2, run3=True) - ('dQx.b2_op', 'dQx.b2_op', 'dQpx.b2_op', 'dQpx.b2_op') - - .. code-block:: python - - >>> get_lhc_tune_and_chroma_knobs("HLLHC", beam=2) - ('kqtf.b2_sq', 'kqtd.b2_sq', 'ksf.b2_sq', 'ksd.b2_sq') - """ - beam = 2 if beam == 4 else beam - if run3: - suffix = "_op" - elif telescopic_squeeze: - suffix = "_sq" - else: - suffix = "" - - if accelerator.upper() not in ("LHC", "HLLHC"): - logger.error("Invalid accelerator name, only 'LHC' and 'HLLHC' implemented") - raise NotImplementedError(f"Accelerator '{accelerator}' not implemented.") - - return { - "LHC": ( - f"dQx.b{beam}{suffix}", - f"dQy.b{beam}{suffix}", - f"dQpx.b{beam}{suffix}", - f"dQpy.b{beam}{suffix}", - ), - "HLLHC": ( - f"kqtf.b{beam}{suffix}", - f"kqtd.b{beam}{suffix}", - f"ksf.b{beam}{suffix}", - f"ksd.b{beam}{suffix}", - ), - }[accelerator.upper()] - - -def get_magnets_powering( - madx: Madx, patterns: Sequence[str] = [r"^mb\.", r"^mq\.", r"^ms\."], brho: Union[str, float] = None, **kwargs -) -> tfs.TfsDataFrame: - r""" - .. versionadded:: 0.17.0 - - Gets the twiss table with additional defined columns for the given *patterns*. - - .. note:: - Here are below certain useful patterns for the ``LHC`` and their meaning: - - * ``^mb\.`` :math:`\rightarrow` main bends. - * ``^mq\.`` :math:`\rightarrow` main quadrupoles. - * ``^ms\.`` :math:`\rightarrow` main sextupoles. - * ``^mb[rswx]`` :math:`\rightarrow` separation dipoles. - * ``^mq[mwxy]`` :math:`\rightarrow` insertion quads. - * ``^mqt.1[23]`` :math:`\rightarrow` short tuning quads (12 & 13). - * ``^mqtl`` :math:`\rightarrow` long tuning quads. - * ``^mcbx`` :math:`\rightarrow` crossing scheme magnets. - * ``^mcb[cy]`` :math:`\rightarrow` crossing scheme magnets. - - To make no selection, one can give ``patterns=[""]`` and this will give back - the results for *all* elements. One can also give a specific magnet's exact - name to include it in the results. - - .. note:: - The ``TWISS`` flag will be fully cleared after running this function. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - patterns (Sequence[str]): a list of regex patterns to define which elements - should be selected and included in the returned table. Defaults to selecting - the main bends, quads and sextupoles. See the note admonition above for - useful patterns to select specific ``LHC`` magnet families. - brho (Union[str, float]): optional, an explicit definition for the magnetic - rigidity in :math:`Tm^{-1}`. If not given, it will be assumed that - a ``brho`` quantity is defined in the ``MAD-X`` globals. - **kwargs: any keyword argument will be passed to `~.twiss.get_pattern_twiss` and - later on to the ``TWISS`` command executed in ``MAD-X``. - - Returns: - A `~tfs.TfsDataFrame` of the ``TWISS`` table, with the relevant newly defined columns - and including the elements matching the regex *patterns* that were provided. - - Example: - .. code-block:: python - - >>> sextupoles_powering = get_magnets_powering(madx, patterns=[r"^ms\."]) - """ - logger.debug("Computing magnets field and powering limits proportions") - NEW_COLNAMES = ["name", "keyword", "ampere", "imax", "percent", "kn", "kmax", "integrated_field", "L"] - NEW_COLNAMES = list(set(NEW_COLNAMES + kwargs.pop("columns", []))) # in case user gives explicit columns - _list_field_currents(madx, brho=brho) - return twiss.get_pattern_twiss(madx, columns=NEW_COLNAMES, patterns=patterns, **kwargs) - - -def get_lhc_bpms_twiss_and_rdts(madx: Madx) -> tfs.TfsDataFrame: - """ - .. versionadded:: 0.19.0 - - Runs a ``TWISS`` on the currently active sequence for all ``LHC`` BPMs. The coupling RDTs - are also computed through a CMatrix approach via `optics_functions.coupling.coupling_via_cmatrix`. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - - Returns: - A `~tfs.frame.TfsDataFrame` of the ``TWISS`` table with basic default columns, as well as one - new column for each of the coupling RDTs. The coupling RDTs are returned as complex numbers. - - Example: - .. code-block:: python - - >>> twiss_with_rdts = get_lhc_bpms_twiss_and_rdts(madx) - """ - twiss_tfs = twiss.get_pattern_twiss( # need chromatic flag as we're dealing with coupling - madx, patterns=["^BPM.*B[12]$"], columns=MONITOR_TWISS_COLUMNS, chrom=True - ) - twiss_tfs.columns = twiss_tfs.columns.str.upper() # optics_functions needs capitalized names - twiss_tfs.NAME = twiss_tfs.NAME.str.upper() - twiss_tfs[["F1001", "F1010"]] = coupling_via_cmatrix(twiss_tfs, output=["rdts"]) - return twiss_tfs - - -def get_sizes_at_ip(madx: Madx, ip: int, geom_emit_x: float = None, geom_emit_y: float = None) -> Tuple[float, float]: - """ - .. versionadded:: 1.0.0 - - Get the Lebedev beam sizes (horizontal and vertical) at the provided LHC *ip*. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - ip (int): the IP to get the sizes at. - geom_emit_x (float): the horizontal geometrical emittance to use for the - calculation. If not provided, will look for the values of the - ``geometric_emit_x`` variable in ``MAD-X``. - geom_emit_y (float): the vertical geometrical emittance to use for the - calculation. If not provided, will look for the values of the - ``geometric_emit_y`` variable in ``MAD-X``. - - Returns: - A tuple of the horizontal and vertical beam sizes at the provided *IP*. - - Example: - .. code-block:: python - - >>> ip5_x, ip5_y = get_size_at_ip(madx, ip=5) - """ - logger.debug(f"Getting horizotnal and vertical sizes at IP{ip:d} through Ripken parameters") - geom_emit_x = geom_emit_x or madx.globals["geometric_emit_x"] - geom_emit_y = geom_emit_y or madx.globals["geometric_emit_y"] - - twiss_tfs = twiss.get_twiss_tfs(madx, chrom=True, ripken=True) - twiss_tfs = _add_beam_size_to_df(twiss_tfs, geom_emit_x, geom_emit_y) - return twiss_tfs.loc[f"IP{ip:d}"].SIZE_X, twiss_tfs.loc[f"IP{ip:d}"].SIZE_Y - - -# ----- Helpers ----- # - - -def _all_lhc_arcs(beam: int) -> List[str]: - """ - Generates and returns the names of all LHC arcs for a given beam. - Initial implementation credits go to :user:`Joschua Dilly `. - - Args: - beam (int): beam to get names for. - - Returns: - The list of names. - """ - return [f"A{i+1}{(i+1)%8+1}B{beam:d}" for i in range(8)] - - -def _list_field_currents(madx: Madx, brho: Union[str, float] = None) -> None: - """ - Creates additional columns for the ``TWISS`` table with the magnets' total fields - and currents, to help later on determine which proportion of their maximum powering - the current setting is using. This is an implementation of the old utility script - located at **/afs/cern.ch/eng/lhc/optics/V6.503/toolkit/list_fields_currents.madx**. - - .. important:: - Certain quantities are assumed to be defined in the ``MAD-X`` globals, such as - ``brho``, or available in the magnets definition, such as ``calib``. For this - reason, this script most likely only works for the ``(HL)LHC`` sequences where - those are defined. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - brho (Union[str, float]): optional, an explicit definition for the magnetic - rigidity in :math:`Tm^{-1}`. If not given, it will be assumed that - a ``brho`` quantity is defined in the ``MAD-X`` globals and this one will - be used. - """ - logger.debug("Creating additional TWISS table columns for magnets' fields and currents") - - if brho is not None: - logger.trace(f"Setting 'brho' to explicitely defined '{brho}'") - madx.globals["brho"] = brho - - # Define strength := table(twiss, k0l) + ... + table(twiss, k5sl) + table(twiss, hkick) + table(twiss, vkick); - madx.globals["strength"] = ( - " + ".join(f"table(twiss, {a.lower()})" for a in _get_k_strings(stop=6)) - + " + table(twiss, hkick) + table(twiss, vkick)" - ) - - # All here are given as strings to make it deferred expressions in MAD-X - madx.globals["epsilon"] = 1e-20 # to avoid divisions by zero - madx.globals["length"] = "table(twiss, l) + table(twiss, lrad) + epsilon" - madx.globals["kmaxx"] = "table(twiss, kmax) + epsilon" - madx.globals["calibration"] = "table(twiss, calib) + epsilon" - madx.globals["kn"] = "abs(strength) / length" - # madx.globals["rho"] = "kn / (kn + epsilon) / (kn + epsilon)" - - madx.globals["field"] = "kn * brho" - madx.globals["percent"] = "field * 100 / (kmaxx + epsilon)" - madx.globals["ampere"] = "field / calibration" - madx.globals["imax"] = "kmaxx / calibration" - madx.globals["integrated_field"] = "field * length" diff --git a/pyhdtoolkit/cpymadtools/lhc/__init__.py b/pyhdtoolkit/cpymadtools/lhc/__init__.py new file mode 100644 index 00000000..6880f968 --- /dev/null +++ b/pyhdtoolkit/cpymadtools/lhc/__init__.py @@ -0,0 +1,69 @@ +""" +.. _cpymadtools-lhc: + +LHC-Specific Utilities +---------------------- + +Module with functions to perform ``MAD-X`` actions through a `~cpymad.madx.Madx` object, +that are specific to LHC and HLLHC machines. + +.. important:: + + The functions documented below are shown as coming from private modules (**_coupling**, + **_misc**, **_setup** etc). They are still all accessible at the `pyhdtoolkit.cpymadtools.lhc` + level, but any user is free to import and use them directly from the private modules if they + wish to do so. In short, the two options below are both valid: + + .. tabbed:: Importing from the lhc module + + .. code-block:: python + + from pyhdtoolkit.cpymadtools.lhc import LHCSetup + # use this now + + .. tabbed:: Importing from the private module + + .. code-block:: python + + from pyhdtoolkit.cpymadtools.lhc._setup import LHCSetup + # use this now +""" +from ._coupling import correct_lhc_global_coupling, get_lhc_bpms_twiss_and_rdts +from ._elements import add_markers_around_lhc_ip, install_ac_dipole_as_kicker, install_ac_dipole_as_matrix +from ._errors import misalign_lhc_ir_quadrupoles, misalign_lhc_triplets +from ._misc import ( + get_lhc_bpms_list, + get_lhc_tune_and_chroma_knobs, + get_sizes_at_ip, + make_sixtrack_output, + reset_lhc_bump_flags, +) +from ._powering import ( + apply_lhc_colinearity_knob, + apply_lhc_colinearity_knob_delta, + apply_lhc_coupling_knob, + apply_lhc_rigidity_waist_shift_knob, + carry_colinearity_knob_over, + deactivate_lhc_arc_sextupoles, + power_landau_octupoles, + switch_magnetic_errors, + vary_independent_ir_quadrupoles, +) +from ._queries import ( + get_current_orbit_setup, + get_magnets_powering, + query_arc_correctors_powering, + query_triplet_correctors_powering, +) +from ._routines import correct_lhc_global_coupling, correct_lhc_orbit, do_kmodulation +from ._setup import ( + LHCSetup, + lhc_orbit_variables, + make_lhc_beams, + make_lhc_thin, + prepare_lhc_run2, + prepare_lhc_run3, + re_cycle_sequence, + setup_lhc_orbit, +) +from ._twiss import get_ips_twiss, get_ir_twiss diff --git a/pyhdtoolkit/cpymadtools/lhc/_coupling.py b/pyhdtoolkit/cpymadtools/lhc/_coupling.py new file mode 100644 index 00000000..135be366 --- /dev/null +++ b/pyhdtoolkit/cpymadtools/lhc/_coupling.py @@ -0,0 +1,86 @@ +""" +.. _lhc-coupling: + +**Coupling Utilities** + +The functions below are betatron coupling utilities for the ``LHC``. +""" +import tfs + +from cpymad.madx import Madx +from loguru import logger +from optics_functions.coupling import coupling_via_cmatrix + +from pyhdtoolkit.cpymadtools import twiss +from pyhdtoolkit.cpymadtools.constants import MONITOR_TWISS_COLUMNS + + +def correct_lhc_global_coupling( + madx: Madx, beam: int = 1, telescopic_squeeze: bool = True, calls: int = 100, tolerance: float = 1.0e-21 +) -> None: + """ + .. versionadded:: 0.20.0 + + A littly tricky matching routine to perform a decent global coupling correction using + the ``LHC`` coupling knobs. + + .. important:: + This routine makes use of some matching tricks and uses the ``SUMM`` table's + ``dqmin`` variable for the matching. It should be considered a helpful little + trick, but it is not a perfect solution. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + beam (int): which beam you want to perform the matching for, should be `1` or + `2`. Defaults to `1`. + telescopic_squeeze (bool): If set to `True`, uses the coupling knobs + for Telescopic Squeeze configuration. Defaults to `True`. + calls (int): max number of varying calls to perform when matching. Defaults to 100. + tolerance (float): tolerance for successfull matching. Defaults to :math:`10^{-21}`. + + Example: + .. code-block:: python + + >>> correct_lhc_global_coupling(madx, sequence="lhcb1", telescopic_squeeze=True) + """ + suffix = "_sq" if telescopic_squeeze else "" + sequence = f"lhcb{beam:d}" + logger.debug(f"Attempting to correct global coupling through matching, on sequence '{sequence}'") + + real_knob, imag_knob = f"CMRS.b{beam:d}{suffix}", f"CMIS.b{beam:d}{suffix}" + logger.debug(f"Matching using the coupling knobs '{real_knob}' and '{imag_knob}'") + madx.command.match(chrom=True, sequence=sequence) + madx.command.gweight(dqmin=1, Q1=0) + madx.command.global_(dqmin=0, Q1=62.28) + madx.command.vary(name=real_knob, step=1.0e-8) + madx.command.vary(name=imag_knob, step=1.0e-8) + madx.command.lmdif(calls=calls, tolerance=tolerance) + madx.command.endmatch() + + +def get_lhc_bpms_twiss_and_rdts(madx: Madx) -> tfs.TfsDataFrame: + """ + .. versionadded:: 0.19.0 + + Runs a ``TWISS`` on the currently active sequence for all ``LHC`` BPMs. The coupling RDTs + are also computed through a CMatrix approach via `optics_functions.coupling.coupling_via_cmatrix`. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + + Returns: + A `~tfs.frame.TfsDataFrame` of the ``TWISS`` table with basic default columns, as well as one + new column for each of the coupling RDTs. The coupling RDTs are returned as complex numbers. + + Example: + .. code-block:: python + + >>> twiss_with_rdts = get_lhc_bpms_twiss_and_rdts(madx) + """ + twiss_tfs = twiss.get_pattern_twiss( # need chromatic flag as we're dealing with coupling + madx, patterns=["^BPM.*B[12]$"], columns=MONITOR_TWISS_COLUMNS, chrom=True + ) + twiss_tfs.columns = twiss_tfs.columns.str.upper() # optics_functions needs capitalized names + twiss_tfs.NAME = twiss_tfs.NAME.str.upper() + twiss_tfs[["F1001", "F1010"]] = coupling_via_cmatrix(twiss_tfs, output=["rdts"]) + return twiss_tfs diff --git a/pyhdtoolkit/cpymadtools/lhc/_elements.py b/pyhdtoolkit/cpymadtools/lhc/_elements.py new file mode 100644 index 00000000..5e99bf8f --- /dev/null +++ b/pyhdtoolkit/cpymadtools/lhc/_elements.py @@ -0,0 +1,233 @@ +""" +.. _lhc-elements: + +**Elements Utilities** + +The functions below are utilities to install elements or markers in the ``LHC``. +""" +from cpymad.madx import Madx +from loguru import logger + + +def install_ac_dipole_as_kicker( + madx: Madx, + deltaqx: float, + deltaqy: float, + sigma_x: float, + sigma_y: float, + beam: int = 1, + start_turn: int = 100, + ramp_turns: int = 2000, + top_turns: int = 6600, +) -> None: + """ + .. versionadded:: 0.15.0 + + Installs an AC dipole as a kicker element in (HL)LHC beam 1 or 2, for tracking. This function + assumes that you have already defined lhcb1/lhcb2 sequence, made a beam for it (``BEAM`` + command or `~lhc.make_lhc_beams` function), matched to your desired working point and made + a ``TWISS`` call. + + .. important:: + In a real machine, the AC Dipole does impact the orbit as well as the betatron + functions when turned on (:cite:t:`Miyamoto:ACD:2008`, part III). In ``MAD-X`` + however, it cannot be modeled to do both at the same time. This routine introduces + an AC Dipole as a kicker element so that its effect can be seen on particle trajectory + in tracking. It **does not** affect ``TWISS`` functions. + + One can find a full example use of the function for tracking in the + :ref:`AC Dipole Tracking ` example gallery. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + deltaqx (float): the deltaQx (horizontal tune excitation) used by the AC dipole. + deltaqy (float): the deltaQy (vertical tune excitation) used by the AC dipole. + sigma_x (float): the horizontal amplitude to drive the beam to, in bunch sigma. + sigma_y (float): the vertical amplitude to drive the beam to, in bunch sigma. + beam (int): the LHC beam to install the AC Dipole into, either 1 or 2. Defaults to 1. + start_turn (int): the turn at which to start ramping up the AC dipole. Defaults to 100. + ramp_turns (int): the number of turns to use for the ramp-up and the ramp-down of the AC dipole. + This number is important in order to preserve the adiabaticity of the cycle. Defaults to 2000 + as in the LHC. + top_turns (int): the number of turns to drive the beam for. Defaults to 6600 as in the LHC. + + Example: + .. code-block:: python + + >>> install_ac_dipole_as_kicker( + ... madx, + ... deltaqx=-0.01, # driven horizontal tune to Qxd = 62.31 - 0.01 = 62.30 + ... deltaqy=0.012, # driven vertical tune to Qyd = 60.32 + 0.012 = 60.332 + ... sigma_x=2, # bunch amplitude kick in the horizontal plane + ... sigma_y=2, # bunch amplitude kick in the vertical plane + ... beam=1, # beam for which to install and kick + ... start_turn=100, # when to turn on the AC Dipole + ... ramp_turns=2000, # how many turns to ramp up/down the AC Dipole + ... top_turns=6600, # how many turns to keep the AC Dipole at full kick + ... ) + """ + logger.warning("This AC Dipole is implemented as a kicker and will not affect TWISS functions!") + logger.debug("This routine should be done after 'match', 'twiss' and 'makethin' for the appropriate beam") + + if top_turns > 6600: + logger.warning( + f"Configuring the AC Dipole for {top_turns:d} of driving is fine for MAD-X but is " + "higher than what the device can do in the (HL)LHC! Beware." + ) + ramp1, ramp2 = start_turn, start_turn + ramp_turns + ramp3 = ramp2 + top_turns + ramp4 = ramp3 + ramp_turns + + logger.debug("Retrieving tunes from internal tables") + q1, q2 = madx.table.summ.q1[0], madx.table.summ.q2[0] + logger.debug(f"Retrieved values are q1 = {q1:.5f}, q2 = {q2:.5f}") + q1_dipole, q2_dipole = q1 + deltaqx, q2 + deltaqy + + logger.debug("Querying BETX and BETY at AC Dipole location") + # All below is done as model_creator macros with `.input()` calls + madx.input(f"pbeam = beam%lhcb{beam:d}->pc;") + madx.input(f"betxac = table(twiss, MKQA.6L4.B{beam:d}, BEAM, betx);") + madx.input(f"betyac = table(twiss, MKQA.6L4.B{beam:d}, BEAM, bety);") + + logger.debug("Calculating AC Dipole voltage values") + madx.input(f"voltx = 0.042 * pbeam * ABS({deltaqx}) / SQRT(180.0 * betxac) * {sigma_x}") + madx.input(f"volty = 0.042 * pbeam * ABS({deltaqy}) / SQRT(177.0 * betyac) * {sigma_y}") + + logger.debug("Defining kicker elements for transverse planes") + madx.input( + f"MKACH.6L4.B{beam:d}: hacdipole, l=0, freq:={q1_dipole}, lag=0, volt=voltx, ramp1={ramp1}, " + f"ramp2={ramp2}, ramp3={ramp3}, ramp4={ramp4};" + ) + madx.input( + f"MKACV.6L4.B{beam:d}: vacdipole, l=0, freq:={q2_dipole}, lag=0, volt=volty, ramp1={ramp1}, " + f"ramp2={ramp2}, ramp3={ramp3}, ramp4={ramp4};" + ) + + logger.debug(f"Installing AC Dipole kicker with driven tunes of Qx_D = {q1_dipole:.5f} | Qy_D = {q2_dipole:.5f}") + madx.command.seqedit(sequence=f"lhcb{beam:d}") + madx.command.flatten() + # The kicker version is meant for a thin lattice and is installed a right at MKQA.6L4.B[12] (at=0) + madx.command.install(element=f"MKACH.6L4.B{beam:d}", at=0, from_=f"MKQA.6L4.B{beam:d}") + madx.command.install(element=f"MKACV.6L4.B{beam:d}", at=0, from_=f"MKQA.6L4.B{beam:d}") + madx.command.endedit() + + logger.warning( + f"Sequence LHCB{beam:d} is now re-USEd for changes to take effect. Beware that this will reset it, " + "remove errors etc." + ) + madx.use(sequence=f"lhcb{beam:d}") + + +def install_ac_dipole_as_matrix(madx: Madx, deltaqx: float, deltaqy: float, beam: int = 1) -> None: + """ + .. versionadded:: 0.15.0 + + Installs an AC dipole as a matrix element in (HL)LHC beam 1 or 2, to see its effect on TWISS functions + This function assumes that you have already defined lhcb1/lhcb2 sequence, made a beam for it (``BEAM`` + command or `~lhc.make_lhc_beams` function), matched to your desired working point and made a ``TWISS`` + call. + + This function's use is very similar to that of `~.lhc.install_ac_dipole_as_kicker`. + + .. important:: + In a real machine, the AC Dipole does impact the orbit as well as the betatron + functions when turned on (:cite:t:`Miyamoto:ACD:2008`, part III). In ``MAD-X`` + however, it cannot be modeled to do both at the same time. This routine introduces + an AC Dipole as a matrix element so that its effect can be seen on ``TWISS`` functions. + It **does not** affect tracking. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + deltaqx (float): the deltaQx (horizontal tune excitation) used by the AC dipole. + deltaqy (float): the deltaQy (vertical tune excitation) used by the AC dipole. + beam (int): the LHC beam to install the AC Dipole into, either 1 or 2. Defaults to 1. + + Example: + .. code-block:: python + + >>> install_ac_dipole_as_matrix(madx, deltaqx=-0.01, deltaqy=0.012, beam=1) + """ + logger.warning("This AC Dipole is implemented as a matrix and will not affect particle tracking!") + logger.debug("This routine should be done after 'match', 'twiss' and 'makethin' for the appropriate beam.") + + logger.debug("Retrieving tunes from internal tables") + q1, q2 = madx.table.summ.q1[0], madx.table.summ.q2[0] + logger.debug(f"Retrieved values are q1 = {q1:.5f}, q2 = {q2:.5f}") + q1_dipole, q2_dipole = q1 + deltaqx, q2 + deltaqy + + logger.debug("Querying BETX and BETY at AC Dipole location") + # All below is done as model_creator macros with `.input()` calls + madx.input(f"betxac = table(twiss, MKQA.6L4.B{beam:d}, BEAM, betx);") + madx.input(f"betyac = table(twiss, MKQA.6L4.B{beam:d}, BEAM, bety);") + + logger.debug("Calculating AC Dipole matrix terms") + madx.input(f"hacmap21 = 2 * (cos(2*pi*{q1_dipole}) - cos(2*pi*{q1})) / (betxac * sin(2*pi*{q1}));") + madx.input(f"vacmap43 = 2 * (cos(2*pi*{q2_dipole}) - cos(2*pi*{q2})) / (betyac * sin(2*pi*{q2}));") + + logger.debug("Defining matrix elements for transverse planes") + madx.input(f"hacmap: matrix, l=0, rm21=hacmap21;") + madx.input(f"vacmap: matrix, l=0, rm43=vacmap43;") + + logger.debug(f"Installing AC Dipole matrix with driven tunes of Qx_D = {q1_dipole:.5f} | Qy_D = {q2_dipole:.5f}") + madx.command.seqedit(sequence=f"lhcb{beam:d}") + madx.command.flatten() + # The matrix version is meant for a thick lattice and is installed a little after MKQA.6L4.B[12] + madx.command.install(element="hacmap", at="1.583 / 2", from_=f"MKQA.6L4.B{beam:d}") + madx.command.install(element="vacmap", at="1.583 / 2", from_=f"MKQA.6L4.B{beam:d}") + madx.command.endedit() + + logger.warning( + f"Sequence LHCB{beam:d} is now re-USEd for changes to take effect. Beware that this will reset it, " + "remove errors etc." + ) + madx.use(sequence=f"lhcb{beam:d}") + + +def add_markers_around_lhc_ip(madx: Madx, sequence: str, ip: int, n_markers: int, interval: float) -> None: + """ + .. versionadded:: 1.0.0 + + Adds some simple marker elements left and right of an IP point, to increase the granularity of optics + functions returned from a ``TWISS`` call. + + .. warning:: + You will most likely need to have sliced the sequence before calling this function, + as otherwise there is a risk on getting a negative drift depending on the affected + IP. This would lead to the remote ``MAD-X`` process to crash. + + .. warning:: + After editing the *sequence* to add markers, the ``USE`` command will be run for the changes to apply. + This means the caveats of ``USE`` apply, for instance the erasing of previously defined errors, orbits + corrections etc. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + sequence (str): which sequence to use the routine on. + ip (int): The interaction point around which to add markers. + n_markers (int): how many markers to add on each side of the IP. + interval (float): the distance between markers, in [m]. Giving ``interval=0.05`` will + place a marker every 5cm (starting 5cm away from the IP on each side). + + Example: + .. code-block:: python + + >>> add_markers_around_lhc_ip( + ... madx, sequence=f"lhcb1", ip=1, n_markers=1000, interval=0.001 + ... ) + """ + logger.debug(f"Adding {n_markers:d} markers on each side of IP{ip:d}") + madx.command.seqedit(sequence=sequence) + madx.command.flatten() + for i in range(1, n_markers + 1): + madx.command.install( + element=f"MARKER.LEFT.IP{ip:d}.{i:02d}", class_="MARKER", at=-i * interval, from_=f"IP{ip:d}" + ) + madx.command.install( + element=f"MARKER.RIGHT.IP{ip:d}.{i:02d}", class_="MARKER", at=i * interval, from_=f"IP{ip:d}" + ) + madx.command.flatten() + madx.command.endedit() + logger.warning( + f"Sequence '{sequence}' will be USEd for new markers to be taken in consideration, beware that this will erase errors etc." + ) + madx.use(sequence=sequence) diff --git a/pyhdtoolkit/cpymadtools/errors.py b/pyhdtoolkit/cpymadtools/lhc/_errors.py similarity index 73% rename from pyhdtoolkit/cpymadtools/errors.py rename to pyhdtoolkit/cpymadtools/lhc/_errors.py index 9b819d02..12c05731 100644 --- a/pyhdtoolkit/cpymadtools/errors.py +++ b/pyhdtoolkit/cpymadtools/lhc/_errors.py @@ -1,21 +1,16 @@ """ -.. _cpymadtools-errors: +.. _lhc-errors: -Errors Assignments ------------------- +**Errors Utilities** -Module with functions to perform ``MAD-X`` errors setups and manipulations through a `~cpymad.madx.Madx` -object, mainly for LHC and HLLHC machines. +The functions below are utilities to implement errors in elements of the ``LHC``. """ from typing import Dict, List, Sequence from cpymad.madx import Madx from loguru import logger -# ----- Constants ----- # - -# After number 10 are either MQ or MQT quadrupole elements, which officially belong to the arcs -IR_QUADS_PATTERNS: Dict[int, List[str]] = { +LHC_IR_QUADS_PATTERNS: Dict[int, List[str]] = { 1: ["^MQXA.1{side}{ip:d}", "^MQXFA.[AB]1{side}{ip:d}"], # Q1 LHC, Q1A & Q1B HL-LHC 2: ["^MQXB.[AB]2{side}{ip:d}", "^MQXB.[AB]2{side}{ip:d}"], # Q2A & Q2B LHC, Q2A & Q2B HL-LHC 3: ["^MQXA.3{side}{ip:d}", "^MQXFA.[AB]3{side}{ip:d}"], # Q3 LHC, Q3A & Q3B HL-LHC @@ -29,57 +24,42 @@ } -# ----- Utilites ----- # - - -def switch_magnetic_errors(madx: Madx, **kwargs) -> None: +def misalign_lhc_triplets( + madx: Madx, ip: int, sides: Sequence[str] = ("r", "l"), table: str = "triplet_errors", **kwargs +) -> None: """ - .. versionadded:: 0.7.0 + .. versionadded:: 0.9.0 - Applies magnetic field orders. This will only work for LHC and HLLHC machines. - Initial implementation credits go to :user:`Joschua Dilly `. + Apply misalignment errors to IR triplet quadrupoles on a given side of a given IP. In case of a + sliced lattice, this will misalign all slices of each magnet together. This is a convenience wrapper + around the `~.misalign_lhc_ir_quadrupoles` function, see that function's docstring for more + information. Args: madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - **kwargs: The setting works through keyword arguments, and several specific - kwargs are expected. `default` sets global default to this value (defaults to `False`). - `AB#` sets the default for all of that order, the order being the `#` number. `A#` or - `B#` sets the default for systematic and random of this id. `A#s`, `B#r`, etc. sets the - specific value for this given order. In all kwargs, the order # should be in the range - [1...15], where 1 == dipolar field. + ip (int): the interaction point around which to apply errors. + sides (Sequence[str]): sides of the IP to apply error on the triplets, either L or R or both. + Case-insensitive. Defaults to both. + table (str): the name of the internal table that will save the assigned errors. Defaults to + `triplet_errors`. + **kwargs: Any keyword argument is given to the ``EALIGN`` command, including the error to apply + (`DX`, `DY`, `DPSI` etc) as a string, like it would be given directly into ``MAD-X``. Examples: - Set random values for (alsmost) all of these orders: + A random, gaussian truncated ``DX`` misalignment: .. code-block:: python - >>> random_kwargs = {} - >>> for order in range(1, 16): - ... for ab in "AB": - ... random_kwargs[f"{ab}{order:d}"] = random.randint(0, 20) - >>> switch_magnetic_errors(madx, **random_kwargs) + >>> misalign_lhc_triplets(madx, ip=1, sides="RL", dx="1E-5 * TGAUSS(2.5)") - Set a given value for ``B6`` order magnetic errors: + A random, gaussian truncated ``DPSI`` misalignment: .. code-block:: python - >>> switch_magnetic_errors(madx, "B6"=1e-4) + >>> misalign_lhc_triplets(madx, ip=5, sides="RL", dpsi="0.001 * TGAUSS(2.5)") """ - logger.debug("Setting magnetic errors") - global_default = kwargs.get("default", False) - - for order in range(1, 16): - logger.trace(f"Setting up for order {order}") - order_default = kwargs.get(f"AB{order:d}", global_default) - - for ab in "AB": - ab_default = kwargs.get(f"{ab}{order:d}", order_default) - for sr in "sr": - name = f"{ab}{order:d}{sr}" - error_value = int(kwargs.get(name, ab_default)) - logger.trace(f"Setting global for 'ON_{name}' to {error_value}") - madx.globals[f"ON_{name}"] = error_value + misalign_lhc_ir_quadrupoles(madx, ips=[ip], beam=None, quadrupoles=(1, 2, 3), sides=sides, table=table, **kwargs) def misalign_lhc_ir_quadrupoles( @@ -171,7 +151,7 @@ def misalign_lhc_ir_quadrupoles( raise ValueError("Invalid 'sides' parameter") sides = [side.upper() for side in sides] - logger.trace("Clearing error flag") + logger.debug("Clearing error flag") madx.select(flag="error", clear=True) logger.debug(f"Applying alignment errors to IR quads '{quadrupoles}', with arguments {kwargs}") @@ -179,7 +159,7 @@ def misalign_lhc_ir_quadrupoles( logger.debug(f"Applying errors for IR{ip}") for side in sides: for quad_number in quadrupoles: - for quad_pattern in IR_QUADS_PATTERNS[quad_number]: + for quad_pattern in LHC_IR_QUADS_PATTERNS[quad_number]: # Triplets are single aperture and don't need beam information, others do if quad_number <= 3: madx.select(flag="error", pattern=quad_pattern.format(side=side, ip=ip)) @@ -191,43 +171,5 @@ def misalign_lhc_ir_quadrupoles( logger.debug(f"Saving assigned errors in internal table '{table}'") madx.command.etable(table=table) - logger.trace("Clearing up error flag") + logger.debug("Clearing up error flag") madx.select(flag="error", clear=True) - - -def misalign_lhc_triplets( - madx: Madx, ip: int, sides: Sequence[str] = ("r", "l"), table: str = "triplet_errors", **kwargs -) -> None: - """ - .. versionadded:: 0.9.0 - - Apply misalignment errors to IR triplet quadrupoles on a given side of a given IP. In case of a - sliced lattice, this will misalign all slices of each magnet together. This is a convenience wrapper - around the `~.errors.misalign_lhc_ir_quadrupoles` function, see that function's docstring for more - information. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - ip (int): the interaction point around which to apply errors. - sides (Sequence[str]): sides of the IP to apply error on the triplets, either L or R or both. - Case-insensitive. Defaults to both. - table (str): the name of the internal table that will save the assigned errors. Defaults to - `triplet_errors`. - **kwargs: Any keyword argument is given to the ``EALIGN`` command, including the error to apply - (`DX`, `DY`, `DPSI` etc) as a string, like it would be given directly into ``MAD-X``. - - Examples: - - A random, gaussian truncated ``DX`` misalignment: - - .. code-block:: python - - >>> misalign_lhc_triplets(madx, ip=1, sides="RL", dx="1E-5 * TGAUSS(2.5)") - - A random, gaussian truncated ``DPSI`` misalignment: - - .. code-block:: python - - >>> misalign_lhc_triplets(madx, ip=5, sides="RL", dpsi="0.001 * TGAUSS(2.5)") - """ - misalign_lhc_ir_quadrupoles(madx, ips=[ip], beam=None, quadrupoles=(1, 2, 3), sides=sides, table=table, **kwargs) diff --git a/pyhdtoolkit/cpymadtools/lhc/_misc.py b/pyhdtoolkit/cpymadtools/lhc/_misc.py new file mode 100644 index 00000000..863d4314 --- /dev/null +++ b/pyhdtoolkit/cpymadtools/lhc/_misc.py @@ -0,0 +1,202 @@ +""" +.. _lhc-mist: + +**Miscellaneous Utilities** + +The functions below are miscellaneous utilities for the ``LHC``. +""" +from typing import List, Tuple + +from cpymad.madx import Madx +from loguru import logger + +from pyhdtoolkit.cpymadtools import twiss +from pyhdtoolkit.cpymadtools.constants import ( + LHC_ANGLE_FLAGS, + LHC_CROSSING_ANGLE_FLAGS, + LHC_EXPERIMENT_STATE_FLAGS, + LHC_IP2_SPECIAL_FLAG, + LHC_IP_OFFSET_FLAGS, + LHC_PARALLEL_SEPARATION_FLAGS, +) +from pyhdtoolkit.optics.ripken import _add_beam_size_to_df + + +def make_sixtrack_output(madx: Madx, energy: int) -> None: + """ + .. versionadded:: 0.15.0 + + Prepare output for a ``SixTrack`` run. Initial implementation credits go to + :user:`Joschua Dilly `. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + energy (float): beam energy, in [GeV]. + + Example: + .. code-block:: python + + >>> make_sixtrack_output(madx, energy=6800) + """ + logger.debug("Preparing outputs for SixTrack") + + logger.debug("Powering RF cavities") + madx.globals["VRF400"] = 8 if energy < 5000 else 16 # is 6 at injection for protons iirc? + madx.globals["LAGRF400.B1"] = 0.5 # cavity phase difference in units of 2pi + madx.globals["LAGRF400.B2"] = 0.0 + + logger.debug("Executing TWISS and SIXTRACK commands") + madx.twiss() # used by sixtrack + madx.sixtrack(cavall=True, radius=0.017) # this value is only ok for HL(LHC) magnet radius + + +def reset_lhc_bump_flags(madx: Madx) -> None: + """ + .. versionadded:: 0.15.0 + + Resets all LHC IP bump flags to 0. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + + Example: + .. code-block:: python + + >>> reset_lhc_bump_flags(madx) + """ + logger.debug("Resetting all LHC IP bump flags") + ALL_BUMPS = ( + LHC_ANGLE_FLAGS + + LHC_CROSSING_ANGLE_FLAGS + + LHC_EXPERIMENT_STATE_FLAGS + + LHC_IP2_SPECIAL_FLAG + + LHC_IP_OFFSET_FLAGS + + LHC_PARALLEL_SEPARATION_FLAGS + ) + with madx.batch(): + madx.globals.update({bump: 0 for bump in ALL_BUMPS}) + + +def get_lhc_tune_and_chroma_knobs( + accelerator: str, beam: int = 1, telescopic_squeeze: bool = True, run3: bool = False +) -> Tuple[str, str, str, str]: + """ + .. versionadded:: 0.16.0 + + Gets names of knobs needed to match tunes and chromaticities as a tuple of strings, + for the LHC or HLLHC machines. Initial implementation credits go to + :user:`Joschua Dilly `. + + Args: + accelerator (str): Accelerator either 'LHC' (dQ[xy], dQp[xy] knobs) or 'HLLHC' + (kqt[fd], ks[fd] knobs). + beam (int): Beam to use, for the knob names. Defaults to 1. + telescopic_squeeze (bool): if set to `True`, returns the knobs for Telescopic + Squeeze configuration. Defaults to `True` to reflect run III scenarios. + run3 (bool): if set to `True`, returns the Run 3 `*_op` knobs. Defaults to `False`. + + Returns: + A `tuple` of strings with knobs for ``(qx, qy, dqx, dqy)``. + + Examples: + .. code-block:: python + + >>> get_lhc_tune_and_chroma_knobs("LHC", beam=1, telescopic_squeeze=False) + ('dQx.b1', 'dQy.b1', 'dQpx.b1', 'dQpy.b1') + + .. code-block:: python + + >>> get_lhc_tune_and_chroma_knobs("LHC", beam=2, run3=True) + ('dQx.b2_op', 'dQx.b2_op', 'dQpx.b2_op', 'dQpx.b2_op') + + .. code-block:: python + + >>> get_lhc_tune_and_chroma_knobs("HLLHC", beam=2) + ('kqtf.b2_sq', 'kqtd.b2_sq', 'ksf.b2_sq', 'ksd.b2_sq') + """ + beam = 2 if beam == 4 else beam + if run3: + suffix = "_op" + elif telescopic_squeeze: + suffix = "_sq" + else: + suffix = "" + + if accelerator.upper() not in ("LHC", "HLLHC"): + logger.error("Invalid accelerator name, only 'LHC' and 'HLLHC' implemented") + raise NotImplementedError(f"Accelerator '{accelerator}' not implemented.") + + return { + "LHC": ( + f"dQx.b{beam}{suffix}", + f"dQy.b{beam}{suffix}", + f"dQpx.b{beam}{suffix}", + f"dQpy.b{beam}{suffix}", + ), + "HLLHC": ( + f"kqtf.b{beam}{suffix}", + f"kqtd.b{beam}{suffix}", + f"ksf.b{beam}{suffix}", + f"ksd.b{beam}{suffix}", + ), + }[accelerator.upper()] + + +def get_lhc_bpms_list(madx: Madx) -> List[str]: + """ + .. versionadded:: 0.16.0 + + Returns the list of monitoring BPMs for the current LHC sequence in use. + The BPMs are queried through a regex in the result of a ``TWISS`` command. + + .. note:: + As this function calls the ``TWISS`` command and requires that ``TWISS`` can + succeed on your sequence. + + Args: + madx (cpymad.madx.Madx): an instantiated cpymad.madx.Madx object. + + Returns: + The `list` of BPM names. + + Example: + .. code-block:: python + + >>> observation_bpms = get_lhc_bpms_list(madx) + """ + twiss_df = twiss.get_twiss_tfs(madx).reset_index() + bpms_df = twiss_df[twiss_df.NAME.str.contains("^bpm.*B[12]$", case=False, regex=True)] + return bpms_df.NAME.tolist() + + +def get_sizes_at_ip(madx: Madx, ip: int, geom_emit_x: float = None, geom_emit_y: float = None) -> Tuple[float, float]: + """ + .. versionadded:: 1.0.0 + + Get the Lebedev beam sizes (horizontal and vertical) at the provided LHC *ip*. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + ip (int): the IP to get the sizes at. + geom_emit_x (float): the horizontal geometrical emittance to use for the + calculation. If not provided, will look for the values of the + ``geometric_emit_x`` variable in ``MAD-X``. + geom_emit_y (float): the vertical geometrical emittance to use for the + calculation. If not provided, will look for the values of the + ``geometric_emit_y`` variable in ``MAD-X``. + + Returns: + A tuple of the horizontal and vertical beam sizes at the provided *IP*. + + Example: + .. code-block:: python + + >>> ip5_x, ip5_y = get_size_at_ip(madx, ip=5) + """ + logger.debug(f"Getting horizotnal and vertical sizes at IP{ip:d} through Ripken parameters") + geom_emit_x = geom_emit_x or madx.globals["geometric_emit_x"] + geom_emit_y = geom_emit_y or madx.globals["geometric_emit_y"] + + twiss_tfs = twiss.get_twiss_tfs(madx, chrom=True, ripken=True) + twiss_tfs = _add_beam_size_to_df(twiss_tfs, geom_emit_x, geom_emit_y) + return twiss_tfs.loc[f"IP{ip:d}"].SIZE_X, twiss_tfs.loc[f"IP{ip:d}"].SIZE_Y diff --git a/pyhdtoolkit/cpymadtools/lhc/_powering.py b/pyhdtoolkit/cpymadtools/lhc/_powering.py new file mode 100644 index 00000000..4a09346d --- /dev/null +++ b/pyhdtoolkit/cpymadtools/lhc/_powering.py @@ -0,0 +1,412 @@ +""" +.. _lhc-powering: + +**Powering Utilities** + +The functions below are magnets or knobs powering utilities for the ``LHC``. +""" +from typing import Dict, List, Sequence + +from cpymad.madx import Madx +from loguru import logger + + +def apply_lhc_colinearity_knob(madx: Madx, colinearity_knob_value: float = 0, ir: int = None) -> None: + """ + .. versionadded:: 0.15.0 + + Applies the a trim of the LHC colinearity knob. + + .. note:: + If you don't know what this is, you really should not be using this function. + + .. tip:: + The convention, which is also the one I implemented in ``LSA`` for the ``LHC``, is that a + positive value of the colinearity knob results in a powering increase of the ``MQSX`` *right* + of the IP, and a powering decrease of the ``MQSX`` *left* of the IP. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + colinearity_knob_value (float): Units of the colinearity knob to apply. Defaults to 0 so users + don't mess up local IR coupling by mistake. This should be a positive integer, normally between 1 + and 10. + ir (int): The Interaction Region to apply the knob to, should be one of [1, 2, 5, 8]. + Classically 1 or 5. + + Example: + .. code-block:: python + + >>> apply_lhc_colinearity_knob(madx, colinearity_knob_value=5, ir=1) + """ + logger.debug(f"Applying Colinearity knob with a unit setting of {colinearity_knob_value}") + logger.warning("You should re-match tunes & chromaticities after this colinearity knob is applied") + knob_variables = (f"KQSX3.R{ir:d}", f"KQSX3.L{ir:d}") # MQSX IP coupling correctors powering + right_knob, left_knob = knob_variables + + madx.globals[right_knob] = colinearity_knob_value * 1e-4 + logger.debug(f"Set '{right_knob}' to {madx.globals[right_knob]}") + madx.globals[left_knob] = -1 * colinearity_knob_value * 1e-4 + logger.debug(f"Set '{left_knob}' to {madx.globals[left_knob]}") + + +def apply_lhc_colinearity_knob_delta(madx: Madx, colinearity_knob_delta: float = 0, ir: int = None) -> None: + """ + .. versionadded:: 0.21.0 + + This is essentially the same as `.apply_lhc_colinearity_knob`, but instead of a applying fixed powering + value, it applies a delta to the (potentially) existing value. + + .. note:: + If you don't know what this is, you really should not be using this function. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + colinearity_knob_delta (float): Units of the colinearity knob to vary the existing powerings with. + Defaults to 0. + ir (int): The Interaction Region to apply the knob to, should be one of [1, 2, 5, 8]. + Classically 1 or 5. + + Example: + .. code-block:: python + + >>> apply_lhc_colinearity_knob_delta(madx, colinearity_knob_delta=3.5, ir=1) + """ + logger.debug(f"Applying Colinearity knob delta of {colinearity_knob_delta}") + logger.warning("You should re-match tunes & chromaticities after this delta is applied") + knob_variables = (f"KQSX3.R{ir:d}", f"KQSX3.L{ir:d}") # MQSX IP coupling correctors powering + right_knob, left_knob = knob_variables + + logger.debug("Query current knob values") + current_right = madx.eval(right_knob) # ugly, but avoids KeyError if not defined yet + current_left = madx.eval(left_knob) # augly, but avoids KeyError if not defined yet + logger.debug(f"Current right knob value is {current_right}") + logger.debug(f"Current left knob value is {current_left}") + + madx.globals[right_knob] = current_right + colinearity_knob_delta * 1e-4 + logger.debug(f"Set '{right_knob}' to {madx.globals[right_knob]}") + madx.globals[left_knob] = current_left - colinearity_knob_delta * 1e-4 + logger.debug(f"Set '{left_knob}' to {madx.globals[left_knob]}") + + +def apply_lhc_rigidity_waist_shift_knob( + madx: Madx, rigidty_waist_shift_value: float = 0, ir: int = None, side: str = "left" +) -> None: + """ + .. versionadded:: 0.15.0 + + Applies a trim of the LHC rigidity waist shift knob, moving the waist left or right of IP. + The waist shift is achieved by moving all four betatron waists simltaneously: unbalancing + the triplet powering knobs of the left and right-hand sides of the IP. + + .. note:: + If you don't know what this is, you really should not be using this function. + + .. warning:: + Applying the shift will modify your tunes and is likely to flip them, making a subsequent matching + impossible if your lattice has coupling. To avoid this, one should match to tunes split further apart + before applying the waist shift knob, and then match to the desired working point. For instance for + the LHC, matching to (62.27, 60.36) before applying and afterwards rematching to (62.31, 60.32) usually + works well. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + rigidty_waist_shift_value (float): Units of the rigidity waist shift knob (positive values only). + ir (int): The Interaction Region to apply the knob to, should be one of [1, 2, 5, 8]. + Classically 1 or 5. + side (str): Which side of the IP to move the waist to, determines a sign in the calculation. + Defaults to `left`, which means :math:`s_{\\mathrm{waist}} \\lt s_{\\mathrm{ip}}` (and + setting it to `right` would move the waist such that + :math:`s_{\\mathrm{waist}} \\gt s_{\\mathrm{ip}}`). + + Example: + .. code-block:: python + + >>> # It is recommended to re-match tunes after this routine + >>> matching.match_tunes(madx, "lhc", "lhcb1", 62.27, 60.36) + >>> apply_lhc_rigidity_waist_shift_knob(madx, rigidty_waist_shift_value=1.5, ir=5) + >>> matching.match_tunes(madx, "lhc", "lhcb1", 62.31, 60.32) + """ + logger.debug(f"Applying Rigidity Waist Shift knob with a unit setting of {rigidty_waist_shift_value}") + logger.warning("You should re-match tunes & chromaticities after this rigid waist shift knob is applied") + right_knob, left_knob = f"kqx.r{ir:d}", f"kqx.l{ir:d}" # IP triplet default knob (no trims) + + current_right_knob = madx.globals[right_knob] + current_left_knob = madx.globals[left_knob] + + if side.lower() == "left": + madx.globals[right_knob] = (1 - rigidty_waist_shift_value * 0.005) * current_right_knob + madx.globals[left_knob] = (1 + rigidty_waist_shift_value * 0.005) * current_left_knob + elif side.lower() == "right": + madx.globals[right_knob] = (1 + rigidty_waist_shift_value * 0.005) * current_right_knob + madx.globals[left_knob] = (1 - rigidty_waist_shift_value * 0.005) * current_left_knob + else: + logger.error(f"Given side '{side}' invalid, only 'left' and 'right' are accepted values.") + raise ValueError("Invalid value for parameter 'side'.") + + logger.debug(f"Set '{right_knob}' to {madx.globals[right_knob]}") + logger.debug(f"Set '{left_knob}' to {madx.globals[left_knob]}") + + +def apply_lhc_coupling_knob( + madx: Madx, coupling_knob: float = 0, beam: int = 1, telescopic_squeeze: bool = True +) -> None: + """ + .. versionadded:: 0.15.0 + + Applies a trim of the LHC coupling knob to reach the desired :math:`|C^{-}|` value. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + coupling_knob (float): Desired value for the Cminus, typically a few units of ``1E-3``. + Defaults to 0 so users don't mess up coupling by mistake. + beam (int): beam to apply the knob to. Defaults to beam 1. + telescopic_squeeze (bool): if set to `True`, uses the knobs for Telescopic Squeeze configuration. + Defaults to `True` since `v0.9.0`. + + Example: + .. code-block:: python + + >>> apply_lhc_coupling_knob(madx, coupling_knob=5e-4, beam=1) + """ + # NOTE: for maintainers, no `_op` suffix on ATS coupling knobs, only `_sq` even in Run 3 + logger.debug("Applying coupling knob") + logger.warning("You should re-match tunes & chromaticities after this coupling knob is applied") + suffix = "_sq" if telescopic_squeeze else "" + # NOTE: Only using this knob will give a dqmin very close to coupling_knob + # If one wants to also assign f"CMIS.b{beam:d}{suffix}" the dqmin will be > coupling_knob + knob_name = f"CMRS.b{beam:d}{suffix}" + + logger.debug(f"Knob '{knob_name}' is {madx.globals[knob_name]} before implementation") + madx.globals[knob_name] = coupling_knob + logger.debug(f"Set '{knob_name}' to {madx.globals[knob_name]}") + + +def carry_colinearity_knob_over(madx: Madx, ir: int, to_left: bool = True) -> None: + """ + .. versionadded:: 0.20.0 + + Removes the powering setting on one side of the colinearty knob and applies it to the + other side. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + ir (int): The Interaction Region around which to apply the change, should be + one of [1, 2, 5, 8]. + to_left (bool): If `True`, the magnet right of IP is de-powered of and its powering + is transferred to the magnet left of IP. If `False`, then the opposite happens. + Defaults to `True`. + + Example: + .. code-block:: python + + >>> carry_colinearity_knob_over(madx, ir=5, to_left=True) + """ + side = "left" if to_left else "right" + logger.debug(f"Carrying colinearity knob powering around IP{ir:d} over to the {side} side") + + left_variable, right_variable = f"kqsx3.l{ir:d}", f"kqsx3.r{ir:d}" + left_powering, right_powering = madx.globals[left_variable], madx.globals[right_variable] + logger.debug(f"Current powering values are: '{left_variable}'={left_powering} | '{right_variable}'={left_powering}") + + new_left = left_powering + right_powering if to_left else 0 + new_right = 0 if to_left else left_powering + right_powering + logger.debug(f"New powering values are: '{left_variable}'={new_left} | '{right_variable}'={new_right}") + madx.globals[left_variable] = new_left + madx.globals[right_variable] = new_right + logger.debug("New powerings applied") + + +def power_landau_octupoles(madx: Madx, beam: int, mo_current: float, defective_arc: bool = False) -> None: + """ + .. versionadded:: 0.15.0 + + Powers the Landau octupoles in the (HL)LHC. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + beam (int): beam to use. + mo_current (float): `MO` powering, in [A]. + defective_arc: If set to `True`, the ``KOD`` in Arc 56 are powered for less ``Imax``. + + Example: + .. code-block:: python + + >>> power_landau_octupoles(madx, beam=1, mo_current=350, defect_arc=True) + """ + try: + brho = madx.globals.nrj * 1e9 / madx.globals.clight # clight is MAD-X constant + except AttributeError as madx_error: + logger.exception("The global MAD-X variable 'NRJ' should have been set in the optics files but is not defined.") + raise EnvironmentError("No 'NRJ' variable found in scripts") from madx_error + + logger.debug(f"Powering Landau Octupoles, beam {beam} @ {madx.globals.nrj} GeV with {mo_current} A.") + strength = mo_current / madx.globals.Imax_MO * madx.globals.Kmax_MO / brho + beam = 2 if beam == 4 else beam + + for arc in _all_lhc_arcs(beam): + for fd in "FD": + octupole = f"KO{fd}.{arc}" + logger.debug(f"Powering element '{octupole}' at {strength} Amps") + madx.globals[octupole] = strength + + if defective_arc and (beam == 1): + madx.globals["KOD.A56B1"] = strength * 4.65 / 6 # defective MO group + + +def deactivate_lhc_arc_sextupoles(madx: Madx, beam: int) -> None: + """ + .. versionadded:: 0.15.0 + + Deactivates all arc sextupoles in the (HL)LHC. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + beam (int): beam to use. + + Example: + .. code-block:: python + + >>> deactivate_lhc_arc_sextupoles(madx, beam=1) + """ + # KSF1 and KSD2 - Strong sextupoles of sectors 81/12/45/56 + # KSF2 and KSD1 - Weak sextupoles of sectors 81/12/45/56 + # Rest: Weak sextupoles in sectors 78/23/34/67 + logger.debug(f"Deactivating all arc sextupoles for beam {beam}.") + beam = 2 if beam == 4 else beam + + for arc in _all_lhc_arcs(beam): + for fd in "FD": + for i in (1, 2): + sextupole = f"KS{fd}{i:d}.{arc}" + logger.debug(f"De-powering element '{sextupole}'") + madx.globals[sextupole] = 0.0 + + +def vary_independent_ir_quadrupoles( + madx: Madx, quad_numbers: Sequence[int], ip: int, sides: Sequence[str] = ("r", "l"), beam: int = 1 +) -> None: + """ + .. versionadded:: 0.15.0 + + Sends the ``VARY`` commands for the desired quadrupoles in the IR surrounding the provided *ip*. + The independent quadrupoles for which this is implemented are Q4 to Q13 included. This is useful + to setup some specific matching involving these elements. + + .. important:: + It is necessary to have defined a ``brho`` variable when creating your beams. If one has used + `make_lhc_beams` to create the beams, this has already been done automatically. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + quad_numbers (Sequence[int]): quadrupoles to be varied, by number (aka position from IP). + ip (int): the IP around which to apply the instructions. + sides (Sequence[str]): the sides of IP to act on. Should be `R` for right and `L` for left, + accepts these letters case-insensitively. Defaults to both sides of the IP. + beam (int): the beam for which to apply the instructions. Defaults to 1. + + Example: + .. code-block:: python + + >>> vary_independent_ir_quadrupoles( + ... madx, quad_numbers=[10, 11, 12, 13], ip=1, sides=("r", "l") + ... ) + """ + if ( + ip not in (1, 2, 5, 8) + or any(side.upper() not in ("R", "L") for side in sides) + or any(quad not in (4, 5, 6, 7, 8, 9, 10, 11, 12, 13) for quad in quad_numbers) + ): + logger.error("Either the IP number of the side provided are invalid, not applying any error.") + raise ValueError("Invalid 'quad_numbers', 'ip', 'sides' argument") + + logger.debug(f"Preparing a knob involving quadrupoles {quad_numbers}") + # Each quad has a specific power circuit used for their k1 boundaries + power_circuits: Dict[int, str] = { + 4: "mqy", + 5: "mqml", + 6: "mqml", + 7: "mqm", + 8: "mqml", + 9: "mqm", + 10: "mqml", + 11: "mqtli", + 12: "mqt", + 13: "mqt", + } + for quad in quad_numbers: + circuit = power_circuits[quad] + for side in sides: + logger.debug(f"Sending vary command for Q{quad}{side.upper()}{ip}") + madx.command.vary( + name=f"kq{'t' if quad >= 11 else ''}{'l' if quad == 11 else ''}{quad}.{side}{ip}b{beam}", + step=1e-7, + lower=f"-{circuit}.{'b' if quad == 7 else ''}{quad}{side}{ip}.b{beam}->kmax/brho", + upper=f"+{circuit}.{'b' if quad == 7 else ''}{quad}{side}{ip}.b{beam}->kmax/brho", + ) + + +def switch_magnetic_errors(madx: Madx, **kwargs) -> None: + """ + .. versionadded:: 0.7.0 + + Applies magnetic field orders. This will only work for LHC and HLLHC machines. + Initial implementation credits go to :user:`Joschua Dilly `. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + **kwargs: The setting works through keyword arguments, and several specific + kwargs are expected. `default` sets global default to this value (defaults to `False`). + `AB#` sets the default for all of that order, the order being the `#` number. `A#` or + `B#` sets the default for systematic and random of this id. `A#s`, `B#r`, etc. sets the + specific value for this given order. In all kwargs, the order # should be in the range + [1...15], where 1 == dipolar field. + + Examples: + + Set random values for (alsmost) all of these orders: + + .. code-block:: python + + >>> random_kwargs = {} + >>> for order in range(1, 16): + ... for ab in "AB": + ... random_kwargs[f"{ab}{order:d}"] = random.randint(0, 20) + >>> switch_magnetic_errors(madx, **random_kwargs) + + Set a given value for ``B6`` order magnetic errors: + + .. code-block:: python + + >>> switch_magnetic_errors(madx, "B6"=1e-4) + """ + logger.debug("Setting magnetic errors") + global_default = kwargs.get("default", False) + + for order in range(1, 16): + logger.debug(f"Setting up for order {order}") + order_default = kwargs.get(f"AB{order:d}", global_default) + + for ab in "AB": + ab_default = kwargs.get(f"{ab}{order:d}", order_default) + for sr in "sr": + name = f"{ab}{order:d}{sr}" + error_value = int(kwargs.get(name, ab_default)) + logger.debug(f"Setting global for 'ON_{name}' to {error_value}") + madx.globals[f"ON_{name}"] = error_value + + +# ----- Helpers ----- # + + +def _all_lhc_arcs(beam: int) -> List[str]: + """ + Generates and returns the names of all LHC arcs for a given beam. + Initial implementation credits go to :user:`Joschua Dilly `. + + Args: + beam (int): beam to get names for. + + Returns: + The list of names. + """ + return [f"A{i+1}{(i+1)%8+1}B{beam:d}" for i in range(8)] diff --git a/pyhdtoolkit/cpymadtools/lhc/_queries.py b/pyhdtoolkit/cpymadtools/lhc/_queries.py new file mode 100644 index 00000000..f0fb2dd6 --- /dev/null +++ b/pyhdtoolkit/cpymadtools/lhc/_queries.py @@ -0,0 +1,290 @@ +""" +.. _lhc-queries: + +**Querying Utilities** + +The functions below are settings query utilities for the ``LHC``. +""" +from typing import Dict, Sequence, Union + +import tfs + +from cpymad.madx import Madx +from loguru import logger + +from pyhdtoolkit.cpymadtools import twiss +from pyhdtoolkit.cpymadtools.constants import ( + LHC_KCD_KNOBS, + LHC_KCO_KNOBS, + LHC_KCOSX_KNOBS, + LHC_KCOX_KNOBS, + LHC_KCS_KNOBS, + LHC_KCSSX_KNOBS, + LHC_KCSX_KNOBS, + LHC_KCTX_KNOBS, + LHC_KO_KNOBS, + LHC_KQS_KNOBS, + LHC_KQSX_KNOBS, + LHC_KQTF_KNOBS, + LHC_KSF_KNOBS, + LHC_KSS_KNOBS, +) +from pyhdtoolkit.cpymadtools.lhc._setup import lhc_orbit_variables +from pyhdtoolkit.cpymadtools.utils import _get_k_strings + + +def get_magnets_powering( + madx: Madx, patterns: Sequence[str] = [r"^mb\.", r"^mq\.", r"^ms\."], brho: Union[str, float] = None, **kwargs +) -> tfs.TfsDataFrame: + r""" + .. versionadded:: 0.17.0 + + Gets the twiss table with additional defined columns for the given *patterns*. + + .. note:: + Here are below certain useful patterns for the ``LHC`` and their meaning: + + * ``^mb\.`` :math:`\rightarrow` main bends. + * ``^mq\.`` :math:`\rightarrow` main quadrupoles. + * ``^ms\.`` :math:`\rightarrow` main sextupoles. + * ``^mb[rswx]`` :math:`\rightarrow` separation dipoles. + * ``^mq[mwxy]`` :math:`\rightarrow` insertion quads. + * ``^mqt.1[23]`` :math:`\rightarrow` short tuning quads (12 & 13). + * ``^mqtl`` :math:`\rightarrow` long tuning quads. + * ``^mcbx`` :math:`\rightarrow` crossing scheme magnets. + * ``^mcb[cy]`` :math:`\rightarrow` crossing scheme magnets. + + To make no selection, one can give ``patterns=[""]`` and this will give back + the results for *all* elements. One can also give a specific magnet's exact + name to include it in the results. + + .. note:: + The ``TWISS`` flag will be fully cleared after running this function. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + patterns (Sequence[str]): a list of regex patterns to define which elements + should be selected and included in the returned table. Defaults to selecting + the main bends, quads and sextupoles. See the note admonition above for + useful patterns to select specific ``LHC`` magnet families. + brho (Union[str, float]): optional, an explicit definition for the magnetic + rigidity in :math:`Tm^{-1}`. If not given, it will be assumed that + a ``brho`` quantity is defined in the ``MAD-X`` globals. + **kwargs: any keyword argument will be passed to `~.twiss.get_pattern_twiss` and + later on to the ``TWISS`` command executed in ``MAD-X``. + + Returns: + A `~tfs.TfsDataFrame` of the ``TWISS`` table, with the relevant newly defined columns + and including the elements matching the regex *patterns* that were provided. + + Example: + .. code-block:: python + + >>> sextupoles_powering = get_magnets_powering(madx, patterns=[r"^ms\."]) + """ + logger.debug("Computing magnets field and powering limits proportions") + NEW_COLNAMES = ["name", "keyword", "ampere", "imax", "percent", "kn", "kmax", "integrated_field", "L"] + NEW_COLNAMES = list(set(NEW_COLNAMES + kwargs.pop("columns", []))) # in case user gives explicit columns + _list_field_currents(madx, brho=brho) + return twiss.get_pattern_twiss(madx, columns=NEW_COLNAMES, patterns=patterns, **kwargs) + + +def query_arc_correctors_powering(madx: Madx) -> Dict[str, float]: + """ + .. versionadded:: 0.15.0 + + Queries for the arc corrector strengths and returns their values as a percentage of + their max powering. This is a port of one of the **corr_value.madx** file's macros + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object with an + active (HL)LHC sequence. + + Returns: + A `dict` with the percentage for each corrector. + + Example: + .. code-block:: python + + >>> arc_knobs = query_arc_correctors_powering(madx) + """ + logger.debug("Querying triplets correctors powering") + result: Dict[str, float] = {} + + logger.debug("Querying arc tune trim quadrupole correctors (MQTs) powering") + k_mqt_max = 120 / madx.globals.brho # 120 T/m + result.update({knob: 100 * _knob_value(madx, knob) / k_mqt_max for knob in LHC_KQTF_KNOBS}) + + logger.debug("Querying arc short straight sections skew quadrupole correctors (MQSs) powering") + k_mqs_max = 120 / madx.globals.brho # 120 T/m + result.update({knob: 100 * _knob_value(madx, knob) / k_mqs_max for knob in LHC_KQS_KNOBS}) + + logger.debug("Querying arc sextupole correctors (MSs) powering") + k_ms_max = 1.280 * 2 / 0.017 ** 2 / madx.globals.brho # 1.28 T @ 17 mm + result.update({knob: 100 * _knob_value(madx, knob) / k_ms_max for knob in LHC_KSF_KNOBS}) + + logger.debug("Querying arc skew sextupole correctors (MSSs) powering") + k_mss_max = 1.280 * 2 / 0.017 ** 2 / madx.globals.brho # 1.28 T @ 17 mm + result.update({knob: 100 * _knob_value(madx, knob) / k_mss_max for knob in LHC_KSS_KNOBS}) + + logger.debug("Querying arc spool piece (skew) sextupole correctors (MCSs) powering") + k_mcs_max = 0.471 * 2 / 0.017 ** 2 / madx.globals.brho # 0.471 T @ 17 mm + result.update({knob: 100 * _knob_value(madx, knob) / k_mcs_max for knob in LHC_KCS_KNOBS}) + + logger.debug("Querying arc spool piece (skew) octupole correctors (MCOs) powering") + k_mco_max = 0.040 * 6 / 0.017 ** 3 / madx.globals.brho # 0.04 T @ 17 mm + result.update({knob: 100 * _knob_value(madx, knob) / k_mco_max for knob in LHC_KCO_KNOBS}) + + logger.debug("Querying arc spool piece (skew) decapole correctors (MCDs) powering") + k_mcd_max = 0.100 * 24 / 0.017 ** 4 / madx.globals.brho # 0.1 T @ 17 mm + result.update({knob: 100 * _knob_value(madx, knob) / k_mcd_max for knob in LHC_KCD_KNOBS}) + + logger.debug("Querying arc short straight sections octupole correctors (MOs) powering") + k_mo_max = 0.29 * 6 / 0.017 ** 3 / madx.globals.brho # 0.29 T @ 17 mm + result.update({knob: 100 * _knob_value(madx, knob) / k_mo_max for knob in LHC_KO_KNOBS}) + return result + + +def query_triplet_correctors_powering(madx: Madx) -> Dict[str, float]: + """ + .. versionadded:: 0.15.0 + + Queries for the triplet corrector strengths and returns their values as a percentage of + their max powering. This is a port of one of the **corr_value.madx** file's macros. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object with an + active (HL)LHC sequence. + + Returns: + A `dict` with the percentage for each corrector. + + Example: + .. code-block:: python + + >>> triplet_knobs = query_triplet_correctors_powering(madx) + """ + logger.debug("Querying triplets correctors powering") + result: Dict[str, float] = {} + + logger.debug("Querying triplet skew quadrupole correctors (MQSXs) powering") + k_mqsx_max = 1.360 / 0.017 / madx.globals.brho # 1.36 T @ 17mm + result.update({knob: 100 * _knob_value(madx, knob) / k_mqsx_max for knob in LHC_KQSX_KNOBS}) + + logger.debug("Querying triplet sextupole correctors (MCSXs) powering") + k_mcsx_max = 0.028 * 2 / 0.017 ** 2 / madx.globals.brho # 0.028 T @ 17 mm + result.update({knob: 100 * _knob_value(madx, knob) / k_mcsx_max for knob in LHC_KCSX_KNOBS}) + + logger.debug("Querying triplet skew sextupole correctors (MCSSXs) powering") + k_mcssx_max = 0.11 * 2 / 0.017 ** 2 / madx.globals.brho # 0.11 T @ 17 mm + result.update({knob: 100 * _knob_value(madx, knob) / k_mcssx_max for knob in LHC_KCSSX_KNOBS}) + + logger.debug("Querying triplet octupole correctors (MCOXs) powering") + k_mcox_max = 0.045 * 6 / 0.017 ** 3 / madx.globals.brho # 0.045 T @ 17 mm + result.update({knob: 100 * _knob_value(madx, knob) / k_mcox_max for knob in LHC_KCOX_KNOBS}) + + logger.debug("Querying triplet skew octupole correctors (MCOSXs) powering") + k_mcosx_max = 0.048 * 6 / 0.017 ** 3 / madx.globals.brho # 0.048 T @ 17 mm + result.update({knob: 100 * _knob_value(madx, knob) / k_mcosx_max for knob in LHC_KCOSX_KNOBS}) + + logger.debug("Querying triplet decapole correctors (MCTXs) powering") + k_mctx_max = 0.01 * 120 / 0.017 ** 5 / madx.globals.brho # 0.010 T @ 17 mm + result.update({knob: 100 * _knob_value(madx, knob) / k_mctx_max for knob in LHC_KCTX_KNOBS}) + return result + + +def get_current_orbit_setup(madx: Madx) -> Dict[str, float]: + """ + .. versionadded:: 0.8.0 + + Get the current values for the (HL)LHC orbit variables. Initial implementation credits go to + :user:`Joschua Dilly `. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + + Returns: + A `dict` of all orbit variables set, and their values as set in the ``MAD-X`` globals. + + Example: + .. code-block:: python + + >>> orbit_setup = get_current_orbit_setup(madx) + """ + logger.debug("Extracting orbit variables from global table") + variables, specials = lhc_orbit_variables() + return {orbit_variable: madx.globals[orbit_variable] for orbit_variable in variables + list(specials.keys())} + + +# ----- Helpers ----- # + + +def _list_field_currents(madx: Madx, brho: Union[str, float] = None) -> None: + """ + Creates additional columns for the ``TWISS`` table with the magnets' total fields + and currents, to help later on determine which proportion of their maximum powering + the current setting is using. This is an implementation of the old utility script + located at **/afs/cern.ch/eng/lhc/optics/V6.503/toolkit/list_fields_currents.madx**. + + .. important:: + Certain quantities are assumed to be defined in the ``MAD-X`` globals, such as + ``brho``, or available in the magnets definition, such as ``calib``. For this + reason, this script most likely only works for the ``(HL)LHC`` sequences where + those are defined. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + brho (Union[str, float]): optional, an explicit definition for the magnetic + rigidity in :math:`Tm^{-1}`. If not given, it will be assumed that + a ``brho`` quantity is defined in the ``MAD-X`` globals and this one will + be used. + """ + logger.debug("Creating additional TWISS table columns for magnets' fields and currents") + + if brho is not None: + logger.trace(f"Setting 'brho' to explicitely defined '{brho}'") + madx.globals["brho"] = brho + + # Define strength := table(twiss, k0l) + ... + table(twiss, k5sl) + table(twiss, hkick) + table(twiss, vkick); + madx.globals["strength"] = ( + " + ".join(f"table(twiss, {a.lower()})" for a in _get_k_strings(stop=6)) + + " + table(twiss, hkick) + table(twiss, vkick)" + ) + + # All here are given as strings to make it deferred expressions in MAD-X + madx.globals["epsilon"] = 1e-20 # to avoid divisions by zero + madx.globals["length"] = "table(twiss, l) + table(twiss, lrad) + epsilon" + madx.globals["kmaxx"] = "table(twiss, kmax) + epsilon" + madx.globals["calibration"] = "table(twiss, calib) + epsilon" + madx.globals["kn"] = "abs(strength) / length" + # madx.globals["rho"] = "kn / (kn + epsilon) / (kn + epsilon)" + + madx.globals["field"] = "kn * brho" + madx.globals["percent"] = "field * 100 / (kmaxx + epsilon)" + madx.globals["ampere"] = "field / calibration" + madx.globals["imax"] = "kmaxx / calibration" + madx.globals["integrated_field"] = "field * length" + + +def _knob_value(madx: Madx, knob: str) -> float: + """ + Queryies the current value of a given *knob* name in the ``MAD-X`` process, and defaults + to 0 (as ``MAD-X`` does) in case that knob has not been defined in the current process. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + knob (str): the name the knob. + + Returns: + The knob value if it was defined, otherwise 0. + + Example: + .. code-block:: python + + >>> _knob_value(madx, knob="underfined_for_sure") + 0 + """ + try: + return madx.globals[knob] + except KeyError: # cpymad gives a 'Variable not defined: var_name' + return 0 diff --git a/pyhdtoolkit/cpymadtools/lhc/_routines.py b/pyhdtoolkit/cpymadtools/lhc/_routines.py new file mode 100644 index 00000000..b60a8232 --- /dev/null +++ b/pyhdtoolkit/cpymadtools/lhc/_routines.py @@ -0,0 +1,186 @@ +import numpy as np + +""" +.. _lhc-routines: + +**Routine Utilities** + +The functions below are routines mimicking manipulations that would be done in the ``LHC``. +""" +import tfs + +from cpymad.madx import Madx +from loguru import logger + +from pyhdtoolkit.cpymadtools.lhc._twiss import get_ir_twiss + + +def do_kmodulation( + madx: Madx, ir: int = 1, side: str = "right", steps: int = 100, stepsize: float = 3e-8, **kwargs +) -> tfs.TfsDataFrame: + r""" + .. versionadded:: 0.20.0 + + Simulates a K-Modulation measurement by varying the powering of Q1 left or + right of the IP, and returning the tune variations resulting from this + modulation. + + .. note:: + At the end of the simulation, the powering of the quadrupole is reset + to the value it had at the time of function call. + + .. tip:: + From these, one can then calculate the :math:`\beta`-functions at the Q1 + and then at the IP, plus the possible waist shift, according to + :cite:t:`Carlier:AccuracyFeasibilityMeasurement2017`. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + ir (int): the IR in which to perform the modulation. Defaults to 1. + side (str): which side of the IP to use the Q1 to perform the modulation. + Should be either ``right`` or ``left``, case-insensitive. Defaults to + ``right``. + steps (int): the number of steps to perform in the modulations, aka the number + of "measurements". Defaults to 100. + stepsize (float): the increment in powering for Q1, in direct values of the + powering variable used in ``MAD-X``. Defaults to 3e-8. + **kwargs: Any additional keyword arguments to pass to down to the ``MAD-X`` + ``TWISS`` command, such as ``chrom``, ``ripken`` or ``centre``. + + Returns: + A `~tfs.TfsDataFrame` containing the tune values at each powering step. + + Example: + + .. code-block:: python + + >>> tune_results = do_kmodulation(madx, ir=1, side="right", steps=100, stepsize=3e-8) + """ + element = f"MQXA.1R{ir:d}" if side.lower() == "right" else f"MQXA.1L{ir:d}" + powering_variable = f"KTQX1.R{ir:d}" if side.lower() == "right" else f"KTQX1.L{ir:d}" + + logger.debug(f"Saving current magnet powering for '{element}'") + old_powering = madx.globals[powering_variable] + minval = old_powering - steps / 2 * stepsize + maxval = old_powering + steps / 2 * stepsize + k_powerings = np.linspace(minval, maxval, steps + 1) + results = tfs.TfsDataFrame( + index=k_powerings, + columns=["K", "TUNEX", "ERRTUNEX", "TUNEY", "ERRTUNEY"], + headers={ + "TITLE": "K-Modulation", + "ELEMENT": element, + "VARIABLE": powering_variable, + "STEPS": steps, + "STEP_SIZE": stepsize, + }, + dtype=float, + ) + + logger.debug(f"Modulating quadrupole '{element}'") + for powering in k_powerings: + logger.trace(f"Modulation of '{element}' - Setting '{powering_variable}' to {powering}") + madx.globals[powering_variable] = powering + df = get_ir_twiss(madx, ir=ir, centre=True, columns=["k1l", "l"], **kwargs) + results.loc[powering].K = df.loc[element.lower()].k1l / df.loc[element.lower()].l # Store K + results.loc[powering].TUNEX = madx.table.summ.q1[0] # Store Qx + results.loc[powering].TUNEY = madx.table.summ.q2[0] # Store Qy + + logger.debug(f"Resetting '{element}' powering") + madx.globals[powering_variable] = old_powering + + results.index.name = powering_variable + results.ERRTUNEX = 0 # No measurement error from MAD-X + results.ERRTUNEY = 0 # No measurement error from MAD-X + return results + + +def correct_lhc_global_coupling( + madx: Madx, beam: int = 1, telescopic_squeeze: bool = True, calls: int = 100, tolerance: float = 1.0e-21 +) -> None: + """ + .. versionadded:: 0.20.0 + + A littly tricky matching routine to perform a decent global coupling correction using + the ``LHC`` coupling knobs. + + .. important:: + This routine makes use of some matching tricks and uses the ``SUMM`` table's + ``dqmin`` variable for the matching. It should be considered a helpful little + trick, but it is not a perfect solution. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + beam (int): which beam you want to perform the matching for, should be `1` or + `2`. Defaults to `1`. + telescopic_squeeze (bool): If set to `True`, uses the coupling knobs + for Telescopic Squeeze configuration. Defaults to `True`. + calls (int): max number of varying calls to perform when matching. Defaults to 100. + tolerance (float): tolerance for successfull matching. Defaults to :math:`10^{-21}`. + + Example: + .. code-block:: python + + >>> correct_lhc_global_coupling(madx, sequence="lhcb1", telescopic_squeeze=True) + """ + suffix = "_sq" if telescopic_squeeze else "" + sequence = f"lhcb{beam:d}" + logger.debug(f"Attempting to correct global coupling through matching, on sequence '{sequence}'") + + real_knob, imag_knob = f"CMRS.b{beam:d}{suffix}", f"CMIS.b{beam:d}{suffix}" + logger.debug(f"Matching using the coupling knobs '{real_knob}' and '{imag_knob}'") + madx.command.match(chrom=True, sequence=sequence) + madx.command.gweight(dqmin=1, Q1=0) + madx.command.global_(dqmin=0, Q1=62.28) + madx.command.vary(name=real_knob, step=1.0e-8) + madx.command.vary(name=imag_knob, step=1.0e-8) + madx.command.lmdif(calls=calls, tolerance=tolerance) + madx.command.endmatch() + + +def correct_lhc_orbit( + madx: Madx, + sequence: str, + orbit_tolerance: float = 1e-14, + iterations: int = 3, + mode: str = "micado", + **kwargs, +) -> None: + """ + .. versionadded:: 0.9.0 + + Routine for orbit correction using ``MCB.*`` elements in the LHC. This uses the + ``CORRECT`` command in ``MAD-X`` behind the scenes, refer to the + `MAD-X manual `_ for + usage information. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + sequence (str): which sequence to use the routine on. + orbit_tolerance (float): the tolerance for the correction. Defaults to 1e-14. + iterations (int): the number of iterations of the correction to perform. + Defaults to 3. + mode (str): the method to use for the correction. Defaults to ``micado`` as in + the `CORRECT` command. + **kwargs: Any keyword argument that can be given to the ``MAD-X`` ``CORRECT`` + command, such as ``mode``, ``ncorr``, etc. + + Example: + .. code-block:: python + + >>> correct_lhc_orbit(madx, sequence="lhcb1", plane="y") + """ + logger.debug("Starting orbit correction") + for default_kicker in ("kicker", "hkicker", "vkicker", "virtualcorrector"): + logger.trace(f"Disabling default corrector class '{default_kicker}'") + madx.command.usekick(sequence=sequence, status="off", class_=default_kicker) + + logger.debug("Selecting '^MCB.*' correctors") + madx.command.usekick(sequence=sequence, status="on", pattern="^MCB.*") + madx.command.usemonitor(sequence=sequence, status="on", class_="monitor") + + for _ in range(iterations): + logger.trace("Doing orbit correction for Y then X plane") + madx.twiss(chrom=True) + madx.command.correct(sequence=sequence, plane="y", flag="ring", error=orbit_tolerance, mode=mode, **kwargs) + madx.command.correct(sequence=sequence, plane="x", flag="ring", error=orbit_tolerance, mode=mode, **kwargs) diff --git a/pyhdtoolkit/cpymadtools/lhc/_setup.py b/pyhdtoolkit/cpymadtools/lhc/_setup.py new file mode 100644 index 00000000..8aa30e91 --- /dev/null +++ b/pyhdtoolkit/cpymadtools/lhc/_setup.py @@ -0,0 +1,530 @@ +""" +.. _lhc-setup: + +**Setup Utilities** + +The functions below are setup utilities for the ``LHC``, to easily get simulations ready. +""" +from pathlib import Path +from typing import Dict, List, Tuple + +from cpymad.madx import Madx +from loguru import logger + +from pyhdtoolkit.cpymadtools.constants import LHC_CROSSING_SCHEMES + +# ----- Setup Utilities ----- # + + +def prepare_lhc_run2( + opticsfile: str, beam: int = 1, use_b4: bool = False, energy: float = 6500, slicefactor: int = None, **kwargs +) -> Madx: + """ + .. versionadded:: 1.0.0 + + Returns a prepared default ``LHC`` setup for the given *opticsfile*, for a Run 2 setup. Both beams + are made with a default Run 2 configuration, and the ``lhcb`` sequence for the given beam is re-cycled + from ``MSIA.EXIT.B{beam}`` as in the ``OMC`` model_creator, and then ``USE``-d. Specific variable settings + can be given as keyword arguments. + + .. important:: + As this is a Run 2 setup, it is assumed that files are organised in the typical setup as found on ``AFS``. + The sequence file will be looked for as a relative location from the optics file: it is assumed that next + to the sequence file is a **PROTON** or **ION** folder with the opticsfiles. + + .. note:: + Matching is **not** performed by this function and should be taken care of by the user, but the working point + should be set by the definitions in the *opticsfile*. Beware that passing specific variables as keyword arguments + might change that working point. + + Args: + opticsfile (str): name of the optics file to be used. Can be the string path to the file or only the opticsfile + name itself, which would be looked for at the **acc-models-lhc/operation/optics/** path. + beam (int): which beam to set up for. Defaults to beam 1. + use_b4 (bool): if `True`, the lhcb4 sequence file will be used. This is the beam 2 sequence but for tracking + purposes. Defaults to `False`. + energy (float): beam energy to set up for, in GeV. Defaults to 6500. + slicefactor (int): if provided, the sequence will be sliced and made thin. Defaults to `None`, + which leads to an unsliced sequence. + **kwargs: if `echo` or `warn` are found in the keyword arguments they will be transmitted as options + to ``MAD-X`` (by default they are given as `False`). Any other keyword argument is transmitted to + the `~cpymad.madx.Madx` creation call. + + Returns: + An instanciated `~cpymad.madx.Madx` object with the required configuration. + + Example: + .. code-block:: python + + >>> madx = prepare_lhc_run2( + ... "/afs/cern.ch/eng/lhc/optics/runII/2018/PROTON/opticsfile.22", beam=2, stdout=True + ... ) + """ + if use_b4 and beam != 2: + logger.error("Cannot use beam 4 sequence file for beam 1") + raise ValueError("Cannot use beam 4 sequence file for beam 1") + + def _run2_sequence_from_opticsfile(opticsfile: Path, use_b4: bool = False) -> Path: + filename = "lhc_as-built.seq" if not use_b4 else "lhcb4_as-built.seq" + seqfile_path = opticsfile.parent.parent / filename + if not seqfile_path.is_file(): + logger.error(f"Could not find sequence file '{filename}' at expected location '{seqfile_path}'") + return seqfile_path + + logger.debug("Creating Run 2 setup MAD-X instance") + echo, warn = kwargs.pop("echo", False), kwargs.pop("warn", False) + + madx = Madx(**kwargs) + madx.option(echo=echo, warn=warn) + logger.debug("Calling sequence") + madx.call(_fullpath(_run2_sequence_from_opticsfile(Path(opticsfile)))) + make_lhc_beams(madx, energy=energy, b4=use_b4) + + if slicefactor: + logger.debug("A slicefactor was provided, slicing the sequence") + make_lhc_thin(madx, sequence=f"lhcb{beam:d}", slicefactor=slicefactor) + make_lhc_beams(madx, energy=energy, b4=use_b4) + + re_cycle_sequence(madx, sequence=f"lhcb{beam:d}", start=f"MSIA.EXIT.B{beam:d}") + + logger.debug("Calling optics file from the 'operation/optics' folder") + madx.call(opticsfile) + + make_lhc_beams(madx, energy=energy, b4=use_b4) + madx.command.use(sequence=f"lhcb{beam:d}") + return madx + + +def prepare_lhc_run3( + opticsfile: str, beam: int = 1, use_b4: bool = False, energy: float = 6800, slicefactor: int = None, **kwargs +) -> Madx: + """ + .. versionadded:: 1.0.0 + + Returns a prepared default ``LHC`` setup for the given *opticsfile*, for a Run 3 setup. Both beams + are made with a default Run 3 configuration, and the provided sequence is re-cycled from ``MSIA.EXIT.[B12]`` + as in the ``OMC`` model_creator, then ``USE``-d. Specific variable settings can be given as keyword arguments. + + .. important:: + As this is a Run 3 setup, it is assumed that the ``acc-models-lhc`` repo is available in the root space,``. + which is needed by the different files in ``acc-models-lhc``. + + .. note:: + Matching is **not** performed by this function and should be taken care of by the user, but the working + point should be set by the variable definitions in the *opticsfile*. + + Args: + opticsfile (str): name of the optics file to be used. Can be the string path to the file or only the opticsfile + name itself, which would be looked for at the **acc-models-lhc/operation/optics/** path. + beam (int): which beam to set up for. Defaults to beam 1. + use_b4 (bool): if `True`, the lhcb4 sequence file will be used. This is the beam 2 sequence but for tracking + purposes. Defaults to `False`. + energy (float): beam energy to set up for, in GeV. Defaults to 6800. + slicefactor (int): if provided, the sequence will be sliced and made thin. Defaults to `None`, + which leads to an unsliced sequence. + **kwargs: if `echo` or `warn` are found in the keyword arguments they will be transmitted as options to ``MAD-X``. + Any other keyword argument is transmitted to the `~cpymad.madx.Madx` creation call. + + Returns: + An instanciated `~cpymad.madx.Madx` object with the required configuration. + + Example: + .. code-block:: python + + >>> madx = prepare_lhc_run3( + ... "R2022a_A30cmC30cmA10mL200cm.madx", slicefactor=4, stdout=True + ... ) + """ + if use_b4 and beam != 2: + logger.error("Cannot use beam 4 sequence file for beam 1") + raise ValueError("Cannot use beam 4 sequence file for beam 1") + + logger.debug("Creating Run 3 setup MAD-X instance") + echo, warn = kwargs.pop("echo", False), kwargs.pop("warn", False) + + madx = Madx(**kwargs) + madx.option(echo=echo, warn=warn) + + sequence = "lhc.seq" if not use_b4 else "lhcb4.seq" + logger.debug(f"Calling sequence file '{sequence}'") + madx.call(f"acc-models-lhc/{sequence}") + make_lhc_beams(madx, energy=energy, b4=use_b4) + + if slicefactor: + logger.debug("A slicefactor was provided, slicing the sequence") + make_lhc_thin(madx, sequence=f"lhcb{beam:d}", slicefactor=slicefactor) + make_lhc_beams(madx, energy=energy, b4=use_b4) + + re_cycle_sequence(madx, sequence=f"lhcb{beam:d}", start=f"MSIA.EXIT.B{beam:d}") + + logger.debug("Calling optics file from the 'operation/optics' folder") + if Path(opticsfile).is_file(): + madx.call(opticsfile) + else: + madx.call(f"acc-models-lhc/operation/optics/{Path(opticsfile).with_suffix('.madx')}") + + make_lhc_beams(madx, energy=energy, b4=use_b4) + madx.command.use(sequence=f"lhcb{beam:d}") + return madx + + +class LHCSetup: + """ + .. versionadded:: 1.0.0 + + This is a context manager to prepare an LHC Run 2 or Run 3 setup: calling sequences and opticsfile, + re-cycling as is done in the ``OMC`` model creator, making beams, potentially slicing, etc. For details + on the achieved setups, look at the `~prepare_lhc_run2` or `~prepare_lhc_run3` functions. + + .. important:: + For the Run 3 setup, it is assumed that the **acc-models-lhc** repo is available in the root space. + + .. note:: + Matching is **not** performed by this setup and should be taken care of by the user, but the working + point should be set by the definitions in the *opticsfile*. + + .. note:: + If you intend to do tracking for beam 2, remember that the ``lhcb4`` sequence needs to be called. + This is handled by giving the ``use_b4`` argument as `True` to the constructor. + + Args: + run (int): which run to set up for, should be 2 or 3. Defaults to run 3. + opticsfile (str): name of the opticsfile to be used. For a Run 2 setup, should be the string path to the file. + For a Run 3 setup, can be the string path to the file or only the opticsfile name itself, which would be + looked for at the **acc-models-lhc/operation/optics/** path. Defaults to `None`, which will raise an error. + beam (int): which beam to set up for. Defaults to beam 1. + use_b4 (bool): if `True`, the lhcb4 sequence file will be used. This is the beam 2 sequence but for tracking + purposes. Defaults to `False`. + energy (float): beam energy to set up for, in GeV. Defaults to 6800, to match the default of run 3. + slicefactor (int): if provided, the sequence will be sliced and "made thin". Defaults to `None`, + which leads to an unsliced sequence. + **kwargs: if `echo` or `warn` are found in the keyword arguments they will be transmitted as options to ``MAD-X``. + Any other keyword argument is transmitted to the `~cpymad.madx.Madx` creation call. + + Returns: + An instanciated context manager `~cpymad.madx.Madx` object with the required configuration. + + Raises: + NotImplementedError: if the *run* argument is not 2 or 3. + AssertionError: if the *opticsfile* argument is not provided. + + Examples: + + Get a Run 2 setup for beam 2: + + .. code-block:: python + + >>> with LHCSetup(run=2, opticsfile="2018/PROTON/opticsfile.22", beam=2) as madx: + ... # do some stuff + + Get a Run 3 setup for beam 1, with a sliced sequence and muted output: + + .. code-block:: python + + >>> with LHCSetup(run=3, opticsfile="R2022a_A30cmC30cmA10mL200cm.madx", slicefactor=4, stdout=False) as madx: + ... # do some stuff + """ + + def __init__( + self, + run: int = 3, + opticsfile: str = None, + beam: int = 1, + use_b4: bool = False, + energy: float = 6800, + slicefactor: int = None, + **kwargs, + ): + assert opticsfile is not None, "An opticsfile must be provided" + if use_b4 and beam != 2: + logger.error("Cannot use beam 4 sequence file for beam 1") + raise ValueError("Cannot use beam 4 sequence file for beam 1") + + if int(run) not in (2, 3): + raise NotImplementedError("This setup is only possible for Run 2 and Run 3 configurations.") + elif run == 2: + self.madx = prepare_lhc_run2( + opticsfile=opticsfile, beam=beam, use_b4=use_b4, energy=energy, slicefactor=slicefactor, **kwargs + ) + else: + self.madx = prepare_lhc_run3( + opticsfile=opticsfile, beam=beam, use_b4=use_b4, energy=energy, slicefactor=slicefactor, **kwargs + ) + + def __enter__(self): + return self.madx + + def __exit__(self, *exc_info): + self.madx.quit() + + +# ----- Configuration Utlites ----- # + + +def make_lhc_beams( + madx: Madx, + energy: float = 7000, + emittance_x: float = 3.75e-6, + emittance_y: float = 3.75e-6, + b4: bool = False, + **kwargs, +) -> None: + """ + .. versionadded:: 0.15.0 + + Defines beams with default configuratons for ``LHCB1`` and ``LHCB2`` sequences. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + energy (float): beam energy, in [GeV]. Defaults to 6500. + emittance_x (float): horizontal emittance in [m]. Will be used to calculate + geometric emittance which is then fed to the ``BEAM`` command. + emittance_y (float): vertical emittance in [m]. Will be used to calculate + geometric emittance which is then fed to the ``BEAM`` command. + b4 (bool): if `True`, will consider one is using ``lhb4`` to do tracking on beam 2, + and will properly set the ``bv`` flag to 1. Defaults to `False`. + **kwargs: Any keyword argument that can be given to the ``MAD-X`` ``BEAM`` command. + + Examples: + + .. code-block:: python + + >>> make_lhc_beams(madx, energy=6800, emittance_x=2.5e-6, emittance_y=3e-6) + + Setting up in a way compatible for tracking of beam 2 (needs to call ``lhcb4`` and set + ``bv`` to 1): + + .. code-block:: python + + >>> make_lhc_beams(madx, energy=6800, emittance_x=2.5e-6, emittance_y=3e-6, b4=True) + """ + logger.debug("Making default beams for 'lhcb1' and 'lhbc2' sequences") + madx.globals["NRJ"] = energy + madx.globals["brho"] = energy * 1e9 / madx.globals.clight + geometric_emit_x = madx.globals["geometric_emit_x"] = emittance_x / (energy / 0.938) + geometric_emit_y = madx.globals["geometric_emit_y"] = emittance_y / (energy / 0.938) + + for beam in (1, 2): + bv = 1 if beam == 1 or b4 is True else -1 + logger.debug(f"Defining beam for sequence 'lhcb{beam:d}'") + madx.command.beam( + sequence=f"lhcb{beam:d}", + particle="proton", + bv=bv, + energy=energy, + npart=1.15e11, + ex=geometric_emit_x, + ey=geometric_emit_y, + sige=4.5e-4, + **kwargs, + ) + + +def make_lhc_thin(madx: Madx, sequence: str, slicefactor: int = 1, **kwargs) -> None: + """ + .. versionadded:: 0.15.0 + + Executes the ``MAKETHIN`` command for the LHC sequence as previously done in ``MAD-X`` macros. + This will use the ``teapot`` style and will enforce ``makedipedge``. + + One can find an exemple use of this function in the :ref:`AC Dipole Tracking ` + and :ref:`Free Tracking ` example galleries. + + Args: + madx (cpymad.madx.Madx): an instantiated `~cpymad.madx.Madx` object. + sequence (str): the sequence to use for the ``MAKETHIN`` command. + slicefactor (int): the slice factor to apply in ``MAKETHIN``, which is a factor + applied to default values for different elements, as did the old macro. Defaults + to 1. + **kwargs: any keyword argument will be transmitted to the ``MAD-X`` ``MAKETHN`` + command, namely ``style`` (will default to ``teapot``) and the ``makedipedge`` + flag (will default to `True`). + + Example: + .. code-block:: python + + >>> make_lhc_thin(madx, sequence="lhcb1", slicefactor=4) + """ + logger.debug(f"Slicing sequence '{sequence}'") + madx.select(flag="makethin", clear=True) + four_slices_patterns = [r"mbx\.", r"mbrb\.", r"mbrc\.", r"mbrs\."] + four_slicefactor_patterns = [ + r"mqwa\.", + r"mqwb\.", + r"mqy\.", + r"mqm\.", + r"mqmc\.", + r"mqml\.", + r"mqtlh\.", + r"mqtli\.", + r"mqt\.", + ] + + logger.debug("Defining slices for general MB and MQ elements") + madx.select(flag="makethin", class_="MB", slice_=2) + madx.select(flag="makethin", class_="MQ", slice_=2 * slicefactor) + + logger.debug("Defining slices for triplets") + madx.select(flag="makethin", class_="mqxa", slice_=16 * slicefactor) + madx.select(flag="makethin", class_="mqxb", slice_=16 * slicefactor) + + logger.debug("Defining slices for various specifc mb elements") + for pattern in four_slices_patterns: + madx.select(flag="makethin", pattern=pattern, slice_=4) + + logger.debug("Defining slices for varous specifc mq elements") + for pattern in four_slicefactor_patterns: + madx.select(flag="makethin", pattern=pattern, slice_=4 * slicefactor) + + madx.use(sequence=sequence) + style = kwargs.get("style", "teapot") + makedipedge = kwargs.get("makedipedge", False) # defaults to False to compensate default TEAPOT style + madx.command.makethin(sequence=sequence, style=style, makedipedge=makedipedge) + + +def re_cycle_sequence(madx: Madx, sequence: str = "lhcb1", start: str = "IP3") -> None: + """ + .. versionadded:: 0.15.0 + + Re-cycles the provided *sequence* from a different starting point, given as *start*. + + One can find an exemple use of this function in the :ref:`AC Dipole Tracking ` + and :ref:`Free Tracking ` example galleries. + + Args: + madx (cpymad.madx.Madx): an instantiated `~cpymad.madx.Madx` object. + sequence (str): the sequence to re-cycle. + start (str): element to start the new cycle from. + + Example: + .. code-block:: python + + >>> re_cycle_sequence(madx, sequence="lhcb1", start="MSIA.EXIT.B1") + """ + logger.debug(f"Re-cycling sequence '{sequence}' from {start}") + madx.command.seqedit(sequence=sequence) + madx.command.flatten() + madx.command.cycle(start=start) + madx.command.endedit() + + +def lhc_orbit_variables() -> Tuple[List[str], Dict[str, str]]: + """ + .. versionadded:: 0.8.0 + + Get the variable names used for orbit setup in the (HL)LHC. Initial implementation + credits go to :user:`Joschua Dilly `. + + Returns: + A `tuple` with a `list` of all orbit variables, and a `dict` of additional variables, + that in the default configurations have the same value as another variable. + + Example: + .. code-block:: python + + >>> variables, specials = lhc_orbit_variables() + """ + logger.trace("Returning (HL)LHC orbit variables") + on_variables = ( + "crab1", + "crab5", # exists only in HL-LHC + "x1", + "sep1", + "o1", + "oh1", + "ov1", + "x2", + "sep2", + "o2", + "oe2", + "a2", + "oh2", + "ov2", + "x5", + "sep5", + "o5", + "oh5", + "ov5", + "x8", + "sep8", + "o8", + "a8", + "sep8h", + "x8v", + "oh8", + "ov8", + "alice", + "sol_alice", + "lhcb", + "sol_atlas", + "sol_cms", + ) + variables = [f"on_{var}" for var in on_variables] + [f"phi_IR{ir:d}" for ir in (1, 2, 5, 8)] + special = { + "on_ssep1": "on_sep1", + "on_xx1": "on_x1", + "on_ssep5": "on_sep5", + "on_xx5": "on_x5", + } + return variables, special + + +def setup_lhc_orbit(madx: Madx, scheme: str = "flat", **kwargs) -> Dict[str, float]: + """ + .. versionadded:: 0.8.0 + + Automated orbit setup for (HL)LHC runs, for some default schemes. It is assumed that at + least sequence and optics files have been called. Initial implementation credits go to + :user:`Joschua Dilly `. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + scheme (str): the default scheme to apply, as defined in the ``LHC_CROSSING_SCHEMES`` + constant. Accepted values are keys of `LHC_CROSSING_SCHEMES`. Defaults to *flat* + (every orbit variable to 0). + **kwargs: Any standard crossing scheme variables (``on_x1``, ``phi_IR1``, etc). Values + given here override the values in the default scheme configurations. + + Returns: + A `dict` of all orbit variables set, and their values as set in the ``MAD-X`` globals. + + Example: + .. code-block:: python + + >>> orbit_setup = setup_lhc_orbit(madx, scheme="lhc_top") + """ + if scheme not in LHC_CROSSING_SCHEMES.keys(): + logger.error(f"Invalid scheme parameter, should be one of {LHC_CROSSING_SCHEMES.keys()}") + raise ValueError("Invalid scheme parameter given") + + logger.debug("Getting orbit variables") + variables, special = lhc_orbit_variables() + + scheme_dict = LHC_CROSSING_SCHEMES[scheme] + final_scheme = {} + + for orbit_variable in variables: + variable_value = kwargs.get(orbit_variable, scheme_dict.get(orbit_variable, 0)) + logger.trace(f"Setting orbit variable '{orbit_variable}' to {variable_value}") + # Sets value in MAD-X globals & returned dict, taken from scheme dict or kwargs if provided + madx.globals[orbit_variable] = final_scheme[orbit_variable] = variable_value + + for special_variable, copy_from in special.items(): + special_variable_value = kwargs.get(special_variable, madx.globals[copy_from]) + logger.trace(f"Setting special orbit variable '{special_variable}' to {special_variable_value}") + # Sets value in MAD-X globals & returned dict, taken from a given global or kwargs if provided + madx.globals[special_variable] = final_scheme[special_variable] = special_variable_value + + return final_scheme + + +# ----- Helpers ----- # + + +def _fullpath(filepath: Path) -> str: + """ + .. versionadded:: 1.0.0 + + Returns the full string path to the provided *filepath*. + """ + return str(filepath.absolute()) diff --git a/pyhdtoolkit/cpymadtools/lhc/_twiss.py b/pyhdtoolkit/cpymadtools/lhc/_twiss.py new file mode 100644 index 00000000..51da9a38 --- /dev/null +++ b/pyhdtoolkit/cpymadtools/lhc/_twiss.py @@ -0,0 +1,78 @@ +""" +.. _lhc-twiss: + +**Twiss Utilities** + +The functions below are twiss utilities for the ``LHC`` insertion regions. +""" +from typing import Sequence + +import tfs + +from cpymad.madx import Madx +from loguru import logger + +from pyhdtoolkit.cpymadtools import twiss +from pyhdtoolkit.cpymadtools.constants import DEFAULT_TWISS_COLUMNS + + +def get_ips_twiss(madx: Madx, columns: Sequence[str] = DEFAULT_TWISS_COLUMNS, **kwargs) -> tfs.TfsDataFrame: + """ + .. versionadded:: 0.9.0 + + Quickly get the ``TWISS`` table for certain variables at IP locations only. The ``SUMM`` table will be + included as the `~tfs.frame.TfsDataFrame`'s header dictionary. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + columns (Sequence[str]): the variables to be returned, as columns in the DataFrame. + **kwargs: Any keyword argument that can be given to the ``MAD-X`` ``TWISS`` command, such as ``chrom``, + ``ripken``, ``centre``; or starting coordinates with ``betx``, ``bety`` etc. + + Returns: + A `~tfs.frame.TfsDataFrame` of the ``TWISS`` table's sub-selection. + + Example: + .. code-block:: python + + >>> ips_df = get_ips_twiss(madx, chrom=True, ripken=True) + """ + logger.debug("Getting Twiss at IPs") + return twiss.get_pattern_twiss(madx=madx, columns=columns, patterns=["IP"], **kwargs) + + +def get_ir_twiss(madx: Madx, ir: int, columns: Sequence[str] = DEFAULT_TWISS_COLUMNS, **kwargs) -> tfs.TfsDataFrame: + """ + .. versionadded:: 0.9.0 + + Quickly get the ``TWISS`` table for certain variables for one Interaction Region, meaning at the IP and + Q1 to Q3 both left and right of the IP. The ``SUMM`` table will be included as the `~tfs.frame.TfsDataFrame`'s + header dictionary. + + Args: + madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. + ir (int): which interaction region to get the TWISS for. + columns (Sequence[str]): the variables to be returned, as columns in the DataFrame. + **kwargs: Any keyword argument that can be given to the ``MAD-X`` ``TWISS`` command, such as ``chrom``, + ``ripken``, ``centre``; or starting coordinates with ``betx``, ``bety`` etc. + + Returns: + A `~tfs.frame.TfsDataFrame` of the ``TWISS`` table's sub-selection. + + Example: + .. code-block:: python + + >>> ir_df = get_ir_twiss(madx, chrom=True, ripken=True) + """ + logger.debug(f"Getting Twiss for IR{ir:d}") + return twiss.get_pattern_twiss( + madx=madx, + columns=columns, + patterns=[ + f"IP{ir:d}", + f"MQXA.[12345][RL]{ir:d}", # Q1 and Q3 LHC + f"MQXB.[AB][12345][RL]{ir:d}", # Q2A and Q2B LHC + f"MQXF[AB].[AB][12345][RL]{ir:d}", # Q1 to Q3 A and B HL-LHC + ], + **kwargs, + ) diff --git a/pyhdtoolkit/cpymadtools/orbit.py b/pyhdtoolkit/cpymadtools/orbit.py deleted file mode 100644 index a952d20a..00000000 --- a/pyhdtoolkit/cpymadtools/orbit.py +++ /dev/null @@ -1,198 +0,0 @@ -""" -.. _cpymadtools-orbit: - -Orbit Handling --------------- - -Module with functions to perform ``MAD-X`` orbit setup through a `~cpymad.madx.Madx` object, -mainly for LHC and HLLHC machines. -""" -from typing import Dict, List, Tuple - -from cpymad.madx import Madx -from loguru import logger - -from pyhdtoolkit.cpymadtools.constants import LHC_CROSSING_SCHEMES - -# ----- Utilities ----- # - - -def lhc_orbit_variables() -> Tuple[List[str], Dict[str, str]]: - """ - .. versionadded:: 0.8.0 - - Get the variable names used for orbit setup in the (HL)LHC. Initial implementation - credits go to :user:`Joschua Dilly `. - - Returns: - A `tuple` with a `list` of all orbit variables, and a `dict` of additional variables, - that in the default configurations have the same value as another variable. - - Example: - .. code-block:: python - - >>> variables, specials = lhc_orbit_variables() - """ - logger.trace("Returning (HL)LHC orbit variables") - on_variables = ( - "crab1", - "crab5", # exists only in HL-LHC - "x1", - "sep1", - "o1", - "oh1", - "ov1", - "x2", - "sep2", - "o2", - "oe2", - "a2", - "oh2", - "ov2", - "x5", - "sep5", - "o5", - "oh5", - "ov5", - "x8", - "sep8", - "o8", - "a8", - "sep8h", - "x8v", - "oh8", - "ov8", - "alice", - "sol_alice", - "lhcb", - "sol_atlas", - "sol_cms", - ) - variables = [f"on_{var}" for var in on_variables] + [f"phi_IR{ir:d}" for ir in (1, 2, 5, 8)] - special = { - "on_ssep1": "on_sep1", - "on_xx1": "on_x1", - "on_ssep5": "on_sep5", - "on_xx5": "on_x5", - } - return variables, special - - -def setup_lhc_orbit(madx: Madx, scheme: str = "flat", **kwargs) -> Dict[str, float]: - """ - .. versionadded:: 0.8.0 - - Automated orbit setup for (HL)LHC runs, for some default schemes. It is assumed that at - least sequence and optics files have been called. Initial implementation credits go to - :user:`Joschua Dilly `. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - scheme (str): the default scheme to apply, as defined in the ``LHC_CROSSING_SCHEMES`` - constant. Accepted values are keys of `LHC_CROSSING_SCHEMES`. Defaults to *flat* - (every orbit variable to 0). - **kwargs: Any standard crossing scheme variables (``on_x1``, ``phi_IR1``, etc). Values - given here override the values in the default scheme configurations. - - Returns: - A `dict` of all orbit variables set, and their values as set in the ``MAD-X`` globals. - - Example: - .. code-block:: python - - >>> orbit_setup = setup_lhc_orbit(madx, scheme="lhc_top") - """ - if scheme not in LHC_CROSSING_SCHEMES.keys(): - logger.error(f"Invalid scheme parameter, should be one of {LHC_CROSSING_SCHEMES.keys()}") - raise ValueError("Invalid scheme parameter given") - - logger.debug("Getting orbit variables") - variables, special = lhc_orbit_variables() - - scheme_dict = LHC_CROSSING_SCHEMES[scheme] - final_scheme = {} - - for orbit_variable in variables: - variable_value = kwargs.get(orbit_variable, scheme_dict.get(orbit_variable, 0)) - logger.trace(f"Setting orbit variable '{orbit_variable}' to {variable_value}") - # Sets value in MAD-X globals & returned dict, taken from scheme dict or kwargs if provided - madx.globals[orbit_variable] = final_scheme[orbit_variable] = variable_value - - for special_variable, copy_from in special.items(): - special_variable_value = kwargs.get(special_variable, madx.globals[copy_from]) - logger.trace(f"Setting special orbit variable '{special_variable}' to {special_variable_value}") - # Sets value in MAD-X globals & returned dict, taken from a given global or kwargs if provided - madx.globals[special_variable] = final_scheme[special_variable] = special_variable_value - - return final_scheme - - -def get_current_orbit_setup(madx: Madx) -> Dict[str, float]: - """ - .. versionadded:: 0.8.0 - - Get the current values for the (HL)LHC orbit variables. Initial implementation credits go to - :user:`Joschua Dilly `. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - - Returns: - A `dict` of all orbit variables set, and their values as set in the ``MAD-X`` globals. - - Example: - .. code-block:: python - - >>> orbit_setup = get_current_orbit_setup(madx) - """ - logger.debug("Extracting orbit variables from global table") - variables, specials = lhc_orbit_variables() - return {orbit_variable: madx.globals[orbit_variable] for orbit_variable in variables + list(specials.keys())} - - -def correct_lhc_orbit( - madx: Madx, - sequence: str, - orbit_tolerance: float = 1e-14, - iterations: int = 3, - mode: str = "micado", - **kwargs, -) -> None: - """ - .. versionadded:: 0.9.0 - - Routine for orbit correction using ``MCB.*`` elements in the LHC. This uses the - ``CORRECT`` command in ``MAD-X`` behind the scenes, refer to the - `MAD-X manual `_ for - usage information. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - sequence (str): which sequence to use the routine on. - orbit_tolerance (float): the tolerance for the correction. Defaults to 1e-14. - iterations (int): the number of iterations of the correction to perform. - Defaults to 3. - mode (str): the method to use for the correction. Defaults to ``micado`` as in - the `CORRECT` command. - **kwargs: Any keyword argument that can be given to the ``MAD-X`` ``CORRECT`` - command, such as ``mode``, ``ncorr``, etc. - - Example: - .. code-block:: python - - >>> correct_lhc_orbit(madx, sequence="lhcb1", plane="y") - """ - logger.debug("Starting orbit correction") - for default_kicker in ("kicker", "hkicker", "vkicker", "virtualcorrector"): - logger.trace(f"Disabling default corrector class '{default_kicker}'") - madx.command.usekick(sequence=sequence, status="off", class_=default_kicker) - - logger.debug("Selecting '^MCB.*' correctors") - madx.command.usekick(sequence=sequence, status="on", pattern="^MCB.*") - madx.command.usemonitor(sequence=sequence, status="on", class_="monitor") - - for _ in range(iterations): - logger.trace("Doing orbit correction for Y then X plane") - madx.twiss(chrom=True) - madx.command.correct(sequence=sequence, plane="y", flag="ring", error=orbit_tolerance, mode=mode, **kwargs) - madx.command.correct(sequence=sequence, plane="x", flag="ring", error=orbit_tolerance, mode=mode, **kwargs) diff --git a/pyhdtoolkit/cpymadtools/setup.py b/pyhdtoolkit/cpymadtools/setup.py deleted file mode 100644 index c0c7be69..00000000 --- a/pyhdtoolkit/cpymadtools/setup.py +++ /dev/null @@ -1,268 +0,0 @@ -""" -.. _cpymadtools-setup: - -MAD-X Setup Utilities ---------------------- - -Module with a few convenient functions and context managers to easily set up machine in ``MAD-X``. -So far functionality is implemented for either Run 2 or Run 3 type simulations of the LHC. -""" -from pathlib import Path - -from cpymad.madx import Madx -from loguru import logger - -from pyhdtoolkit.cpymadtools import lhc - - -def prepare_lhc_run2( - opticsfile: str, beam: int = 1, use_b4: bool = False, energy: float = 6500, slicefactor: int = None, **kwargs -) -> Madx: - """ - .. versionadded:: 1.0.0 - - Returns a prepared default ``LHC`` setup for the given *opticsfile*, for a Run 2 setup. Both beams are made with a default Run III - configuration, and the ``lhcb1`` sequence is re-cycled from ``MSIA.EXIT.B1`` as in the ``OMC`` model_creator, and - then ``USE``-d. Specific variable settings can be given as keyword arguments. - - .. important:: - As this is a Run 2 setup, it is assumed that files are organised in the typical setup as found on ``AFS``. - The sequence file will be looked for as a relative location from the optics file: it is assumed that next - to the sequence file is a **PROTON** or **ION** folder with the opticsfiles. - - .. note:: - Matching is **not** performed by this function and should be taken care of by the user, but the working point - should be set by the definitions in the *opticsfile*. Beware that passing specific variables as keyword arguments - might change that working point. - - Args: - opticsfile (str): name of the optics file to be used. Can be the string path to the file or only the opticsfile - name itself, which would be looked for at the **acc-models-lhc/operation/optics/** path. - beam (int): which beam to set up for. Defaults to beam 1. - use_b4 (bool): if `True`, the lhcb4 sequence file will be used. This is the beam 2 sequence but for tracking - purposes. Defaults to `False`. - energy (float): beam energy to set up for, in GeV. Defaults to 6500. - slicefactor (int): if provided, the sequence will be sliced and made thin. Defaults to `None`, - which leads to an unsliced sequence. - **kwargs: if `echo` or `warn` are found in the keyword arguments they will be transmitted as options - to ``MAD-X`` (by default they are given as `False`). Any other keyword argument is transmitted to - the `~cpymad.madx.Madx` creation call. - - Returns: - An instanciated `~cpymad.madx.Madx` object with the required configuration. - - Example: - .. code-block:: python - - >>> madx = prepare_lhc_run2( - ... "/afs/cern.ch/eng/lhc/optics/runII/2018/PROTON/opticsfile.22", beam=2, stdout=True - ... ) - """ - if use_b4 and beam != 2: - logger.error("Cannot use beam 4 sequence file for beam 1") - raise ValueError("Cannot use beam 4 sequence file for beam 1") - - def _run2_sequence_from_opticsfile(opticsfile: Path, use_b4: bool = False) -> Path: - filename = "lhc_as-built.seq" if not use_b4 else "lhcb4_as-built.seq" - seqfile_path = opticsfile.parent.parent / filename - if not seqfile_path.is_file(): - logger.error("Could not find sequence file '{filename}' at expected location '{seqfile_path}'") - return seqfile_path - - logger.debug("Creating Run 3 setup MAD-X instance") - echo, warn = kwargs.pop("echo", False), kwargs.pop("warn", False) - - madx = Madx(**kwargs) - madx.option(echo=echo, warn=warn) - logger.debug("Calling sequence") - madx.call(_fullpath(_run2_sequence_from_opticsfile(Path(opticsfile)), use_b4=use_b4)) - lhc.make_lhc_beams(madx, energy=energy, b4=use_b4) - - if slicefactor: - logger.debug("A slicefactor was provided, slicing the sequence") - lhc.make_lhc_thin(madx, sequence=f"lhcb{beam:d}", slicefactor=slicefactor) - lhc.make_lhc_beams(madx, energy=energy, b4=use_b4) - - lhc.re_cycle_sequence(madx, sequence=f"lhcb{beam:d}", start=f"MSIA.EXIT.B{beam:d}") - - logger.debug("Calling optics file from the 'operation/optics' folder") - madx.call(opticsfile) - - lhc.make_lhc_beams(madx, energy=energy, b4=use_b4) - madx.command.use(sequence=f"lhcb{beam:d}") - return madx - - -def prepare_lhc_run3( - opticsfile: str, beam: int = 1, use_b4: bool = False, energy: float = 6800, slicefactor: int = None, **kwargs -) -> Madx: - """ - .. versionadded:: 1.0.0 - - Returns a prepared default ``LHC`` setup for the given *opticsfile*, for a Run 3 setup. Both beams - are made with a default Run 3 configuration, and the provided sequence is re-cycled from ``MSIA.EXIT.[B12]`` - as in the ``OMC`` model_creator, then ``USE``-d. Specific variable settings can be given as keyword arguments. - - .. important:: - As this is a Run 3 setup, it is assumed that the ``acc-models-lhc`` repo is available in the root space,``. - which is needed by the different files in ``acc-models-lhc``. - - .. note:: - Matching is **not** performed by this function and should be taken care of by the user, but the working - point should be set by the variable definitions in the *opticsfile*. - - Args: - opticsfile (str): name of the optics file to be used. Can be the string path to the file or only the opticsfile - name itself, which would be looked for at the **acc-models-lhc/operation/optics/** path. - beam (int): which beam to set up for. Defaults to beam 1. - use_b4 (bool): if `True`, the lhcb4 sequence file will be used. This is the beam 2 sequence but for tracking - purposes. Defaults to `False`. - energy (float): beam energy to set up for, in GeV. Defaults to 6800. - slicefactor (int): if provided, the sequence will be sliced and made thin. Defaults to `None`, - which leads to an unsliced sequence. - **kwargs: if `echo` or `warn` are found in the keyword arguments they will be transmitted as options to ``MAD-X``. - Any other keyword argument is transmitted to the `~cpymad.madx.Madx` creation call. - - Returns: - An instanciated `~cpymad.madx.Madx` object with the required configuration. - - Example: - .. code-block:: python - - >>> madx = prepare_lhc_run3( - ... "R2022a_A30cmC30cmA10mL200cm.madx", slicefactor=4, stdout=True - ... ) - """ - if use_b4 and beam != 2: - logger.error("Cannot use beam 4 sequence file for beam 1") - raise ValueError("Cannot use beam 4 sequence file for beam 1") - - logger.debug("Creating Run 3 setup MAD-X instance") - echo, warn = kwargs.pop("echo", False), kwargs.pop("warn", False) - - madx = Madx(**kwargs) - madx.option(echo=echo, warn=warn) - - sequence = "lhc.seq" if not use_b4 else "lhcb4.seq" - logger.debug(f"Calling sequence file '{sequence}'") - madx.call(f"acc-models-lhc/{sequence}") - lhc.make_lhc_beams(madx, energy=energy, b4=use_b4) - - if slicefactor: - logger.debug("A slicefactor was provided, slicing the sequence") - lhc.make_lhc_thin(madx, sequence=f"lhcb{beam:d}", slicefactor=slicefactor) - lhc.make_lhc_beams(madx, energy=energy, b4=use_b4) - - lhc.re_cycle_sequence(madx, sequence=f"lhcb{beam:d}", start=f"MSIA.EXIT.B{beam:d}") - - logger.debug("Calling optics file from the 'operation/optics' folder") - if Path(opticsfile).is_file(): - madx.call(opticsfile) - else: - madx.call(f"acc-models-lhc/operation/optics/{Path(opticsfile).with_suffix('.madx')}") - - lhc.make_lhc_beams(madx, energy=energy, b4=use_b4) - madx.command.use(sequence=f"lhcb{beam:d}") - return madx - - -class LHCSetup: - """ - .. versionadded:: 1.0.0 - - This is a context manager to prepare an LHC Run 2 or Run 3 setup: calling sequences and opticsfile, - re-cycling as is done in the ``OMC`` model creator, making beams, potentially slicing, etc. For details - on the achieved setups, look at the `~prepare_lhc_run2` or `~prepare_lhc_run3` functions. - - .. important:: - For the Run 3 setup, it is assumed that the **acc-models-lhc** repo is available in the root space. - - .. note:: - Matching is **not** performed by this setup and should be taken care of by the user, but the working - point should be set by the definitions in the *opticsfile*. - - .. note:: - If you intend to do tracking for beam 2, remember that the ``lhcb4`` sequence needs to be called. - This is handled by giving the ``use_b4`` argument as `True` to the constructor. - - Args: - run (int): which run to set up for, should be 2 or 3. Defaults to run 3. - opticsfile (str): name of the opticsfile to be used. For a Run 2 setup, should be the string path to the file. - For a Run 3 setup, can be the string path to the file or only the opticsfile name itself, which would be - looked for at the **acc-models-lhc/operation/optics/** path. Defaults to `None`, which will raise an error. - beam (int): which beam to set up for. Defaults to beam 1. - use_b4 (bool): if `True`, the lhcb4 sequence file will be used. This is the beam 2 sequence but for tracking - purposes. Defaults to `False`. - energy (float): beam energy to set up for, in GeV. Defaults to 6800, to match the default of run 3. - slicefactor (int): if provided, the sequence will be sliced and "made thin". Defaults to `None`, - which leads to an unsliced sequence. - **kwargs: if `echo` or `warn` are found in the keyword arguments they will be transmitted as options to ``MAD-X``. - Any other keyword argument is transmitted to the `~cpymad.madx.Madx` creation call. - - Returns: - An instanciated context manager `~cpymad.madx.Madx` object with the required configuration. - - Raises: - NotImplementedError: if the *run* argument is not 2 or 3. - AssertionError: if the *opticsfile* argument is not provided. - - Examples: - - Get a Run 2 setup for beam 2: - - .. code-block:: python - - >>> with LHCSetup(run=2, opticsfile="2018/PROTON/opticsfile.22", beam=2) as madx: - ... # do some stuff - - Get a Run 3 setup for beam 1, with a sliced sequence and muted output: - - .. code-block:: python - - >>> with LHCSetup(run=3, opticsfile="R2022a_A30cmC30cmA10mL200cm.madx", slicefactor=4, stdout=False) as madx: - ... # do some stuff - """ - - def __init__( - self, - run: int = 3, - opticsfile: str = None, - beam: int = 1, - use_b4: bool = False, - energy: float = 6800, - slicefactor: int = None, - **kwargs, - ): - assert opticsfile is not None, "An opticsfile must be provided" - if use_b4 and beam != 2: - logger.error("Cannot use beam 4 sequence file for beam 1") - raise ValueError("Cannot use beam 4 sequence file for beam 1") - - if int(run) not in (2, 3): - raise NotImplementedError("This setup is only possible for Run 2 and Run 3 configurations.") - elif run == 2: - self.madx = prepare_lhc_run2( - opticsfile=opticsfile, beam=beam, use_b4=use_b4, energy=energy, slicefactor=slicefactor, **kwargs - ) - else: - self.madx = prepare_lhc_run3( - opticsfile=opticsfile, beam=beam, use_b4=use_b4, energy=energy, slicefactor=slicefactor, **kwargs - ) - - def __enter__(self): - return self.madx - - def __exit__(self, *exc_info): - self.madx.quit() - - -# ----- Helpers ----- # - - -def _fullpath(filepath: Path) -> str: - """ - .. versionadded:: 1.0.0 - - Returns the full string path to the provided *filepath*. - """ - return str(filepath.absolute()) diff --git a/pyhdtoolkit/cpymadtools/twiss.py b/pyhdtoolkit/cpymadtools/twiss.py index 4bf9093d..ed1b1cbc 100644 --- a/pyhdtoolkit/cpymadtools/twiss.py +++ b/pyhdtoolkit/cpymadtools/twiss.py @@ -129,65 +129,3 @@ def get_twiss_tfs(madx: Madx, **kwargs) -> tfs.TfsDataFrame: twiss_tfs.index = twiss_tfs.index.str.upper() twiss_tfs.headers = {var.upper(): madx.table.summ[var][0] for var in madx.table.summ} return twiss_tfs - - -def get_ips_twiss(madx: Madx, columns: Sequence[str] = DEFAULT_TWISS_COLUMNS, **kwargs) -> tfs.TfsDataFrame: - """ - .. versionadded:: 0.9.0 - - Quickly get the ``TWISS`` table for certain variables at IP locations only. The ``SUMM`` table will be - included as the `~tfs.frame.TfsDataFrame`'s header dictionary. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - columns (Sequence[str]): the variables to be returned, as columns in the DataFrame. - **kwargs: Any keyword argument that can be given to the ``MAD-X`` ``TWISS`` command, such as ``chrom``, - ``ripken``, ``centre``; or starting coordinates with ``betx``, ``bety`` etc. - - Returns: - A `~tfs.frame.TfsDataFrame` of the ``TWISS`` table's sub-selection. - - Example: - .. code-block:: python - - >>> ips_df = get_ips_twiss(madx, chrom=True, ripken=True) - """ - logger.debug("Getting Twiss at IPs") - return get_pattern_twiss(madx=madx, columns=columns, patterns=["IP"], **kwargs) - - -def get_ir_twiss(madx: Madx, ir: int, columns: Sequence[str] = DEFAULT_TWISS_COLUMNS, **kwargs) -> tfs.TfsDataFrame: - """ - .. versionadded:: 0.9.0 - - Quickly get the ``TWISS`` table for certain variables for one Interaction Region, meaning at the IP and - Q1 to Q3 both left and right of the IP. The ``SUMM`` table will be included as the `~tfs.frame.TfsDataFrame`'s - header dictionary. - - Args: - madx (cpymad.madx.Madx): an instanciated `~cpymad.madx.Madx` object. - ir (int): which interaction region to get the TWISS for. - columns (Sequence[str]): the variables to be returned, as columns in the DataFrame. - **kwargs: Any keyword argument that can be given to the ``MAD-X`` ``TWISS`` command, such as ``chrom``, - ``ripken``, ``centre``; or starting coordinates with ``betx``, ``bety`` etc. - - Returns: - A `~tfs.frame.TfsDataFrame` of the ``TWISS`` table's sub-selection. - - Example: - .. code-block:: python - - >>> ir_df = get_ir_twiss(madx, chrom=True, ripken=True) - """ - logger.debug(f"Getting Twiss for IR{ir:d}") - return get_pattern_twiss( - madx=madx, - columns=columns, - patterns=[ - f"IP{ir:d}", - f"MQXA.[12345][RL]{ir:d}", # Q1 and Q3 LHC - f"MQXB.[AB][12345][RL]{ir:d}", # Q2A and Q2B LHC - f"MQXF[AB].[AB][12345][RL]{ir:d}", # Q1 to Q3 A and B HL-LHC - ], - **kwargs, - ) diff --git a/pyhdtoolkit/cpymadtools/utils.py b/pyhdtoolkit/cpymadtools/utils.py index 49d47a75..570a0a6d 100644 --- a/pyhdtoolkit/cpymadtools/utils.py +++ b/pyhdtoolkit/cpymadtools/utils.py @@ -9,6 +9,7 @@ from pathlib import Path from typing import List, Union +import pandas as pd import tfs from cpymad.madx import Madx @@ -84,7 +85,11 @@ def get_table_tfs(madx: Madx, table_name: str, headers_table: str = "SUMM") -> t >>> twiss_tfs = get_table_tfs(madx, table_name="TWISS") """ logger.debug(f"Extracting table {table_name} into a TfsDataFrame") - dframe = tfs.TfsDataFrame(madx.table[table_name].dframe()) + # Converting to dict and then DataFrame because the madx.table.name.dframe() + # method sometimes complains about element names and crashes (mostly seen) + # when exporting error tables. + dframe = pd.DataFrame.from_dict(dict(madx.table[table_name])) + dframe = tfs.TfsDataFrame(dframe) dframe.columns = dframe.columns.str.upper() if "NAME" in dframe.columns: diff --git a/pyhdtoolkit/plotting/styles/paper.py b/pyhdtoolkit/plotting/styles/paper.py index 6ee8afe7..e45a2fa7 100644 --- a/pyhdtoolkit/plotting/styles/paper.py +++ b/pyhdtoolkit/plotting/styles/paper.py @@ -21,7 +21,7 @@ SINGLE_COLUMN: Dict[str, PlotSetting] = { # ------ Lines ------ # "lines.linewidth": 1.3, # Width of plot lines - "lines.markersize": 5, # Marker size, in points + "lines.markersize": 2, # Marker size, in points # ------ Patches ------ # "patch.linewidth": 1.2, # Width of patches edge lines # ------ Fonts ------ # @@ -54,9 +54,9 @@ "legend.frameon": True, # Make a dedicated patch for the legend "legend.framealpha": 0.85, # Legend patch transparency factor "legend.fancybox": True, # Use rounded box for legend background - "legend.fontsize": 18, # Legend text font size + "legend.fontsize": 24, # Legend text font size # ------ Figure ------ # - "figure.figsize": (12, 8), # Size of the figure + "figure.figsize": (11, 7), # Size of the figure "figure.titlesize": 20, # Size of the figure title "figure.subplot.left": 0.13, # Left side limit of the subplots of the figure "figure.subplot.top": 0.92, # Top side limit of the subplots of the figure @@ -81,19 +81,19 @@ # ------ Axes ------ # "axes.linewidth": 1.1, # Linewidth of axes edges "axes.titlesize": 20, # Fontsize of the axes title - "axes.labelsize": 20, # Fontsize of the x and y axis labels + "axes.labelsize": 26, # Fontsize of the x and y axis labels "axes.formatter.limits": (-4, 5), # Switch to scientific notations when order of magnitude reaches ±1e3 "axes.formatter.use_mathtext": True, # Format with i.e 10^{4} instead of 1e4 "axes.formatter.useoffset": False, # Do not use the annoying offset on top of yticks # ------ Horizontal Ticks ------ # "xtick.major.size": 7, # Size (length) of the major xtick locators "xtick.major.width": 1.6, # Width of the major xtick locators - "xtick.labelsize": 17, # Fontsize of the x axis tick labels + "xtick.labelsize": 25, # Fontsize of the x axis tick labels "xtick.direction": "in", # Show xticks towards inside of figure # ------ Vertical Ticks ------ # "ytick.major.size": 7, # Size (length) of the major ytick locators "ytick.major.width": 1.6, # Width of the major ytick locators - "ytick.labelsize": 17, # Fontsize of the y axis tick labels + "ytick.labelsize": 25, # Fontsize of the y axis tick labels "ytick.direction": "in", # Show yticks towards inside of figure # ----- Grids ----- # "grid.linestyle": "--", # Dashed grids (when explicitely asked for) @@ -102,9 +102,9 @@ "legend.frameon": True, # Make a dedicated patch for the legend "legend.framealpha": 0.85, # Legend patch transparency factor "legend.fancybox": True, # Use rounded box for legend background - "legend.fontsize": 17, # Legend text font size + "legend.fontsize": 21, # Legend text font size # ------ Figure ------ # - "figure.figsize": (22, 12), # Size of the figure + "figure.figsize": (18, 11), # Size of the figure "figure.titlesize": 20, # Size of the figure title "figure.subplot.left": 0.13, # Left side of the subplots of the figure "figure.subplot.bottom": 0.15, # Bottom side of the subplots of the figure diff --git a/pyhdtoolkit/utils/_misc.py b/pyhdtoolkit/utils/_misc.py index 4b361ee6..392f575c 100644 --- a/pyhdtoolkit/utils/_misc.py +++ b/pyhdtoolkit/utils/_misc.py @@ -22,7 +22,7 @@ from loguru import logger from pyhdtoolkit import __version__ -from pyhdtoolkit.cpymadtools import errors +from pyhdtoolkit.cpymadtools import lhc # ----- Constants ----- # @@ -67,23 +67,23 @@ def apply_colin_corrs_balance(madx: Madx) -> None: >>> apply_colin_corrs_balance(madx) """ # ----- Let's balance IR1 ----- # - errors.misalign_lhc_ir_quadrupoles(madx, ips=[1], beam=1, quadrupoles=[3], sides="L", DPSI=-1.61e-3) - errors.misalign_lhc_ir_quadrupoles(madx, ips=[1], beam=1, quadrupoles=[3], sides="R", DPSI=1.41e-3) + lhc.misalign_lhc_ir_quadrupoles(madx, ips=[1], beam=1, quadrupoles=[3], sides="L", DPSI=-1.61e-3) + lhc.misalign_lhc_ir_quadrupoles(madx, ips=[1], beam=1, quadrupoles=[3], sides="R", DPSI=1.41e-3) madx.globals["kqsx3.l1"] = 8e-4 madx.globals["kqsx3.r1"] = 7e-4 # ----- Let's balance IR2 ----- # - errors.misalign_lhc_ir_quadrupoles(madx, ips=[2], beam=1, quadrupoles=[3], sides="L", DPSI=-2.84e-3) - errors.misalign_lhc_ir_quadrupoles(madx, ips=[2], beam=1, quadrupoles=[3], sides="R", DPSI=2.84e-3) + lhc.misalign_lhc_ir_quadrupoles(madx, ips=[2], beam=1, quadrupoles=[3], sides="L", DPSI=-2.84e-3) + lhc.misalign_lhc_ir_quadrupoles(madx, ips=[2], beam=1, quadrupoles=[3], sides="R", DPSI=2.84e-3) madx.globals["kqsx3.l2"] = -14e-4 madx.globals["kqsx3.r2"] = -14e-4 # ----- Let's balance IR5 ----- # - errors.misalign_lhc_ir_quadrupoles(madx, ips=[5], beam=1, quadrupoles=[3], sides="L", DPSI=-1.21e-3) - errors.misalign_lhc_ir_quadrupoles(madx, ips=[5], beam=1, quadrupoles=[3], sides="R", DPSI=1.21e-3) + lhc.misalign_lhc_ir_quadrupoles(madx, ips=[5], beam=1, quadrupoles=[3], sides="L", DPSI=-1.21e-3) + lhc.misalign_lhc_ir_quadrupoles(madx, ips=[5], beam=1, quadrupoles=[3], sides="R", DPSI=1.21e-3) madx.globals["kqsx3.l5"] = 6e-4 madx.globals["kqsx3.r5"] = 6e-4 # ----- Let's balance IR8 ----- # - errors.misalign_lhc_ir_quadrupoles(madx, ips=[8], beam=1, quadrupoles=[3], sides="L", DPSI=-1e-3) - errors.misalign_lhc_ir_quadrupoles(madx, ips=[8], beam=1, quadrupoles=[3], sides="R", DPSI=1e-3) + lhc.misalign_lhc_ir_quadrupoles(madx, ips=[8], beam=1, quadrupoles=[3], sides="L", DPSI=-1e-3) + lhc.misalign_lhc_ir_quadrupoles(madx, ips=[8], beam=1, quadrupoles=[3], sides="R", DPSI=1e-3) madx.globals["kqsx3.l8"] = -5e-4 madx.globals["kqsx3.r8"] = -5e-4 madx.command.twiss(chrom=True) diff --git a/pyhdtoolkit/version.py b/pyhdtoolkit/version.py index e8bf26b6..00609a22 100644 --- a/pyhdtoolkit/version.py +++ b/pyhdtoolkit/version.py @@ -1,4 +1,4 @@ -VERSION = "1.0.0" +VERSION = "1.1.0" def version_info() -> str: diff --git a/tests/conftest.py b/tests/conftest.py index 07ef3816..45e6e8ec 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,7 @@ from cpymad.madx import Madx from pyhdtoolkit.cpymadtools import lhc -from pyhdtoolkit.cpymadtools.generators import LatticeGenerator +from pyhdtoolkit.cpymadtools._generators import LatticeGenerator from pyhdtoolkit.cpymadtools.matching import match_tunes_and_chromaticities BASE_LATTICE = LatticeGenerator.generate_base_cas_lattice() diff --git a/tests/inputs/madx/PROTON/opticsfile.22 b/tests/inputs/madx/PROTON/opticsfile.22 new file mode 100644 index 00000000..0c69c013 --- /dev/null +++ b/tests/inputs/madx/PROTON/opticsfile.22 @@ -0,0 +1,1477 @@ +NRJ := 6500.000000 ; +ARC_SQUEEZE := 1.000000 ; + + !***BETAS in IR1 and IR5*** +betx_IP1 := 0.300000 ; +bety_IP1 := 0.300000 ; +betx_IP5 := 0.300000 ; +bety_IP5 := 0.300000 ; + + !***Exp. configuration in IR1, IR2, IR5 and IR8*** + on_x1 := 160.000 ; + on_sep1:= -0.550 ; + on_oh1 := 0.000 ; + on_ov1 := 0.000 ; + phi_IR1:= 90.000 ; + on_ssep1:=on_sep1; + on_xx1 := on_x1 ; + on_x5 := 160.000 ; + on_sep5:= 0.550 ; + on_oh5 := 0.000 ; + on_ov5 := -1.800 ; + phi_IR5:= 0.000 ; + on_ssep5:=on_sep5; + on_xx5 := on_x5 ; + + !**Spurious dispersion correction +on_disp := 0.000 ; + + on_x2 := 200.000 ; + on_sep2:= 1.000 ; + on_a2 := 0.000 ; + on_o2 := 0.000 ; + on_oh2 := 0.000 ; + on_ov2 := -2.000 ; + phi_IR2:= 90.000 ; + on_x8 := -250.000 ; + on_sep8:= -1.000 ; + on_a8 := 0.000 ; + on_o8 := 0.000 ; + on_oh8 := 0.000 ; + on_ov8 := 0.000 ; + phi_IR8:= 180.000 ; + + !** Experimental solenoids +abas:= 12.00/ 6.0*clight/(7E12)*on_sol_atlas; +abls:= 6.05/12.1*clight/(7E12)*on_sol_alice ; +abcs:= 52.00/13.0*clight/(7E12)*on_sol_cms ; + + !***Ring Geometry*** + + !Separation/recombination dipoles +kd1.lr1 := ad1.lr1/l.mbxw; +kd2.l1 := ad2.l5/l.mbrc ; +kd2.r1 := ad2.r5/l.mbrc ; +kd1.l2 := ad1.l2/l.mbx ; +kd1.r2 := ad1.r2/l.mbx ; +kd2.l2 := ad2.l2/l.mbrc ; +kd2.r2 := ad2.r2/l.mbrc ; +kd3.lr3 := ad3.lr3/l.mbw ; +kd4.lr3 := ad4.lr3/l.mbw ; +kd3.l4 := ad3.l4/l.mbrs ; +kd3.r4 := ad3.r4/l.mbrs ; +kd4.l4 := ad4.l4/l.mbrb ; +kd4.r4 := ad4.r4/l.mbrb ; +kd34.lr3 := ad3.lr3/l.mbw ; +kd34.lr7 := ad3.lr7/l.mbw ; +kd1.lr5 := ad1.lr5/l.mbxw; +kd2.l5 := ad2.l5/l.mbrc ; +kd2.r5 := ad2.r5/l.mbrc ; +kd3.lr7 := ad3.lr7/l.mbw ; +kd4.lr7 := ad4.lr7/l.mbw ; +kd1.l8 := ad1.l8/l.mbx ; +kd1.r8 := ad1.r8/l.mbx ; +kd2.l8 := ad2.l8/l.mbrc ; +kd2.r8 := ad2.r8/l.mbrc ; +ksumd2.l1b2 := kd2.l1 ; +ksumd2.l2b2 := kd2.l2 ; +ksumd2.l5b2 := kd2.l5 ; +ksumd2.l8b2 := kd2.l8 ; +ksumd2.r1b2 := kd2.l1 ; +ksumd2.r2b2 := kd2.l2 ; +ksumd2.r5b2 := kd2.l5 ; +ksumd2.r8b2 := kd2.l8 ; + + !Main dipoles +kb.a12 := ab.a12/l.mb ; +kb.a23 := ab.a23/l.mb ; +kb.a34 := ab.a34/l.mb ; +kb.a45 := ab.a45/l.mb ; +kb.a56 := ab.a56/l.mb ; +kb.a67 := ab.a67/l.mb ; +kb.a78 := ab.a78/l.mb ; +kb.a81 := ab.a81/l.mb ; + + !***IR1 Optics*** +KQX.L1 := -0.874970435349E-02 ; +KTQX1.L1 := 0.725484931411E-04 ; +KTQX2.L1 := -0.575915858911E-04 ; +KQX.R1 := -KQX.L1 ; +KTQX1.R1 := -KTQX1.L1 ; +KTQX2.R1 := -KTQX2.L1 ; + + !Beam1 +KQ4.L1B1 := 0.214551112322E-02 ; +KQ4.R1B1 := -0.214551112322E-02 ; +KQ5.L1B1 := -0.123757116295E-02 ; +KQ5.R1B1 := 0.110356755457E-02 ; +KQ6.L1B1 := 0.500000000000E-03 ; +KQ6.R1B1 := -0.500000000000E-03 ; +KQ7.L1B1 := -0.783425743660E-02 ; +KQ7.R1B1 := 0.754930884262E-02 ; +KQ8.L1B1 := 0.794263450412E-02 ; +KQ8.R1B1 := -0.727715002555E-02 ; +KQ9.L1B1 := -0.665423187096E-02 ; +KQ9.R1B1 := 0.652650679531E-02 ; +KQ10.L1B1 := 0.697605396174E-02 ; +KQ10.R1B1 := -0.663424308263E-02 ; +KQTL11.L1B1 := 0.198469900849E-02 ; +KQTL11.R1B1 := -0.276428479544E-03 ; +KQT12.L1B1 := -0.129140383036E-02 ; +KQT12.R1B1 := -0.370295812418E-02 ; +KQT13.L1B1 := 0.166239611081E-02 ; +KQT13.R1B1 := -0.544675448835E-03 ; + + !Beam2 +KQ4.L1B2 := -0.206042573481E-02 ; +KQ4.R1B2 := 0.206042573481E-02 ; +KQ5.L1B2 := 0.934832469634E-03 ; +KQ5.R1B2 := -0.115285119508E-02 ; +KQ6.L1B2 := -0.500000000000E-03 ; +KQ6.R1B2 := 0.500000000000E-03 ; +KQ7.L1B2 := 0.756473337392E-02 ; +KQ7.R1B2 := -0.750372157248E-02 ; +KQ8.L1B2 := -0.773107435225E-02 ; +KQ8.R1B2 := 0.786878537479E-02 ; +KQ9.L1B2 := 0.657772683063E-02 ; +KQ9.R1B2 := -0.688029561925E-02 ; +KQ10.L1B2 := -0.642615004754E-02 ; +KQ10.R1B2 := 0.715481542090E-02 ; +KQTL11.L1B2 := -0.580216275538E-03 ; +KQTL11.R1B2 := 0.656127015958E-03 ; +KQT12.L1B2 := -0.983976289471E-03 ; +KQT12.R1B2 := -0.193097610101E-02 ; +KQT13.L1B2 := -0.904510740678E-03 ; +KQT13.R1B2 := 0.461637331829E-02 ; + + !***IR1 X-scheme*** +ACBXV1.L1x := 0.384726259271E-07 ; +ACBXV1.L1s := -0.800000000000E-05 ; +ACBXV1.L1 := ( 0.384726259271E-07 )*sin(phi_IR1*twopi/360.)*on_x1 +( -0.800000000000E-05 )*cos(phi_IR1*twopi/360.)*on_sep1 ; +ACBXV1.R1x := -0.384726259271E-07 ; +ACBXV1.R1s := -0.800000000000E-05 ; +ACBXV1.R1 := ( -0.384726259271E-07 )*sin(phi_IR1*twopi/360.)*on_x1 +( -0.800000000000E-05 )*cos(phi_IR1*twopi/360.)*on_sep1 ; +ACBXH1.L1x := 0.384726259271E-07 ; +ACBXH1.L1s := 0.800000000000E-05 ; +ACBXH1.L1 := ( 0.384726259271E-07 )*cos(phi_IR1*twopi/360.)*on_x1 +( 0.800000000000E-05 )*sin(phi_IR1*twopi/360.)*on_sep1 ; +ACBXH1.R1x := -0.384726259271E-07 ; +ACBXH1.R1s := 0.800000000000E-05 ; +ACBXH1.R1 := ( -0.384726259271E-07 )*cos(phi_IR1*twopi/360.)*on_x1 +( 0.800000000000E-05 )*sin(phi_IR1*twopi/360.)*on_sep1 ; +ACBXV2.L1x := 0.384726259271E-07 ; +ACBXV2.L1s := -0.800000000000E-05 ; +ACBXV2.L1 := ( 0.384726259271E-07 )*sin(phi_IR1*twopi/360.)*on_x1 +( -0.800000000000E-05 )*cos(phi_IR1*twopi/360.)*on_sep1 ; +ACBXV2.R1x := -0.384726259271E-07 ; +ACBXV2.R1s := -0.800000000000E-05 ; +ACBXV2.R1 := ( -0.384726259271E-07 )*sin(phi_IR1*twopi/360.)*on_x1 +( -0.800000000000E-05 )*cos(phi_IR1*twopi/360.)*on_sep1 ; +ACBXH2.L1x := 0.384726259271E-07 ; +ACBXH2.L1s := 0.800000000000E-05 ; +ACBXH2.L1 := ( 0.384726259271E-07 )*cos(phi_IR1*twopi/360.)*on_x1 +( 0.800000000000E-05 )*sin(phi_IR1*twopi/360.)*on_sep1 ; +ACBXH2.R1x := -0.384726259271E-07 ; +ACBXH2.R1s := 0.800000000000E-05 ; +ACBXH2.R1 := ( -0.384726259271E-07 )*cos(phi_IR1*twopi/360.)*on_x1 +( 0.800000000000E-05 )*sin(phi_IR1*twopi/360.)*on_sep1 ; +ACBXV3.L1x := 0.384726259271E-07 ; +ACBXV3.L1s := -0.800000000000E-05 ; +ACBXV3.L1 := ( 0.384726259271E-07 )*sin(phi_IR1*twopi/360.)*on_x1 +( -0.800000000000E-05 )*cos(phi_IR1*twopi/360.)*on_sep1 ; +ACBXV3.R1x := -0.384726259271E-07 ; +ACBXV3.R1s := -0.800000000000E-05 ; +ACBXV3.R1 := ( -0.384726259271E-07 )*sin(phi_IR1*twopi/360.)*on_x1 +( -0.800000000000E-05 )*cos(phi_IR1*twopi/360.)*on_sep1 ; +ACBXH3.L1x := 0.384726259271E-07 ; +ACBXH3.L1s := 0.800000000000E-05 ; +ACBXH3.L1 := ( 0.384726259271E-07 )*cos(phi_IR1*twopi/360.)*on_x1 +( 0.800000000000E-05 )*sin(phi_IR1*twopi/360.)*on_sep1 ; +ACBXH3.R1x := -0.384726259271E-07 ; +ACBXH3.R1s := 0.800000000000E-05 ; +ACBXH3.R1 := ( -0.384726259271E-07 )*cos(phi_IR1*twopi/360.)*on_x1 +( 0.800000000000E-05 )*sin(phi_IR1*twopi/360.)*on_sep1 ; + + !Beam1 +ACBYVS4.L1B1x := -0.192359259110E-06 ; +ACBYVS4.L1B1s := -0.205054921265E-04 ; +ACBYVS4.L1B1ov:= 0.342970557171E-04 ; +ACBYVS4.L1B1 := ( -0.192359259110E-06 )*sin(phi_IR1*twopi/360.)*on_x1+( -0.205054921265E-04 )*cos(phi_IR1*twopi/360.)*on_sep1+( 0.342970557171E-04 )*on_ov1; +ACBYVS4.R1B1x := 0.173802286497E-06 ; +ACBYVS4.R1B1s := -0.103049015033E-05 ; +ACBYVS4.R1B1ov:= 0.326168314277E-04 ; +ACBYVS4.R1B1 := ( 0.173802286497E-06 )*sin(phi_IR1*twopi/360.)*on_x1+( -0.103049015033E-05 )*cos(phi_IR1*twopi/360.)*on_sep1+( 0.326168314277E-04 )*on_ov1; +ACBCV5.L1B1x := -0.139988294359E-06 ; +ACBCV5.L1B1s := 0.986922497863E-05 ; +ACBCV5.L1B1ov := 0.320070238556E-04 ; +ACBCV5.L1B1 := ( -0.139988294359E-06 )*sin(phi_IR1*twopi/360.)*on_x1+( 0.986922497863E-05 )*cos(phi_IR1*twopi/360.)*on_sep1+( 0.320070238556E-04 )*on_ov1; +ACBCV6.R1B1x := 0.798933449514E-07 ; +ACBCV6.R1B1s := -0.542760731881E-05 ; +ACBCV6.R1B1ov := 0.304389889969E-04 ; +ACBCV6.R1B1 := ( 0.798933449514E-07 )*sin(phi_IR1*twopi/360.)*on_x1+( -0.542760731881E-05 )*cos(phi_IR1*twopi/360.)*on_sep1+( 0.304389889969E-04 )*on_ov1; +ACBYHS4.L1B1x := -0.179919409681E-06 ; +ACBYHS4.L1B1s := 0.144619539815E-05 ; +ACBYHS4.L1B1oh:= 0.346413371309E-04 ; +ACBYHS4.L1B1 := ( -0.179919409681E-06 )*cos(phi_IR1*twopi/360.)*on_x1+( 0.144619539815E-05 )*sin(phi_IR1*twopi/360.)*on_sep1+( 0.346413371309E-04 )*on_oh1; +ACBYHS4.R1B1x := 0.162543399050E-06 ; +ACBYHS4.R1B1s := 0.226064728598E-04 ; +ACBYHS4.R1B1oh:= 0.319011474060E-04 ; +ACBYHS4.R1B1 := ( 0.162543399050E-06 )*cos(phi_IR1*twopi/360.)*on_x1+( 0.226064728598E-04 )*sin(phi_IR1*twopi/360.)*on_sep1+( 0.319011474060E-04 )*on_oh1; +ACBCH6.L1B1x := -0.718952934586E-07 ; +ACBCH6.L1B1s := 0.488416649413E-05 ; +ACBCH6.L1B1oh := 0.323283174242E-04 ; +ACBCH6.L1B1 := ( -0.718952934586E-07 )*cos(phi_IR1*twopi/360.)*on_x1+( 0.488416649413E-05 )*sin(phi_IR1*twopi/360.)*on_sep1+( 0.323283174242E-04 )*on_oh1; +ACBCH5.R1B1x := 0.168109563360E-06 ; +ACBCH5.R1B1s := -0.118510930233E-04 ; +ACBCH5.R1B1oh := 0.297710915616E-04 ; +ACBCH5.R1B1 := ( 0.168109563360E-06 )*cos(phi_IR1*twopi/360.)*on_x1+( -0.118510930233E-04 )*sin(phi_IR1*twopi/360.)*on_sep1+( 0.297710915616E-04 )*on_oh1; +ACBCH8.L1B1oh := -0.149743227551E-04 ; +ACBCH8.L1B1 := ( -0.149743227551E-04)*on_oh1; +ACBCV7.L1B1ov := -0.380706326499E-04 ; +ACBCV7.L1B1 := ( -0.380706326499E-04)*on_ov1; +ACBCH7.R1B1oh := -0.398916549560E-04 ; +ACBCH7.R1B1 := ( -0.398916549560E-04)*on_oh1; +ACBCV8.R1B1ov := -0.144941830566E-04 ; +ACBCV8.R1B1 := ( -0.144941830566E-04)*on_ov1; + + !Beam2 +ACBYVS4.L1B2x := 0.180448717037E-06 ; +ACBYVS4.L1B2s := 0.148201966713E-05 ; +ACBYVS4.L1B2ov:= 0.334196692000E-04 ; +ACBYVS4.L1B2 := ( 0.180448717037E-06 )*sin(phi_IR1*twopi/360.)*on_x1+( 0.148201966713E-05 )*cos(phi_IR1*twopi/360.)*on_sep1+( 0.334196692000E-04 )*on_ov1; +ACBYVS4.R1B2x := -0.163545876283E-06 ; +ACBYVS4.R1B2s := 0.225368454035E-04 ; +ACBYVS4.R1B2ov:= 0.312922318650E-04 ; +ACBYVS4.R1B2 := ( -0.163545876283E-06 )*sin(phi_IR1*twopi/360.)*on_x1+( 0.225368454035E-04 )*cos(phi_IR1*twopi/360.)*on_sep1+( 0.312922318650E-04 )*on_ov1; +ACBCV6.L1B2x := 0.734306679359E-07 ; +ACBCV6.L1B2s := 0.498856128444E-05 ; +ACBCV6.L1B2ov := 0.311882208827E-04 ; +ACBCV6.L1B2 := ( 0.734306679359E-07 )*sin(phi_IR1*twopi/360.)*on_x1+( 0.498856128444E-05 )*cos(phi_IR1*twopi/360.)*on_sep1+( 0.311882208827E-04 )*on_ov1; +ACBCV5.R1B2x := -0.168256926151E-06 ; +ACBCV5.R1B2s := -0.118621731914E-04 ; +ACBCV5.R1B2ov := 0.292028336210E-04 ; +ACBCV5.R1B2 := ( -0.168256926151E-06 )*sin(phi_IR1*twopi/360.)*on_x1+( -0.118621731914E-04 )*cos(phi_IR1*twopi/360.)*on_sep1+( 0.292028336210E-04 )*on_ov1; +ACBYHS4.L1B2x := 0.193326515308E-06 ; +ACBYHS4.L1B2s := -0.204363857358E-04 ; +ACBYHS4.L1B2oh:= 0.354328695194E-04 ; +ACBYHS4.L1B2 := ( 0.193326515308E-06 )*cos(phi_IR1*twopi/360.)*on_x1+( -0.204363857358E-04 )*sin(phi_IR1*twopi/360.)*on_sep1+( 0.354328695194E-04 )*on_oh1; +ACBYHS4.R1B2x := -0.172256283920E-06 ; +ACBYHS4.R1B2s := -0.925599320625E-06 ; +ACBYHS4.R1B2oh:= 0.334817489996E-04 ; +ACBYHS4.R1B2 := ( -0.172256283920E-06 )*cos(phi_IR1*twopi/360.)*on_x1+( -0.925599320625E-06 )*sin(phi_IR1*twopi/360.)*on_sep1+( 0.334817489996E-04 )*on_oh1; +ACBCH5.L1B2x := 0.139573123688E-06 ; +ACBCH5.L1B2s := 0.983938702358E-05 ; +ACBCH5.L1B2oh := 0.330669987924E-04 ; +ACBCH5.L1B2 := ( 0.139573123688E-06 )*cos(phi_IR1*twopi/360.)*on_x1+( 0.983938702358E-05 )*sin(phi_IR1*twopi/360.)*on_sep1+( 0.330669987924E-04 )*on_oh1; +ACBCH6.R1B2x := -0.795191844826E-07 ; +ACBCH6.R1B2s := -0.540209925166E-05 ; +ACBCH6.R1B2oh := 0.312461555825E-04 ; +ACBCH6.R1B2 := ( -0.795191844826E-07 )*cos(phi_IR1*twopi/360.)*on_x1+( -0.540209925166E-05 )*sin(phi_IR1*twopi/360.)*on_sep1+( 0.312461555825E-04 )*on_oh1; +ACBCV8.L1B2ov := -0.153897651293E-04 ; +ACBCV8.L1B2 := ( -0.153897651293E-04)*on_ov1; +ACBCH7.L1B2oh := -0.373062157095E-04 ; +ACBCH7.L1B2 := ( -0.373062157095E-04)*on_oh1; +ACBCV7.R1B2ov := -0.398860335681E-04 ; +ACBCV7.R1B2 := ( -0.398860335681E-04)*on_ov1; +ACBCH8.R1B2oh := -0.147651854945E-04 ; +ACBCH8.R1B2 := ( -0.147651854945E-04)*on_oh1; + + !***IR5 Optics*** +KQX.L5 := -0.874970435349E-02 ; +KTQX1.L5 := 0.725484931411E-04 ; +KTQX2.L5 := -0.575915858911E-04 ; +KQX.R5 := -KQX.L5 ; +KTQX1.R5 := -KTQX1.L5 ; +KTQX2.R5 := -KTQX2.L5 ; + + !Beam1 +KQ4.L5B1 := 0.214551112322E-02 ; +KQ4.R5B1 := -0.214551112322E-02 ; +KQ5.L5B1 := -0.123757116295E-02 ; +KQ5.R5B1 := 0.110356755457E-02 ; +KQ6.L5B1 := 0.500000000000E-03 ; +KQ6.R5B1 := -0.500000000000E-03 ; +KQ7.L5B1 := -0.783425743660E-02 ; +KQ7.R5B1 := 0.754930884262E-02 ; +KQ8.L5B1 := 0.794263450412E-02 ; +KQ8.R5B1 := -0.727715002555E-02 ; +KQ9.L5B1 := -0.665423187096E-02 ; +KQ9.R5B1 := 0.652650679531E-02 ; +KQ10.L5B1 := 0.697605396174E-02 ; +KQ10.R5B1 := -0.663424308263E-02 ; +KQTL11.L5B1 := 0.198469900849E-02 ; +KQTL11.R5B1 := -0.276428479544E-03 ; +KQT12.L5B1 := -0.129140383036E-02 ; +KQT12.R5B1 := -0.370295812418E-02 ; +KQT13.L5B1 := 0.166239611081E-02 ; +KQT13.R5B1 := -0.544675448835E-03 ; + + !Beam2 +KQ4.L5B2 := -0.206042573481E-02 ; +KQ4.R5B2 := 0.206042573481E-02 ; +KQ5.L5B2 := 0.934832469634E-03 ; +KQ5.R5B2 := -0.115285119508E-02 ; +KQ6.L5B2 := -0.500000000000E-03 ; +KQ6.R5B2 := 0.500000000000E-03 ; +KQ7.L5B2 := 0.756473337392E-02 ; +KQ7.R5B2 := -0.750372157248E-02 ; +KQ8.L5B2 := -0.773107435225E-02 ; +KQ8.R5B2 := 0.786878537479E-02 ; +KQ9.L5B2 := 0.657772683063E-02 ; +KQ9.R5B2 := -0.688029561925E-02 ; +KQ10.L5B2 := -0.642615004754E-02 ; +KQ10.R5B2 := 0.715481542090E-02 ; +KQTL11.L5B2 := -0.580216275538E-03 ; +KQTL11.R5B2 := 0.656127015958E-03 ; +KQT12.L5B2 := -0.983976289471E-03 ; +KQT12.R5B2 := -0.193097610101E-02 ; +KQT13.L5B2 := -0.904510740678E-03 ; +KQT13.R5B2 := 0.461637331829E-02 ; + + !***IR5 X-scheme*** +ACBXV1.L5x := 0.384726259271E-07 ; +ACBXV1.L5s := 0.800000000000E-05 ; +ACBXV1.L5 := ( 0.384726259271E-07 )*sin(phi_IR5*twopi/360.)*on_x5 +( 0.800000000000E-05 )*cos(phi_IR5*twopi/360.)*on_sep5 ; +ACBXV1.R5x := -0.384726259271E-07 ; +ACBXV1.R5s := 0.800000000000E-05 ; +ACBXV1.R5 := ( -0.384726259271E-07 )*sin(phi_IR5*twopi/360.)*on_x5 +( 0.800000000000E-05 )*cos(phi_IR5*twopi/360.)*on_sep5 ; +ACBXH1.L5x := 0.384726259271E-07 ; +ACBXH1.L5s := -0.800000000000E-05 ; +ACBXH1.L5 := ( 0.384726259271E-07 )*cos(phi_IR5*twopi/360.)*on_x5 +( -0.800000000000E-05 )*sin(phi_IR5*twopi/360.)*on_sep5 ; +ACBXH1.R5x := -0.384726259271E-07 ; +ACBXH1.R5s := -0.800000000000E-05 ; +ACBXH1.R5 := ( -0.384726259271E-07 )*cos(phi_IR5*twopi/360.)*on_x5 +( -0.800000000000E-05 )*sin(phi_IR5*twopi/360.)*on_sep5 ; +ACBXV2.L5x := 0.384726259271E-07 ; +ACBXV2.L5s := 0.800000000000E-05 ; +ACBXV2.L5 := ( 0.384726259271E-07 )*sin(phi_IR5*twopi/360.)*on_x5 +( 0.800000000000E-05 )*cos(phi_IR5*twopi/360.)*on_sep5 ; +ACBXV2.R5x := -0.384726259271E-07 ; +ACBXV2.R5s := 0.800000000000E-05 ; +ACBXV2.R5 := ( -0.384726259271E-07 )*sin(phi_IR5*twopi/360.)*on_x5 +( 0.800000000000E-05 )*cos(phi_IR5*twopi/360.)*on_sep5 ; +ACBXH2.L5x := 0.384726259271E-07 ; +ACBXH2.L5s := -0.800000000000E-05 ; +ACBXH2.L5 := ( 0.384726259271E-07 )*cos(phi_IR5*twopi/360.)*on_x5 +( -0.800000000000E-05 )*sin(phi_IR5*twopi/360.)*on_sep5 ; +ACBXH2.R5x := -0.384726259271E-07 ; +ACBXH2.R5s := -0.800000000000E-05 ; +ACBXH2.R5 := ( -0.384726259271E-07 )*cos(phi_IR5*twopi/360.)*on_x5 +( -0.800000000000E-05 )*sin(phi_IR5*twopi/360.)*on_sep5 ; +ACBXV3.L5x := 0.384726259271E-07 ; +ACBXV3.L5s := 0.800000000000E-05 ; +ACBXV3.L5 := ( 0.384726259271E-07 )*sin(phi_IR5*twopi/360.)*on_x5 +( 0.800000000000E-05 )*cos(phi_IR5*twopi/360.)*on_sep5 ; +ACBXV3.R5x := -0.384726259271E-07 ; +ACBXV3.R5s := 0.800000000000E-05 ; +ACBXV3.R5 := ( -0.384726259271E-07 )*sin(phi_IR5*twopi/360.)*on_x5 +( 0.800000000000E-05 )*cos(phi_IR5*twopi/360.)*on_sep5 ; +ACBXH3.L5x := 0.384726259271E-07 ; +ACBXH3.L5s := -0.800000000000E-05 ; +ACBXH3.L5 := ( 0.384726259271E-07 )*cos(phi_IR5*twopi/360.)*on_x5 +( -0.800000000000E-05 )*sin(phi_IR5*twopi/360.)*on_sep5 ; +ACBXH3.R5x := -0.384726259271E-07 ; +ACBXH3.R5s := -0.800000000000E-05 ; +ACBXH3.R5 := ( -0.384726259271E-07 )*cos(phi_IR5*twopi/360.)*on_x5 +( -0.800000000000E-05 )*sin(phi_IR5*twopi/360.)*on_sep5 ; + + !Beam1 +ACBYVS4.L5B1x := -0.162556758663E-06 ; +ACBYVS4.L5B1s := 0.226065791006E-04 ; +ACBYVS4.L5B1ov:= 0.331707441066E-04 ; +ACBYVS4.L5B1 := ( -0.162556758663E-06 )*sin(phi_IR5*twopi/360.)*on_x5+( 0.226065791006E-04 )*cos(phi_IR5*twopi/360.)*on_sep5+( 0.331707441066E-04 )*on_ov5; +ACBYVS4.R5B1x := 0.180728360870E-06 ; +ACBYVS4.R5B1s := 0.150101760141E-05 ; +ACBYVS4.R5B1ov:= 0.337409718151E-04 ; +ACBYVS4.R5B1 := ( 0.180728360870E-06 )*sin(phi_IR5*twopi/360.)*on_x5+( 0.150101760141E-05 )*cos(phi_IR5*twopi/360.)*on_sep5+( 0.337409718151E-04 )*on_ov5; +ACBCV5.L5B1x := -0.168101113807E-06 ; +ACBCV5.L5B1s := -0.118511888362E-04 ; +ACBCV5.L5B1ov := 0.309559166444E-04 ; +ACBCV5.L5B1 := ( -0.168101113807E-06 )*sin(phi_IR5*twopi/360.)*on_x5+( -0.118511888362E-04 )*cos(phi_IR5*twopi/360.)*on_sep5+( 0.309559166444E-04 )*on_ov5; +ACBCV6.R5B1x := 0.726101933163E-07 ; +ACBCV6.R5B1s := 0.493282158738E-05 ; +ACBCV6.R5B1ov := 0.314880699587E-04 ; +ACBCV6.R5B1 := ( 0.726101933163E-07 )*sin(phi_IR5*twopi/360.)*on_x5+( 0.493282158738E-05 )*cos(phi_IR5*twopi/360.)*on_sep5+( 0.314880699587E-04 )*on_ov5; +ACBYHS4.L5B1x := -0.173123512284E-06 ; +ACBYHS4.L5B1s := -0.984519914665E-06 ; +ACBYHS4.L5B1oh:= 0.334913772030E-04 ; +ACBYHS4.L5B1 := ( -0.173123512284E-06 )*cos(phi_IR5*twopi/360.)*on_x5+( -0.984519914665E-06 )*sin(phi_IR5*twopi/360.)*on_sep5+( 0.334913772030E-04 )*on_oh5; +ACBYHS4.R5B1x := 0.192318110005E-06 ; +ACBYHS4.R5B1s := -0.205074675312E-04 ; +ACBYHS4.R5B1oh:= 0.328732865379E-04 ; +ACBYHS4.R5B1 := ( 0.192318110005E-06 )*cos(phi_IR5*twopi/360.)*on_x5+( -0.205074675312E-04 )*sin(phi_IR5*twopi/360.)*on_sep5+( 0.328732865379E-04 )*on_oh5; +ACBCH6.L5B1x := -0.791737507404E-07 ; +ACBCH6.L5B1s := -0.537862441309E-05 ; +ACBCH6.L5B1oh := 0.312551409058E-04 ; +ACBCH6.L5B1 := ( -0.791737507404E-07 )*cos(phi_IR5*twopi/360.)*on_x5+( -0.537862441309E-05 )*sin(phi_IR5*twopi/360.)*on_sep5+( 0.312551409058E-04 )*on_oh5; +ACBCH5.R5B1x := 0.139749042701E-06 ; +ACBCH5.R5B1s := 0.985178280076E-05 ; +ACBCH5.R5B1oh := 0.306783204689E-04 ; +ACBCH5.R5B1 := ( 0.139749042701E-06 )*cos(phi_IR5*twopi/360.)*on_x5+( 0.985178280076E-05 )*sin(phi_IR5*twopi/360.)*on_sep5+( 0.306783204689E-04 )*on_oh5; +ACBCH8.L5B1oh := -0.141906840238E-04 ; +ACBCH8.L5B1 := ( -0.141906840238E-04)*on_oh5; +ACBCV7.L5B1ov := -0.356937084562E-04 ; +ACBCV7.L5B1 := ( -0.356937084562E-04)*on_ov5; +ACBCH7.R5B1oh := -0.424523184816E-04 ; +ACBCH7.R5B1 := ( -0.424523184816E-04)*on_oh5; +ACBCV8.R5B1ov := -0.152728663020E-04 ; +ACBCV8.R5B1 := ( -0.152728663020E-04)*on_ov5; + + !Beam2 +ACBYVS4.L5B2x := 0.173372860185E-06 ; +ACBYVS4.L5B2s := -0.100131662387E-05 ; +ACBYVS4.L5B2ov:= 0.322917565701E-04 ; +ACBYVS4.L5B2 := ( 0.173372860185E-06 )*sin(phi_IR5*twopi/360.)*on_x5+( -0.100131662387E-05 )*cos(phi_IR5*twopi/360.)*on_sep5+( 0.322917565701E-04 )*on_ov5; +ACBYVS4.R5B2x := -0.193385934387E-06 ; +ACBYVS4.R5B2s := -0.204331106844E-04 ; +ACBYVS4.R5B2ov:= 0.322403218465E-04 ; +ACBYVS4.R5B2 := ( -0.193385934387E-06 )*sin(phi_IR5*twopi/360.)*on_x5+( -0.204331106844E-04 )*cos(phi_IR5*twopi/360.)*on_sep5+( 0.322403218465E-04 )*on_ov5; +ACBCV6.L5B2x := 0.807091155434E-07 ; +ACBCV6.L5B2s := -0.548302746551E-05 ; +ACBCV6.L5B2ov := 0.301356195530E-04 ; +ACBCV6.L5B2 := ( 0.807091155434E-07 )*sin(phi_IR5*twopi/360.)*on_x5+( -0.548302746551E-05 )*cos(phi_IR5*twopi/360.)*on_sep5+( 0.301356195530E-04 )*on_ov5; +ACBCV5.R5B2x := -0.139966082224E-06 ; +ACBCV5.R5B2s := 0.986765862325E-05 ; +ACBCV5.R5B2ov := 0.300876191521E-04 ; +ACBCV5.R5B2 := ( -0.139966082224E-06 )*sin(phi_IR5*twopi/360.)*on_x5+( 0.986765862325E-05 )*cos(phi_IR5*twopi/360.)*on_sep5+( 0.300876191521E-04 )*on_ov5; +ACBYHS4.L5B2x := 0.163532574189E-06 ; +ACBYHS4.L5B2s := 0.225367479679E-04 ; +ACBYHS4.L5B2oh:= 0.342320393477E-04 ; +ACBYHS4.L5B2 := ( 0.163532574189E-06 )*cos(phi_IR5*twopi/360.)*on_x5+( 0.225367479679E-04 )*sin(phi_IR5*twopi/360.)*on_sep5+( 0.342320393477E-04 )*on_oh5; +ACBYHS4.R5B2x := -0.179115198078E-06 ; +ACBYHS4.R5B2s := 0.139155650164E-05 ; +ACBYHS4.R5B2oh:= 0.346293516491E-04 ; +ACBYHS4.R5B2 := ( -0.179115198078E-06 )*cos(phi_IR5*twopi/360.)*on_x5+( 0.139155650164E-05 )*sin(phi_IR5*twopi/360.)*on_sep5+( 0.346293516491E-04 )*on_oh5; +ACBCH5.L5B2x := 0.168265376857E-06 ; +ACBCH5.L5B2s := -0.118620843454E-04 ; +ACBCH5.L5B2oh := 0.319463486623E-04 ; +ACBCH5.L5B2 := ( 0.168265376857E-06 )*cos(phi_IR5*twopi/360.)*on_x5+( -0.118620843454E-04 )*sin(phi_IR5*twopi/360.)*on_sep5+( 0.319463486623E-04 )*on_oh5; +ACBCH6.R5B2x := -0.722467502716E-07 ; +ACBCH6.R5B2s := 0.490804977586E-05 ; +ACBCH6.R5B2oh := 0.323171322192E-04 ; +ACBCH6.R5B2 := ( -0.722467502716E-07 )*cos(phi_IR5*twopi/360.)*on_x5+( 0.490804977586E-05 )*sin(phi_IR5*twopi/360.)*on_sep5+( 0.323171322192E-04 )*on_oh5; +ACBCV8.L5B2ov := -0.146181060208E-04 ; +ACBCV8.L5B2 := ( -0.146181060208E-04)*on_ov5; +ACBCH7.L5B2oh := -0.348707658739E-04 ; +ACBCH7.L5B2 := ( -0.348707658739E-04)*on_oh5; +ACBCV7.R5B2ov := -0.423976199046E-04 ; +ACBCV7.R5B2 := ( -0.423976199046E-04)*on_ov5; +ACBCH8.R5B2oh := -0.155743967149E-04 ; +ACBCH8.R5B2 := ( -0.155743967149E-04)*on_oh5; + + !***IR2 Optics*** +KQX.L2 := 0.877985714100E-02 ; +KTQX1.L2 := 0.000000000000E+00 ; +KTQX2.L2 := 0.000000000000E+00 ; +KQX.R2 := -KQX.L2 ; +KTQX1.R2 := -KTQX1.L2 ; +KTQX2.R2 := -KTQX2.L2 ; + + !Beam1 +KQ4.L2B1 := -0.353103506617E-02 ; +KQ4.R2B1 := 0.356861847814E-02 ; +KQ5.L2B1 := 0.409004925853E-02 ; +KQ5.R2B1 := -0.409004925853E-02 ; +KQ6.L2B1 := -0.464276883602E-02 ; +KQ6.R2B1 := 0.431729279029E-02 ; +KQ7.L2B1 := 0.742452490562E-02 ; +KQ7.R2B1 := -0.649443596107E-02 ; +KQ8.L2B1 := -0.555710872677E-02 ; +KQ8.R2B1 := 0.662645580447E-02 ; +KQ9.L2B1 := 0.672314508622E-02 ; +KQ9.R2B1 := -0.586640262463E-02 ; +KQ10.L2B1 := -0.656063228743E-02 ; +KQ10.R2B1 := 0.725367401015E-02 ; +KQTL11.L2B1 := 0.736900069350E-03 ; +KQTL11.R2B1 := -0.625166038240E-03 ; +KQT12.L2B1 := -0.227827190325E-02 ; +KQT12.R2B1 := -0.113354098650E-02 ; +KQT13.L2B1 := 0.170084113440E-02 ; +KQT13.R2B1 := -0.212672177800E-02 ; + + !Beam2 +KQ4.L2B2 := 0.430404477862E-02 ; +KQ4.R2B2 := -0.364249700784E-02 ; +KQ5.L2B2 := -0.464045425356E-02 ; +KQ5.R2B2 := 0.435269858277E-02 ; +KQ6.L2B2 := 0.483609298698E-02 ; +KQ6.R2B2 := -0.404420149851E-02 ; +KQ7.L2B2 := -0.808908884610E-02 ; +KQ7.R2B2 := 0.662298240828E-02 ; +KQ8.L2B2 := 0.699994223819E-02 ; +KQ8.R2B2 := -0.494356365528E-02 ; +KQ9.L2B2 := -0.689363400837E-02 ; +KQ9.R2B2 := 0.588932535981E-02 ; +KQ10.L2B2 := 0.722448078686E-02 ; +KQ10.R2B2 := -0.546127949571E-02 ; +KQTL11.L2B2 := 0.966221506666E-03 ; +KQTL11.R2B2 := 0.264801530521E-03 ; +KQT12.L2B2 := -0.343193597831E-02 ; +KQT12.R2B2 := 0.633371153000E-03 ; +KQT13.L2B2 := 0.248338876050E-02 ; +KQT13.R2B2 := -0.219358716293E-02 ; + + !***IR2 X-scheme*** +abxwt.l2 := -0.0000772587268993839836*on_alice ; +abwmd.l2 := +0.0001472587268993839840*on_alice ; +abaw.r2 := -0.0001335474860334838000*on_alice ; +abxwt.r2 := +0.0000635474860334838004*on_alice ; +ACBXV1.L2x := 0.794117647059E-07; +ACBXV1.L2 := 0.794117647059E-07 * on_x2; +ACBXV1.R2x := -0.794117647059E-07; +ACBXV1.R2 := -0.794117647059E-07 * on_x2; +ACBXH1.L2s := 0.800000000000E-05; +ACBXH1.L2 := 0.800000000000E-05 * on_sep2; +ACBXH1.R2s := 0.800000000000E-05; +ACBXH1.R2 := 0.800000000000E-05 * on_sep2; +ACBXV2.L2x := 0.794117647059E-07; +ACBXV2.L2 := 0.794117647059E-07 * on_x2; +ACBXV2.R2x := -0.794117647059E-07; +ACBXV2.R2 := -0.794117647059E-07 * on_x2; +ACBXH2.L2s := 0.800000000000E-05; +ACBXH2.L2 := 0.800000000000E-05 * on_sep2; +ACBXH2.R2s := 0.800000000000E-05; +ACBXH2.R2 := 0.800000000000E-05 * on_sep2; +ACBXV3.L2x := 0.794117647059E-07; +ACBXV3.L2 := 0.794117647059E-07 * on_x2; +ACBXV3.R2x := -0.794117647059E-07; +ACBXV3.R2 := -0.794117647059E-07 * on_x2; +ACBXH3.L2s := 0.800000000000E-05; +ACBXH3.L2 := 0.800000000000E-05 * on_sep2; +ACBXH3.R2s := 0.800000000000E-05; +ACBXH3.R2 := 0.800000000000E-05 * on_sep2; + + !Beam1 + ACBYVS4.L2B1x := -0.315522417345E-06 ; + ACBYVS4.L2B1o := 0.423535626683E-04 ; + ACBYVS4.L2B1ov:= 0.896902118879E-05 ; + ACBYVS4.L2B1 := -0.315522417345E-06 * on_x2 + ( 0.423535626683E-04) * on_o2 + ( 0.896902118879E-05) * on_ov2; + ACBYV4.L2B1 := 0.000000000000E+00 * on_x2 + ( 0.000000000000E+00) * on_o2 + ( 0.896902118879E-05) * on_ov2; + ACBYVS4.R2B1x := 0.131753443317E-06 ; + ACBYVS4.R2B1o := 0.104855514277E-03 ; + ACBYVS4.R2B1ov:= 0.218395575379E-04 ; + ACBYVS4.R2B1 := 0.131753443317E-06 * on_x2 + ( 0.104855514277E-03) * on_o2 + ( 0.218395575379E-04) * on_ov2; + ACBYVS5.L2B1x := -0.823829676039E-07 ; + ACBYVS5.L2B1o := -0.455783290889E-04 ; + ACBYVS5.L2B1ov:= 0.108151798207E-04 ; + ACBYVS5.L2B1 := -0.823829676039E-07 * on_x2 + ( -0.455783290889E-04) * on_o2 + ( 0.108151798207E-04) * on_ov2; + ACBCVS5.R2B1x := 0.201139829322E-06 ; + ACBCVS5.R2B1o := -0.516603427584E-04 ; + ACBCVS5.R2B1ov:= -0.207042504750E-05 ; + ACBCVS5.R2B1 := 0.201139829322E-06 * on_x2 + ( -0.516603427584E-04) * on_o2 + ( -0.207042504750E-05) * on_ov2; + ACBCV5.R2B1 := 0.000000000000E+00 * on_x2 + ( 0.000000000000E+00) * on_o2 + ( -0.000000000000E+00) * on_ov2; + ACBYHS4.L2B1s := 0.138110530557E-04 ; + ACBYHS4.L2B1a := 0.551512679412E-06 ; + ACBYHS4.L2B1oh:= 0.214600608420E-04 ; + ACBYHS4.L2B1 := 0.138110530557E-04 * on_sep2 + ( 0.551512679412E-06) * on_a2 + ( 0.214600608420E-04) * on_oh2; + ACBYHS4.R2B1s := -0.634361104169E-05 ; + ACBYHS4.R2B1a := -0.388521291660E-06 ; + ACBYHS4.R2B1oh:= 0.796269566447E-05 ; + ACBYHS4.R2B1 := -0.634361104169E-05 * on_sep2 + ( -0.388521291660E-06) * on_a2 + ( 0.796269566447E-05) * on_oh2; + ACBYH4.R2B1 := 0.000000000000E+00 * on_sep2 + ( 0.000000000000E+00) * on_a2 + ( 0.796269566447E-05) * on_oh2; + ACBYHS5.L2B1s := -0.298814264840E-05 ; + ACBYHS5.L2B1a := -0.540180469635E-06 ; + ACBYHS5.L2B1oh:= -0.756221047826E-06 ; + ACBYHS5.L2B1 := -0.298814264840E-05 * on_sep2 + ( -0.540180469635E-06) * on_a2 + ( -0.756221047826E-06) * on_oh2; + ACBYH5.L2B1 := 0.000000000000E+00 * on_x2 + ( 0.000000000000E+00) * on_o2 + ( -0.000000000000E+00) * on_oh2; + ACBCHS5.R2B1s := 0.231937733241E-04 ; + ACBCHS5.R2B1a := 0.103847489144E-05 ; + ACBCHS5.R2B1oh:= 0.126999971668E-04 ; + ACBCHS5.R2B1 := 0.231937733241E-04 * on_sep2 + ( 0.103847489144E-05) * on_a2 + ( 0.126999971668E-04) * on_oh2; + ACBCH6.R2B1oh := -0.148620448466E-04 ; + ACBCH6.R2B1 :=( -0.148620448466E-04)*on_oh2; + ACBCV6.L2B1ov := -0.167403101607E-04 ; + ACBCV6.L2B1 :=( -0.167403101607E-04)*on_ov2; + ACBCH7.L2B1oh := -0.200271616601E-04 ; + ACBCH7.L2B1 :=( -0.200271616601E-04)*on_oh2; + ACBCV7.R2B1ov := -0.203813191686E-04 ; + ACBCV7.R2B1 :=( -0.203813191686E-04)*on_ov2; + + !Beam2 + ACBYVS4.L2B2x := 0.172911488092E-06 ; + ACBYVS4.L2B2o := 0.942845694810E-04 ; + ACBYVS4.L2B2ov:= 0.224851527017E-04 ; + ACBYVS4.L2B2 := 0.172911488092E-06 * on_x2 + ( 0.942845694810E-04) * on_o2 + ( 0.224851527017E-04) * on_ov2; + ACBYVS4.R2B2x := -0.282834087324E-06 ; + ACBYVS4.R2B2o := 0.604383570664E-04 ; + ACBYVS4.R2B2ov:= 0.780528696689E-05 ; + ACBYVS4.R2B2 := -0.282834087324E-06 * on_x2 + ( 0.604383570664E-04) * on_o2 + ( 0.780528696689E-05) * on_ov2; + ACBYV4.R2B2 := 0.000000000000E+00 * on_x2 + ( 0.000000000000E+00) * on_o2 + ( 0.780528696689E-05) * on_ov2; + ACBYVS5.L2B2x := 0.160568990578E-06 ; + ACBYVS5.L2B2o := -0.412402133671E-04 ; + ACBYVS5.L2B2ov:= -0.754854860424E-05 ; + ACBYVS5.L2B2 := 0.160568990578E-06 * on_x2 + ( -0.412402133671E-04) * on_o2 + ( -0.754854860424E-05) * on_ov2; + ACBYV5.L2B2 := 0.000000000000E+00 * on_x2 + ( 0.000000000000E+00) * on_o2 + ( -0.000000000000E+00) * on_ov2; + ACBCVS5.R2B2x := -0.124841096576E-06 ; + ACBCVS5.R2B2o := -0.690682516578E-04 ; + ACBCVS5.R2B2ov:= 0.130479840796E-04 ; + ACBCVS5.R2B2 := -0.124841096576E-06 * on_x2 + ( -0.690682516578E-04) * on_o2 + ( 0.130479840796E-04) * on_ov2; + ACBYHS4.L2B2s := -0.291444743307E-05 ; + ACBYHS4.L2B2a := -0.259977403854E-07 ; + ACBYHS4.L2B2oh:= 0.708172439106E-05 ; + ACBYHS4.L2B2 := -0.291444743307E-05 * on_sep2 + ( -0.259977403854E-07) * on_a2 + ( 0.708172439106E-05) * on_oh2; + ACBYH4.L2B2 := 0.000000000000E+00 * on_sep2 + ( 0.000000000000E+00) * on_a2 + ( 0.708172439106E-05) * on_oh2; + ACBYHS4.R2B2s := -0.150017569447E-04 ; + ACBYHS4.R2B2a := -0.766765609038E-06 ; + ACBYHS4.R2B2oh:= 0.227638094067E-04 ; + ACBYHS4.R2B2 := -0.150017569447E-04 * on_sep2 + ( -0.766765609038E-06) * on_a2 + ( 0.227638094067E-04) * on_oh2; + ACBYHS5.L2B2s := -0.155879833270E-04 ; + ACBYHS5.L2B2a := -0.697935166206E-06 ; + ACBYHS5.L2B2oh:= -0.370074767788E-06 ; + ACBYHS5.L2B2 := -0.155879833270E-04 * on_sep2 + ( -0.697935166206E-06) * on_a2 + ( -0.370074767788E-06) * on_oh2; + ACBCHS5.R2B2s := 0.373646349777E-05 ; + ACBCHS5.R2B2a := 0.675460329505E-06 ; + ACBCHS5.R2B2oh:= -0.774813093699E-05 ; + ACBCHS5.R2B2 := 0.373646349777E-05 * on_sep2 + ( 0.675460329505E-06) * on_a2 + ( -0.774813093699E-05) * on_oh2; + ACBCH5.R2B2 := 0.000000000000E+00 * on_sep2 + ( 0.000000000000E+00) * on_a2 + ( -0.000000000000E+00) * on_oh2; + ACBCH6.L2B2oh := -0.132177481002E-04 ; + ACBCH6.L2B2 :=( -0.132177481002E-04)*on_oh2; + ACBCV6.R2B2ov := -0.145682479691E-04 ; + ACBCV6.R2B2 :=( -0.145682479691E-04)*on_ov2; + ACBCH7.R2B2oh := -0.212438582698E-04 ; + ACBCH7.R2B2 :=( -0.212438582698E-04)*on_oh2; + ACBCV7.L2B2ov := -0.209838076148E-04 ; + ACBCV7.L2B2 :=( -0.209838076148E-04)*on_ov2; + + !***IR8 Optics*** +KQX.L8 := 0.877985714100E-02 ; +KTQX1.L8 := 0.000000000000E+00 ; +KTQX2.L8 := 0.000000000000E+00 ; +KQX.R8 := -KQX.L8 ; +KTQX1.R8 := -KTQX1.L8 ; +KTQX2.R8 := -KTQX2.L8 ; + + !Beam1 +KQ4.L8B1 := -0.314943025155E-02 ; +KQ4.R8B1 := 0.307196942177E-02 ; +KQ5.L8B1 := 0.372476745195E-02 ; +KQ5.R8B1 := -0.278273827416E-02 ; +KQ6.L8B1 := -0.583337951111E-02 ; +KQ6.R8B1 := 0.448363792776E-02 ; +KQ7.L8B1 := 0.803257150319E-02 ; +KQ7.R8B1 := -0.650744334798E-02 ; +KQ8.L8B1 := -0.668383256379E-02 ; +KQ8.R8B1 := 0.787151903070E-02 ; +KQ9.L8B1 := 0.661003993695E-02 ; +KQ9.R8B1 := -0.731216189282E-02 ; +KQ10.L8B1 := -0.612215085302E-02 ; +KQ10.R8B1 := 0.737829179334E-02 ; +KQTL11.L8B1 := 0.446997954089E-04 ; +KQTL11.R8B1 := -0.439513243734E-04 ; +KQT12.L8B1 := 0.151187934875E-02 ; +KQT12.R8B1 := -0.287272666006E-02 ; +KQT13.L8B1 := -0.155942600909E-03 ; +KQT13.R8B1 := 0.438311592078E-02 ; + + !Beam2 +KQ4.L8B2 := 0.315228250964E-02 ; +KQ4.R8B2 := -0.310911706860E-02 ; +KQ5.L8B2 := -0.285931864063E-02 ; +KQ5.R8B2 := 0.308630082000E-02 ; +KQ6.L8B2 := 0.540287515572E-02 ; +KQ6.R8B2 := -0.485831901406E-02 ; +KQ7.L8B2 := -0.650057212443E-02 ; +KQ7.R8B2 := 0.693422710320E-02 ; +KQ8.L8B2 := 0.757222198706E-02 ; +KQ8.R8B2 := -0.707050406174E-02 ; +KQ9.L8B2 := -0.697279283262E-02 ; +KQ9.R8B2 := 0.701812989608E-02 ; +KQ10.L8B2 := 0.737287181137E-02 ; +KQ10.R8B2 := -0.658401954856E-02 ; +KQTL11.L8B2 := -0.136283305978E-02 ; +KQTL11.R8B2 := 0.668623234841E-04 ; +KQT12.L8B2 := -0.120199877064E-02 ; +KQT12.R8B2 := 0.269007144603E-02 ; +KQT13.L8B2 := 0.318148761375E-02 ; +KQT13.R8B2 := 0.258927899012E-02 ; + + !***IR8 X-scheme*** +abxws.l8 := -0.000045681598453109894*on_lhcb ; +abxwh.l8 := +0.000180681598453109894*on_lhcb ; +ablw.r8 := -0.000180681598453109894*on_lhcb ; +abxws.r8 := +0.000045681598453109894*on_lhcb ; +ACBXV1.L8s := 0.800000000000E-05; +ACBXV1.L8 := 0.800000000000E-05 * on_sep8; +ACBXV1.R8s := 0.800000000000E-05; +ACBXV1.R8 := 0.800000000000E-05 * on_sep8; +ACBXH1.L8x := 0.794117647059E-07; +ACBXH1.L8 := 0.794117647059E-07 * on_x8; +ACBXH1.R8x := -0.794117647059E-07; +ACBXH1.R8 := -0.794117647059E-07 * on_x8; +ACBXV2.L8s := 0.800000000000E-05; +ACBXV2.L8 := 0.800000000000E-05 * on_sep8; +ACBXV2.R8s := 0.800000000000E-05; +ACBXV2.R8 := 0.800000000000E-05 * on_sep8; +ACBXH2.L8x := 0.794117647059E-07; +ACBXH2.L8 := 0.794117647059E-07 * on_x8; +ACBXH2.R8x := -0.794117647059E-07; +ACBXH2.R8 := -0.794117647059E-07 * on_x8; +ACBXV3.L8s := 0.800000000000E-05; +ACBXV3.L8 := 0.800000000000E-05 * on_sep8; +ACBXV3.R8s := 0.800000000000E-05; +ACBXV3.R8 := 0.800000000000E-05 * on_sep8; +ACBXH3.L8x := 0.794117647059E-07; +ACBXH3.L8 := 0.794117647059E-07 * on_x8; +ACBXH3.R8x := -0.794117647059E-07; +ACBXH3.R8 := -0.794117647059E-07 * on_x8; + + !Beam1 + ACBYVS4.L8B1s := -0.140045443082E-05 ; + ACBYVS4.L8B1a := 0.167200209978E-06 ; + ACBYVS4.L8B1ov:= 0.111540659712E-04 ; + ACBYVS4.L8B1 := -0.140045443082E-05 * on_sep8 + ( 0.167200209978E-06) * on_a8 + ( 0.111540659712E-04) * on_ov8; + ACBYV4.L8B1 := 0.000000000000E+00 * on_sep8 + ( 0.000000000000E+00) * on_a8 + ( 0.111540659712E-04) * on_ov8; + ACBYVS4.R8B1s := 0.135952678688E-04 ; + ACBYVS4.R8B1a := -0.512371108997E-06 ; + ACBYVS4.R8B1ov:= 0.180966714768E-04 ; + ACBYVS4.R8B1 := 0.135952678688E-04 * on_sep8 + ( -0.512371108997E-06) * on_a8 + ( 0.180966714768E-04) * on_ov8; + ACBCVS5.L8B1s := 0.152795299324E-04 ; + ACBCVS5.L8B1a := -0.684127239894E-06 ; + ACBCVS5.L8B1ov:= 0.116753976896E-04 ; + ACBCVS5.L8B1 := 0.152795299324E-04 * on_sep8 + ( -0.684127239894E-06) * on_a8 + ( 0.116753976896E-04) * on_ov8; + ACBYVS5.R8B1s := -0.287376018914E-05 ; + ACBYVS5.R8B1a := 0.519442839387E-06 ; + ACBYVS5.R8B1ov:= 0.212875082216E-04 ; + ACBYVS5.R8B1 := -0.287376018914E-05 * on_sep8 + ( 0.519442839387E-06) * on_a8 + ( 0.212875082216E-04) * on_ov8; + ACBYV5.R8B1 := 0.000000000000E+00 * on_sep8 + ( 0.000000000000E+00) * on_a8 + ( 0.000000000000E+00) * on_ov8; + ACBYHS4.L8B1x := -0.204304848194E-06 ; + ACBYHS4.L8B1o := 0.862118963239E-04 ; + ACBYHS4.L8B1oh:= 0.218474783071E-04 ; + ACBYHS4.L8B1 := -0.204304848194E-06 * on_x8 + ( 0.862118963239E-04) * on_o8 + ( 0.218474783071E-04) * on_oh8; + ACBYHS4.R8B1x := 0.307025175781E-06 ; + ACBYHS4.R8B1o := 0.470483396071E-04 ; + ACBYHS4.R8B1oh:= 0.949940753015E-05 ; + ACBYHS4.R8B1 := 0.307025175781E-06 * on_x8 + ( 0.470483396071E-04) * on_o8 + ( 0.949940753015E-05) * on_oh8; + ACBYH4.R8B1 := 0.000000000000E+00 * on_x8 + ( 0.000000000000E+00) * on_o8 + ( 0.949940753015E-05) * on_oh8; + ACBCHS5.L8B1x := -0.160000214798E-06 ; + ACBCHS5.L8B1o := -0.410895884417E-04 ; + ACBCHS5.L8B1oh:= 0.982293386046E-05 ; + ACBCHS5.L8B1 := -0.160000214798E-06 * on_x8 + ( -0.410895884417E-04) * on_o8 + ( 0.982293386046E-05) * on_oh8; + ACBCH5.L8B1 := 0.000000000000E+00 * on_sep8 + ( 0.000000000000E+00) * on_a8 + ( 0.000000000000E+00) * on_oh8; + ACBYHS5.R8B1x := 0.840407701853E-07 ; + ACBYHS5.R8B1o := -0.464887701935E-04 ; + ACBYHS5.R8B1oh:= 0.128275846070E-04 ; + ACBYHS5.R8B1 := 0.840407701853E-07 * on_x8 + ( -0.464887701935E-04) * on_o8 + ( 0.128275846070E-04) * on_oh8; + ACBCH6.R8B1oh := -0.177302545116E-04 ; + ACBCH6.R8B1 :=( -0.177302545116E-04)*on_oh8; + ACBCV6.L8B1ov := -0.208186066217E-04 ; + ACBCV6.L8B1 :=( -0.208186066217E-04)*on_ov8; + ACBCH7.L8B1oh := -0.203887110639E-04 ; + ACBCH7.L8B1 :=( -0.203887110639E-04)*on_oh8; + ACBCV7.R8B1ov := -0.168883475142E-04 ; + ACBCV7.R8B1 :=( -0.168883475142E-04)*on_ov8; + + !Beam2 + ACBYVS4.L8B2s := -0.136375499974E-04 ; + ACBYVS4.L8B2a := 0.520013760957E-06 ; + ACBYVS4.L8B2ov:= 0.230405607262E-04 ; + ACBYVS4.L8B2 := -0.136375499974E-04 * on_sep8 + ( 0.520013760957E-06) * on_a8 + ( 0.230405607262E-04) * on_ov8; + ACBYVS4.R8B2s := 0.148393619988E-05 ; + ACBYVS4.R8B2a := -0.170938031266E-06 ; + ACBYVS4.R8B2ov:= 0.947600464846E-05 ; + ACBYVS4.R8B2 := 0.148393619988E-05 * on_sep8 + ( -0.170938031266E-06) * on_a8 + ( 0.947600464846E-05) * on_ov8; + ACBYV4.R8B2 := 0.000000000000E+00 * on_sep8 + ( 0.000000000000E+00) * on_a8 + ( 0.947600464846E-05) * on_ov8; + ACBCVS5.L8B2s := 0.287667269264E-05 ; + ACBCVS5.L8B2a := -0.519969285225E-06 ; + ACBCVS5.L8B2ov:= 0.252838033298E-04 ; + ACBCVS5.L8B2 := 0.287667269264E-05 * on_sep8 + ( -0.519969285225E-06) * on_a8 + ( 0.252838033298E-04) * on_ov8; + ACBCV5.L8B2 := 0.000000000000E+00 * on_sep8 + ( 0.000000000000E+00) * on_a8 + ( 0.000000000000E+00) * on_ov8; + ACBYVS5.R8B2s := -0.155371253210E-04 ; + ACBYVS5.R8B2a := 0.695660842236E-06 ; + ACBYVS5.R8B2ov:= 0.146025542335E-04 ; + ACBYVS5.R8B2 := -0.155371253210E-04 * on_sep8 + ( 0.695660842236E-06) * on_a8 + ( 0.146025542335E-04) * on_ov8; + ACBYHS4.L8B2x := 0.308530867451E-06 ; + ACBYHS4.L8B2o := 0.462154372683E-04 ; + ACBYHS4.L8B2oh:= 0.108382450534E-04 ; + ACBYHS4.L8B2 := 0.308530867451E-06 * on_x8 + ( 0.462154372683E-04) * on_o8 + ( 0.108382450534E-04) * on_oh8; + ACBYH4.L8B2 := 0.000000000000E+00 * on_x8 + ( 0.000000000000E+00) * on_o8 + ( 0.108382450534E-04) * on_oh8; + ACBYHS4.R8B2x := -0.204743725076E-06 ; + ACBYHS4.R8B2o := 0.860991885350E-04 ; + ACBYHS4.R8B2oh:= 0.175731720002E-04 ; + ACBYHS4.R8B2 := -0.204743725076E-06 * on_x8 + ( 0.860991885350E-04) * on_o8 + ( 0.175731720002E-04) * on_oh8; + ACBCHS5.L8B2x := 0.841485799124E-07 ; + ACBCHS5.L8B2o := -0.465484072198E-04 ; + ACBCHS5.L8B2oh:= 0.603627045092E-05 ; + ACBCHS5.L8B2 := 0.841485799124E-07 * on_x8 + ( -0.465484072198E-04) * on_o8 + ( 0.603627045092E-05) * on_oh8; + ACBYHS5.R8B2x := -0.156089974021E-06 ; + ACBYHS5.R8B2o := -0.400854011384E-04 ; + ACBYHS5.R8B2oh:= 0.162781402228E-04 ; + ACBYHS5.R8B2 := -0.156089974021E-06 * on_x8 + ( -0.400854011384E-04) * on_o8 + ( 0.162781402228E-04) * on_oh8; + ACBYH5.R8B2 := 0.000000000000E+00 * on_sep8 + ( 0.000000000000E+00) * on_a8 + ( 0.000000000000E+00) * on_oh8; + ACBCH6.L8B2oh := -0.202291398328E-04 ; + ACBCH6.L8B2 :=( -0.202291398328E-04)*on_oh8; + ACBCV6.R8B2ov := -0.176865739929E-04 ; + ACBCV6.R8B2 :=( -0.176865739929E-04)*on_ov8; + ACBCH7.R8B2oh := -0.163998023640E-04 ; + ACBCH7.R8B2 :=( -0.163998023640E-04)*on_oh8; + ACBCV7.L8B2ov := -0.215021307629E-04 ; + ACBCV7.L8B2 :=( -0.215021307629E-04)*on_ov8; + + !***IR4 Optics*** + + !Beam1 +KQ5.L4B1 := 0.446614652916E-02 ; +KQ5.R4B1 := -0.482983813625E-02 ; +KQ6.L4B1 := -0.513783187984E-02 ; +KQ6.R4B1 := 0.588523115292E-02 ; +KQ7.L4B1 := 0.683999121598E-02 ; +KQ7.R4B1 := -0.691299594268E-02 ; +KQ8.L4B1 := -0.468931256673E-02 ; +KQ8.R4B1 := 0.844529750337E-02 ; +KQ9.L4B1 := 0.634473352819E-02 ; +KQ9.R4B1 := -0.578619524910E-02 ; +KQ10.L4B1 := -0.567412104477E-02 ; +KQ10.R4B1 := 0.710611920457E-02 ; +KQTL11.L4B1 := 0.385240894100E-03 ; +KQTL11.R4B1 := 0.325708224500E-03 ; +KQT12.L4B1 := 0.198372924230E-02 ; +KQT12.R4B1 := 0.855091365912E-04 ; +KQT13.L4B1 := -0.511265569583E-03 ; +KQT13.R4B1 := -0.294481052687E-02 ; + + !Beam2 +KQ5.L4B2 := -0.422434481976E-02 ; +KQ5.R4B2 := 0.484419847834E-02 ; +KQ6.L4B2 := 0.584611901385E-02 ; +KQ6.R4B2 := -0.619963196957E-02 ; +KQ7.L4B2 := -0.507087983996E-02 ; +KQ7.R4B2 := 0.634858110237E-02 ; +KQ8.L4B2 := 0.853843208507E-02 ; +KQ8.R4B2 := -0.695732601997E-02 ; +KQ9.L4B2 := -0.513005206679E-02 ; +KQ9.R4B2 := 0.616240666583E-02 ; +KQ10.L4B2 := 0.715008908924E-02 ; +KQ10.R4B2 := -0.569718194207E-02 ; +KQTL11.L4B2 := 0.902227970175E-03 ; +KQTL11.R4B2 := 0.649758580317E-03 ; +KQT12.L4B2 := 0.109124656140E-02 ; +KQT12.R4B2 := 0.201232031675E-02 ; +KQT13.L4B2 := 0.501618931000E-03 ; +KQT13.R4B2 := -0.228258340580E-02 ; + + !***IR6 Optics*** + + !Beam1 +KQ4.L6B1 := -0.488141473400E-02 ; +KQ4.R6B1 := 0.572549637769E-02 ; +KQ5.L6B1 := 0.659855070920E-02 ; +KQ5.R6B1 := -0.665255376088E-02 ; +KQ8.L6B1 := -0.547517398760E-02 ; +KQ8.R6B1 := 0.779674934848E-02 ; +KQ9.L6B1 := 0.667536875169E-02 ; +KQ9.R6B1 := -0.645838417696E-02 ; +KQ10.L6B1 := -0.772924565360E-02 ; +KQ10.R6B1 := 0.708915262339E-02 ; +KQTL11.L6B1 := 0.722931626641E-03 ; +KQTL11.R6B1 := -0.866234208859E-04 ; +KQT12.L6B1 := -0.325299180995E-02 ; +KQT12.R6B1 := -0.164072250986E-02 ; +KQT13.L6B1 := 0.272351392307E-04 ; +KQT13.R6B1 := 0.194704064350E-02 ; + + !Beam2 +KQ4.L6B2 := 0.566120656023E-02 ; +KQ4.R6B2 := -0.483383773000E-02 ; +KQ5.L6B2 := -0.676980402311E-02 ; +KQ5.R6B2 := 0.642911072627E-02 ; +KQ8.L6B2 := 0.792929682788E-02 ; +KQ8.R6B2 := -0.515140034592E-02 ; +KQ9.L6B2 := -0.706447120368E-02 ; +KQ9.R6B2 := 0.670181924199E-02 ; +KQ10.L6B2 := 0.718633111850E-02 ; +KQ10.R6B2 := -0.737432148761E-02 ; +KQTL11.L6B2 := -0.111068423838E-02 ; +KQTL11.R6B2 := 0.497231225358E-03 ; +KQT12.L6B2 := 0.131837659441E-02 ; +KQT12.R6B2 := 0.427512390615E-02 ; +KQT13.L6B2 := 0.265791995335E-02 ; +KQT13.R6B2 := -0.207135078019E-02 ; + + !***IR3 Optics*** +KQ4.LR3 := 0.124128400000E-02 ; +KQT4.L3 := 0.688713000000E-03 ; +KQT4.R3 := 0.688713000000E-03 ; +KQ5.LR3 := -0.130392400000E-02 ; +KQT5.L3 := 0.972084000000E-03 ; +KQT5.R3 := 0.972084000000E-03 ; + + !Beam1 +KQ6.L3B1 := 0.265206600700E-02 ; +KQ6.R3B1 := -0.248284002200E-02 ; +KQTL7.L3B1 := -0.199490058500E-02 ; +KQTL7.R3B1 := 0.910271209100E-03 ; +KQTL8.L3B1 := 0.129306774100E-03 ; +KQTL8.R3B1 := 0.250745464100E-02 ; +KQTL9.L3B1 := -0.471507917000E-02 ; +KQTL9.R3B1 := -0.746685541000E-04 ; +KQTL10.L3B1 := 0.915285061000E-03 ; +KQTL10.R3B1 := 0.285281176400E-02 ; +KQTL11.L3B1 := -0.338523656500E-03 ; +KQTL11.R3B1 := -0.363123332200E-02 ; +KQT12.L3B1 := 0.284276661600E-02 ; +KQT12.R3B1 := 0.500000000000E-02 ; +KQT13.L3B1 := -0.635371688300E-03 ; +KQT13.R3B1 := -0.456628965700E-02 ; + + !Beam2 +KQ6.L3B2 := -0.247436871800E-02 ; +KQ6.R3B2 := 0.267567475900E-02 ; +KQTL7.L3B2 := 0.766905226600E-03 ; +KQTL7.R3B2 := -0.281553667400E-02 ; +KQTL8.L3B2 := 0.219362332600E-02 ; +KQTL8.R3B2 := -0.148739570200E-03 ; +KQTL9.L3B2 := 0.847198389400E-05 ; +KQTL9.R3B2 := -0.396947896700E-02 ; +KQTL10.L3B2 := 0.214887891600E-02 ; +KQTL10.R3B2 := 0.851839112500E-03 ; +KQTL11.L3B2 := -0.341390900600E-02 ; +KQTL11.R3B2 := 0.110161035700E-02 ; +KQT12.L3B2 := 0.918454053400E-03 ; +KQT12.R3B2 := 0.280357642100E-02 ; +KQT13.L3B2 := -0.508018044000E-02 ; +KQT13.R3B2 := -0.632055499900E-03 ; + + !***IR7 Optics*** +KQ4.LR7 := 0.131382724100E-02 ; +KQT4.L7 := 0.331689344000E-03 ; +KQT4.R7 := 0.331689344000E-03 ; +KQ5.LR7 := -0.133553657300E-02 ; +KQT5.L7 := -0.326577060000E-04 ; +KQT5.R7 := -0.326577060000E-04 ; + + !Beam1 +KQ6.L7B1 := 0.327544691300E-02 ; +KQ6.R7B1 := -0.312605402900E-02 ; +KQTL7.L7B1 := 0.160052266300E-02 ; +KQTL7.R7B1 := 0.499838836300E-02 ; +KQTL8.L7B1 := -0.624140752500E-03 ; +KQTL8.R7B1 := 0.959695294500E-03 ; +KQTL9.L7B1 := 0.277954164400E-03 ; +KQTL9.R7B1 := 0.378348784800E-02 ; +KQTL10.L7B1 := 0.448635355000E-02 ; +KQTL10.R7B1 := -0.859843781000E-03 ; +KQTL11.L7B1 := 0.224710281400E-02 ; +KQTL11.R7B1 := -0.999078869700E-04 ; +KQT12.L7B1 := 0.826676741300E-03 ; +KQT12.R7B1 := 0.193842715400E-02 ; +KQT13.L7B1 := 0.213314307900E-02 ; +KQT13.R7B1 := 0.111487778800E-02 ; + + !Beam2 +KQ6.L7B2 := -0.297393932800E-02 ; +KQ6.R7B2 := 0.331824954500E-02 ; +KQTL7.L7B2 := 0.420169109000E-02 ; +KQTL7.R7B2 := 0.204320340600E-04 ; +KQTL8.L7B2 := 0.139916502700E-02 ; +KQTL8.R7B2 := 0.127931436900E-02 ; +KQTL9.L7B2 := 0.389102772700E-02 ; +KQTL9.R7B2 := -0.521687969000E-03 ; +KQTL10.L7B2 := 0.707120156500E-03 ; +KQTL10.R7B2 := 0.474066404700E-02 ; +KQTL11.L7B2 := 0.128032099700E-03 ; +KQTL11.R7B2 := 0.117163623700E-02 ; +KQT12.L7B2 := 0.426896307200E-02 ; +KQT12.R7B2 := -0.203306740500E-02 ; +KQT13.L7B2 := -0.420459552000E-03 ; +KQT13.R7B2 := 0.184240525000E-02 ; + + !***Arc Optics*** + !QF/QD +KQF.A81 := 0.870329953900E-02 ; +KQF.A12 := 0.870329953900E-02 ; +KQF.A45 := 0.870329953900E-02 ; +KQF.A56 := 0.870329953900E-02 ; +KQD.A81 := -0.870475552100E-02 ; +KQD.A12 := -0.870475552100E-02 ; +KQD.A45 := -0.870475552100E-02 ; +KQD.A56 := -0.870475552100E-02 ; +KQF.A78 := 0.877219370500E-02 ; +KQF.A23 := 0.874003742200E-02 ; +KQF.A34 := 0.874003742200E-02 ; +KQF.A67 := 0.877219370500E-02 ; +KQD.A78 := -0.885967069500E-02 ; +KQD.A23 := -0.855353408600E-02 ; +KQD.A34 := -0.855353408600E-02 ; +KQD.A67 := -0.885967069500E-02 ; + + !QTF/QTD BEAM1 +dQx.b1 := 0.000000000000E+00 ; +dQy.b1 := 0.000000000000E+00 ; +dQx.b1_sq := 0.000000000000E+00 ; +dQy.b1_sq := 0.000000000000E+00 ; + +KQTF.A81B1 := 0.000000000000E+00 + ( 0.386712697356E-02) * dQx.b1 + ( 0.714404818290E-03) * dQy.b1 + ( 0.000000000000E+00) * dQx.b1_sq + ( 0.000000000000E+00) * dQy.b1_sq ; +KQTF.A12B1 := 0.000000000000E+00 + ( 0.386712697356E-02) * dQx.b1 + ( 0.714404818290E-03) * dQy.b1 + ( 0.000000000000E+00) * dQx.b1_sq + ( 0.000000000000E+00) * dQy.b1_sq ; +KQTF.A45B1 := 0.000000000000E+00 + ( 0.386712697356E-02) * dQx.b1 + ( 0.714404818290E-03) * dQy.b1 + ( 0.000000000000E+00) * dQx.b1_sq + ( 0.000000000000E+00) * dQy.b1_sq ; +KQTF.A56B1 := 0.000000000000E+00 + ( 0.386712697356E-02) * dQx.b1 + ( 0.714404818290E-03) * dQy.b1 + ( 0.000000000000E+00) * dQx.b1_sq + ( 0.000000000000E+00) * dQy.b1_sq ; +KQTD.A81B1 := 0.000000000000E+00 + (-0.675151714265E-03) * dQx.b1 + (-0.361436046931E-02) * dQy.b1 + ( 0.000000000000E+00) * dQx.b1_sq + ( 0.000000000000E+00) * dQy.b1_sq ; +KQTD.A12B1 := 0.000000000000E+00 + (-0.675151714265E-03) * dQx.b1 + (-0.361436046931E-02) * dQy.b1 + ( 0.000000000000E+00) * dQx.b1_sq + ( 0.000000000000E+00) * dQy.b1_sq ; +KQTD.A45B1 := 0.000000000000E+00 + (-0.675151714265E-03) * dQx.b1 + (-0.361436046931E-02) * dQy.b1 + ( 0.000000000000E+00) * dQx.b1_sq + ( 0.000000000000E+00) * dQy.b1_sq ; +KQTD.A56B1 := 0.000000000000E+00 + (-0.675151714265E-03) * dQx.b1 + (-0.361436046931E-02) * dQy.b1 + ( 0.000000000000E+00) * dQx.b1_sq + ( 0.000000000000E+00) * dQy.b1_sq ; +KQTF.A78B1 := 0.761119694300E-03 + ( 0.386712697356E-02) * dQx.b1 + ( 0.714404818290E-03) * dQy.b1 + ( 0.724644665413E-02) * dQx.b1_sq + ( 0.132484451020E-02) * dQy.b1_sq ; +KQTF.A23B1 := -0.771991245000E-03 + ( 0.386712697356E-02) * dQx.b1 + ( 0.714404818290E-03) * dQy.b1 + ( 0.724644665413E-02) * dQx.b1_sq + ( 0.132484451020E-02) * dQy.b1_sq ; +KQTF.A34B1 := -0.771991245000E-03 + ( 0.386712697356E-02) * dQx.b1 + ( 0.714404818290E-03) * dQy.b1 + ( 0.724644665413E-02) * dQx.b1_sq + ( 0.132484451020E-02) * dQy.b1_sq ; +KQTF.A67B1 := 0.761119694300E-03 + ( 0.386712697356E-02) * dQx.b1 + ( 0.714404818290E-03) * dQy.b1 + ( 0.724644665413E-02) * dQx.b1_sq + ( 0.132484451020E-02) * dQy.b1_sq ; +KQTD.A78B1 := -0.933337382400E-03 + (-0.675151714265E-03) * dQx.b1 + (-0.361436046931E-02) * dQy.b1 + (-0.134618584897E-02) * dQx.b1_sq + (-0.720260248926E-02) * dQy.b1_sq ; +KQTD.A23B1 := 0.915761029700E-03 + (-0.675151714265E-03) * dQx.b1 + (-0.361436046931E-02) * dQy.b1 + (-0.134618584897E-02) * dQx.b1_sq + (-0.720260248926E-02) * dQy.b1_sq ; +KQTD.A34B1 := 0.915761029700E-03 + (-0.675151714265E-03) * dQx.b1 + (-0.361436046931E-02) * dQy.b1 + (-0.134618584897E-02) * dQx.b1_sq + (-0.720260248926E-02) * dQy.b1_sq ; +KQTD.A67B1 := -0.933337382400E-03 + (-0.675151714265E-03) * dQx.b1 + (-0.361436046931E-02) * dQy.b1 + (-0.134618584897E-02) * dQx.b1_sq + (-0.720260248926E-02) * dQy.b1_sq ; + + !QTF/QTD BEAM2 +dQx.b2 := 0.000000000000E+00 ; +dQy.b2 := 0.000000000000E+00 ; +dQx.b2_sq := 0.000000000000E+00 ; +dQy.b2_sq := 0.000000000000E+00 ; + +KQTF.A81B2 := 0.000000000000E+00 + ( 0.362545460533E-02) * dQx.b2 + ( 0.671002838591E-03) * dQy.b2 + ( 0.000000000000E+00) * dQx.b2_sq + ( 0.000000000000E+00) * dQy.b2_sq ; +KQTF.A12B2 := 0.000000000000E+00 + ( 0.362545460533E-02) * dQx.b2 + ( 0.671002838591E-03) * dQy.b2 + ( 0.000000000000E+00) * dQx.b2_sq + ( 0.000000000000E+00) * dQy.b2_sq ; +KQTF.A45B2 := 0.000000000000E+00 + ( 0.362545460533E-02) * dQx.b2 + ( 0.671002838591E-03) * dQy.b2 + ( 0.000000000000E+00) * dQx.b2_sq + ( 0.000000000000E+00) * dQy.b2_sq ; +KQTF.A56B2 := 0.000000000000E+00 + ( 0.362545460533E-02) * dQx.b2 + ( 0.671002838591E-03) * dQy.b2 + ( 0.000000000000E+00) * dQx.b2_sq + ( 0.000000000000E+00) * dQy.b2_sq ; +KQTD.A81B2 := 0.000000000000E+00 + (-0.676071957293E-03) * dQx.b2 + (-0.362160071886E-02) * dQy.b2 + ( 0.000000000000E+00) * dQx.b2_sq + ( 0.000000000000E+00) * dQy.b2_sq ; +KQTD.A12B2 := 0.000000000000E+00 + (-0.676071957293E-03) * dQx.b2 + (-0.362160071886E-02) * dQy.b2 + ( 0.000000000000E+00) * dQx.b2_sq + ( 0.000000000000E+00) * dQy.b2_sq ; +KQTD.A45B2 := 0.000000000000E+00 + (-0.676071957293E-03) * dQx.b2 + (-0.362160071886E-02) * dQy.b2 + ( 0.000000000000E+00) * dQx.b2_sq + ( 0.000000000000E+00) * dQy.b2_sq ; +KQTD.A56B2 := 0.000000000000E+00 + (-0.676071957293E-03) * dQx.b2 + (-0.362160071886E-02) * dQy.b2 + ( 0.000000000000E+00) * dQx.b2_sq + ( 0.000000000000E+00) * dQy.b2_sq ; +KQTF.A78B2 := -0.761119694300E-03 + ( 0.362545460533E-02) * dQx.b2 + ( 0.671002838591E-03) * dQy.b2 + ( 0.724623885254E-02) * dQx.b2_sq + ( 0.132971878439E-02) * dQy.b2_sq ; +KQTF.A23B2 := 0.771991245000E-03 + ( 0.362545460533E-02) * dQx.b2 + ( 0.671002838591E-03) * dQy.b2 + ( 0.724623885254E-02) * dQx.b2_sq + ( 0.132971878439E-02) * dQy.b2_sq ; +KQTF.A34B2 := 0.771991245000E-03 + ( 0.362545460533E-02) * dQx.b2 + ( 0.671002838591E-03) * dQy.b2 + ( 0.724623885254E-02) * dQx.b2_sq + ( 0.132971878439E-02) * dQy.b2_sq ; +KQTF.A67B2 := -0.761119694300E-03 + ( 0.362545460533E-02) * dQx.b2 + ( 0.671002838591E-03) * dQy.b2 + ( 0.724623885254E-02) * dQx.b2_sq + ( 0.132971878439E-02) * dQy.b2_sq ; +KQTD.A78B2 := 0.933337382400E-03 + (-0.676071957293E-03) * dQx.b2 + (-0.362160071886E-02) * dQy.b2 + (-0.134994243959E-02) * dQx.b2_sq + (-0.723143214654E-02) * dQy.b2_sq ; +KQTD.A23B2 := -0.915761029700E-03 + (-0.676071957293E-03) * dQx.b2 + (-0.362160071886E-02) * dQy.b2 + (-0.134994243959E-02) * dQx.b2_sq + (-0.723143214654E-02) * dQy.b2_sq ; +KQTD.A34B2 := -0.915761029700E-03 + (-0.676071957293E-03) * dQx.b2 + (-0.362160071886E-02) * dQy.b2 + (-0.134994243959E-02) * dQx.b2_sq + (-0.723143214654E-02) * dQy.b2_sq ; +KQTD.A67B2 := 0.933337382400E-03 + (-0.676071957293E-03) * dQx.b2 + (-0.362160071886E-02) * dQy.b2 + (-0.134994243959E-02) * dQx.b2_sq + (-0.723143214654E-02) * dQy.b2_sq ; + + !Sextupole BEAM1 +dQpx.b1 := 0.000000000000E+00 ; +dQpy.b1 := 0.000000000000E+00 ; +dQpx.b1_sq := 0.000000000000E+00 ; +dQpy.b1_sq := 0.000000000000E+00 ; + + !Strong sextupoles of sectors 81/12/45/56 +KSF1.A81B1 := 0.271376899705E+00 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSF1.A12B1 := 0.223849527802E+00 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSF1.A45B1 := 0.250744955008E+00 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSF1.A56B1 := 0.226852708527E+00 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSD2.A81B1 := -0.382962210512E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSD2.A12B1 := -0.400075367202E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSD2.A45B1 := -0.365061701240E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSD2.A56B1 := -0.427692756487E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; + + !Weak sextupoles of sectors 81/12/45/56 +KSF2.A81B1 := 0.602589494162E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSF2.A12B1 := 0.602589494162E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSF2.A45B1 := 0.602589494162E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSF2.A56B1 := 0.602589494162E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSD1.A81B1 := -0.992577274856E-01 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSD1.A12B1 := -0.992577274856E-01 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSD1.A45B1 := -0.992577274856E-01 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; +KSD1.A56B1 := -0.992577274856E-01 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + ( 0.000000000000E+00) * dQpx.b1_sq + ( 0.000000000000E+00) * dQpy.b1_sq ; + + !Weak sextupoles of sectors 78/23/34/67 +KSF1.A78B1 := 0.713363027010E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.119947463930E-02) * dQpx.b1_sq + ( 0.219879408568E-03) * dQpy.b1_sq ; +KSF2.A78B1 := 0.713363027010E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.119947463930E-02) * dQpx.b1_sq + ( 0.219879408568E-03) * dQpy.b1_sq ; +KSF1.A23B1 := 0.713363027010E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.119947463930E-02) * dQpx.b1_sq + ( 0.219879408568E-03) * dQpy.b1_sq ; +KSF2.A23B1 := 0.713363027010E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.119947463930E-02) * dQpx.b1_sq + ( 0.219879408568E-03) * dQpy.b1_sq ; +KSF1.A34B1 := 0.713363027010E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.119947463930E-02) * dQpx.b1_sq + ( 0.219879408568E-03) * dQpy.b1_sq ; +KSF2.A34B1 := 0.713363027010E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.119947463930E-02) * dQpx.b1_sq + ( 0.219879408568E-03) * dQpy.b1_sq ; +KSF1.A67B1 := 0.713363027010E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.119947463930E-02) * dQpx.b1_sq + ( 0.219879408568E-03) * dQpy.b1_sq ; +KSF2.A67B1 := 0.713363027010E-01 + ( 0.596051042311E-03) * dQpx.b1 + ( 0.110084106309E-03) * dQpy.b1 + ( 0.119947463930E-02) * dQpx.b1_sq + ( 0.219879408568E-03) * dQpy.b1_sq ; +KSD1.A78B1 := -0.123006785438E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + (-0.375045363311E-03) * dQpx.b1_sq + (-0.200168621860E-02) * dQpy.b1_sq ; +KSD2.A78B1 := -0.123006785438E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + (-0.375045363311E-03) * dQpx.b1_sq + (-0.200168621860E-02) * dQpy.b1_sq ; +KSD1.A23B1 := -0.123006785438E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + (-0.375045363311E-03) * dQpx.b1_sq + (-0.200168621860E-02) * dQpy.b1_sq ; +KSD2.A23B1 := -0.123006785438E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + (-0.375045363311E-03) * dQpx.b1_sq + (-0.200168621860E-02) * dQpy.b1_sq ; +KSD1.A34B1 := -0.123006785438E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + (-0.375045363311E-03) * dQpx.b1_sq + (-0.200168621860E-02) * dQpy.b1_sq ; +KSD2.A34B1 := -0.123006785438E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + (-0.375045363311E-03) * dQpx.b1_sq + (-0.200168621860E-02) * dQpy.b1_sq ; +KSD1.A67B1 := -0.123006785438E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + (-0.375045363311E-03) * dQpx.b1_sq + (-0.200168621860E-02) * dQpy.b1_sq ; +KSD2.A67B1 := -0.123006785438E+00 + (-0.185561383879E-03) * dQpx.b1 + (-0.994097213717E-03) * dQpy.b1 + (-0.375045363311E-03) * dQpx.b1_sq + (-0.200168621860E-02) * dQpy.b1_sq ; + + !Sextupole BEAM2 +dQpx.b2 := 0.000000000000E+00 ; +dQpy.b2 := 0.000000000000E+00 ; +dQpx.b2_sq := 0.000000000000E+00 ; +dQpy.b2_sq := 0.000000000000E+00 ; + + !Strong sextupoles of sectors 81/12/45/56 +KSF2.A81B2 := 0.213429553700E+00 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSF2.A12B2 := 0.245046265549E+00 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSF2.A45B2 := 0.221674085323E+00 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSF2.A56B2 := 0.250526164961E+00 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSD1.A81B2 := -0.417423146767E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSD1.A12B2 := -0.371890020956E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSD1.A45B2 := -0.419434955775E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSD1.A56B2 := -0.367196051685E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; + + !Weak sextupoles of sectors 81/12/45/56 +KSF1.A81B2 := 0.606216043024E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSF1.A12B2 := 0.606216043024E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSF1.A45B2 := 0.606216043024E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSF1.A56B2 := 0.606216043024E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSD2.A81B2 := -0.999800547286E-01 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSD2.A12B2 := -0.999800547286E-01 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSD2.A45B2 := -0.999800547286E-01 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; +KSD2.A56B2 := -0.999800547286E-01 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + ( 0.000000000000E+00) * dQpx.b2_sq + ( 0.000000000000E+00) * dQpy.b2_sq ; + + !Weak sextupoles of sectors 78/23/34/67 +KSF1.A78B2 := 0.782410470527E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.119952095433E-02) * dQpx.b2_sq + ( 0.220149391639E-03) * dQpy.b2_sq ; +KSF2.A78B2 := 0.782410470527E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.119952095433E-02) * dQpx.b2_sq + ( 0.220149391639E-03) * dQpy.b2_sq ; +KSF1.A23B2 := 0.782410470527E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.119952095433E-02) * dQpx.b2_sq + ( 0.220149391639E-03) * dQpy.b2_sq ; +KSF2.A23B2 := 0.782410470527E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.119952095433E-02) * dQpx.b2_sq + ( 0.220149391639E-03) * dQpy.b2_sq ; +KSF1.A34B2 := 0.782410470527E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.119952095433E-02) * dQpx.b2_sq + ( 0.220149391639E-03) * dQpy.b2_sq ; +KSF2.A34B2 := 0.782410470527E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.119952095433E-02) * dQpx.b2_sq + ( 0.220149391639E-03) * dQpy.b2_sq ; +KSF1.A67B2 := 0.782410470527E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.119952095433E-02) * dQpx.b2_sq + ( 0.220149391639E-03) * dQpy.b2_sq ; +KSF2.A67B2 := 0.782410470527E-01 + ( 0.596873325192E-03) * dQpx.b2 + ( 0.110454102201E-03) * dQpy.b2 + ( 0.119952095433E-02) * dQpx.b2_sq + ( 0.220149391639E-03) * dQpy.b2_sq ; +KSD1.A78B2 := -0.125655487920E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + (-0.377453762946E-03) * dQpx.b2_sq + (-0.200283999349E-02) * dQpy.b2_sq ; +KSD2.A78B2 := -0.125655487920E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + (-0.377453762946E-03) * dQpx.b2_sq + (-0.200283999349E-02) * dQpy.b2_sq ; +KSD1.A23B2 := -0.125655487920E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + (-0.377453762946E-03) * dQpx.b2_sq + (-0.200283999349E-02) * dQpy.b2_sq ; +KSD2.A23B2 := -0.125655487920E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + (-0.377453762946E-03) * dQpx.b2_sq + (-0.200283999349E-02) * dQpy.b2_sq ; +KSD1.A34B2 := -0.125655487920E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + (-0.377453762946E-03) * dQpx.b2_sq + (-0.200283999349E-02) * dQpy.b2_sq ; +KSD2.A34B2 := -0.125655487920E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + (-0.377453762946E-03) * dQpx.b2_sq + (-0.200283999349E-02) * dQpy.b2_sq ; +KSD1.A67B2 := -0.125655487920E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + (-0.377453762946E-03) * dQpx.b2_sq + (-0.200283999349E-02) * dQpy.b2_sq ; +KSD2.A67B2 := -0.125655487920E+00 + (-0.187409127394E-03) * dQpx.b2 + (-0.993816048260E-03) * dQpy.b2 + (-0.377453762946E-03) * dQpx.b2_sq + (-0.200283999349E-02) * dQpy.b2_sq ; + + !MQS BEAM1 +CMRS.b1 := 0.000000000000E+00 ; +CMIS.b1 := 0.000000000000E+00 ; +CMRS.b1_sq := 0.000000000000E+00 ; +CMIS.b1_sq := 0.000000000000E+00 ; +ona2_b1 := 0.000000000000E+00 ; + + KQS.R1B1 := ( 0.000000000000E+00) * ona2_b1 + ( 0.266278479040E-01) * CMRS.b1 + (-0.899733288016E-02) * CMIS.b1 + ( 0.000000000000E+00) * CMRS.b1_sq + ( 0.000000000000E+00) * CMIS.b1_sq ; + KQS.L2B1 := ( 0.000000000000E+00) * ona2_b1 + ( 0.266278479040E-01) * CMRS.b1 + (-0.899733288016E-02) * CMIS.b1 + ( 0.000000000000E+00) * CMRS.b1_sq + ( 0.000000000000E+00) * CMIS.b1_sq ; +KQS.A23B1 := ( 0.000000000000E+00) * ona2_b1 + ( 0.142516736842E-01) * CMRS.b1 + ( 0.848602983914E-02) * CMIS.b1 + ( 0.302173156154E-01) * CMRS.b1_sq + ( 0.109843179604E-01) * CMIS.b1_sq ; + KQS.R3B1 := ( 0.000000000000E+00) * ona2_b1 + (-0.171205193764E-01) * CMRS.b1 + (-0.807870546221E-02) * CMIS.b1 + (-0.402300957758E-01) * CMRS.b1_sq + (-0.822964594698E-02) * CMIS.b1_sq ; + KQS.L4B1 := ( 0.000000000000E+00) * ona2_b1 + (-0.171205193764E-01) * CMRS.b1 + (-0.807870546221E-02) * CMIS.b1 + (-0.402300957758E-01) * CMRS.b1_sq + (-0.822964594698E-02) * CMIS.b1_sq ; +KQS.A45B1 := ( 0.000000000000E+00) * ona2_b1 + ( 0.113812285983E-01) * CMRS.b1 + ( 0.955159460427E-02) * CMIS.b1 + ( 0.000000000000E+00) * CMRS.b1_sq + ( 0.000000000000E+00) * CMIS.b1_sq ; + KQS.R5B1 := ( 0.000000000000E+00) * ona2_b1 + ( 0.792323136002E-02) * CMRS.b1 + ( 0.100926247998E-01) * CMIS.b1 + ( 0.000000000000E+00) * CMRS.b1_sq + ( 0.000000000000E+00) * CMIS.b1_sq ; + KQS.L6B1 := ( 0.000000000000E+00) * ona2_b1 + ( 0.792323136002E-02) * CMRS.b1 + ( 0.100926247998E-01) * CMIS.b1 + ( 0.000000000000E+00) * CMRS.b1_sq + ( 0.000000000000E+00) * CMIS.b1_sq ; +KQS.A67B1 := ( 0.000000000000E+00) * ona2_b1 + (-0.158692136780E-01) * CMRS.b1 + ( 0.106460324212E-01) * CMIS.b1 + (-0.709778694350E-01) * CMRS.b1_sq + ( 0.349381515069E-01) * CMIS.b1_sq ; + KQS.R7B1 := ( 0.000000000000E+00) * ona2_b1 + (-0.739140462540E-02) * CMRS.b1 + (-0.987710657697E-02) * CMIS.b1 + (-0.549901960504E-02) * CMRS.b1_sq + (-0.185504800255E-01) * CMIS.b1_sq ; + KQS.L8B1 := ( 0.000000000000E+00) * ona2_b1 + (-0.739140462540E-02) * CMRS.b1 + (-0.987710657697E-02) * CMIS.b1 + (-0.549901960504E-02) * CMRS.b1_sq + (-0.185504800255E-01) * CMIS.b1_sq ; +KQS.A81B1 := ( 0.000000000000E+00) * ona2_b1 + ( 0.241324775639E-01) * CMRS.b1 + (-0.962582146500E-02) * CMIS.b1 + ( 0.000000000000E+00) * CMRS.b1_sq + ( 0.000000000000E+00) * CMIS.b1_sq ; + + !MQS BEAM2 +CMRS.b2 := 0.000000000000E+00 ; +CMIS.b2 := 0.000000000000E+00 ; +CMRS.b2_sq := 0.000000000000E+00 ; +CMIS.b2_sq := 0.000000000000E+00 ; +ona2_b2 := 0.000000000000E+00 ; + +KQS.A12B2 := ( 0.519213248459E-03) * ona2_b2 + ( 0.124458484817E-01) * CMRS.b2 + (-0.207596749726E-01) * CMIS.b2 + ( 0.000000000000E+00) * CMRS.b2_sq + ( 0.000000000000E+00) * CMIS.b2_sq ; + KQS.R2B2 := ( -0.952785714091E-03) * ona2_b2 + ( 0.121456161967E-01) * CMRS.b2 + ( 0.397509215137E-02) * CMIS.b2 + ( 0.200920340631E-01) * CMRS.b2_sq + ( 0.712846355318E-02) * CMIS.b2_sq ; + KQS.L3B2 := ( -0.952785714091E-03) * ona2_b2 + ( 0.121456161967E-01) * CMRS.b2 + ( 0.397509215137E-02) * CMIS.b2 + ( 0.200920340631E-01) * CMRS.b2_sq + ( 0.712846355318E-02) * CMIS.b2_sq ; +KQS.A34B2 := ( -0.217284900157E-03) * ona2_b2 + (-0.179258964749E-01) * CMRS.b2 + ( 0.371667140033E-02) * CMIS.b2 + (-0.405188393546E-01) * CMRS.b2_sq + ( 0.212647436428E-01) * CMIS.b2_sq ; + KQS.R4B2 := ( 0.186949354181E-03) * ona2_b2 + ( 0.128662566995E-01) * CMRS.b2 + ( 0.360504223421E-02) * CMIS.b2 + ( 0.000000000000E+00) * CMRS.b2_sq + ( 0.000000000000E+00) * CMIS.b2_sq ; + KQS.L5B2 := ( 0.186949354181E-03) * ona2_b2 + ( 0.128662566995E-01) * CMRS.b2 + ( 0.360504223421E-02) * CMIS.b2 + ( 0.000000000000E+00) * CMRS.b2_sq + ( 0.000000000000E+00) * CMIS.b2_sq ; +KQS.A56B2 := ( 0.397814910113E-03) * ona2_b2 + ( 0.148124920807E-01) * CMRS.b2 + ( 0.138602241563E-02) * CMIS.b2 + ( 0.000000000000E+00) * CMRS.b2_sq + ( 0.000000000000E+00) * CMIS.b2_sq ; + KQS.R6B2 := ( -0.138800614213E-03) * ona2_b2 + (-0.614988295119E-02) * CMRS.b2 + ( 0.179020058982E-01) * CMIS.b2 + (-0.327505145607E-01) * CMRS.b2_sq + ( 0.624417187334E-01) * CMIS.b2_sq ; + KQS.L7B2 := ( -0.138800614213E-03) * ona2_b2 + (-0.614988295119E-02) * CMRS.b2 + ( 0.179020058982E-01) * CMIS.b2 + (-0.327505145607E-01) * CMRS.b2_sq + ( 0.624417187334E-01) * CMIS.b2_sq ; +KQS.A78B2 := ( 0.907653646559E-03) * ona2_b2 + (-0.117937801373E-01) * CMRS.b2 + (-0.447830183312E-02) * CMIS.b2 + (-0.188089814503E-01) * CMRS.b2_sq + (-0.897287738080E-02) * CMIS.b2_sq ; + KQS.R8B2 := ( 0.173286377641E-03) * ona2_b2 + ( 0.144218507771E-01) * CMRS.b2 + (-0.211979276194E-01) * CMIS.b2 + ( 0.000000000000E+00) * CMRS.b2_sq + ( 0.000000000000E+00) * CMIS.b2_sq ; + KQS.L1B2 := ( 0.173286377641E-03) * ona2_b2 + ( 0.144218507771E-01) * CMRS.b2 + (-0.211979276194E-01) * CMIS.b2 + ( 0.000000000000E+00) * CMRS.b2_sq + ( 0.000000000000E+00) * CMIS.b2_sq ; + + !MSS BEAM1 +ona3_b1 := 0.000000000000E+00 ; + +KSS.A12B1 := ( 0.000000000000E+00) * ona3_b1 ; +KSS.A23B1 := ( 0.000000000000E+00) * ona3_b1 ; +KSS.A34B1 := ( 0.000000000000E+00) * ona3_b1 ; +KSS.A45B1 := ( 0.000000000000E+00) * ona3_b1 ; +KSS.A56B1 := ( 0.000000000000E+00) * ona3_b1 ; +KSS.A67B1 := ( 0.000000000000E+00) * ona3_b1 ; +KSS.A78B1 := ( 0.000000000000E+00) * ona3_b1 ; +KSS.A81B1 := ( 0.000000000000E+00) * ona3_b1 ; + + !MSS BEAM2 +ona3_b2 := 0.000000000000E+00 ; + +KSS.A12B2 := ( 0.000000000000E+00) * ona3_b2 ; +KSS.A23B2 := ( 0.000000000000E+00) * ona3_b2 ; +KSS.A34B2 := ( 0.000000000000E+00) * ona3_b2 ; +KSS.A45B2 := ( 0.000000000000E+00) * ona3_b2 ; +KSS.A56B2 := ( 0.000000000000E+00) * ona3_b2 ; +KSS.A67B2 := ( 0.000000000000E+00) * ona3_b2 ; +KSS.A78B2 := ( 0.000000000000E+00) * ona3_b2 ; +KSS.A81B2 := ( 0.000000000000E+00) * ona3_b2 ; + + !OF/OD BEAM1 +ON_MO.b1 := 0.000000000000E+00 ; +KOF.B1 := 0.000000000000E+00 ; +KOD.B1 := 0.000000000000E+00 ; +KOF.A12B1 := -0.600000000000E+01 *ON_MO.b1 + KOF.B1; +KOF.A23B1 := -0.600000000000E+01 *ON_MO.b1 + KOF.B1; +KOF.A34B1 := -0.600000000000E+01 *ON_MO.b1 + KOF.B1; +KOF.A45B1 := -0.600000000000E+01 *ON_MO.b1 + KOF.B1; +KOF.A56B1 := -0.600000000000E+01 *ON_MO.b1 + KOF.B1; +KOF.A67B1 := -0.600000000000E+01 *ON_MO.b1 + KOF.B1; +KOF.A78B1 := -0.600000000000E+01 *ON_MO.b1 + KOF.B1; +KOF.A81B1 := -0.600000000000E+01 *ON_MO.b1 + KOF.B1; +KOD.A12B1 := -0.600000000000E+01 *ON_MO.b1 + KOD.B1; +KOD.A23B1 := -0.600000000000E+01 *ON_MO.b1 + KOD.B1; +KOD.A34B1 := -0.600000000000E+01 *ON_MO.b1 + KOD.B1; +KOD.A45B1 := -0.600000000000E+01 *ON_MO.b1 + KOD.B1; +KOD.A56B1 := -0.465000000000E+01 *ON_MO.b1 + KOD.B1; +KOD.A67B1 := -0.600000000000E+01 *ON_MO.b1 + KOD.B1; +KOD.A78B1 := -0.600000000000E+01 *ON_MO.b1 + KOD.B1; +KOD.A81B1 := -0.600000000000E+01 *ON_MO.b1 + KOD.B1; + + !OF/OD BEAM2 +ON_MO.b2 := 0.000000000000E+00 ; +KOF.B2 := 0.000000000000E+00 ; +KOD.B2 := 0.000000000000E+00 ; +KOF.A12B2 := -0.600000000000E+01 *ON_MO.b2 + KOF.B2; +KOF.A23B2 := -0.600000000000E+01 *ON_MO.b2 + KOF.B2; +KOF.A34B2 := -0.600000000000E+01 *ON_MO.b2 + KOF.B2; +KOF.A45B2 := -0.600000000000E+01 *ON_MO.b2 + KOF.B2; +KOF.A56B2 := -0.600000000000E+01 *ON_MO.b2 + KOF.B2; +KOF.A67B2 := -0.600000000000E+01 *ON_MO.b2 + KOF.B2; +KOF.A78B2 := -0.600000000000E+01 *ON_MO.b2 + KOF.B2; +KOF.A81B2 := -0.600000000000E+01 *ON_MO.b2 + KOF.B2; +KOD.A12B2 := -0.600000000000E+01 *ON_MO.b2 + KOD.B2; +KOD.A23B2 := -0.600000000000E+01 *ON_MO.b2 + KOD.B2; +KOD.A34B2 := -0.600000000000E+01 *ON_MO.b2 + KOD.B2; +KOD.A45B2 := -0.600000000000E+01 *ON_MO.b2 + KOD.B2; +KOD.A56B2 := -0.600000000000E+01 *ON_MO.b2 + KOD.B2; +KOD.A67B2 := -0.600000000000E+01 *ON_MO.b2 + KOD.B2; +KOD.A78B2 := -0.600000000000E+01 *ON_MO.b2 + KOD.B2; +KOD.A81B2 := -0.600000000000E+01 *ON_MO.b2 + KOD.B2; + + !! MCB-beam1 for spurious dispersion correction + + !! MCB in sector 81 and 12 +acbh14.r8b1x := 0.000000000000E+00 ; +acbh14.r8b1s := 0.000000000000E+00 ; +acbh14.r8b1 := (( 0.000000000000E+00 )*cos(phi_IR1*twopi/360.)*on_xx1+( 0.000000000000E+00 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh16.r8b1x := 0.538313739487E-07 ; +acbh16.r8b1s := -0.116047333838E-05 ; +acbh16.r8b1 := (( 0.538313739487E-07 )*cos(phi_IR1*twopi/360.)*on_xx1+( -0.116047333838E-05 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh14.l1b1x := -0.426999663097E-09 ; +acbh14.l1b1s := 0.887836506229E-08 ; +acbh14.l1b1 := (( -0.426999663097E-09 )*cos(phi_IR1*twopi/360.)*on_xx1+( 0.887836506229E-08 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh12.l1b1x := -0.541985171505E-07 ; +acbh12.l1b1s := 0.116839308098E-05 ; +acbh12.l1b1 := (( -0.541985171505E-07 )*cos(phi_IR1*twopi/360.)*on_xx1+( 0.116839308098E-05 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh13.r1b1x := -0.495795933192E-07 ; +acbh13.r1b1s := -0.386101235691E-06 ; +acbh13.r1b1 := (( -0.495795933192E-07 )*cos(phi_IR1*twopi/360.)*on_xx1+( -0.386101235691E-06 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh15.r1b1x := -0.429922635876E-11 ; +acbh15.r1b1s := 0.948776298107E-10 ; +acbh15.r1b1 := (( -0.429922635876E-11 )*cos(phi_IR1*twopi/360.)*on_xx1+( 0.948776298107E-10 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh15.l2b1x := 0.495782855607E-07 ; +acbh15.l2b1s := 0.386095179541E-06 ; +acbh15.l2b1 := (( 0.495782855607E-07 )*cos(phi_IR1*twopi/360.)*on_xx1+( 0.386095179541E-06 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh13.l2b1x := 0.000000000000E+00 ; +acbh13.l2b1s := 0.000000000000E+00 ; +acbh13.l2b1 := (( 0.000000000000E+00 )*cos(phi_IR1*twopi/360.)*on_xx1+( 0.000000000000E+00 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv13.r8b1x := 0.000000000000E+00 ; +acbv13.r8b1s := 0.000000000000E+00 ; +acbv13.r8b1 := (( 0.000000000000E+00 )*sin(phi_IR1*twopi/360.)*on_xx1+( 0.000000000000E+00 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv15.r8b1x := -0.452722837572E-07 ; +acbv15.r8b1s := -0.293388241730E-06 ; +acbv15.r8b1 := (( -0.452722837572E-07 )*sin(phi_IR1*twopi/360.)*on_xx1+( -0.293388241730E-06 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv15.l1b1x := -0.101885533716E-09 ; +acbv15.l1b1s := -0.758739054141E-09 ; +acbv15.l1b1 := (( -0.101885533716E-09 )*sin(phi_IR1*twopi/360.)*on_xx1+( -0.758739054141E-09 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv13.l1b1x := 0.451673227909E-07 ; +acbv13.l1b1s := 0.292694333515E-06 ; +acbv13.l1b1 := (( 0.451673227909E-07 )*sin(phi_IR1*twopi/360.)*on_xx1+( 0.292694333515E-06 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv12.r1b1x := 0.592721033390E-07 ; +acbv12.r1b1s := -0.123484903932E-05 ; +acbv12.r1b1 := (( 0.592721033390E-07 )*sin(phi_IR1*twopi/360.)*on_xx1+( -0.123484903932E-05 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv14.r1b1x := 0.149933269569E-09 ; +acbv14.r1b1s := -0.273845590051E-08 ; +acbv14.r1b1 := (( 0.149933269569E-09 )*sin(phi_IR1*twopi/360.)*on_xx1+( -0.273845590051E-08 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv16.l2b1x := -0.591070454614E-07 ; +acbv16.l2b1s := 0.123130835359E-05 ; +acbv16.l2b1 := (( -0.591070454614E-07 )*sin(phi_IR1*twopi/360.)*on_xx1+( 0.123130835359E-05 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv14.l2b1x := 0.000000000000E+00 ; +acbv14.l2b1s := 0.000000000000E+00 ; +acbv14.l2b1 := (( 0.000000000000E+00 )*sin(phi_IR1*twopi/360.)*on_xx1+( 0.000000000000E+00 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; + + !! MCB in sector 45 and 56 +acbh14.r4b1x := 0.000000000000E+00 ; +acbh14.r4b1s := 0.000000000000E+00 ; +acbh14.r4b1 := (( 0.000000000000E+00 )*cos(phi_IR5*twopi/360.)*on_xx5+( 0.000000000000E+00 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh16.r4b1x := 0.594331926774E-07 ; +acbh16.r4b1s := 0.128019112117E-05 ; +acbh16.r4b1 := (( 0.594331926774E-07 )*cos(phi_IR5*twopi/360.)*on_xx5+( 0.128019112117E-05 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh14.l5b1x := -0.472043999865E-09 ; +acbh14.l5b1s := -0.979859287914E-08 ; +acbh14.l5b1 := (( -0.472043999865E-09 )*cos(phi_IR5*twopi/360.)*on_xx5+( -0.979859287914E-08 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh12.l5b1x := -0.598384663057E-07 ; +acbh12.l5b1s := -0.128892735317E-05 ; +acbh12.l5b1 := (( -0.598384663057E-07 )*cos(phi_IR5*twopi/360.)*on_xx5+( -0.128892735317E-05 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh13.r5b1x := -0.491469921272E-07 ; +acbh13.r5b1s := 0.377263507621E-06 ; +acbh13.r5b1 := (( -0.491469921272E-07 )*cos(phi_IR5*twopi/360.)*on_xx5+( 0.377263507621E-06 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh15.r5b1x := -0.449227060447E-11 ; +acbh15.r5b1s := -0.857653972551E-10 ; +acbh15.r5b1 := (( -0.449227060447E-11 )*cos(phi_IR5*twopi/360.)*on_xx5+( -0.857653972551E-10 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh15.l6b1x := 0.491455886905E-07 ; +acbh15.l6b1s := -0.377256215340E-06 ; +acbh15.l6b1 := (( 0.491455886905E-07 )*cos(phi_IR5*twopi/360.)*on_xx5+( -0.377256215340E-06 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh13.l6b1x := 0.000000000000E+00 ; +acbh13.l6b1s := 0.000000000000E+00 ; +acbh13.l6b1 := (( 0.000000000000E+00 )*cos(phi_IR5*twopi/360.)*on_xx5+( 0.000000000000E+00 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv13.r4b1x := 0.000000000000E+00 ; +acbv13.r4b1s := 0.000000000000E+00 ; +acbv13.r4b1 := (( 0.000000000000E+00 )*sin(phi_IR5*twopi/360.)*on_xx5+( 0.000000000000E+00 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv15.r4b1x := -0.478763655856E-07 ; +acbv15.r4b1s := 0.310750895338E-06 ; +acbv15.r4b1 := (( -0.478763655856E-07 )*sin(phi_IR5*twopi/360.)*on_xx5+( 0.310750895338E-06 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv15.l5b1x := -0.107741576135E-09 ; +acbv15.l5b1s := 0.809116413262E-09 ; +acbv15.l5b1 := (( -0.107741576135E-09 )*sin(phi_IR5*twopi/360.)*on_xx5+( 0.809116413262E-09 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv13.l5b1x := 0.477653166539E-07 ; +acbv13.l5b1s := -0.310011551504E-06 ; +acbv13.l5b1 := (( 0.477653166539E-07 )*sin(phi_IR5*twopi/360.)*on_xx5+( -0.310011551504E-06 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv12.r5b1x := 0.544111960590E-07 ; +acbv12.r5b1s := 0.113344600777E-05 ; +acbv12.r5b1 := (( 0.544111960590E-07 )*sin(phi_IR5*twopi/360.)*on_xx5+( 0.113344600777E-05 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv14.r5b1x := 0.137082125206E-09 ; +acbv14.r5b1s := 0.249765924547E-08 ; +acbv14.r5b1 := (( 0.137082125206E-09 )*sin(phi_IR5*twopi/360.)*on_xx5+( 0.249765924547E-08 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv16.l6b1x := -0.542595304573E-07 ; +acbv16.l6b1s := -0.113019448115E-05 ; +acbv16.l6b1 := (( -0.542595304573E-07 )*sin(phi_IR5*twopi/360.)*on_xx5+( -0.113019448115E-05 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv14.l6b1x := 0.000000000000E+00 ; +acbv14.l6b1s := 0.000000000000E+00 ; +acbv14.l6b1 := (( 0.000000000000E+00 )*sin(phi_IR1*twopi/360.)*on_xx5+( 0.000000000000E+00 )*cos(phi_IR1*twopi/360.)*on_ssep5)*ON_DISP ; + + !! MCB-beam2 for spurious dispersion correction + + !! MCB in sector 81 and 12 +acbh13.r8b2x := 0.000000000000E+00 ; +acbh13.r8b2s := 0.000000000000E+00 ; +acbh13.r8b2 := (( 0.000000000000E+00 )*cos(phi_IR1*twopi/360.)*on_xx1+( 0.000000000000E+00 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh15.r8b2x := 0.522009415515E-07 ; +acbh15.r8b2s := -0.266924828313E-06 ; +acbh15.r8b2 := (( 0.522009415515E-07 )*cos(phi_IR1*twopi/360.)*on_xx1+( -0.266924828313E-06 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh15.l1b2x := -0.300306051574E-11 ; +acbh15.l1b2s := -0.107802474050E-09 ; +acbh15.l1b2 := (( -0.300306051574E-11 )*cos(phi_IR1*twopi/360.)*on_xx1+( -0.107802474050E-09 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh13.l1b2x := -0.521360651986E-07 ; +acbh13.l1b2s := 0.266660275616E-06 ; +acbh13.l1b2 := (( -0.521360651986E-07 )*cos(phi_IR1*twopi/360.)*on_xx1+( 0.266660275616E-06 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh12.r1b2x := -0.618923089250E-07 ; +acbh12.r1b2s := -0.125751437861E-05 ; +acbh12.r1b2 := (( -0.618923089250E-07 )*cos(phi_IR1*twopi/360.)*on_xx1+( -0.125751437861E-05 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh14.r1b2x := -0.113767524409E-08 ; +acbh14.r1b2s := -0.226243339257E-07 ; +acbh14.r1b2 := (( -0.113767524409E-08 )*cos(phi_IR1*twopi/360.)*on_xx1+( -0.226243339257E-07 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh16.l2b2x := 0.604160901421E-07 ; +acbh16.l2b2s := 0.122764051133E-05 ; +acbh16.l2b2 := (( 0.604160901421E-07 )*cos(phi_IR1*twopi/360.)*on_xx1+( 0.122764051133E-05 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbh14.l2b2x := 0.000000000000E+00 ; +acbh14.l2b2s := 0.000000000000E+00 ; +acbh14.l2b2 := (( 0.000000000000E+00 )*cos(phi_IR1*twopi/360.)*on_xx1+( 0.000000000000E+00 )*sin(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv14.r8b2x := 0.000000000000E+00 ; +acbv14.r8b2s := 0.000000000000E+00 ; +acbv14.r8b2 := (( 0.000000000000E+00 )*sin(phi_IR1*twopi/360.)*on_xx1+( 0.000000000000E+00 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv16.r8b2x := -0.564611980591E-07 ; +acbv16.r8b2s := -0.117565042514E-05 ; +acbv16.r8b2 := (( -0.564611980591E-07 )*sin(phi_IR1*twopi/360.)*on_xx1+( -0.117565042514E-05 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv14.l1b2x := 0.318735517332E-09 ; +acbv14.l1b2s := 0.616762240604E-08 ; +acbv14.l1b2 := (( 0.318735517332E-09 )*sin(phi_IR1*twopi/360.)*on_xx1+( 0.616762240604E-08 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv12.l1b2x := 0.568034078399E-07 ; +acbv12.l1b2s := 0.118290247511E-05 ; +acbv12.l1b2 := (( 0.568034078399E-07 )*sin(phi_IR1*twopi/360.)*on_xx1+( 0.118290247511E-05 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv13.r1b2x := 0.474220038422E-07 ; +acbv13.r1b2s := -0.307363860481E-06 ; +acbv13.r1b2 := (( 0.474220038422E-07 )*sin(phi_IR1*twopi/360.)*on_xx1+( -0.307363860481E-06 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv15.r1b2x := -0.103422558268E-09 ; +acbv15.r1b2s := 0.807693121041E-09 ; +acbv15.r1b2 := (( -0.103422558268E-09 )*sin(phi_IR1*twopi/360.)*on_xx1+( 0.807693121041E-09 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv15.l2b2x := -0.474208254870E-07 ; +acbv15.l2b2s := 0.307389307461E-06 ; +acbv15.l2b2 := (( -0.474208254870E-07 )*sin(phi_IR1*twopi/360.)*on_xx1+( 0.307389307461E-06 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; +acbv13.l2b2x := 0.000000000000E+00 ; +acbv13.l2b2s := 0.000000000000E+00 ; +acbv13.l2b2 := (( 0.000000000000E+00 )*sin(phi_IR1*twopi/360.)*on_xx1+( 0.000000000000E+00 )*cos(phi_IR1*twopi/360.)*on_ssep1)*ON_DISP ; + + !! MCB in sector 45 and 56 +acbh13.r4b2x := 0.000000000000E+00 ; +acbh13.r4b2s := 0.000000000000E+00 ; +acbh13.r4b2 := (( 0.000000000000E+00 )*cos(phi_IR5*twopi/360.)*on_xx5+( 0.000000000000E+00 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh15.r4b2x := 0.495399670342E-07 ; +acbh15.r4b2s := 0.250564906601E-06 ; +acbh15.r4b2 := (( 0.495399670342E-07 )*cos(phi_IR5*twopi/360.)*on_xx5+( 0.250564906601E-06 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh15.l5b2x := -0.257423219263E-11 ; +acbh15.l5b2s := 0.105810427484E-09 ; +acbh15.l5b2 := (( -0.257423219263E-11 )*cos(phi_IR5*twopi/360.)*on_xx5+( 0.105810427484E-09 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh13.l5b2x := -0.494783066835E-07 ; +acbh13.l5b2s := -0.250320641383E-06 ; +acbh13.l5b2 := (( -0.494783066835E-07 )*cos(phi_IR5*twopi/360.)*on_xx5+( -0.250320641383E-06 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh12.r5b2x := -0.600415028765E-07 ; +acbh12.r5b2s := 0.121781501509E-05 ; +acbh12.r5b2 := (( -0.600415028765E-07 )*cos(phi_IR5*twopi/360.)*on_xx5+( 0.121781501509E-05 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh14.r5b2x := -0.110328776565E-08 ; +acbh14.r5b2s := 0.218936790090E-07 ; +acbh14.r5b2 := (( -0.110328776565E-08 )*cos(phi_IR5*twopi/360.)*on_xx5+( 0.218936790090E-07 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh16.l6b2x := 0.586093151573E-07 ; +acbh16.l6b2s := -0.118889194496E-05 ; +acbh16.l6b2 := (( 0.586093151573E-07 )*cos(phi_IR5*twopi/360.)*on_xx5+( -0.118889194496E-05 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbh14.l6b2x := 0.000000000000E+00 ; +acbh14.l6b2s := 0.000000000000E+00 ; +acbh14.l6b2 := (( 0.000000000000E+00 )*cos(phi_IR5*twopi/360.)*on_xx5+( 0.000000000000E+00 )*sin(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv14.r4b2x := 0.000000000000E+00 ; +acbv14.r4b2s := 0.000000000000E+00 ; +acbv14.r4b2 := (( 0.000000000000E+00 )*sin(phi_IR5*twopi/360.)*on_xx5+( 0.000000000000E+00 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv16.r4b2x := -0.563243769083E-07 ; +acbv16.r4b2s := 0.117295785343E-05 ; +acbv16.r4b2 := (( -0.563243769083E-07 )*sin(phi_IR5*twopi/360.)*on_xx5+( 0.117295785343E-05 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv14.l5b2x := 0.318186597653E-09 ; +acbv14.l5b2s := -0.617231929102E-08 ; +acbv14.l5b2 := (( 0.318186597653E-09 )*sin(phi_IR5*twopi/360.)*on_xx5+( -0.617231929102E-08 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv12.l5b2x := 0.566656514748E-07 ; +acbv12.l5b2s := -0.118018207147E-05 ; +acbv12.l5b2 := (( 0.566656514748E-07 )*sin(phi_IR5*twopi/360.)*on_xx5+( -0.118018207147E-05 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv13.r5b2x := 0.484187072999E-07 ; +acbv13.r5b2s := 0.313421871998E-06 ; +acbv13.r5b2 := (( 0.484187072999E-07 )*sin(phi_IR5*twopi/360.)*on_xx5+( 0.313421871998E-06 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv15.r5b2x := -0.105383401076E-09 ; +acbv15.r5b2s := -0.817978838114E-09 ; +acbv15.r5b2 := (( -0.105383401076E-09 )*sin(phi_IR5*twopi/360.)*on_xx5+( -0.817978838114E-09 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv15.l6b2x := -0.484174220834E-07 ; +acbv15.l6b2s := -0.313445431425E-06 ; +acbv15.l6b2 := (( -0.484174220834E-07 )*sin(phi_IR5*twopi/360.)*on_xx5+( -0.313445431425E-06 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; +acbv13.l6b2x := 0.000000000000E+00 ; +acbv13.l6b2s := 0.000000000000E+00 ; +acbv13.l6b2 := (( 0.000000000000E+00 )*sin(phi_IR5*twopi/360.)*on_xx5+( 0.000000000000E+00 )*cos(phi_IR5*twopi/360.)*on_ssep5)*ON_DISP ; + + !/* + !****OPTICS SUMMARY**** + + !Tune and Chroma +Qxb1 = 62.310000; Qyb1 = 60.320000; Qpxb1= 2.000000; Qpyb1= 2.000000; dmux15b1= 30.9565534; dmuy15b1= 29.6485062; +Qxb2 = 62.310000; Qyb2 = 60.320000; Qpxb2= 2.000000; Qpyb2= 2.000000; dmux15b2= 31.0619743; dmuy15b2= 29.7618930; + + !IR Optics summary (phase, twiss param., dispersion) +muxIP1b1= 2.6448000; muyIP1b1= 2.6450000; muxIP1b1_L= 1.1579000; muyIP1b1_L= 1.4907000; muxIP1b1_R= 1.4869000; muyIP1b1_R= 1.1543000; betxIP1b1= 0.300000; betyIP1b1= 0.300000; alfxIP1b1= -0.000000; alfyIP1b1= -0.000000; dxIP1b1= 0.000000; dpxIP1b1= -0.000000; +muxIP1b2= 2.6448000; muyIP1b2= 2.6450000; muxIP1b2_L= 1.4901000; muyIP1b2_L= 1.1587000; muxIP1b2_R= 1.1547000; muyIP1b2_R= 1.4863000; betxIP1b2= 0.300000; betyIP1b2= 0.300000; alfxIP1b2= -0.000000; alfyIP1b2= 0.000000; dxIP1b2= -0.000000; dpxIP1b2= 0.000000; +muxIP5b1= 2.6448000; muyIP5b1= 2.6450000; muxIP5b1_L= 1.1579000; muyIP5b1_L= 1.4907000; muxIP5b1_R= 1.4869000; muyIP5b1_R= 1.1543000; betxIP5b1= 0.300000; betyIP5b1= 0.300000; alfxIP5b1= -0.000000; alfyIP5b1= -0.000000; dxIP5b1= -0.000000; dpxIP5b1= 0.000000; +muxIP5b2= 2.6448000; muyIP5b2= 2.6450000; muxIP5b2_L= 1.4901000; muyIP5b2_L= 1.1587000; muxIP5b2_R= 1.1547000; muyIP5b2_R= 1.4863000; betxIP5b2= 0.300000; betyIP5b2= 0.300000; alfxIP5b2= -0.000000; alfyIP5b2= 0.000000; dxIP5b2= 0.000000; dpxIP5b2= -0.000000; +muxIP2b1= 2.9500000; muyIP2b1= 2.7450000; betxIP2b1= 10.000000; betyIP2b1= 10.000000; alfxIP2b1= 0.000000; alfyIP2b1= 0.000000; dxIP2b1= -0.000000; dpxIP2b1= -0.000000; +muxIP2b2= 2.9500000; muyIP2b2= 2.7450000; betxIP2b2= 10.000000; betyIP2b2= 10.000000; alfxIP2b2= 0.000000; alfyIP2b2= -0.000000; dxIP2b2= -0.000000; dpxIP2b2= -0.000000; +muxIP8b1= 3.0200000; muyIP8b1= 2.8000000; betxIP8b1= 3.000000; betyIP8b1= 3.000000; alfxIP8b1= -0.000000; alfyIP8b1= 0.000000; dxIP8b1= 0.000000; dpxIP8b1= -0.000000; +muxIP8b2= 3.0200000; muyIP8b2= 2.8000000; betxIP8b2= 3.000000; betyIP8b2= 3.000000; alfxIP8b2= 0.000000; alfyIP8b2= 0.000000; dxIP8b2= -0.000000; dpxIP8b2= -0.000000; +muxIP4b1= 2.1400000; muyIP4b1= 1.7200000; betxIP4b1= 239.413644; betyIP4b1= 242.774144; alfxIP4b1= 0.495763; alfyIP4b1= -0.373724; dxIP4b1= 0.000000; dpxIP4b1= -0.000000; +muxIP4b2= 2.1600000; muyIP4b2= 1.7200000; betxIP4b2= 231.105188; betyIP4b2= 303.948682; alfxIP4b2= -0.500292; alfyIP4b2= 0.498879; dxIP4b2= -0.000000; dpxIP4b2= -0.000000; +muxIP6b1= 2.1800000; muyIP6b1= 1.9800000; betxIP6b1= 203.082060; betyIP6b1= 175.629946; alfxIP6b1= -0.693376; alfyIP6b1= 0.667606; dxIP6b1= -0.364966; dpxIP6b1= -0.001250; +muxIP6b2= 2.1600000; muyIP6b2= 1.9800000; betxIP6b2= 193.038151; betyIP6b2= 182.794275; alfxIP6b2= 0.605227; alfyIP6b2= -0.600047; dxIP6b2= -0.225261; dpxIP6b2= -0.000510; +muxIP3b1= 2.2230000; muyIP3b1= 1.9650000; betxIP3b1= 121.566844; betyIP3b1= 218.585060; alfxIP3b1= 2.295731; alfyIP3b1= -2.642890; dxIP3b1= -0.537375; dpxIP3b1= -0.006869; +muxIP3b2= 2.2230000; muyIP3b2= 1.9650000; betxIP3b2= 121.567284; betyIP3b2= 218.584477; alfxIP3b2= -2.295728; alfyIP3b2= 2.642905; dxIP3b2= -0.445260; dpxIP3b2= 0.008749; +muxIP7b1= 2.4640000; muyIP7b1= 2.0000000; betxIP7b1= 120.813252; betyIP7b1= 149.430470; alfxIP7b1= 1.276977; alfyIP7b1= -1.385146; dxIP7b1= -0.169987; dpxIP7b1= -0.000000; +muxIP7b2= 2.4640000; muyIP7b2= 2.0000000; betxIP7b2= 120.813252; betyIP7b2= 149.430471; alfxIP7b2= -1.276977; alfyIP7b2= 1.385146; dxIP7b2= -0.008803; dpxIP7b2= -0.000000; + + !Xscheme summary in IR1, IR2,IR5 and IR8 +xIP1b1=-0.0005500015; yIP1b1=-0.0000000001; pxIP1b1=-0.0000000003; pyIP1b1= 0.0001599977; +xIP1b2= 0.0005500005; yIP1b2=-0.0000000000; pxIP1b2= 0.0000000044; pyIP1b2=-0.0001599980; +xIP2b1= 0.0009999995; yIP2b1=-0.0019999992; pxIP2b1= 0.0000002928; pyIP2b1= 0.0002700000; +xIP2b2=-0.0010000047; yIP2b2=-0.0019999944; pxIP2b2=-0.0000002913; pyIP2b2=-0.0002699991; +xIP5b1= 0.0000000001; yIP5b1=-0.0012500003; pxIP5b1= 0.0001599973; pyIP5b1= 0.0000000036; +xIP5b2=-0.0000000000; yIP5b2=-0.0023500011; pxIP5b2=-0.0001599972; pyIP5b2=-0.0000000021; +xIP8b1=-0.0000000041; yIP8b1=-0.0009999993; pxIP8b1=-0.0003849873; pyIP8b1=-0.0000018109; +xIP8b2=-0.0000000041; yIP8b2= 0.0010000031; pxIP8b2= 0.0003849885; pyIP8b2= 0.0000018089; + + !Arc Optics summary +muxcell81b1=0.24998197; muycell81b1=0.24998197; mux81b1= 5.2178933; muy81b1= 5.2437868; +muxcell45b1=0.24998197; muycell45b1=0.24998197; mux45b1= 5.2178933; muy45b1= 5.2437868; +muxcell12b2=0.24998197; muycell12b2=0.24998197; mux12b2= 5.2178933; muy12b2= 5.2437868; +muxcell56b2=0.24998197; muycell56b2=0.24998197; mux56b2= 5.2178933; muy56b2= 5.2437868; +muxcell12b1=0.25000000; muycell12b1=0.25000000; mux12b1= 5.2441653; muy12b1= 5.2182697; +muxcell56b1=0.25000000; muycell56b1=0.25000000; mux56b1= 5.2441653; muy56b1= 5.2182697; +muxcell81b2=0.25000000; muycell81b2=0.25000000; mux81b2= 5.2441653; muy81b2= 5.2182697; +muxcell45b2=0.25000000; muycell45b2=0.25000000; mux45b2= 5.2441653; muy45b2= 5.2182697; +muxcell23b1=0.25278573; muycell23b1=0.24296472; mux23b1= 5.2552629; muy23b1= 5.0687037; +muxcell78b2=0.25184855; muycell78b2=0.25634235; mux78b2= 5.2352463; muy78b2= 5.3488243; +muxcell34b1=0.25278573; muycell34b1=0.24296472; mux34b1= 5.2814318; muy34b1= 5.0427460; +muxcell67b2=0.25184855; muycell67b2=0.25634235; mux67b2= 5.2619207; muy67b2= 5.3222263; +muxcell67b1=0.25186692; muycell67b1=0.25636098; mux67b1= 5.2775277; muy67b1= 5.4073245; +muxcell34b2=0.25280379; muycell34b2=0.24298226; mux34b2= 5.2973354; muy34b2= 5.1243893; +muxcell78b1=0.25186692; muycell78b1=0.25636098; mux78b1= 5.3050602; muy78b1= 5.3771129; +muxcell23b2=0.25280379; muycell23b2=0.24298226; mux23b2= 5.3247802; muy23b2= 5.1004473; + !*/ + + + return ; diff --git a/tests/test_cpymadtools/test_correctors.py b/tests/test_cpymadtools/test_correctors.py deleted file mode 100644 index e976f1ed..00000000 --- a/tests/test_cpymadtools/test_correctors.py +++ /dev/null @@ -1,78 +0,0 @@ -import random - -from pyhdtoolkit.cpymadtools.constants import ( - LHC_KCD_KNOBS, - LHC_KCO_KNOBS, - LHC_KCOSX_KNOBS, - LHC_KCOX_KNOBS, - LHC_KCS_KNOBS, - LHC_KCSSX_KNOBS, - LHC_KCSX_KNOBS, - LHC_KCTX_KNOBS, - LHC_KO_KNOBS, - LHC_KQS_KNOBS, - LHC_KQSX_KNOBS, - LHC_KQTF_KNOBS, - LHC_KSF_KNOBS, - LHC_KSS_KNOBS, - LHC_TRIPLETS_REGEX, -) -from pyhdtoolkit.cpymadtools.correctors import ( - query_arc_correctors_powering, - query_triplet_correctors_powering, -) -from pyhdtoolkit.cpymadtools.lhc import make_lhc_beams - -ALL_TRIPLET_CORRECTOR_KNOBS = ( - LHC_KQSX_KNOBS + LHC_KCSX_KNOBS + LHC_KCSSX_KNOBS + LHC_KCOX_KNOBS + LHC_KCOSX_KNOBS + LHC_KCTX_KNOBS -) -ALL_ARC_CORRECTOR_KNOBS = ( - LHC_KQTF_KNOBS - + LHC_KQS_KNOBS - + LHC_KSF_KNOBS - + LHC_KSS_KNOBS - + LHC_KCS_KNOBS - + LHC_KCO_KNOBS - + LHC_KCD_KNOBS - + LHC_KO_KNOBS -) - - -def test_query_undefined_triplet_corrector_knobs(_bare_lhc_madx): - madx = _bare_lhc_madx - make_lhc_beams(madx) # parameters don't matter, just need beams and brho defined - triplet_knobs = query_triplet_correctors_powering(madx) - assert all(knob in triplet_knobs for knob in ALL_TRIPLET_CORRECTOR_KNOBS) - assert all(knob_value == 0 for knob_value in triplet_knobs.values()) # as none were set - - -def test_query_defined_triplet_corrector_knobs(_bare_lhc_madx): - madx = _bare_lhc_madx - make_lhc_beams(madx) # parameters don't matter, just need beams and brho defined - fake_knob_values = {knob: random.random() for knob in ALL_TRIPLET_CORRECTOR_KNOBS} - with madx.batch(): - madx.globals.update(fake_knob_values) - triplet_knobs = query_triplet_correctors_powering(madx) - - assert all(knob in triplet_knobs for knob in ALL_TRIPLET_CORRECTOR_KNOBS) - assert all(knob_value != 0 for knob_value in triplet_knobs.values()) - - -def test_query_undefined_arc_corrector_knobs(_bare_lhc_madx): - madx = _bare_lhc_madx - make_lhc_beams(madx) # parameters don't matter, just need beams and brho defined - arc_knobs = query_arc_correctors_powering(madx) - assert all(knob in arc_knobs for knob in ALL_ARC_CORRECTOR_KNOBS) - assert all(abs(knob_value) < 115 for knob_value in arc_knobs.values()) # set in opticsfile - - -def test_query_defined_arc_corrector_knobs(_bare_lhc_madx): - madx = _bare_lhc_madx - make_lhc_beams(madx) # parameters don't matter, just need beams and brho defined - fake_knob_values = {knob: random.random() for knob in ALL_ARC_CORRECTOR_KNOBS} - with madx.batch(): - madx.globals.update(fake_knob_values) - arc_knobs = query_arc_correctors_powering(madx) - - assert all(knob in arc_knobs for knob in ALL_ARC_CORRECTOR_KNOBS) - assert all(knob_value != 0 for knob_value in arc_knobs.values()) diff --git a/tests/test_cpymadtools/test_errors.py b/tests/test_cpymadtools/test_errors.py deleted file mode 100644 index a8396e96..00000000 --- a/tests/test_cpymadtools/test_errors.py +++ /dev/null @@ -1,97 +0,0 @@ -import random - -import pytest - -from pyhdtoolkit.cpymadtools.errors import ( - misalign_lhc_ir_quadrupoles, - misalign_lhc_triplets, - switch_magnetic_errors, -) - - -def test_magnetic_errors_switch_no_kwargs(_non_matched_lhc_madx): - madx = _non_matched_lhc_madx - switch_magnetic_errors(madx) - - for order in range(1, 16): - for ab in "AB": - for sr in "sr": - assert madx.globals[f"ON_{ab}{order:d}{sr}"] == 0 - - -def test_magnetic_errors_switch_with_kwargs(_non_matched_lhc_madx): - madx = _non_matched_lhc_madx - random_kwargs = {} - - for order in range(1, 16): - for ab in "AB": - random_kwargs[f"{ab}{order:d}"] = random.randint(0, 20) - - switch_magnetic_errors(madx, **random_kwargs) - - for order in range(1, 16): - for ab in "AB": - for sr in "sr": - assert madx.globals[f"ON_{ab}{order:d}{sr}"] == random_kwargs[f"{ab}{order:d}"] - - -@pytest.mark.parametrize("ips", [[1], [2], [5], [8], [1, 5], [1, 2, 5, 8]]) # also test sequences -@pytest.mark.parametrize("sides", ["R", "L", "RL", "r", "l", "rl"]) -@pytest.mark.parametrize("quadrupoles", [[1, 3, 5, 7, 9], list(range(1, 11))]) -def test_misalign_lhc_ir_quadrupoles(_non_matched_lhc_madx, ips, sides, quadrupoles): - madx = _non_matched_lhc_madx - misalign_lhc_ir_quadrupoles( - madx, - ips=ips, - quadrupoles=quadrupoles, - beam=1, - sides=sides, - dx="1E-3 * TGAUSS(2.5)", - dpsi="1E-3 * TGAUSS(2.5)", - ) - error_table = madx.table["ir_quads_errors"].dframe().copy() - assert all(error_table["dx"] != 0) - assert all(error_table["dpsi"] != 0) - - -def test_misalign_lhc_ir_quadrupoles_specific_value(_non_matched_lhc_madx): - madx = _non_matched_lhc_madx - misalign_lhc_ir_quadrupoles(madx, ips=[1, 5], quadrupoles=list(range(1, 11)), beam=1, sides="RL", dy="0.001") - error_table = madx.table["ir_quads_errors"].dframe().copy() - assert all(error_table["dy"] == 0.001) - - -def test_misalign_lhc_ir_quadrupoles_raises_on_wrong_side(_non_matched_lhc_madx, caplog): - madx = _non_matched_lhc_madx - with pytest.raises(ValueError): - misalign_lhc_ir_quadrupoles(madx, ips=[8], quadrupoles=[1], beam=2, sides="Z", dy="0.001") - - for record in caplog.records: - assert record.levelname == "ERROR" - - -def test_misalign_lhc_ir_quadrupoles_raises_on_wrong_ip(_non_matched_lhc_madx, caplog): - madx = _non_matched_lhc_madx - with pytest.raises(ValueError): - misalign_lhc_ir_quadrupoles(madx, ips=[100], quadrupoles=[1], beam=2, sides="R", dy="0.001") - - for record in caplog.records: - assert record.levelname == "ERROR" - - -def test_misalign_lhc_ir_quadrupoles_raises_on_wrong_beam(_non_matched_lhc_madx, caplog): - madx = _non_matched_lhc_madx - with pytest.raises(ValueError): - misalign_lhc_ir_quadrupoles(madx, ips=[2], quadrupoles=[1], beam=10, sides="L", dy="0.001") - - for record in caplog.records: - assert record.levelname == "ERROR" - - -def test_misalign_lhc_triplets(_non_matched_lhc_madx): - # for coverage as this calls `misalign_lhc_ir_quadrupoles` tested above - madx = _non_matched_lhc_madx - misalign_lhc_triplets(madx, ip=1, sides="RL", dx="1E-3 * TGAUSS(2.5)", dpsi="1E-3 * TGAUSS(2.5)") - error_table = madx.table["triplet_errors"].dframe().copy() - assert all(error_table["dx"] != 0) - assert all(error_table["dpsi"] != 0) diff --git a/tests/test_cpymadtools/test_generators.py b/tests/test_cpymadtools/test_generators.py index 0a79748e..0d30177d 100644 --- a/tests/test_cpymadtools/test_generators.py +++ b/tests/test_cpymadtools/test_generators.py @@ -2,7 +2,7 @@ import pytest -from pyhdtoolkit.cpymadtools.generators import LatticeGenerator +from pyhdtoolkit.cpymadtools._generators import LatticeGenerator def test_base_cas_lattice_generation(): diff --git a/tests/test_cpymadtools/test_lhc.py b/tests/test_cpymadtools/test_lhc.py index 838cb425..00ad0d83 100644 --- a/tests/test_cpymadtools/test_lhc.py +++ b/tests/test_cpymadtools/test_lhc.py @@ -3,8 +3,6 @@ import pickle import random -from mimetypes import init - import numpy as np import pytest import tfs @@ -13,16 +11,32 @@ from pandas.testing import assert_frame_equal from pyhdtoolkit.cpymadtools.constants import ( + DEFAULT_TWISS_COLUMNS, LHC_ANGLE_FLAGS, LHC_CROSSING_ANGLE_FLAGS, + LHC_CROSSING_SCHEMES, LHC_EXPERIMENT_STATE_FLAGS, LHC_IP2_SPECIAL_FLAG, LHC_IP_OFFSET_FLAGS, + LHC_KCD_KNOBS, + LHC_KCO_KNOBS, + LHC_KCOSX_KNOBS, + LHC_KCOX_KNOBS, + LHC_KCS_KNOBS, + LHC_KCSSX_KNOBS, + LHC_KCSX_KNOBS, + LHC_KCTX_KNOBS, + LHC_KO_KNOBS, + LHC_KQS_KNOBS, + LHC_KQSX_KNOBS, + LHC_KQTF_KNOBS, + LHC_KSF_KNOBS, + LHC_KSS_KNOBS, LHC_PARALLEL_SEPARATION_FLAGS, + LHC_TRIPLETS_REGEX, ) from pyhdtoolkit.cpymadtools.lhc import ( - _all_lhc_arcs, - _get_k_strings, + LHCSetup, add_markers_around_lhc_ip, apply_lhc_colinearity_knob, apply_lhc_colinearity_knob_delta, @@ -30,8 +44,12 @@ apply_lhc_rigidity_waist_shift_knob, carry_colinearity_knob_over, correct_lhc_global_coupling, + correct_lhc_orbit, deactivate_lhc_arc_sextupoles, do_kmodulation, + get_current_orbit_setup, + get_ips_twiss, + get_ir_twiss, get_lhc_bpms_list, get_lhc_bpms_twiss_and_rdts, get_lhc_tune_and_chroma_knobs, @@ -39,18 +57,267 @@ get_sizes_at_ip, install_ac_dipole_as_kicker, install_ac_dipole_as_matrix, + lhc_orbit_variables, make_lhc_beams, make_lhc_thin, make_sixtrack_output, + misalign_lhc_ir_quadrupoles, + misalign_lhc_triplets, power_landau_octupoles, + query_arc_correctors_powering, + query_triplet_correctors_powering, re_cycle_sequence, reset_lhc_bump_flags, + setup_lhc_orbit, + switch_magnetic_errors, vary_independent_ir_quadrupoles, ) +from pyhdtoolkit.cpymadtools.lhc._powering import _all_lhc_arcs +from pyhdtoolkit.cpymadtools.matching import match_tunes_and_chromaticities from pyhdtoolkit.cpymadtools.track import track_single_particle +from pyhdtoolkit.cpymadtools.utils import _get_k_strings + +ALL_TRIPLET_CORRECTOR_KNOBS = ( + LHC_KQSX_KNOBS + LHC_KCSX_KNOBS + LHC_KCSSX_KNOBS + LHC_KCOX_KNOBS + LHC_KCOSX_KNOBS + LHC_KCTX_KNOBS +) +ALL_ARC_CORRECTOR_KNOBS = ( + LHC_KQTF_KNOBS + + LHC_KQS_KNOBS + + LHC_KSF_KNOBS + + LHC_KSS_KNOBS + + LHC_KCS_KNOBS + + LHC_KCO_KNOBS + + LHC_KCD_KNOBS + + LHC_KO_KNOBS +) +CURRENT_DIR = pathlib.Path(__file__).parent # tests/tests_cpymadtools dir +TESTS_DIR = CURRENT_DIR.parent # tests directory +INPUTS_DIR = TESTS_DIR / "inputs" +PROTON_DIR = INPUTS_DIR / "madx" / "PROTON" + + +def test_query_undefined_triplet_corrector_knobs(_bare_lhc_madx): + madx = _bare_lhc_madx + make_lhc_beams(madx) # parameters don't matter, just need beams and brho defined + triplet_knobs = query_triplet_correctors_powering(madx) + assert all(knob in triplet_knobs for knob in ALL_TRIPLET_CORRECTOR_KNOBS) + assert all(knob_value == 0 for knob_value in triplet_knobs.values()) # as none were set + + +def test_query_defined_triplet_corrector_knobs(_bare_lhc_madx): + madx = _bare_lhc_madx + make_lhc_beams(madx) # parameters don't matter, just need beams and brho defined + fake_knob_values = {knob: random.random() for knob in ALL_TRIPLET_CORRECTOR_KNOBS} + with madx.batch(): + madx.globals.update(fake_knob_values) + triplet_knobs = query_triplet_correctors_powering(madx) + + assert all(knob in triplet_knobs for knob in ALL_TRIPLET_CORRECTOR_KNOBS) + assert all(knob_value != 0 for knob_value in triplet_knobs.values()) + + +def test_query_undefined_arc_corrector_knobs(_bare_lhc_madx): + madx = _bare_lhc_madx + make_lhc_beams(madx) # parameters don't matter, just need beams and brho defined + arc_knobs = query_arc_correctors_powering(madx) + assert all(knob in arc_knobs for knob in ALL_ARC_CORRECTOR_KNOBS) + assert all(abs(knob_value) < 115 for knob_value in arc_knobs.values()) # set in opticsfile + + +def test_query_defined_arc_corrector_knobs(_bare_lhc_madx): + madx = _bare_lhc_madx + make_lhc_beams(madx) # parameters don't matter, just need beams and brho defined + fake_knob_values = {knob: random.random() for knob in ALL_ARC_CORRECTOR_KNOBS} + with madx.batch(): + madx.globals.update(fake_knob_values) + arc_knobs = query_arc_correctors_powering(madx) + + assert all(knob in arc_knobs for knob in ALL_ARC_CORRECTOR_KNOBS) + assert all(knob_value != 0 for knob_value in arc_knobs.values()) + + +def test_magnetic_errors_switch_no_kwargs(_non_matched_lhc_madx): + madx = _non_matched_lhc_madx + switch_magnetic_errors(madx) + + for order in range(1, 16): + for ab in "AB": + for sr in "sr": + assert madx.globals[f"ON_{ab}{order:d}{sr}"] == 0 + + +def test_magnetic_errors_switch_with_kwargs(_non_matched_lhc_madx): + madx = _non_matched_lhc_madx + random_kwargs = {} + + for order in range(1, 16): + for ab in "AB": + random_kwargs[f"{ab}{order:d}"] = random.randint(0, 20) + + switch_magnetic_errors(madx, **random_kwargs) + + for order in range(1, 16): + for ab in "AB": + for sr in "sr": + assert madx.globals[f"ON_{ab}{order:d}{sr}"] == random_kwargs[f"{ab}{order:d}"] + + +@pytest.mark.parametrize("ips", [[1], [2], [5], [8], [1, 5], [1, 2, 5, 8]]) # also test sequences +@pytest.mark.parametrize("sides", ["R", "L", "RL", "r", "l", "rl"]) +@pytest.mark.parametrize("quadrupoles", [[1, 3, 5, 7, 9], list(range(1, 11))]) +def test_misalign_lhc_ir_quadrupoles(_non_matched_lhc_madx, ips, sides, quadrupoles): + madx = _non_matched_lhc_madx + misalign_lhc_ir_quadrupoles( + madx, + ips=ips, + quadrupoles=quadrupoles, + beam=1, + sides=sides, + dx="1E-3 * TGAUSS(2.5)", + dpsi="1E-3 * TGAUSS(2.5)", + ) + error_table = madx.table["ir_quads_errors"].dframe().copy() + assert all(error_table["dx"] != 0) + assert all(error_table["dpsi"] != 0) + + +def test_misalign_lhc_ir_quadrupoles_specific_value(_non_matched_lhc_madx): + madx = _non_matched_lhc_madx + misalign_lhc_ir_quadrupoles(madx, ips=[1, 5], quadrupoles=list(range(1, 11)), beam=1, sides="RL", dy="0.001") + error_table = madx.table["ir_quads_errors"].dframe().copy() + assert all(error_table["dy"] == 0.001) + + +def test_misalign_lhc_ir_quadrupoles_raises_on_wrong_side(_non_matched_lhc_madx, caplog): + madx = _non_matched_lhc_madx + with pytest.raises(ValueError): + misalign_lhc_ir_quadrupoles(madx, ips=[8], quadrupoles=[1], beam=2, sides="Z", dy="0.001") + + for record in caplog.records: + assert record.levelname == "ERROR" + + +def test_misalign_lhc_ir_quadrupoles_raises_on_wrong_ip(_non_matched_lhc_madx, caplog): + madx = _non_matched_lhc_madx + with pytest.raises(ValueError): + misalign_lhc_ir_quadrupoles(madx, ips=[100], quadrupoles=[1], beam=2, sides="R", dy="0.001") + + for record in caplog.records: + assert record.levelname == "ERROR" + + +def test_misalign_lhc_ir_quadrupoles_raises_on_wrong_beam(_non_matched_lhc_madx, caplog): + madx = _non_matched_lhc_madx + with pytest.raises(ValueError): + misalign_lhc_ir_quadrupoles(madx, ips=[2], quadrupoles=[1], beam=10, sides="L", dy="0.001") + + for record in caplog.records: + assert record.levelname == "ERROR" + + +def test_misalign_lhc_triplets(_non_matched_lhc_madx): + # for coverage as this calls `misalign_lhc_ir_quadrupoles` tested above + madx = _non_matched_lhc_madx + misalign_lhc_triplets(madx, ip=1, sides="RL", dx="1E-3 * TGAUSS(2.5)", dpsi="1E-3 * TGAUSS(2.5)") + error_table = madx.table["triplet_errors"].dframe().copy() + assert all(error_table["dx"] != 0) + assert all(error_table["dpsi"] != 0) + + +def test_lhc_orbit_variables(): + assert lhc_orbit_variables() == ( + [ + "on_crab1", + "on_crab5", + "on_x1", + "on_sep1", + "on_o1", + "on_oh1", + "on_ov1", + "on_x2", + "on_sep2", + "on_o2", + "on_oe2", + "on_a2", + "on_oh2", + "on_ov2", + "on_x5", + "on_sep5", + "on_o5", + "on_oh5", + "on_ov5", + "on_x8", + "on_sep8", + "on_o8", + "on_a8", + "on_sep8h", + "on_x8v", + "on_oh8", + "on_ov8", + "on_alice", + "on_sol_alice", + "on_lhcb", + "on_sol_atlas", + "on_sol_cms", + "phi_IR1", + "phi_IR2", + "phi_IR5", + "phi_IR8", + ], + {"on_ssep1": "on_sep1", "on_xx1": "on_x1", "on_ssep5": "on_sep5", "on_xx5": "on_x5"}, + ) -CURRENT_DIR = pathlib.Path(__file__).parent -INPUTS_DIR = CURRENT_DIR.parent / "inputs" + +def test_lhc_orbit_setup_fals_on_unknown_scheme(_non_matched_lhc_madx, caplog): + madx = _non_matched_lhc_madx + + with pytest.raises(ValueError): + setup_lhc_orbit(madx, scheme="unknown") + + for record in caplog.records: + assert record.levelname == "ERROR" + + +@pytest.mark.parametrize("scheme", list(LHC_CROSSING_SCHEMES.keys())) +def test_lhc_orbit_setup(scheme, _non_matched_lhc_madx): + madx = _non_matched_lhc_madx + setup_lhc_orbit(madx, scheme=scheme) + variables, special = lhc_orbit_variables() + + for orbit_variable in variables: + value = LHC_CROSSING_SCHEMES[scheme].get(orbit_variable, 0) + assert madx.globals[orbit_variable] == value + + for special_variable, copy_from in special.items(): + assert madx.globals[special_variable] == madx.globals[copy_from] + + +def test_get_orbit_setup(_non_matched_lhc_madx): + madx = _non_matched_lhc_madx + setup_lhc_orbit(madx, scheme="flat") + setup = get_current_orbit_setup(madx) + + assert isinstance(setup, dict) + assert all(orbit_var in setup.keys() for orbit_var in lhc_orbit_variables()[0]) + assert all(special_var in setup.keys() for special_var in lhc_orbit_variables()[1]) + + +def test_orbit_correction(_bare_lhc_madx): + madx = _bare_lhc_madx + re_cycle_sequence(madx, sequence="lhcb1", start="IP3") + _ = setup_lhc_orbit(madx, scheme="flat") + make_lhc_beams(madx) + madx.use(sequence="lhcb1") + match_tunes_and_chromaticities(madx, "lhc", "lhcb1", 62.31, 60.32, 2.0, 2.0) + assert math.isclose(madx.table.summ["xcorms"][0], 0, abs_tol=1e-10) # rms of horizontal CO + + madx.select(flag="error", pattern="MQ.13R3.B1") # arc quad in sector 34 + madx.command.ealign(dx="1E-3") + madx.twiss() + assert madx.table.summ["xcorms"][0] > 1e-3 + + correct_lhc_orbit(madx, sequence="lhcb1") + assert math.isclose(madx.table.summ["xcorms"], 0, abs_tol=1e-5) def test_all_lhc_arcs(): @@ -469,6 +736,50 @@ def test_get_ip_beam_sizes(_non_matched_lhc_madx, ip): assert math.isclose(ver, 1.27415e-05, abs_tol=1e-7) +def test_get_ips_twiss(_ips_twiss_path, _matched_lhc_madx): + madx = _matched_lhc_madx + + reference_df = tfs.read(_ips_twiss_path) + ips_df = get_ips_twiss(madx) + # assert_dict_equal(reference_df.headers, ips_df.headers) # bugged at the moment + assert_frame_equal(reference_df.set_index("name"), ips_df.set_index("name")) + + +@pytest.mark.parametrize("ir", [1, 5]) +def test_get_irs_twiss(ir, _matched_lhc_madx): + madx = _matched_lhc_madx + + reference_df = tfs.read(INPUTS_DIR / "cpymadtools" / f"ir{ir:d}_twiss.tfs") + ir_df = get_ir_twiss(madx, ir=ir) + # assert_dict_equal(reference_df.headers, ir_df.headers) # bugged at the moment + assert_frame_equal(reference_df.set_index("name"), ir_df.set_index("name")) + + extra_columns = ["k0l", "k0sl", "k1l", "k1sl", "k2l", "k2sl", "sig11", "sig12", "sig21", "sig22"] + ir_extra_columns_df = get_ir_twiss(madx, ir=ir, columns=DEFAULT_TWISS_COLUMNS + extra_columns) + assert all([colname in ir_extra_columns_df.columns for colname in extra_columns]) + + +# ------------------- Requires acc-models-lhc ------------------- # + +# Only runs if the acc-models-lhc is accessible at root level +@pytest.mark.skipif(not (TESTS_DIR.parent / "acc-models-lhc").is_dir(), reason="acc-models-lhc not found") +def test_lhc_run3_setup(): + with LHCSetup(run=3, opticsfile="R2022a_A30cmC30cmA10mL200cm.madx") as madx: + for ip in [1, 2, 5, 8]: + for beam in [1, 2]: + for plane in ["x", "y"]: + assert madx.globals[f"tar_on_{plane}ip{ip:d}b{beam:d}"] is not None + + +def test_lhc_run2_setup(_proton_opticsfile): + # If works properly we have beams with lhc seq and old 30cm optics + # And there the optics are matched for specific tune values + with LHCSetup(run=2, opticsfile=_proton_opticsfile) as madx: + madx.command.twiss() + assert math.isclose(madx.table.summ.q1[0], 62.31, abs_tol=1e-6) + assert math.isclose(madx.table.summ.q2[0], 60.32, abs_tol=1e-6) + + # ---------------------- Private Utilities ---------------------- # @@ -490,3 +801,13 @@ def _reference_twiss_rdts() -> pathlib.Path: @pytest.fixture() def _reference_kmodulation() -> pathlib.Path: return INPUTS_DIR / "cpymadtools" / "kmodulation.tfs" + + +@pytest.fixture() +def _ips_twiss_path() -> pathlib.Path: + return INPUTS_DIR / "cpymadtools" / "ips_twiss.tfs" + + +@pytest.fixture() +def _proton_opticsfile() -> str: + return str((PROTON_DIR / "opticsfile.22").absolute()) diff --git a/tests/test_cpymadtools/test_matching.py b/tests/test_cpymadtools/test_matching.py index d1b76471..141cfcee 100644 --- a/tests/test_cpymadtools/test_matching.py +++ b/tests/test_cpymadtools/test_matching.py @@ -6,7 +6,7 @@ from cpymad.madx import Madx -from pyhdtoolkit.cpymadtools.generators import LatticeGenerator +from pyhdtoolkit.cpymadtools._generators import LatticeGenerator from pyhdtoolkit.cpymadtools.matching import match_chromaticities, match_tunes, match_tunes_and_chromaticities BASE_LATTICE = LatticeGenerator.generate_base_cas_lattice() diff --git a/tests/test_cpymadtools/test_orbit.py b/tests/test_cpymadtools/test_orbit.py deleted file mode 100644 index c92c4a6c..00000000 --- a/tests/test_cpymadtools/test_orbit.py +++ /dev/null @@ -1,109 +0,0 @@ -import math - -import pytest - -from pyhdtoolkit.cpymadtools.constants import LHC_CROSSING_SCHEMES -from pyhdtoolkit.cpymadtools.lhc import make_lhc_beams, re_cycle_sequence -from pyhdtoolkit.cpymadtools.matching import match_tunes_and_chromaticities -from pyhdtoolkit.cpymadtools.orbit import ( - correct_lhc_orbit, - get_current_orbit_setup, - lhc_orbit_variables, - setup_lhc_orbit, -) - - -def test_lhc_orbit_variables(): - assert lhc_orbit_variables() == ( - [ - "on_crab1", - "on_crab5", - "on_x1", - "on_sep1", - "on_o1", - "on_oh1", - "on_ov1", - "on_x2", - "on_sep2", - "on_o2", - "on_oe2", - "on_a2", - "on_oh2", - "on_ov2", - "on_x5", - "on_sep5", - "on_o5", - "on_oh5", - "on_ov5", - "on_x8", - "on_sep8", - "on_o8", - "on_a8", - "on_sep8h", - "on_x8v", - "on_oh8", - "on_ov8", - "on_alice", - "on_sol_alice", - "on_lhcb", - "on_sol_atlas", - "on_sol_cms", - "phi_IR1", - "phi_IR2", - "phi_IR5", - "phi_IR8", - ], - {"on_ssep1": "on_sep1", "on_xx1": "on_x1", "on_ssep5": "on_sep5", "on_xx5": "on_x5"}, - ) - - -def test_lhc_orbit_setup_fals_on_unknown_scheme(_non_matched_lhc_madx, caplog): - madx = _non_matched_lhc_madx - - with pytest.raises(ValueError): - setup_lhc_orbit(madx, scheme="unknown") - - for record in caplog.records: - assert record.levelname == "ERROR" - - -@pytest.mark.parametrize("scheme", list(LHC_CROSSING_SCHEMES.keys())) -def test_lhc_orbit_setup(scheme, _non_matched_lhc_madx): - madx = _non_matched_lhc_madx - setup_lhc_orbit(madx, scheme=scheme) - variables, special = lhc_orbit_variables() - - for orbit_variable in variables: - value = LHC_CROSSING_SCHEMES[scheme].get(orbit_variable, 0) - assert madx.globals[orbit_variable] == value - - for special_variable, copy_from in special.items(): - assert madx.globals[special_variable] == madx.globals[copy_from] - - -def test_get_orbit_setup(_non_matched_lhc_madx): - madx = _non_matched_lhc_madx - setup_lhc_orbit(madx, scheme="flat") - setup = get_current_orbit_setup(madx) - - assert isinstance(setup, dict) - assert all(orbit_var in setup.keys() for orbit_var in lhc_orbit_variables()[0]) - assert all(special_var in setup.keys() for special_var in lhc_orbit_variables()[1]) - - -def test_orbit_correction(_bare_lhc_madx): - madx = _bare_lhc_madx - re_cycle_sequence(madx, sequence="lhcb1", start="IP3") - _ = setup_lhc_orbit(madx, scheme="flat") - make_lhc_beams(madx) - madx.use(sequence="lhcb1") - match_tunes_and_chromaticities(madx, "lhc", "lhcb1", 62.31, 60.32, 2.0, 2.0) - assert madx.table.summ["xcorms"][0] == 0 # rms of horizontal CO - - madx.select(flag="error", pattern="MQ.13R3.B1") # arc quad in sector 34 - madx.command.ealign(dx="1E-3") - madx.twiss() - assert madx.table.summ["xcorms"][0] > 1e-3 - - correct_lhc_orbit(madx, sequence="lhcb1") - assert math.isclose(madx.table.summ["xcorms"], 0, abs_tol=1e-5) diff --git a/tests/test_cpymadtools/test_ptc.py b/tests/test_cpymadtools/test_ptc.py index 6d69fa8e..a4327fca 100644 --- a/tests/test_cpymadtools/test_ptc.py +++ b/tests/test_cpymadtools/test_ptc.py @@ -7,7 +7,7 @@ from pandas import DataFrame from pandas.testing import assert_frame_equal -from pyhdtoolkit.cpymadtools.generators import LatticeGenerator +from pyhdtoolkit.cpymadtools._generators import LatticeGenerator from pyhdtoolkit.cpymadtools.matching import match_tunes_and_chromaticities from pyhdtoolkit.cpymadtools.ptc import get_amplitude_detuning, get_rdts, ptc_track_particle, ptc_twiss diff --git a/tests/test_cpymadtools/test_tune.py b/tests/test_cpymadtools/test_tune.py index 182458ab..8ae4d290 100644 --- a/tests/test_cpymadtools/test_tune.py +++ b/tests/test_cpymadtools/test_tune.py @@ -6,9 +6,8 @@ import pytest import tfs -from pyhdtoolkit.cpymadtools.lhc import make_lhc_thin, re_cycle_sequence +from pyhdtoolkit.cpymadtools.lhc import make_lhc_thin, re_cycle_sequence, setup_lhc_orbit from pyhdtoolkit.cpymadtools.matching import match_tunes_and_chromaticities -from pyhdtoolkit.cpymadtools.orbit import setup_lhc_orbit from pyhdtoolkit.cpymadtools.tune import get_footprint_lines, get_footprint_patches, make_footprint_table # Forcing non-interactive Agg backend so rendering is done similarly across platforms during tests diff --git a/tests/test_cpymadtools/test_twiss.py b/tests/test_cpymadtools/test_twiss.py index 899f29e9..1e07991a 100644 --- a/tests/test_cpymadtools/test_twiss.py +++ b/tests/test_cpymadtools/test_twiss.py @@ -6,7 +6,7 @@ from pandas.testing import assert_frame_equal from pyhdtoolkit.cpymadtools.constants import DEFAULT_TWISS_COLUMNS # for coverage -from pyhdtoolkit.cpymadtools.twiss import get_ips_twiss, get_ir_twiss, get_twiss_tfs +from pyhdtoolkit.cpymadtools.twiss import get_twiss_tfs CURRENT_DIR = pathlib.Path(__file__).parent INPUTS_DIR = CURRENT_DIR.parent / "inputs" @@ -19,37 +19,9 @@ def test_twiss_tfs(_twiss_export, _matched_base_lattice): assert_frame_equal(twiss_tfs, from_disk) -def test_get_ips_twiss(_ips_twiss_path, _matched_lhc_madx): - madx = _matched_lhc_madx - - reference_df = tfs.read(_ips_twiss_path) - ips_df = get_ips_twiss(madx) - # assert_dict_equal(reference_df.headers, ips_df.headers) # bugged at the moment - assert_frame_equal(reference_df.set_index("name"), ips_df.set_index("name")) - - -@pytest.mark.parametrize("ir", [1, 5]) -def test_get_irs_twiss(ir, _matched_lhc_madx): - madx = _matched_lhc_madx - - reference_df = tfs.read(INPUTS_DIR / "cpymadtools" / f"ir{ir:d}_twiss.tfs") - ir_df = get_ir_twiss(madx, ir=ir) - # assert_dict_equal(reference_df.headers, ir_df.headers) # bugged at the moment - assert_frame_equal(reference_df.set_index("name"), ir_df.set_index("name")) - - extra_columns = ["k0l", "k0sl", "k1l", "k1sl", "k2l", "k2sl", "sig11", "sig12", "sig21", "sig22"] - ir_extra_columns_df = get_ir_twiss(madx, ir=ir, columns=DEFAULT_TWISS_COLUMNS + extra_columns) - assert all([colname in ir_extra_columns_df.columns for colname in extra_columns]) - - # ---------------------- Private Utilities ---------------------- # -@pytest.fixture() -def _ips_twiss_path() -> pathlib.Path: - return INPUTS_DIR / "cpymadtools" / "ips_twiss.tfs" - - @pytest.fixture() def _twiss_export() -> pathlib.Path: return INPUTS_DIR / "cpymadtools" / "twiss_export.tfs" diff --git a/tests/test_plotting/test_lattice.py b/tests/test_plotting/test_lattice.py index a447a660..1c4f072b 100644 --- a/tests/test_plotting/test_lattice.py +++ b/tests/test_plotting/test_lattice.py @@ -6,7 +6,7 @@ from cpymad.madx import Madx -from pyhdtoolkit.cpymadtools.generators import LatticeGenerator +from pyhdtoolkit.cpymadtools._generators import LatticeGenerator from pyhdtoolkit.cpymadtools.matching import match_tunes_and_chromaticities from pyhdtoolkit.plotting.lattice import plot_latwiss, plot_machine_survey diff --git a/tests/test_plotting/test_phasespace.py b/tests/test_plotting/test_phasespace.py index 59061a36..76715a71 100644 --- a/tests/test_plotting/test_phasespace.py +++ b/tests/test_plotting/test_phasespace.py @@ -8,7 +8,7 @@ from cpymad.madx import Madx -from pyhdtoolkit.cpymadtools.generators import LatticeGenerator +from pyhdtoolkit.cpymadtools._generators import LatticeGenerator from pyhdtoolkit.cpymadtools.matching import match_tunes_and_chromaticities from pyhdtoolkit.cpymadtools.track import track_single_particle from pyhdtoolkit.plotting.phasespace import (