Skip to content

Commit

Permalink
Fix: MAD-X Variable Name Length Limit (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
fsoubelet authored May 31, 2022
1 parent 3e4ed73 commit feb0aec
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 24 deletions.
2 changes: 1 addition & 1 deletion pylhc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
__title__ = "pylhc"
__description__ = "An accelerator physics script collection for the OMC team at CERN."
__url__ = "https://github.com/pylhc/pylhc"
__version__ = "0.7.1"
__version__ = "0.7.2"
__author__ = "pylhc"
__author_email__ = "[email protected]"
__license__ = "MIT"
Expand Down
34 changes: 32 additions & 2 deletions pylhc/lsa_to_madx.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@
Two files, **LHCBEAM_MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_definition.tfs** and **LHCBEAM_MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_knob.madx** will be written to disk.
.. warning::
In ``MAD-X``, variable names with 48 or more characters will cause an issue.
As a consequence, this script will automatically truncate the knob name if needed when created the trim variable name.
One should not be surprised if long ``LSA`` knob names appear slightly differently in the created ``MAD-X`` files, then functionality stays intact.
For instance, the knob ``LHCBEAM/MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos`` will lead to the following trim variable definition:
.. code-block:: fortran
trim_D_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos = 1.0;
In order to reproduce a specific machine configuration at a given time, one can gather all knobs and their trim values for this configuration in a text file and feed this file to the script.
In this file, each line should hold a knob name as it appears in LSA and its trim value.
Lines starting with a ``#`` character will be ignored.
Expand Down Expand Up @@ -143,8 +154,7 @@ def get_madx_script_from_definition_dataframe(deltas_df: tfs.TfsDataFrame, lsa_k
change_commands = [f"! Start of change commands for knob: {lsa_knob}"]

# Set this to 1 by default but can be changed by the user to reproduce a given trim
knob_itself = lsa_knob.split("/")[-1] # without the LHCBEAM[12]?/ part
trim_variable = f"{knob_itself}_trim"
trim_variable = _get_trim_variable(lsa_knob)
change_commands.append("! Change this value to reproduce a different trim")
change_commands.append(f"! Beware some knobs are not so linear in their trims")
change_commands.append(f"{trim_variable} = {trim};")
Expand All @@ -157,6 +167,26 @@ def get_madx_script_from_definition_dataframe(deltas_df: tfs.TfsDataFrame, lsa_k
return "\n".join(change_commands)


def _get_trim_variable(lsa_knob: str) -> str:
"""
Generates the ``MAD-X`` trim variable name from an ``LSA`` knob.
Handles the variable name character limit of ``MAD-X``.
"""
knob_itself = lsa_knob.split("/")[-1] # without the LHCBEAM[12]?/ part

# MAD-X will crash if the variable name is >48 characters or longer! It will also silently fail
# if the variable name starts with an underscore or a digit. Adding "trim_" at the start circumvents
# the latter two, and we make sure to truncate the knob so that the result is <=47 characters
if len(knob_itself) > 42:
LOG.info(f"Knob '{knob_itself}' is too long to be a MAD-X variable and will be truncated.")
knob_itself = knob_itself[-42:]
LOG.debug(f"Truncated knob name to '{knob_itself}'.")

trim_variable = f"trim_{knob_itself.lstrip('_')}"

return trim_variable


# ----- Script Part ----- #


Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
! Start of change commands for knob: LHCBEAM/MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos
! Start of change commands for knob: LHCBEAM/ATS_Test_Knob
! Change this value to reproduce a different trim
! Beware some knobs are not so linear in their trims
MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim = 1.0;
trim_ATS_Test_Knob = 1.0;
! Impacted variables
kq9.r1b1 = kq9.r1b1 + ( 0.000139519135701 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq5.r1b1 = kq5.r1b1 + ( -0.000208665238461 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq7.l1b1 = kq7.l1b1 + ( -1.65434776136e-05 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq8.r1b1 = kq8.r1b1 + ( -5.16630898346e-05 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq8.l1b1 = kq8.l1b1 + ( 4.70197155664e-05 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq10.r1b1 = kq10.r1b1 + ( -1.96085402422e-05 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq4.l1b1 = kq4.l1b1 + ( 7.35134890419e-05 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq4.r1b1 = kq4.r1b1 + ( 4.70408231195e-05 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq10.l1b1 = kq10.l1b1 + ( -2.47050375037e-05 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq7.r1b1 = kq7.r1b1 + ( -2.3806014724e-05 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq9.l1b1 = kq9.l1b1 + ( 0.000118330906844 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq5.l1b1 = kq5.l1b1 + ( -0.000214221465285 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq6.r1b1 = kq6.r1b1 + ( 0.000218127839616 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
kq6.l1b1 = kq6.l1b1 + ( 0.000125226986711 ) * MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos_trim;
! End of change commands for knob: LHCBEAM/MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos
kq9.r1b1 = kq9.r1b1 + ( 0.000139519135701 ) * trim_ATS_Test_Knob;
kq5.r1b1 = kq5.r1b1 + ( -0.000208665238461 ) * trim_ATS_Test_Knob;
kq7.l1b1 = kq7.l1b1 + ( -1.65434776136e-05 ) * trim_ATS_Test_Knob;
kq8.r1b1 = kq8.r1b1 + ( -5.16630898346e-05 ) * trim_ATS_Test_Knob;
kq8.l1b1 = kq8.l1b1 + ( 4.70197155664e-05 ) * trim_ATS_Test_Knob;
kq10.r1b1 = kq10.r1b1 + ( -1.96085402422e-05 ) * trim_ATS_Test_Knob;
kq4.l1b1 = kq4.l1b1 + ( 7.35134890419e-05 ) * trim_ATS_Test_Knob;
kq4.r1b1 = kq4.r1b1 + ( 4.70408231195e-05 ) * trim_ATS_Test_Knob;
kq10.l1b1 = kq10.l1b1 + ( -2.47050375037e-05 ) * trim_ATS_Test_Knob;
kq7.r1b1 = kq7.r1b1 + ( -2.3806014724e-05 ) * trim_ATS_Test_Knob;
kq9.l1b1 = kq9.l1b1 + ( 0.000118330906844 ) * trim_ATS_Test_Knob;
kq5.l1b1 = kq5.l1b1 + ( -0.000214221465285 ) * trim_ATS_Test_Knob;
kq6.r1b1 = kq6.r1b1 + ( 0.000218127839616 ) * trim_ATS_Test_Knob;
kq6.l1b1 = kq6.l1b1 + ( 0.000125226986711 ) * trim_ATS_Test_Knob;
! End of change commands for knob: LHCBEAM/ATS_Test_Knob
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@ Knob %s "LHCBEAM/MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos"
@ Knob %s "LHCBEAM/ATS_Test_Knob"
@ Optics %s "R2022a_A30cmC30cmA10mL200cm"
@ Info %s "In MAD-X it should be 'name = name + DELTA * knobValue'"
* INDEX&&& CIRCUIT DELTA_K
Expand Down
1 change: 1 addition & 0 deletions tests/inputs/lsa_to_madx/knobs_definitions.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# For optics R2017aT_A30C30A10mL300_CTPPS2
#Nonlinear
LHCBEAM/2017_IRNL_IR1a4 0.5
LHCBEAM/2017_IRNL_IR1b3_couplFD 1.0
Expand Down
15 changes: 12 additions & 3 deletions tests/unit/test_lsa_to_madx.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pandas._testing import assert_dict_equal

from pylhc.lsa_to_madx import (
_get_trim_variable,
get_madx_script_from_definition_dataframe,
parse_knobs_and_trim_values_from_file,
)
Expand All @@ -26,10 +27,18 @@ def test_parse_knob_definition_file(self, knobs_file, parsed_definitions):

class TestMADXWriting:
def test_madx_script_writing_from_definition_df(self, knob_definition_df, correct_madx_script):
script = get_madx_script_from_definition_dataframe(
knob_definition_df, lsa_knob="LHCBEAM/MD_ATS_2022_05_04_B1_RigidWaitsShift_IP1pos"
script = get_madx_script_from_definition_dataframe(knob_definition_df, lsa_knob="LHCBEAM/ATS_Test_Knob")
assert script == correct_madx_script

@pytest.mark.parametrize("lsa_knob", ["LHCBEAM/Super_Duper_Long_Name_For_A_Knob_Will_Be_Truncated_For_Sure", "ATS_Test_Knob"])
def test_trim_variable_from_long_knob_name(self, lsa_knob):
"""Testing that the generated trim variable is correctly truncated if too long."""
assert (
_get_trim_variable("ATS_2022_05_08_B1_arc_by_arc_coupling_133cm_30cm")
== "trim_22_05_08_B1_arc_by_arc_coupling_133cm_30cm"
)
assert script == correct_madx_script # TODO: figure why this doesn't work?
assert _get_trim_variable("___knob") == "trim_knob" # make sure we handle several underscores
assert len(_get_trim_variable(lsa_knob)) < 48


# ----- Fixtures ----- #
Expand Down

0 comments on commit feb0aec

Please sign in to comment.