Skip to content

Commit 2c1fe04

Browse files
JoschDfsoubelet
andauthored
Initial Feature Commit (#12)
* Added Coupling and RDTs with Feeddown. * Closest Tune Approach and references * Added tests * Doc Co-authored-by: Felix Soubelet <[email protected]>
1 parent a4e8ea8 commit 2c1fe04

33 files changed

+41328
-8
lines changed

.github/workflows/coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ jobs:
7474
./cc-test-reporter before-build
7575
7676
- name: Run all tests
77-
run: python -m pytest --cov-report xml --cov=tfs
77+
run: python -m pytest --cov-report xml --cov=optics_functions
7878

7979
- name: Push Coverage to CodeClimate
8080
if: ${{ success() }} # only if tests were successful

.zenodo.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"creators": [
3+
{
4+
"name": "OMC-Team",
5+
"affiliation": "CERN"
6+
},
7+
{
8+
"name": "Joschua Dilly",
9+
"affiliation": "CERN",
10+
"orcid": "0000-0001-7864-5448"
11+
},
12+
{
13+
"name": "Rogelio Tomas Garcia",
14+
"affiliation": "CERN",
15+
"orcid": "0000-0002-9857-1703"
16+
},
17+
{
18+
"name": "Tobias Persson",
19+
"affiliation": "CERN"
20+
}
21+
],
22+
"title": "optics_functions",
23+
"description": "Calculate various beam optics functions from TFS-Dataframes."
24+
}

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# optics_functions Changelog
2+
3+
## Version 0.1.0
4+
5+
- Added:
6+
- Coupling calculations
7+
- RDT calculations
8+
- Utilities
9+
- Tests for coupling, rdt and utils
10+
- Documentation
11+
- Workflows

README.md

Lines changed: 215 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,232 @@ This package provides functions to calculate various optics parameters from **MA
1111
## Getting Started
1212

1313
The package depends heavily on another one of our packages, `tfs-pandas`.
14-
Installation is easily done via `pip`. The package is then used as `optics_functions`.
14+
Installation is easily done via `pip`.
15+
The package is then used as `optics_functions`.
1516

1617
```
1718
pip install optics_functions
1819
```
1920

20-
Example:
21+
## Documentation
22+
23+
- Autogenerated docs via `Sphinx` can be found at <https://pylhc.github.io/optics_functions/>.
24+
- General documentation of the OMC-Team is located at <https://pylhc.github.io/>
25+
26+
## Description
27+
28+
This package serves as a library of functions to calculate various optics parameters such as RDTs and coupling from a MAD-X twiss output.
29+
The functionality mainly manipulates and returns TFS files or `TfsDataFrame` objects from the `tfs-pandas` package.
30+
31+
### Modules
32+
33+
- `coupling` - Functions to estimate coupling from twiss dataframes and
34+
different methods to calculate the closest tune approach from
35+
the calculated coupling RDTs.
36+
([**coupling.py**](optics_functions/coupling.py), [**doc**](https://pylhc.github.io/optics_functions/modules/coupling.html))
37+
- `rdt` - Functions for the calculations of Resonance Driving Terms, as well as
38+
getting lists of valid driving term indices for certain orders.
39+
([**rdt.py**](optics_functions/rdt.py), [**doc**](https://pylhc.github.io/optics_functions/modules/rdt.html))
40+
- `utils` - Helper functions to prepare the twiss dataframes for use with the optics
41+
functions as well as reusable utilities,
42+
that are needed within multiple optics calculations.
43+
([**utils.py**](optics_functions/utils.py), [**doc**](https://pylhc.github.io/optics_functions/modules/utils.html))
44+
45+
### Usage Examples
46+
47+
> :warning: In certain scenarios, e.g. in case of non-zero closed orbit, the RDT
48+
> calculations can be unreliable for **thick** lattices.
49+
> Convert to a _thin_ lattice by slicing the lattice reduce the error of the
50+
> analytical approximation.
51+
52+
53+
#### Coupling Example:
2154

2255
```python
23-
import optics_functions
56+
import logging
57+
import sys
58+
59+
import tfs # tfs-pandas
60+
61+
from optics_functions.coupling import coupling_via_cmatrix, closest_tune_approach
62+
from optics_functions.utils import split_complex_columns
2463

25-
# TODO: Include example once functionality is implemented
64+
logging.basicConfig(stream=sys.stdout, level=logging.INFO, format="%(message)s")
65+
66+
# read MAD-X twiss output
67+
df_twiss = tfs.read("twiss.tfs", index="NAME")
68+
69+
# calculate coupling from the cmatrix
70+
df_coupling = coupling_via_cmatrix(df_twiss)
71+
72+
# Example:
73+
# print(df_coupling)
74+
#
75+
# F1001 F1010 ... C22 GAMMA
76+
# NAME ...
77+
# IP3 -0.000000+0.000004j -0.004026+0.003574j ... -0.007140 1.000058
78+
# MCBWV.4R3.B1 0.000001+0.000004j -0.002429+0.004805j ... -0.009601 1.000058
79+
# BPMW.4R3.B1 0.000001+0.000004j -0.002351+0.004843j ... -0.009678 1.000058
80+
# MQWA.A4R3.B1 0.000001+0.000004j -0.001852+0.005055j ... -0.010102 1.000058
81+
# MQWA.B4R3.B1 0.000001+0.000004j -0.001231+0.005241j ... -0.010474 1.000058
82+
# ... ... ... ... ... ...
83+
# MQWB.4L3.B1 -0.000000+0.000004j -0.005059+0.001842j ... -0.003675 1.000058
84+
# MQWA.B4L3.B1 -0.000000+0.000004j -0.004958+0.002098j ... -0.004187 1.000058
85+
# MQWA.A4L3.B1 -0.000000+0.000004j -0.004850+0.002337j ... -0.004666 1.000058
86+
# BPMW.4L3.B1 -0.000000+0.000004j -0.004831+0.002376j ... -0.004743 1.000058
87+
# MCBWH.4L3.B1 -0.000000+0.000004j -0.004691+0.002641j ... -0.005274 1.000058
88+
89+
90+
# calculate the closest tune approach from the complex rdts
91+
df_dqmin = closest_tune_approach(df_coupling,
92+
qx=df_twiss.Q1, qy=df_twiss.Q2,
93+
method='calaga'
94+
)
95+
96+
# Example:
97+
# print(df_dqmin)
98+
#
99+
# DELTAQMIN
100+
# NAME
101+
# IP3 1.760865e-07
102+
# MCBWV.4R3.B1 1.760865e-07
103+
# BPMW.4R3.B1 1.760866e-07
104+
# MQWA.A4R3.B1 1.760865e-07
105+
# MQWA.B4R3.B1 1.760865e-07
106+
# ... ...
107+
# MQWB.4L3.B1 1.760865e-07
108+
# MQWA.B4L3.B1 1.760865e-07
109+
# MQWA.A4L3.B1 1.760866e-07
110+
# BPMW.4L3.B1 1.760865e-07
111+
# MCBWH.4L3.B1 1.760865e-0
112+
113+
# do something with the data.
114+
# (...)
115+
116+
# write out
117+
# as the writer can only handle real data,
118+
# you need to split the rdts into real and imaginary parts before writing
119+
tfs.write("coupling.tfs",
120+
split_complex_columns(df_coupling, columns=["F1001", "F1010"]),
121+
save_index="NAME"
122+
)
26123
```
27124

28-
## Description
125+
#### RDT Example:
29126

30-
This package serves as a library of functions to calculate various optics parameters such as RDTs from a MAD-X twiss output.
31-
The functionality mainly manipulates and returns TFS files or `TfsDataFrame` objects from the `tfs-pandas` package.
127+
```python
128+
import logging
129+
import sys
130+
131+
import tfs # tfs-pandas
132+
133+
from optics_functions.rdt import calculate_rdts, generator, jklm2str
134+
from optics_functions.utils import prepare_twiss_dataframe, split_complex_columns
135+
136+
logging.basicConfig(stream=sys.stdout, level=logging.INFO, format="%(message)s")
137+
138+
# read MAD-X twiss output
139+
df_twiss = tfs.read("twiss.tfs", index="NAME")
140+
141+
# generate all valid RDT names, here for RDTs of order 2
142+
rdts = [jklm2str(*jklm) for jklm in generator(orders=[2])[2]]
143+
144+
# check correct signs (i.e if beam==4), merge twiss and errors,
145+
# add empty K(S)L columns if needed
146+
df_twiss = prepare_twiss_dataframe(df_twiss=df_twiss, df_errors=None, max_order=5)
147+
148+
# do the actual rdt calculation
149+
df_rdts = calculate_rdts(df_twiss, rdts=rdts,
150+
loop_phases=True, # loop over phase-advance calculation, slower but saves memory
151+
feeddown=2, # include feed-down up to this order
152+
complex_columns=True, # complex output
153+
)
154+
155+
# Example:
156+
# print(df_rdts)
157+
# F0002 ... F2000
158+
# NAME ...
159+
# IP3 2.673376-1.045712j ... -2.863617-0.789910j
160+
# MCBWV.4R3.B1 2.475684-1.453081j ... -1.927365-2.260426j
161+
# BPMW.4R3.B1 2.470411-1.462027j ... -1.862287-2.314336j
162+
# MQWA.A4R3.B1 2.440763-1.511004j ... -1.413706-2.612603j
163+
# MQWA.B4R3.B1 2.228282-1.555324j ... -0.788608-2.855177j
164+
# ... ... ... ...
165+
# MQWB.4L3.B1 2.733194+0.167312j ... -2.632290+0.135418j
166+
# MQWA.B4L3.B1 2.763986-0.041253j ... -2.713212+0.063256j
167+
# MQWA.A4L3.B1 2.804960-0.235493j ... -2.847616-0.017922j
168+
# BPMW.4L3.B1 2.858218-0.266543j ... -2.970384-0.032890j
169+
# MCBWH.4L3.B1 2.831426-0.472735j ... -2.966818-0.149180j
170+
171+
# do something with the rdts.
172+
# (...)
173+
174+
# write out
175+
# as the writer can only handle real data, either set real = True above
176+
# or split the rdts into real and imaginary parts before writing
177+
tfs.write("rdts.tfs",
178+
split_complex_columns(df_rdts, columns=rdts),
179+
save_index="NAME"
180+
)
181+
```
182+
183+
#### Appending Example:
184+
185+
```python
186+
import logging
187+
import sys
188+
189+
import tfs # tfs-pandas
190+
191+
from optics_functions.coupling import coupling_via_cmatrix, closest_tune_approach
192+
from optics_functions.utils import split_complex_columns
193+
194+
logging.basicConfig(stream=sys.stdout, level=logging.INFO, format="%(message)s")
195+
196+
# read MAD-X twiss output
197+
df_twiss = tfs.read("twiss.tfs", index="NAME")
198+
199+
# calculate coupling from the cmatrix and append to original dataframe
200+
# output=['rdts'] is used to avoid the output of the gamma and C## columns.
201+
df_twiss[["F1001", "F1010"]] = coupling_via_cmatrix(df_twiss, output=['rdts'])
202+
203+
# Example:
204+
# print(df_twiss)
205+
#
206+
# Headers:
207+
# NAME: TWISS
208+
# TYPE: TWISS
209+
# SEQUENCE: LHCB1
210+
# ...
211+
# ORIGIN: 5.05.02 Linux 64
212+
# DATE: 01/02/21
213+
# TIME: 19.58.08
214+
#
215+
# KEYWORD S ... F1001 F1010
216+
# NAME ...
217+
# IP3 MARKER 0.0000 ... -0.000000+0.000004j -0.004026+0.003574j
218+
# MCBWV.4R3.B1 VKICKER 21.8800 ... 0.000001+0.000004j -0.002429+0.004805j
219+
# BPMW.4R3.B1 MONITOR 22.5205 ... 0.000001+0.000004j -0.002351+0.004843j
220+
# MQWA.A4R3.B1 QUADRUPOLE 26.1890 ... 0.000001+0.000004j -0.001852+0.005055j
221+
# MQWA.B4R3.B1 QUADRUPOLE 29.9890 ... 0.000001+0.000004j -0.001231+0.005241j
222+
# ... ... ... ... ... ...
223+
# MQWB.4L3.B1 QUADRUPOLE 26628.2022 ... -0.000000+0.000004j -0.005059+0.001842j
224+
# MQWA.B4L3.B1 QUADRUPOLE 26632.0022 ... -0.000000+0.000004j -0.004958+0.002098j
225+
# MQWA.A4L3.B1 QUADRUPOLE 26635.8022 ... -0.000000+0.000004j -0.004850+0.002337j
226+
# BPMW.4L3.B1 MONITOR 26636.4387 ... -0.000000+0.000004j -0.004831+0.002376j
227+
# MCBWH.4L3.B1 HKICKER 26641.0332 ... -0.000000+0.000004j -0.004691+0.002641j
228+
```
229+
230+
231+
## Quality checks
232+
233+
- Unit and accuracy tests are run automatically through CI [Github Actions](https://github.com/pylhc/optics_functions/actions). See our workflows in this [readme](.github/workflows/README.md).
234+
- Additional checks for code-complexity, design-rules, test-coverage and duplication are made through [CodeClimate](https://codeclimate.com/github/pylhc/optics_functions).
235+
- Pull requests implementing functionality or fixes are merged into the master branch after passing CI, and getting a reviewer's approval.
236+
237+
### Changelog
238+
239+
See the [CHANGELOG](CHANGELOG.md) file.
32240

33241
## Authors
34242

0 commit comments

Comments
 (0)