-
Notifications
You must be signed in to change notification settings - Fork 0
/
rr_setup.py
382 lines (284 loc) · 13.4 KB
/
rr_setup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
#!/usr/bin/env python
import os
import re
import sys
# import mpi4py.MPI as MPI
import numpy as np
import synergia
import synergia.simulation as SIM
import rr_sextupoles
import rrnova_qt60x
#from rr_options import opts
#####################################
# quick and dirty twiss parameter calculator from 2x2 courant-snyder map array
def map2twiss(csmap):
cosmu = 0.5 * (csmap[0, 0] + csmap[1, 1])
asinmu = 0.5 * (csmap[0, 0] - csmap[1, 1])
if abs(cosmu) > 1.0:
raise RuntimeError("map is unstable")
mu = np.arccos(cosmu)
# beta is positive
if csmap[0, 1] < 0.0:
mu = 2.0 * np.pi - mu
beta = csmap[0, 1] / np.sin(mu)
alpha = asinmu / np.sin(mu)
tune = mu / (2.0 * np.pi)
return (alpha, beta, tune)
def convert_rbends_to_sbends(orig_lattice):
lattice = synergia.lattice.Lattice("rrnova")
for elem in orig_lattice.get_elements():
if elem.get_type_name() == "rbend":
new_elem = synergia.lattice.Lattice_element("sbend", elem.get_name())
new_elem.copy_attributes_from(elem)
ang = elem.get_double_attribute("angle")
length = elem.get_double_attribute("l")
arclength = ang * length / (2.0 * np.sin(ang / 2.0))
new_elem.set_double_attribute("l", arclength)
new_elem.set_double_attribute("e1", ang / 2.0)
new_elem.set_double_attribute("e2", ang / 2.0)
lattice.append(new_elem)
else:
lattice.append(elem)
lattice.set_reference_particle(orig_lattice.get_reference_particle())
return lattice
def keep_qt(lattice):
valid_trim_name_regex = "qt60([1-9])[a-d]"
trimobj = re.compile(valid_trim_name_regex)
for elem in lattice.get_elements():
if elem.get_type_name() == "quadrupole":
qname = elem.get_name()
mo = trimobj.match(elem.get_name())
if mo:
elem.set_string_attribute("no_simplify", "save me!")
return lattice
# Reorder the lattice if needed
def reorder_lattice(lattice, start_element=None):
if start_element:
new_lattice = synergia.lattice.Lattice("mi", lattice.get_element_adaptor_sptr())
elements = lattice.get_elements()
names = [e.get_name() for i in elements]
if opts.start_element not in names:
raise RuntimeError("start element "+opts.start_element+" not in lattice")
start_i = names.index(start_element)
reorder_alements = elements[start_i:] + elements[0:start_i]
for elem in reorder_elements:
new_lattice.append(elem)
new_lattice.set_design_reference_particle(lattice.get_design_reference_particle())
new_lattice.set_reference_particle(lattice.get_reference_particle())
return new_lattice
else:
return lattice
#----------------------------------------------------------------------------------
# lattice is input lattice
# rf_voltage is total RF voltage to distribute over all the cavities
# harmno is the harmonic number
# modifies elements in lattice in-place
def setup_rf_cavities(lattice, rf_voltage, harmno):
# rf cavity voltage, is 1.0 MV total distributed over 18 cavities. MAD8
# expects cavities voltages in units of MV. First count how many cavities
# there are
num_cavities = 0
for elem in lattice.get_elements():
if elem.get_type() == synergia.lattice.element_type.rfcavity:
num_cavities = num_cavities + 1
if num_cavities < 1:
raise RuntimeError("error: set_rf_cavities: no RF cavities found")
# Now set the voltage and harmonic number. Frequency will be set
# later when the lattice is "tuned".
for elem in lattice.get_elements():
# set the harmonic number so the frequency is set
elem.set_double_attribute("harmon", harmno)
elem.set_double_attribute("volt", rf_voltage/num_cavities)
return
#----------------------------------------------------------------------------------
def setup():
raise RuntimeError("Do not call setup anymore, call individual setup routines!")
try:
logger = synergia.utils.parallel_utils.Logger(0, synergia.utils.parallel_utils.LoggerV.DEBUG)
# logger = synergia.utils.Logger(0)
# tjob_0 = MPI.Wtime()
# memlogger = synergia.utils.Logger("memlog")
# ============================================
# get parameters for run
rf_voltage = opts.rf_voltage
print("==== Run Summary ====", file=logger)
print("RF Voltage: ", rf_voltage, file=logger)
if opts.xtune_adjust:
print("x tune adjustment: ", opts.xtune_adjust, file=logger)
else:
print("x tune adjustment: NONE", file=logger)
if opts.ytune_adjust:
print("y tune adjustment: ", opts.ytune_adjust, file=logger)
else:
print("y tune adjustment: NONE", file=logger)
if opts.xchrom_adjust:
print("x chromaticity adjustment: ", opts.xchrom_adjust, file=logger)
else:
print("x chromaticity adjustment: NONE", file=logger)
if opts.ychrom_adjust:
print("y chromaticity adjustment: ", opts.ychrom_adjust, file=logger)
else:
print("y chromaticity adjustment: NONE", file=logger)
# ============================================
# read the lattice and
# turn on the RF by setting voltage, frequency and phase in RF cavities
lattice_file = "RR2020V0922FLAT_fixed"
ring_name = "ring605_fodo"
lattice = synergia.lattice.Mad8_reader().get_lattice(ring_name, lattice_file)
"""
lsexpr = synergia.utils.pylsexpr.read_lsexpr_file("mi20_raw.lsx")
lattice = synergia.lattice.Lattice(lsexpr)
"""
lattice = convert_rbends_to_sbends(lattice)
print("lattice # elements: ", len(lattice.get_elements()))
print("lattice length: ", lattice.get_length())
harmno = 588
if opts.start_element:
print("reordering lattice to start at ", opts.start_element, file=logger)
new_lattice = synergia.lattice.Lattice("mi", lattice.get_element_adaptor_sptr())
copying = False
start_i = -1
elements = lattice.get_elements()
for i in range(len(elements)):
if elements[i].get_name() == opts.start_element:
start_i = i
break
reorder_elements = elements[start_i:] + elements[:start_i]
for elem in reorder_elements:
new_lattice.append(elem)
new_lattice.set_reference_particle(lattice.get_reference_particle())
print("new lattice length: ", new_lattice.get_length(), file=logger)
lattice = new_lattice
if opts.lattice_simplify:
lattice = keep_qt(lattice)
lattice = synergia.lattice.simplify_all(lattice)
print("lattice # elements after simplification: ", len(lattice.get_elements()))
print("lattice length after simplification: ", lattice.get_length())
# ============================================
lattice.set_all_string_attribute("extractor_type", "libff")
# turn on the RF cavities
reference_particle = lattice.get_reference_particle()
energy = reference_particle.get_total_energy()
beta = reference_particle.get_beta()
gamma = reference_particle.get_gamma()
print("energy: ", energy, file=logger)
print("beta: ", beta, file=logger)
print("gamma: ", gamma, file=logger)
# set rf cavity frequency
# harmno * beta * c/ring_length
freq = harmno * beta * synergia.foundation.pconstants.c / lattice.get_length()
# only for informational purposes
print("RF frequency: ", freq, file=logger)
print("Begin setting RF voltage...", file=logger)
# rf cavity voltage, is 1.0 MV total distributed over 18 cavities. MAD8
# expects cavities voltages in units of MV.
num_cavities = 0
for elem in lattice.get_elements():
if elem.get_type() == synergia.lattice.element_type.rfcavity:
# set the harmonic number so the frequency is set
elem.set_double_attribute("harmon", harmno)
# set the first pass frequency so I can get the bucket length
elem.set_double_attribute("freq", freq * 1.0e-6)
if num_cavities < 1:
elem.set_double_attribute("volt", rf_voltage)
num_cavities += 1
else:
elem.set_double_attribute("volt", 0.0)
print("Finish setting RF voltage...", file=logger)
# ============================================
# adjust the tune and chromaticity of requested
SIM.Lattice_simulator.set_closed_orbit_tolerance(1.0e-6)
SIM.Lattice_simulator.tune_circular_lattice(lattice)
tunes = SIM.Lattice_simulator.calculate_tune_and_cdt(lattice)
xtune = tunes[0]
ytune = tunes[1]
chroms = SIM.Lattice_simulator.get_chromaticities(lattice)
xchrom = chroms.horizontal_chromaticity
ychrom = chroms.vertical_chromaticity
# adjust the tunes
print("Unadjusted x tune: ", xtune, file=logger)
print("Unadjusted y tune: ", ytune, file=logger)
if opts.xtune_adjust or opts.ytune_adjust:
if opts.xtune_adjust:
delta_xtune = opts.xtune_adjust - xtune
else:
delta_xtune = 0.0
if opts.ytune_adjust:
delta_ytune = opts.ytune_adjust - ytune
else:
delta_ytune = 0.0
print("Adjusting tunes to:", file=logger)
print("xtune: ", opts.xtune_adjust, file=logger)
print("ytune: ", opts.ytune_adjust, file=logger)
rrnova_qt60x.adjust_rr60_trim_quads(lattice, delta_xtune, delta_ytune)
tunes = SIM.Lattice_simulator.calculate_tune_and_cdt(lattice)
xtune = tunes[0]
ytune = tunes[1]
print("adjusted xtune: ", xtune, file=logger)
print("adjusted ytune: ", ytune, file=logger)
print("Unadjusted x chromaticity: ", xchrom, file=logger)
print("Unadjusted y chromaticity: ", ychrom, file=logger)
if opts.xchrom_adjust or opts.ychrom_adjust:
if opts.xchrom_adjust:
xchrom = opts.xchrom_adjust
if opts.ychrom_adjust:
ychrom = opts.ychrom_adjust
print("Adjusting chromaticities to:", file=logger)
print("x chrom: ", xchrom, file=logger)
print("y chrom: ", ychrom, file=logger)
f_sext, d_sext = rr_sextupoles.get_fd_sextupoles(lattice)
print("There are ", len(f_sext), " focussing sextupoles", file=logger)
print("There are ", len(d_sext), " defocussing sextupoles", file=logger)
SIM.Lattice_simulator.adjust_chromaticities(lattice, xchrom, ychrom, 1.0e-6, 20)
chroms = SIM.Lattice_simulator.get_chromaticities(lattice)
xchrom = chroms.horizontal_chromaticity
ychrom = chroms.vertical_chromaticity
print("adjusted x chrom: ", xchrom, file=logger)
print("adjusted y chrom: ", ychrom, file=logger)
# The lattice is tuned now, write it out
# synergia.utils.write_lsexpr_file(lattice.as_lsexpr(), "mi20_ra_08182020_tuned.lsx")
# Get the covariance matrix
map = SIM.Lattice_simulator.get_linear_one_turn_map(lattice)
print("one turn map from synergia2.5 infrastructure", file=logger)
print(np.array2string(map, max_line_width=200), file=logger)
[l, v] = np.linalg.eig(map)
# print "l: ", l
# print "v: ", v
print("eigenvalues: ", file=logger)
for z in l:
print("|z|: ", abs(z), " z: ", z, " tune: ", np.log(z).imag / (2.0 * np.pi), file=logger)
[ax, bx, qx] = map2twiss(map[0:2, 0:2])
[ay, by, qy] = map2twiss(map[2:4, 2:4])
[az, bz, qz] = map2twiss(map[4:6, 4:6])
stdz = opts.stdz
dpop = stdz / bz
print("Lattice parameters (assuming uncoupled map)", file=logger)
print("alpha_x: ", ax, " alpha_y: ", ay, file=logger)
print("beta_x: ", bx, " beta_y: ", by, file=logger)
print("q_x: ", qx, " q_y: ", qy, file=logger)
print("beta_z: ", bz, file=logger)
print("delta p/p: ", dpop, file=logger)
emitx = opts.norm_emit / (beta * gamma)
emity = opts.norm_emit / (beta * gamma)
stdx = np.sqrt(emitx * bx)
stdy = np.sqrt(emity * by)
print("emitx: ", emitx, file=logger)
print("emity: ", emity, file=logger)
print("target stdx: ", stdx, file=logger)
print("target stdy: ", stdy, file=logger)
# =========================================
#
# get the correlation matrix for bunch generation
correlation_matrix = synergia.bunch.get_correlation_matrix(map, stdx, stdy, stdz / beta, beta, (0, 2, 4))
np.save("correlation_matrix.npy", correlation_matrix)
print(np.array2string(correlation_matrix, max_line_width=200), file=logger)
# write the lattice in json
lattice_file = open("rr_tuned.json", "w")
lattice_file.write(lattice.as_json())
lattice_file.close()
except Exception as e:
sys.stdout.write(str(e) + "\n")
# MPI.COMM_WORLD.Abort(777)
if __name__ == "__main__":
setup()
# main()