Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
bc9e635
Refactor file path handling in LHC model creator and response MAD-X s…
jgray-19 Oct 31, 2025
719a33e
Add MQT extraction functionality and related tests
jgray-19 Oct 31, 2025
a9f58c1
Merge branch 'master' of https://github.com/pylhc/omc3 into fix_madx_…
jgray-19 Oct 31, 2025
484bdb1
Add NXCALS and PySpark as optional dependencies for enhanced function…
jgray-19 Oct 31, 2025
e091de8
Refactor path handling in ModelCreator to return Path objects instead…
jgray-19 Nov 3, 2025
1d280f9
Refactor MAD-X script methods to remove cwd parameter and ensure path…
jgray-19 Nov 4, 2025
fe9c2a5
Remove unused TYPE_CHECKING imports from model creator files
jgray-19 Nov 4, 2025
492e6c7
Fix comparison of modifier paths in check_accel_from_dir_vs_options f…
jgray-19 Nov 4, 2025
59c57ec
Add MQT extraction script and update retrieval function to support ou…
jgray-19 Nov 4, 2025
4afd69b
Add checks for None modifiers in check_accel_from_dir_vs_options func…
jgray-19 Nov 5, 2025
ca8fdcf
Apply suggestion from @fsoubelet
jgray-19 Nov 14, 2025
4298a31
Refactor knob_extraction.py: Improve docstrings and logging consistency
jgray-19 Nov 14, 2025
141c7c3
Refactor model creators to use resolve_madx_path for path handling
jgray-19 Nov 14, 2025
88b1d29
Fix MAD-X job generation logic for last process index check
jgray-19 Nov 14, 2025
896a97f
Reorder functions
jgray-19 Nov 14, 2025
54a56e6
Adjust further based on comments
jgray-19 Nov 14, 2025
3404dae
Enhance MQT extractor documentation and update dependencies for Spark…
jgray-19 Nov 14, 2025
2bd00c8
Fix tests
jgray-19 Nov 14, 2025
9f66b22
Fix test more
jgray-19 Nov 14, 2025
1955e5b
Fix test for windows
jgray-19 Nov 14, 2025
37d03f3
Fix module paths in documentation and add NXCALS module
jgray-19 Nov 29, 2025
b0b13a0
Refactor coupling addition loop to improve readability
jgray-19 Nov 29, 2025
688bba6
Refactor MADX script generation for improved readability
jgray-19 Nov 29, 2025
c9d497d
Rename NXCalResult to NXCALSResult and update references across modules
jgray-19 Nov 29, 2025
8dfce03
Update time handling and parameter types for MQT extraction
jgray-19 Nov 29, 2025
5c8216c
Simplify assertion message formatting in test_main_with_timedelta
jgray-19 Nov 29, 2025
81738e0
Add timezone support by importing timezone from datetime
jgray-19 Nov 29, 2025
ec2198f
Ruff the knob extractor and add to git blame
jgray-19 Nov 29, 2025
6643ed3
Update .git-blame-ignore-revs to include additional formatting commit…
jgray-19 Nov 29, 2025
ad1a536
Clarify LHC context in knob extraction module and related functions
jgray-19 Nov 29, 2025
ee8e3ff
Formatting
jgray-19 Dec 3, 2025
1b2032d
Refactor time parsing functions and consolidate time tools for consis…
jgray-19 Dec 3, 2025
ca36dcc
Refactor MADX path resolution in CorrectionModelCreator for improved …
jgray-19 Dec 3, 2025
e97c9d8
Remove old comment from previous version
jgray-19 Dec 3, 2025
3b5e5cc
Enforce tz aware
jgray-19 Dec 3, 2025
c171cac
Enforce timezones
jgray-19 Dec 3, 2025
927f394
Improve _get_madx_main_sequence_loading
jgray-19 Dec 3, 2025
11d022c
Update time handling in knob and MQT extractors for improved clarity …
jgray-19 Dec 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
820a51e3c67c8675880b9c949ac09f4db8bd8e9f
4e59cd0f7eb6a4279dc3f5cfbaed2b03b1918df3
0c19f7f7aa2e69a46c0e72fb99d4c3a29a1726c1
ec2198f5a98083bf894e5660ea3a1c4349945273
7 changes: 6 additions & 1 deletion doc/entrypoints/scripts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Scripts
:noindex:


.. automodule:: omc3.scripts.kmod_averages
.. automodule:: omc3.scripts.kmod_average
:members:
:noindex:

Expand Down Expand Up @@ -46,6 +46,11 @@ Scripts
:noindex:


.. automodule:: omc3.scripts.create_logbook_entry
:members:
:noindex:


.. automodule:: omc3.scripts.lhc_corrector_list_check
:members:
:noindex:
8 changes: 8 additions & 0 deletions doc/modules/model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,11 @@ Model
:members:
:noindex:


.. automodule:: omc3.model.model_creators.abstract_model_creator
:members:
:noindex:

.. automodule:: omc3.model.model_creators.segment_creator
:members:
:noindex:
16 changes: 16 additions & 0 deletions doc/modules/nxcals.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
NXCALS
**************************

.. automodule:: omc3.nxcals.constants
:members:
:noindex:


.. automodule:: omc3.nxcals.knob_extraction
:members:
:noindex:


.. automodule:: omc3.nxcals.mqt_extraction
:members:
:noindex:
161 changes: 96 additions & 65 deletions omc3/correction/response_madx.py

Large diffs are not rendered by default.

76 changes: 41 additions & 35 deletions omc3/correction/sequence_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

Compare results with case all==0.
"""

from __future__ import annotations

import multiprocessing
Expand Down Expand Up @@ -44,17 +45,17 @@ def evaluate_for_variables(
variable_categories: Sequence[str],
order: int = 4,
num_proc: int = multiprocessing.cpu_count(),
temp_dir: Path | None = None
temp_dir: Path | None = None,
) -> dict:
""" Generate a dictionary containing response matrices for
beta, phase, dispersion, tune and coupling and saves it to a file.

Args:
accel_inst (Accelerator): Accelerator Instance.
variable_categories (list): Categories of the variables/knobs to use. (from .json)
order (int or tuple): Max or [min, max] of K-value order to use.
num_proc (int): Number of processes to use in parallel.
temp_dir (Path): temporary directory. If ``None``, uses model_dir.
"""Generate a dictionary containing response matrices for
beta, phase, dispersion, tune and coupling and saves it to a file.

Args:
accel_inst (Accelerator): Accelerator Instance.
variable_categories (list): Categories of the variables/knobs to use. (from .json)
order (int or tuple): Max or [min, max] of K-value order to use.
num_proc (int): Number of processes to use in parallel.
temp_dir (Path): temporary directory. If ``None``, uses model_dir.
"""
LOG.debug("Generating Fullresponse via Mad-X.")
with timeit(lambda elapsed: LOG.debug(f" Total time generating fullresponse: {elapsed}s")):
Expand Down Expand Up @@ -87,7 +88,8 @@ def _generate_madx_jobs(
num_proc: int,
temp_dir: Path,
) -> None:
""" Generates madx job-files """
"""Generates madx job-files"""

def _assign(var, value):
return f"{var:s} = {value:d};\n"

Expand Down Expand Up @@ -120,14 +122,14 @@ def _do_macro(var):
job_content += "\n"

# last thing to do: get baseline
if proc_index+1 == num_proc:
if proc_index == num_proc - 1:
job_content += _do_macro("0")

_get_jobfile(temp_dir, proc_index).write_text(job_content)


def _call_madx(process_pool: multiprocessing.Pool, temp_dir: str, num_proc: int) -> None: # type: ignore
""" Call madx in parallel """
def _call_madx(process_pool: multiprocessing.Pool, temp_dir: str, num_proc: int) -> None: # type: ignore
"""Call madx in parallel"""
LOG.debug(f"Starting {num_proc:d} MAD-X jobs...")
madx_jobs = [_get_jobfile(temp_dir, index) for index in range(num_proc)]
failed = [LOG.error(fail) for fail in process_pool.map(_launch_single_job, madx_jobs) if fail]
Expand All @@ -137,9 +139,9 @@ def _call_madx(process_pool: multiprocessing.Pool, temp_dir: str, num_proc: int)


def _clean_up(variables: list[str], temp_dir: Path, num_proc: int) -> None:
""" Merge Logfiles and clean temporary outputfiles """
"""Merge Logfiles and clean temporary outputfiles"""
LOG.debug("Cleaning output and printing log...")
for var in (variables + ["0"]):
for var in variables + ["0"]:
table_file = _get_tablefile(temp_dir, var)
with suppress(FileNotFoundError): # py3.8 missing_ok=True
table_file.unlink()
Expand All @@ -166,10 +168,10 @@ def _clean_up(variables: list[str], temp_dir: Path, num_proc: int) -> None:
def _load_madx_results(
variables: Sequence[str],
k_values: list[float],
process_pool: multiprocessing.Pool, # type: ignore
process_pool: multiprocessing.Pool, # type: ignore
temp_dir: str,
) -> dict:
""" Load the madx results in parallel and return var-tfs dictionary """
"""Load the madx results in parallel and return var-tfs dictionary"""
LOG.debug("Loading Madx Results.")
path_and_vars = []
for value in variables:
Expand All @@ -179,7 +181,7 @@ def _load_madx_results(
mapping = dict([(order, {}) for order in k_values] + [(f"{order}L", {}) for order in k_values])
for var, tfs_data in process_pool.map(_load_and_remove_twiss, path_and_vars):
for order in k_values:
diff = (tfs_data[order] - base_tfs[order])
diff = tfs_data[order] - base_tfs[order]
mask = diff != 0 # drop zeros, maybe abs(diff) < eps ?
k_list = diff.loc[mask]
mapping[order][var] = k_list
Expand All @@ -191,30 +193,30 @@ def _load_madx_results(


def _get_orders(order: int) -> Sequence[str]:
""" Returns a list of strings with K-values to be used """
"""Returns a list of strings with K-values to be used"""
try:
return [f"K{i:d}{s:s}" for i in range(3) for s in ["", "S"]]
except TypeError:
return [f"K{i:d}{s:s}" for i in range(*order) for s in ["", "S"]]


def _get_jobfile(folder: Path, index: int) -> Path:
""" Return names for jobfile and iterfile according to index """
"""Return names for jobfile and iterfile according to index"""
return folder / f"job.varmap.{index:d}.madx"


def _get_tablefile(folder: Path, var: str) -> Path:
""" Return name of the variable-specific table file """
"""Return name of the variable-specific table file"""
return folder / f"table.{var}"


def _get_surveyfile(folder: Path, index: int) -> Path:
""" Returns the name of the temporary survey file """
"""Returns the name of the temporary survey file"""
return folder / f"survey.{index:d}.tmp"


def _launch_single_job(inputfile_path: Path):
""" Function for pool to start a single madx job """
"""Function for pool to start a single madx job"""
log_file = inputfile_path.with_name(f"{inputfile_path.name}.log")
try:
madx_wrapper.run_file(inputfile_path, log_file=log_file, cwd=inputfile_path.parent)
Expand All @@ -225,16 +227,18 @@ def _launch_single_job(inputfile_path: Path):


def _load_and_remove_twiss(path_and_var: tuple[Path, str]) -> tuple[str, tfs.TfsDataFrame]:
""" Function for pool to retrieve results """
"""Function for pool to retrieve results"""
path, var = path_and_var
twissfile = _get_tablefile(path, var)
tfs_data = tfs.read(twissfile, index="NAME")
return var, tfs_data


def _create_basic_job(accel_inst: Accelerator, k_values: list[str], variables: Sequence[str]) -> str:
""" Create the madx-job basics needed
TEMPFILE needs to be replaced in the returned string.
def _create_basic_job(
accel_inst: Accelerator, k_values: list[str], variables: Sequence[str]
) -> str:
"""Create the madx-job basics needed
TEMPFILE needs to be replaced in the returned string.
"""
# get nominal setup from creator
creator_class = get_model_creator_class(accel_inst, CreatorType.NOMINAL)
Expand Down Expand Up @@ -297,16 +301,18 @@ def _create_basic_job(accel_inst: Accelerator, k_values: list[str], variables: S


def check_varmap_file(accel_inst: Accelerator, vars_categories):
""" Checks on varmap file and creates it if not in model folder.
"""
"""Checks on varmap file and creates it if not in model folder."""
if accel_inst.modifiers is None:
raise ValueError("Optics not defined. Please provide modifiers.madx. "
"Otherwise MADX evaluation might be unstable.")
raise ValueError(
"Optics not defined. Please provide modifiers.madx. "
"Otherwise MADX evaluation might be unstable."
)

varmap_path = Path(accel_inst.model_dir) / f"varmap_{'_'.join(sorted(set(vars_categories)))}.{EXT}"
varmap_path = (
Path(accel_inst.model_dir) / f"varmap_{'_'.join(sorted(set(vars_categories)))}.{EXT}"
)
if not varmap_path.exists():
LOG.info(f"Variable mapping '{str(varmap_path):s}' not found. "
"Evaluating it via madx.")
LOG.info(f"Variable mapping '{str(varmap_path):s}' not found. Evaluating it via madx.")
mapping = evaluate_for_variables(accel_inst, vars_categories)
write_varmap(varmap_path, mapping)

Expand Down
Loading
Loading