Skip to content

Commit edaa6d4

Browse files
fscarlierJoschD
andauthored
K-Modulation Importer: fixed main function call (#482)
* fixed main function call * fix bug on single IP import --------- Co-authored-by: JoschD <[email protected]>
1 parent 9fdd25c commit edaa6d4

File tree

5 files changed

+90
-73
lines changed

5 files changed

+90
-73
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# OMC3 Changelog
22

3+
#### 2025-03-03 - v0.21.1 - _fscarlier_
4+
5+
- Fixed:
6+
- Correct function call in `omc3.kmod_importer` when running as script.
7+
- Fixed k-mod import for single-IP imports.
8+
39
#### 2025-01-23 - v0.21.0 - _jdilly_, _fscarlier_, _fesoubel_
410

511
- Fixed:

omc3/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
__title__ = "omc3"
1212
__description__ = "An accelerator physics tools package for the OMC team at CERN."
1313
__url__ = "https://github.com/pylhc/omc3"
14-
__version__ = "0.21.0"
14+
__version__ = "0.21.1"
1515
__author__ = "pylhc"
1616
__author_email__ = "[email protected]"
1717
__license__ = "MIT"

omc3/kmod_importer.py

Lines changed: 59 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""
1+
"""
22
Full Import of K-Modulation Results
33
-----------------------------------
44
@@ -9,11 +9,11 @@
99
The results are first sorted by IP and averaged. The averaged results are
1010
written into a sub-folder of the given `output_dir`.
1111
12-
If data for both beams is present, these averages are then used to calculate the
13-
luminosity imbalance between each combination of IPs.
12+
If data for both beams is present, these averages are then used to calculate the
13+
luminosity imbalance between each combination of IPs.
1414
These results are again written out into the same sub-folder of the given `output_dir`.
1515
16-
Finally, the averaged results for the given `beam` are then written out into
16+
Finally, the averaged results for the given `beam` are then written out into
1717
the `beta_kmod` and `betastar` tfs-files in the `output_dir`.
1818
1919
@@ -23,7 +23,7 @@
2323
2424
- **meas_paths** *(PathOrStr)*:
2525
26-
Directories of K-modulation results to import.
26+
Directories of K-modulation results to import.
2727
These need to be the paths to the root-folders containing B1 and B2 sub-dirs.
2828
2929
@@ -35,7 +35,7 @@
3535
- **beam** *(int)*:
3636
3737
Beam for which to import.
38-
38+
3939
4040
- **output_dir** *(PathOrStr)*:
4141
@@ -91,34 +91,34 @@
9191
def _get_params():
9292
"""
9393
Creates and returns the parameters for the kmod_output function.
94-
94+
9595
"""
9696
params = EntryPointParameters()
9797
params.add_parameter(
9898
name="meas_paths",
9999
required=True,
100-
nargs='+',
100+
nargs="+",
101101
type=PathOrStr,
102102
help="Directories of K-modulation results to import. "
103-
"These need to be the paths to the root-folders containing B1 and B2 sub-dirs."
103+
"These need to be the paths to the root-folders containing B1 and B2 sub-dirs.",
104104
)
105105
params.add_parameter(
106106
name="model",
107107
required=True,
108108
type=PathOrStr,
109-
help="Path to the model."
109+
help="Path to the model.",
110110
)
111111
params.add_parameter(
112112
name="beam",
113113
required=True,
114114
type=int,
115-
help="Beam for which to import."
115+
help="Beam for which to import.",
116116
)
117117
params.add_parameter(
118118
name="output_dir",
119119
type=PathOrStr,
120120
required=True,
121-
help="Path to the directory where to write the output files."
121+
help="Path to the directory where to write the output files.",
122122
)
123123
params.add_parameter(
124124
name="show_plots",
@@ -132,32 +132,32 @@ def _get_params():
132132
def import_kmod_results(opt: DotDict) -> None:
133133
"""
134134
Performs the full import procedure of the "raw" K-Modulation results.
135-
135+
136136
Args:
137137
meas_paths (Sequence[Path|str]):
138138
Directories of K-modulation results to import.
139139
These need to be the paths to the root-folders containing B1 and B2 sub-dirs.
140-
140+
141141
model (Path|str):
142142
Path to the model Twiss file.
143-
143+
144144
beam (int):
145145
Beam for which to import.
146-
146+
147147
output_dir (Path|str):
148-
Path to the output directory, i.e. the optics-measurement directory
148+
Path to the output directory, i.e. the optics-measurement directory
149149
into which to import these K-Modulation results.
150-
150+
151151
show_plots (bool):
152152
If True, show the plots. Default: False.
153153
154-
154+
155155
Returns:
156156
Dictionary of kmod-DataFrames by planes.
157157
"""
158158
LOG.info("Starting full K-modulation import.")
159159

160-
# Prepare IO ---
160+
# Prepare IO ---
161161
opt.output_dir = Path(opt.output_dir)
162162
opt.output_dir.mkdir(exist_ok=True)
163163
save_config(opt.output_dir, opt, __file__)
@@ -166,27 +166,25 @@ def import_kmod_results(opt: DotDict) -> None:
166166
average_output_dir.mkdir(exist_ok=True)
167167

168168
df_model = read_model_df(opt.model)
169-
169+
170170
# Perform averaging and import ---
171171
averaged_results = average_all_results(
172-
meas_paths=opt.meas_paths,
173-
df_model=df_model,
174-
beam=opt.beam,
175-
output_dir=average_output_dir
172+
meas_paths=opt.meas_paths,
173+
df_model=df_model,
174+
beam=opt.beam,
175+
output_dir=average_output_dir,
176176
)
177-
177+
178178
calculate_all_lumi_imbalances(
179-
averaged_results,
180-
df_model=df_model,
181-
output_dir=average_output_dir
179+
averaged_results, df_model=df_model, output_dir=average_output_dir
182180
)
183181

184182
results_list = [
185-
df
186-
for ip in averaged_results.keys()
183+
df
184+
for ip in averaged_results.keys()
187185
for df in (
188-
averaged_results[ip][0], # beta-star results
189-
averaged_results[ip][opt.beam] # bpm results of the specific beam
186+
averaged_results[ip][0], # beta-star results
187+
averaged_results[ip][opt.beam], # bpm results of the specific beam
190188
)
191189
]
192190
import_kmod_data(
@@ -199,24 +197,25 @@ def import_kmod_results(opt: DotDict) -> None:
199197

200198
# Averaging ---
201199

200+
202201
def average_all_results(
203202
meas_paths: Sequence[Path | str],
204203
df_model: tfs.TfsDataFrame,
205204
beam: int,
206205
output_dir: Path | str,
207206
show_plots: bool = False,
208207
) -> dict[str, dict[int, tfs.TfsDataFrame]]:
209-
""" Averages all kmod results.
208+
"""Averages all kmod results.
210209
211210
Args:
212-
meas_paths (Sequence[Path | str]): Paths to the K-modulation results.
213-
df_model (tfs.TfsDataFrame): DataFrame with the model.
214-
beam (int): Beam for which to average.
211+
meas_paths (Sequence[Path | str]): Paths to the K-modulation results.
212+
df_model (tfs.TfsDataFrame): DataFrame with the model.
213+
beam (int): Beam for which to average.
215214
output_dir (Path | str, optional): Path to the output directory. Defaults to None.
216215
show_plots (bool, optional): If True, show the plots. Defaults to False.
217216
218217
Returns:
219-
dict[int, tfs.TfsDataFrame]: Averaged kmod results, sorted by IP.
218+
dict[int, tfs.TfsDataFrame]: Averaged kmod results, sorted by IP.
220219
"""
221220
sorted_paths = _sort_paths_by_ip(meas_paths, beam)
222221

@@ -230,16 +229,18 @@ def average_all_results(
230229
meas_paths=paths,
231230
output_dir=output_dir,
232231
plot=True,
233-
show_plots=show_plots
232+
show_plots=show_plots,
234233
)
235234
averaged_results[ip] = average
236235

237236
return averaged_results
238237

239238

240-
def _sort_paths_by_ip(paths: Sequence[str | Path], beam: int) -> dict[str, list[str | Path]]:
241-
""" Sorts the kmod results files by IP.
242-
239+
def _sort_paths_by_ip(
240+
paths: Sequence[str | Path], beam: int
241+
) -> dict[str, list[str | Path]]:
242+
"""Sorts the kmod results files by IP.
243+
243244
Identification of the IP is done by reading the `lsa_results.tfs` files.
244245
"""
245246
sorted_paths = defaultdict(list)
@@ -255,33 +256,39 @@ def _sort_paths_by_ip(paths: Sequence[str | Path], beam: int) -> dict[str, list[
255256

256257
# Lumi Imbalance ---
257258

259+
258260
def calculate_all_lumi_imbalances(
259-
averaged_results: dict[str, dict[int, tfs.TfsDataFrame]],
261+
averaged_results: dict[str, dict[int, tfs.TfsDataFrame]],
260262
df_model: tfs.TfsDataFrame,
261-
output_dir: Path | str = None
263+
output_dir: Path | str = None,
262264
) -> None:
263-
""" Calculates the luminosity imbalance between two IPs.
264-
265+
"""Calculates the luminosity imbalance between two IPs.
266+
265267
Args:
266-
averaged_results (dict[str, dict[int, tfs.TfsDataFrame]]): Averaged kmod results, sorted by IP.
267-
df_model (tfs.TfsDataFrame): DataFrame with the model.
268+
averaged_results (dict[str, dict[int, tfs.TfsDataFrame]]): Averaged kmod results, sorted by IP.
269+
df_model (tfs.TfsDataFrame): DataFrame with the model.
268270
output_dir (Path | str, optional): Path to the output directory. Defaults to None.
269271
270272
Returns:
271273
tfs.TfsDataFrame: DataFrame with the luminosity imbalance.
272274
"""
273275
sets_of_ips = list(combinations(averaged_results.keys(), 2))
274-
for (ipA, ipB) in sets_of_ips:
276+
for ipA, ipB in sets_of_ips:
275277
LOG.debug(f"Calculating lumi imbalance between {ipA} and {ipB}")
276-
betastar = _get_betastar(df_model, ipA) # does not really matter which IP, for output name only
278+
betastar = _get_betastar(
279+
df_model, ipA
280+
) # does not really matter which IP, for output name only
277281

278282
# Calculate luminosity imbalance
279283
data = {ip.lower(): averaged_results[ip][0] for ip in (ipA, ipB)}
280284
try:
281285
df = calculate_lumi_imbalance(**data, output_dir=output_dir, betastar=betastar)
282286
except KeyError as e:
283287
# Most likely because not all data available (e.g. only one beam).
284-
LOG.debug(f"Could not calculate lumi imbalance between {ipA} and {ipB}. Skipping.", exc_info=e)
288+
LOG.debug(
289+
f"Could not calculate lumi imbalance between {ipA} and {ipB}. Skipping.",
290+
exc_info=e,
291+
)
285292
continue
286293

287294
# Print luminosity imbalance
@@ -297,4 +304,4 @@ def _get_betastar(df_model: tfs.TfsDataFrame, ip: str) -> list[float, float]:
297304
# Script Mode ------------------------------------------------------------------
298305

299306
if __name__ == "__main__":
300-
import_kmod_data()
307+
import_kmod_results()

omc3/scripts/kmod_import.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ def convert_betastar_results(
254254
kmod_results = kmod_results.drop(columns=[BEAM])
255255
except KeyError:
256256
# already as index
257-
kmod_results = kmod_results.loc[beam, :]
257+
kmod_results = kmod_results.loc[[beam], :]
258258

259259
kmod_results = kmod_results.set_index(NAME, drop=True)
260260

tests/unit/test_kmod_importer.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
from pathlib import Path
12
import pytest
23
import tfs
34

45
from omc3.kmod_importer import AVERAGE_DIR, import_kmod_results
56
from omc3.optics_measurements.constants import EXT
6-
from tests.conftest import assert_tfsdataframe_equal
7+
from tests.conftest import assert_tfsdataframe_equal, ids_str
78
from tests.unit.test_kmod_averaging import (
89
get_all_tfs_filenames as _get_averaged_filenames,
910
)
@@ -26,13 +27,15 @@
2627
# Tests ---
2728

2829
@pytest.mark.basic
29-
@pytest.mark.parametrize('beam', [1, 2])
30-
def test_full_kmod_import_beam(tmp_path, beam):
31-
beta=get_betastar_model(beam=beam, ip=1)[0]
30+
@pytest.mark.parametrize('beam', [1, 2], ids=ids_str("b{}"))
31+
@pytest.mark.parametrize('ips', ["1", "15"], ids=ids_str("ip{}"))
32+
def test_full_kmod_import(tmp_path: Path, beam: int, ips: str):
33+
ips = [int(ip) for ip in ips]
34+
beta=get_betastar_model(beam=beam, ip=ips[0])[0]
3235

3336
# Run the import ---
3437
import_kmod_results(
35-
meas_paths=[get_measurement_dir(ip=ip, i_meas=i) for ip in (1, 5) for i in range(1, 3)],
38+
meas_paths=[get_measurement_dir(ip=ip, i_meas=i) for ip in ips for i in range(1, 3)],
3639
beam=beam,
3740
model=get_model_path(beam),
3841
output_dir=tmp_path,
@@ -44,26 +47,27 @@ def test_full_kmod_import_beam(tmp_path, beam):
4447
average_dir = tmp_path / AVERAGE_DIR
4548

4649
assert average_dir.is_dir()
47-
assert len(list(average_dir.glob("*.pdf"))) == 6 # beta, beat and waist per IP
48-
assert len(list(average_dir.glob(f"*{EXT}"))) == 7 # AV_BPM: 2*BEAM + 2*IP, AV_BETASTAR: 2*IP, Effective: 1
50+
assert len(list(average_dir.glob("*.pdf"))) == 3 * len(ips) # beta, beat and waist per IP
51+
assert len(list(average_dir.glob(f"*{EXT}"))) == 3 * len(ips) + (len(ips) == 2) # AV_BPM: N_BEAM*N_IP, AV_BETASTAR: N_IPs, Effective: 1 (only when both)
4952

5053
# Check the content ---
5154
# averages --
52-
for ip in (1, 5):
55+
for ip in ips:
5356
for out_name in _get_averaged_filenames(ip, beta=beta):
5457
out_file = tfs.read(average_dir / out_name)
5558
ref_file = tfs.read(get_reference_dir(ip, n_files=2) / out_name)
5659
assert_tfsdataframe_equal(out_file, ref_file, check_like=True)
5760

58-
# lumi --
59-
eff_betas = tfs.read(average_dir / _get_lumi_filename(beta))
60-
eff_betas_ref = tfs.read(REFERENCE_DIR / _get_lumi_filename(beta))
61-
assert_tfsdataframe_equal(eff_betas_ref, eff_betas, check_like=True)
62-
63-
# import --
64-
for plane in "xy":
65-
for ref_path in (_get_bpm_reference_path(beam, plane), _get_betastar_reference_path(beam, plane)):
66-
ref_file = tfs.read(ref_path)
67-
out_file = tfs.read(tmp_path / ref_path.name)
68-
assert_tfsdataframe_equal(ref_file, out_file, check_like=True)
61+
62+
if len(ips) > 1:
63+
# lumi --
64+
eff_betas = tfs.read(average_dir / _get_lumi_filename(beta))
65+
eff_betas_ref = tfs.read(REFERENCE_DIR / _get_lumi_filename(beta))
66+
assert_tfsdataframe_equal(eff_betas_ref, eff_betas, check_like=True)
6967

68+
# import (reference created with IP1 and IP5) --
69+
for plane in "xy":
70+
for ref_path in (_get_bpm_reference_path(beam, plane), _get_betastar_reference_path(beam, plane)):
71+
ref_file = tfs.read(ref_path)
72+
out_file = tfs.read(tmp_path / ref_path.name)
73+
assert_tfsdataframe_equal(ref_file, out_file, check_like=True)

0 commit comments

Comments
 (0)