Skip to content

Commit e460a9a

Browse files
authored
SbS Propagable Refactor (#490)
* save sbs_propagation ini * separated classes
1 parent abce678 commit e460a9a

File tree

14 files changed

+712
-586
lines changed

14 files changed

+712
-586
lines changed

omc3/definitions/formats.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
def get_config_filename(script):
1616
"""Default Filename for config-files. Call from script with ``__file__``."""
1717
return CONFIG_FILENAME.format(
18-
script=Path(script).name.split('.')[0],
18+
script=Path(script).stem,
1919
time=datetime.now(timezone.utc).strftime(TIME)
2020
)
2121

omc3/sbs_propagation.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
from omc3 import model_creator
5656
from omc3.definitions.optics import OpticsMeasurement
5757
from omc3.model import manager as model_manager
58-
from omc3.model.model_creators.manager import get_model_creator_class, CreatorType
5958
from omc3.model.accelerators.accelerator import AcceleratorDefinitionError
6059
from omc3.model.constants import (
6160
ACC_MODELS_PREFIX,
@@ -64,6 +63,7 @@
6463
TWISS_DAT,
6564
TWISS_ELEMENTS_DAT,
6665
)
66+
from omc3.model.model_creators.manager import CreatorType, get_model_creator_class
6767
from omc3.segment_by_segment.constants import logfile
6868
from omc3.segment_by_segment.propagables import Propagable, get_all_propagables
6969
from omc3.segment_by_segment.segments import (
@@ -73,7 +73,7 @@
7373
SegmentModels,
7474
)
7575
from omc3.utils import logging_tools
76-
from omc3.utils.iotools import PathOrStr, PathOrStrOrDict
76+
from omc3.utils.iotools import PathOrStr, PathOrStrOrDict, save_config
7777

7878
if TYPE_CHECKING:
7979
from collections.abc import Callable, Sequence
@@ -86,7 +86,6 @@
8686
ModelCreator,
8787
)
8888

89-
9089
LOGGER = logging_tools.get_logger(__name__)
9190

9291

@@ -139,6 +138,7 @@ def segment_by_segment(opt: DotDict, accel_opt: dict | list) -> dict[str, Segmen
139138

140139
accel: Accelerator = model_manager.get_accelerator(accel_opt)
141140
accel.model_dir = _check_output_directory(opt.output_dir, accel)
141+
save_config(accel.model_dir, opt, __file__, accel_opt)
142142
_maybe_create_nominal_model(accel, fetcher_opts)
143143

144144
measurement = OpticsMeasurement(opt.measurement_dir)
@@ -433,6 +433,8 @@ def _copy_files_from_model_dir(model_dir: Path, output_dir: Path) -> None:
433433
def _bpm_is_in_meas(bpm_name: str, meas: OpticsMeasurement) -> bool:
434434
""" Check if the bpm_name is in the measurement in both planes.
435435
Possible improvement: Check if the error is too high?
436+
437+
TODO: This does not work with single-plane BPM machines, such as SPS. What to do?
436438
"""
437439
return bpm_name in meas.beta_phase_x.index and bpm_name in meas.beta_phase_y.index
438440

omc3/segment_by_segment/constants.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
2-
Segment by Segment: Constants
3-
-----------------------------
2+
Constants
3+
---------
44
55
This module provides constants to be used with segment by segment
66
"""

omc3/segment_by_segment/definitions.py

Lines changed: 2 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
2-
Segment by Segment: Definitions
3-
-------------------------------
2+
Definitions
3+
-----------
44
55
This module provides definitions to be used with segment by segment
66
"""
@@ -11,83 +11,6 @@
1111
from uncertainties.core import Variable
1212
from omc3.utils.math_classes import MathMixin
1313

14-
from omc3.optics_measurements.constants import ERR
15-
from omc3.segment_by_segment.constants import BACKWARD, CORRECTION, EXPECTED, FORWARD
16-
17-
18-
class PropagableColumns:
19-
""" Class to define columns for propagables.
20-
One could also implicitly define the error-columns,
21-
either via __getattr__ or as a wrapper, but I decided to
22-
explicitely name these columns, so that the IDEs can see them
23-
and can help in renaming and autocompletion (jdilly 2023).
24-
"""
25-
def __init__(self, column: str, plane: str = "{}") -> None:
26-
self._column = column
27-
self._plane = plane
28-
29-
def planed(self, plane: str) -> PropagableColumns:
30-
return PropagableColumns(self._column, plane)
31-
32-
@property
33-
def column(self):
34-
return f"{self._column}{self._plane}"
35-
36-
@property
37-
def error_column(self):
38-
return f"{ERR}{self.column}"
39-
40-
# Propagation ---
41-
@property
42-
def forward(self):
43-
return f"{FORWARD}{self.column}"
44-
45-
@property
46-
def error_forward(self):
47-
return f"{ERR}{self.forward}"
48-
49-
@property
50-
def backward(self):
51-
return f"{BACKWARD}{self.column}"
52-
53-
@property
54-
def error_backward(self):
55-
return f"{ERR}{self.backward}"
56-
57-
# Correction ---
58-
@property
59-
def forward_correction(self):
60-
return f"{CORRECTION}{self.forward}"
61-
62-
@property
63-
def error_forward_correction(self):
64-
return f"{ERR}{self.forward_correction}"
65-
66-
@property
67-
def backward_correction(self):
68-
return f"{CORRECTION}{self.backward}"
69-
70-
@property
71-
def error_backward_correction(self):
72-
return f"{ERR}{self.backward_correction}"
73-
74-
# Expectation ---
75-
@property
76-
def forward_expected(self):
77-
return f"{EXPECTED}{self.forward}"
78-
79-
@property
80-
def error_forward_expected(self):
81-
return f"{ERR}{self.forward_expected}"
82-
83-
@property
84-
def backward_expected(self):
85-
return f"{EXPECTED}{self.backward}"
86-
87-
@property
88-
def error_backward_expected(self):
89-
return f"{ERR}{self.backward_expected}"
90-
9114

9215
class Measurement(MathMixin, Variable):
9316
""" Alias for a uncertainties variable.
@@ -110,19 +33,6 @@ def __iter__(self):
11033
return iter(self.as_tuple())
11134

11235

113-
114-
@dataclass
115-
class PropagableBoundaryConditions:
116-
"""Store boundary conditions with error for propagating."""
117-
alpha: Measurement = None
118-
beta: Measurement = None
119-
dispersion: Measurement = None
120-
f1001_amplitude: Measurement = None
121-
f1001_phase: Measurement = None
122-
f1010_amplitude: Measurement = None
123-
f1010_phase: Measurement = None
124-
125-
12636
@dataclass
12737
class MadXBoundaryConditions:
12838
"""Store all boundary conditions for a Mad-X twiss."""

omc3/segment_by_segment/math.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
2-
Segment by Segment: Maths functions
3-
-----------------------------------
2+
Maths Functions
3+
---------------
44
55
This module provides mathematical helper functions, e.g. to propagate errors.
66
"""
@@ -11,10 +11,12 @@
1111
import numpy as np
1212

1313
if TYPE_CHECKING:
14-
from omc3.segment_by_segment.definitions import PropagableBoundaryConditions
14+
from omc3.segment_by_segment.propagables import PropagableBoundaryConditions
1515
from numpy.typing import ArrayLike
1616

1717

18+
# Error Propagation ------------------------------------------------------------
19+
1820
def propagate_error_phase(dphi: ArrayLike, init: PropagableBoundaryConditions) -> ArrayLike:
1921
"""Propagates the phase-error.
2022
See Eq. (2) in [LangnerDevelopmentsSegmentbySegmentTechnique2015]_ .
@@ -192,8 +194,20 @@ def propagate_error_dispersion(beta: ArrayLike, dphi: ArrayLike, init: Propagabl
192194
(np.cos(2 * np.pi * dphi) + alpha0 * np.sin(2 * np.pi * dphi))
193195
)
194196

197+
198+
# Other Math -------------------------------------------------------------------
195199

196200
def phase_diff(phase_a: ArrayLike, phase_b: ArrayLike) -> ArrayLike:
197201
""" Returns the phase difference between phase_a and phase_b, mapped to [-0.5, 0.5]. """
198202
phase_diff = (phase_a - phase_b) % 1
199-
return phase_diff - np.where(phase_diff > 0.5, 1, 0) # this way keeps input type as is (!`where` returns np.array)
203+
return phase_diff - np.where(phase_diff > 0.5, 1, 0) # this way keeps input type as is (!`where` returns np.array)
204+
205+
206+
def quadratic_add(*values):
207+
"""Calculate the root-sum-squared of the given values.
208+
The individual "values" can be ``pd.Series`` and then their
209+
elements are summed by indexs."""
210+
result = 0.
211+
for value in values:
212+
result += value ** 2
213+
return np.sqrt(result)

0 commit comments

Comments
 (0)