|
1
|
#!/usr/bin/python3
|
|
2
|
import sys,os
|
|
3
|
import gc
|
|
4
|
import math
|
|
5
|
import time
|
|
6
|
import numpy as np
|
|
7
|
#import pylab as py
|
|
8
|
import matplotlib.pyplot as plt
|
|
9
|
from scipy.odr import *
|
|
10
|
from subprocess import call
|
|
11
|
from subprocess import check_output
|
|
12
|
|
|
13
|
# Nominal beam position - not corrected for offsets
|
|
14
|
# these were for XEM2/CaFe part 1
|
|
15
|
#NOMINAL_POS = {
|
|
16
|
#'3H07A': {'XPOS': -0.09,
|
|
17
|
# 'YPOS': -0.30},
|
|
18
|
#'3H07B': {'XPOS': -0.49,
|
|
19
|
# 'YPOS': -0.41},
|
|
20
|
#'3H07C': {'XPOS': -0.68,
|
|
21
|
# 'YPOS': -0.49},
|
|
22
|
#'target': {'XPOS': -0.38,
|
|
23
|
# 'YPOS': -0.18}
|
|
24
|
#}
|
|
25
|
|
|
26
|
#updated feb. 22,2023 for CaFe part 2, deuteron
|
|
27
|
#NOMINAL_POS = {
|
|
28
|
#'3H07A': {'XPOS': 0.8,
|
|
29
|
# 'YPOS': -0.6},
|
|
30
|
#'3H07B': {'XPOS': 0.27,
|
|
31
|
# 'YPOS': -0.65},
|
|
32
|
#'3H07C': {'XPOS': 0.2,
|
|
33
|
# 'YPOS': -0.8},
|
|
34
|
#'target': {'XPOS': 0.5,
|
|
35
|
# 'YPOS': -0.45}
|
|
36
|
#}
|
|
37
|
|
|
38
|
#updated sept. 15,2023 for NPS
|
|
39
|
#NOMINAL_POS = {
|
|
40
|
#'3H07A': {'XPOS': 1.7,
|
|
41
|
# 'YPOS': 0.3},
|
|
42
|
#'3H07B': {'XPOS': 0.82,
|
|
43
|
# 'YPOS': -0.02},
|
|
44
|
#'3H07C': {'XPOS': 0.7,
|
|
45
|
# 'YPOS': 0.3},
|
|
46
|
#'target': {'XPOS': 1.34,
|
|
47
|
# 'YPOS': 0.04}
|
|
48
|
#}
|
|
49
|
|
|
50
|
#updated Feb. 21, 2024 after 3H07B work on Feb. 20
|
|
51
|
#NOMINAL_POS = {
|
|
52
|
#'3H07A': {'XPOS': 1.7,
|
|
53
|
# 'YPOS': 0.3},
|
|
54
|
#'3H07B': {'XPOS': 0.62,
|
|
55
|
# 'YPOS': 0.35},
|
|
56
|
#'3H07C': {'XPOS': 0.7,
|
|
57
|
# 'YPOS': 0.3},
|
|
58
|
#'target': {'XPOS': 1.27,
|
|
59
|
# 'YPOS': 0.06}
|
|
60
|
#}
|
|
61
|
|
|
62
|
#updated April 3, 2024 after long down - target moved a little
|
|
63
|
#NOMINAL_POS = {
|
|
64
|
#'3H07A': {'XPOS': 1.85,
|
|
65
|
# 'YPOS': 0.3},
|
|
66
|
#'3H07B': {'XPOS': 0.77,
|
|
67
|
# 'YPOS': 0.35},
|
|
68
|
#'3H07C': {'XPOS': 0.75,
|
|
69
|
# 'YPOS': 0.3},
|
|
70
|
#'target': {'XPOS': 1.27,
|
|
71
|
# 'YPOS': 0.06}
|
|
72
|
#}
|
|
73
|
|
|
74
|
#updated April 7, 2025
|
|
75
|
#NOMINAL_POS = {
|
|
76
|
#'3H07A': {'XPOS': 0,
|
|
77
|
# 'YPOS': 0},
|
|
78
|
#'3H07B': {'XPOS': -1.05,
|
|
79
|
# 'YPOS': 0.23},
|
|
80
|
#'3H07C': {'XPOS': -1.0,
|
|
81
|
# 'YPOS': 0.},
|
|
82
|
#'target': {'XPOS': -0.4,
|
|
83
|
# 'YPOS': 0.1}
|
|
84
|
#}
|
|
85
|
|
|
86
|
#updated April 10, 2025 Per JP
|
|
87
|
NOMINAL_POS = {
|
|
88
|
'3H07A': {'XPOS': 0.25,
|
|
89
|
'YPOS': 0.80},
|
|
90
|
'3H07B': {'XPOS': -0.47,
|
|
91
|
'YPOS': 0.82},
|
|
92
|
'3H07C': {'XPOS': -0.7,
|
|
93
|
'YPOS': 0.8},
|
|
94
|
'target': {'XPOS': -0.06,
|
|
95
|
'YPOS': 0.29}
|
|
96
|
}
|
|
97
|
|
|
98
|
NOMINAL_POS_REF = {
|
|
99
|
'3H07A': {'XPOS': 0.0,
|
|
100
|
'YPOS': 0.0},
|
|
101
|
'3H07B': {'XPOS': 0.0,
|
|
102
|
'YPOS': 0.0},
|
|
103
|
'3H07C': {'XPOS': 0.0,
|
|
104
|
'YPOS': 0.0},
|
|
105
|
'target': {'XPOS': 0.0,
|
|
106
|
'YPOS': 0.0}
|
|
107
|
}
|
|
108
|
|
|
109
|
plt.ion()
|
|
110
|
fig=plt.figure()
|
|
111
|
# Aargh - used old, wrong value
|
|
112
|
#AZ=-370.83
|
|
113
|
AZ=-320.42
|
|
114
|
BZ=-224.97
|
|
115
|
CZ=-129.314
|
|
116
|
|
|
117
|
ZVEC=np.array([AZ,BZ,CZ])
|
|
118
|
|
|
119
|
NOMINAL_ZVEC=np.array([AZ,BZ,CZ])
|
|
120
|
NOMINAL_XVEC=np.array([NOMINAL_POS['3H07A']['XPOS'],NOMINAL_POS['3H07B']['XPOS'],NOMINAL_POS['3H07C']['XPOS']])
|
|
121
|
NOMINAL_YVEC=np.array([NOMINAL_POS['3H07A']['YPOS'],NOMINAL_POS['3H07B']['YPOS'],NOMINAL_POS['3H07C']['YPOS']])
|
|
122
|
|
|
123
|
NOMINAL_XVEC_REF=np.array([NOMINAL_POS_REF['3H07A']['XPOS'],NOMINAL_POS_REF['3H07B']['XPOS'],NOMINAL_POS_REF['3H07C']['XPOS']])
|
|
124
|
NOMINAL_YVEC_REF=np.array([NOMINAL_POS_REF['3H07A']['YPOS'],NOMINAL_POS_REF['3H07B']['YPOS'],NOMINAL_POS_REF['3H07C']['YPOS']])
|
|
125
|
|
|
126
|
## Use slopes from BPM calibration
|
|
127
|
|
|
128
|
## Slopes from DEC 2019 - keep same coordinate system as BPMs
|
|
129
|
#XSLOPE=np.array([0.973,1.096,0.956])
|
|
130
|
#YSLOPE=np.array([0.957,1.16,0.855])
|
|
131
|
|
|
132
|
# calibration, Sept.-Oct. 2023
|
|
133
|
XSLOPE=np.array([1.02,1.06,0.86])
|
|
134
|
YSLOPE=np.array([0.99,1.18,0.88])
|
|
135
|
|
|
136
|
|
|
137
|
#########################
|
|
138
|
# Target Lock Positions #
|
|
139
|
#########################
|
|
140
|
## offsets fom survey Summer 2021
|
|
141
|
#XOFF=np.array([0.05,-0.13,-0.16])
|
|
142
|
#YOFF=np.array([0.17,0.52,-0.17])
|
|
143
|
# from first harp scans, 9/5/2021 23:52
|
|
144
|
#XOFF=np.array([0.293,-0.189,-0.354])
|
|
145
|
#YOFF=np.array([-0.063,0.415,0.321])
|
|
146
|
# January 2022
|
|
147
|
#XOFF=np.array([0.07,-0.33,0.51])
|
|
148
|
#YOFF=np.array([-0.13,0.424,0.27])
|
|
149
|
|
|
150
|
#June 9, 2022
|
|
151
|
#Xoff=np.array([0.17,0.87,1.40])
|
|
152
|
#YOFF=np.array([-0.05,0.204,0.17])
|
|
153
|
|
|
154
|
#Harp survey corrected
|
|
155
|
#XOFF=np.array([0.08,0.39,0.54])
|
|
156
|
#YOFF=np.array([-0.05,0.204,0.17])
|
|
157
|
#XOFF=np.array([-0.17,0.21,0.37])
|
|
158
|
#YOFF=np.array([0.09,0.24,0.23])
|
|
159
|
|
|
160
|
# Offsets from harp scans, September 12, 2023
|
|
161
|
#XOFF=np.array([-0.18,0.51,0.73])
|
|
162
|
#YOFF=np.array([-0.13,0.17,-0.13])
|
|
163
|
|
|
164
|
# calibration, sept-oct 2023
|
|
165
|
#XOFF=np.array([-0.17,0.57,0.82])
|
|
166
|
#YOFF=np.array([-0.12,0.21,-0.16])
|
|
167
|
|
|
168
|
# Harp scan, Feb. 2024 - after BPM 3H07B fix
|
|
169
|
#XOFF=np.array([-0.17,0.78,0.82])
|
|
170
|
#YOFF=np.array([-0.12,-0.27,-0.16])
|
|
171
|
|
|
172
|
# Harp scan, April 3 2025 - needed to set BPM XSOFs back to old values
|
|
173
|
XOFF=np.array([-0.195,0.708,0.549])
|
|
174
|
YOFF=np.array([0.131,-0.091,0.089])
|
|
175
|
|
|
176
|
# Harp scan, July 15 2025 - needed to set BPM XSOFs back to old values
|
|
177
|
#XOFF=np.array([-0.066,0.756,0.937])
|
|
178
|
#YOFF=np.array([0.0885,-0.0322,-0.370])
|
|
179
|
|
|
180
|
# Harp scan, April 10 2025 - after IHA3H07B limit switch issue addressed
|
|
181
|
#XOFF=np.array([-0.196,1.12,1.45])
|
|
182
|
#YOFF=np.array([0.304,-0.553,-0.800])
|
|
183
|
|
|
184
|
# Harp scan, April 11 2025 - after harp check w/calipers
|
|
185
|
#XOFF=np.array([-0.180,0.858,0.915])
|
|
186
|
#YOFF=np.array([0.143,-0.320,-0.291])
|
|
187
|
|
|
188
|
# Harp scan, April 11 2025 - after harp check w/calipers
|
|
189
|
# test
|
|
190
|
#XOFF=np.array([-0.185,0.900,0.817])
|
|
191
|
#YOFF=np.array([0.146,-0.418,-0.255])
|
|
192
|
|
|
193
|
|
|
194
|
#raw variables June 9, 2022
|
|
195
|
#XOFF=np.array([0.114,0.919,1.617])
|
|
196
|
#YOFF=np.array([-0.318,-0.012,0.312])
|
|
197
|
# raw - w/corrected harp survey
|
|
198
|
#XOFF=np.array([0.012,0.445,0.543])
|
|
199
|
#YOFF=np.array([-0.318,-0.012,0.312])
|
|
200
|
|
|
201
|
|
|
202
|
# Jan 2022
|
|
203
|
#XOFF=np.array([0.07,-0.33,0.51])
|
|
204
|
#YOFF=np.array([-0.13,0.424,0.27])
|
|
205
|
|
|
206
|
#XSLOPE=np.array([-0.9843,-1.116,-0.9645])
|
|
207
|
#XOFF=np.array([-0.05355,0.08082,-0.893])
|
|
208
|
|
|
209
|
#YSLOPE=np.array([0.9687,1.166,0.8703])
|
|
210
|
#YOFF=np.array([-0.2027,0.3751,0.466])
|
|
211
|
|
|
212
|
# Fit fro DEC 2019 BPm vs HARP scan . In fit made the Harp X coordinate the same sign as the X epics
|
|
213
|
#XSLOPE=np.array([0.973,1.096,0.956])
|
|
214
|
#XOFF=np.array([-.076,-0.200,0.937])
|
|
215
|
|
|
216
|
#YSLOPE=np.array([0.957,1.16,0.855])
|
|
217
|
#YOFF=np.array([0.17,-0.06,-0.94])
|
|
218
|
|
|
219
|
# changes to offsets from most recent survey
|
|
220
|
#DY=np.array([0.25,0.22,0.20])
|
|
221
|
#DX=np.array([-0.02,-0.09,-0.24])
|
|
222
|
|
|
223
|
# survey numbers above were updated..
|
|
224
|
#DY=np.array([0.21,0.21,0.29])
|
|
225
|
#DX=np.array([0.06,0.05,-0.09])
|
|
226
|
|
|
227
|
# from comparison to harp scans 8/29
|
|
228
|
#DY=np.array([0.36,0.36,0.31])
|
|
229
|
#DX=np.array([0.21,0.12,-0.29])
|
|
230
|
|
|
231
|
# from survey, Feb. 2019 (note these are relative to 2017 survey offsets)
|
|
232
|
#DY=np.array([-0.05,-0.23,-0.46])
|
|
233
|
#DX=np.array([0.16,0.21,0.03])
|
|
234
|
|
|
235
|
# from HARP/BPM comparison, Feb. 9 2019 !!!!WRONG!!!
|
|
236
|
#DY=np.array([0.26,0.21,0.06])
|
|
237
|
#DX=np.array([0.32,0.38,0.09])
|
|
238
|
|
|
239
|
# from HARP/BPM comparison, Feb. 9 2019
|
|
240
|
#DY=np.array([0.38,-0.13,-0.76])
|
|
241
|
#DX=np.array([0.32,0.38,0.09])
|
|
242
|
|
|
243
|
# For Dec 2019 comparison did a BPM vs HARP scan so do not need offset
|
|
244
|
|
|
245
|
#additional, incremental corrections, not fit from full calibration
|
|
246
|
DY=np.array([0.,0.,0.])
|
|
247
|
DX=np.array([0.,0.,0.])
|
|
248
|
|
|
249
|
|
|
250
|
XOFF=XOFF+DX
|
|
251
|
YOFF=YOFF+DY
|
|
252
|
|
|
253
|
EX=np.array([0.1,0.1,0.1])
|
|
254
|
EY=np.array([0.1,0.1,0.1])
|
|
255
|
|
|
256
|
# fit line using both x and y errors
|
|
257
|
def f(B, x):
|
|
258
|
'''Linear function y = m*x + b'''
|
|
259
|
# B is a vector of the parameters.
|
|
260
|
# x is an array of the current x values.
|
|
261
|
# x is in the same format as the x passed to Data or RealData.
|
|
262
|
#
|
|
263
|
# Return an array in the same format as y passed to Data or RealData.
|
|
264
|
return B[0]*x + B[1]
|
|
265
|
|
|
266
|
|
|
267
|
ax1 = fig.add_subplot(221)
|
|
268
|
|
|
269
|
ax2 = fig.add_subplot(223)
|
|
270
|
ax2.set_xlabel('Distance from target (cm)',fontsize=15)
|
|
271
|
|
|
272
|
ax3 = fig.add_subplot(122)
|
|
273
|
|
|
274
|
while True:
|
|
275
|
time.sleep(0.5)
|
|
276
|
#read in epics stuff
|
|
277
|
ibcm=float(check_output("caget -w5 IBC3H00CRCUR4 | awk \ '{print $2}'", shell=True).strip())
|
|
278
|
|
|
279
|
AXraw=float(check_output("caget -w5 IPM3H07A.XPOS | awk \ '{print $2}'", shell=True).strip())
|
|
280
|
BXraw=float(check_output("caget -w5 IPM3H07B.XPOS | awk \ '{print $2}'", shell=True).strip())
|
|
281
|
CXraw=float(check_output("caget -w5 IPM3H07C.XPOS | awk \ '{print $2}'", shell=True).strip())
|
|
282
|
|
|
283
|
AYraw=float(check_output("caget -w5 IPM3H07A.YPOS | awk \ '{print $2}'", shell=True).strip())
|
|
284
|
BYraw=float(check_output("caget -w5 IPM3H07B.YPOS | awk \ '{print $2}'", shell=True).strip())
|
|
285
|
CYraw=float(check_output("caget -w5 IPM3H07C.YPOS | awk \ '{print $2}'", shell=True).strip())
|
|
286
|
|
|
287
|
XRAW=np.array([AXraw,BXraw,CXraw])
|
|
288
|
YRAW=np.array([AYraw,BYraw,CYraw])
|
|
289
|
# test
|
|
290
|
# XRAW=np.array([0.03,-0.57,-0.97])
|
|
291
|
# YRAW=np.array([-1.21,-1.26,-1.48])
|
|
292
|
# test
|
|
293
|
# XRAW=np.array([0.8,0.27,0.2])
|
|
294
|
# YRAW=np.array([-0.6,-0.65,-0.8])
|
|
295
|
# XVEC=(XRAW*XSLOPE+XOFF)
|
|
296
|
# YVEC=YRAW*YSLOPE+YOFF
|
|
297
|
|
|
298
|
if ibcm > 0.1:
|
|
299
|
XVEC=(XRAW*XSLOPE+XOFF)
|
|
300
|
YVEC=YRAW*YSLOPE+YOFF
|
|
301
|
else:
|
|
302
|
XVEC=XRAW*0.0
|
|
303
|
YVEC=YRAW*0.0
|
|
304
|
|
|
305
|
# Show X Position
|
|
306
|
# define 1st plot -x vs. z
|
|
307
|
ax1.plot(NOMINAL_ZVEC, NOMINAL_XVEC, marker='s', color='black', markersize=8,
|
|
308
|
fillstyle='none', linestyle='none')
|
|
309
|
ax1.errorbar(ZVEC, XRAW, yerr=EX, fmt='o', color='blue', markersize=4)
|
|
310
|
ax1.errorbar(ZVEC, XVEC, yerr=EX, fmt='o', color='red', markersize=4)
|
|
311
|
linear = Model(f)
|
|
312
|
mydata = RealData(ZVEC, XVEC, sy=EX)
|
|
313
|
myodr = ODR(mydata, linear, beta0=[1., 2.])
|
|
314
|
myoutput = myodr.run()
|
|
315
|
# myoutput.pprint()
|
|
316
|
# get errors from covariance matrix - standard errors from ODR amplify by chi-squared
|
|
317
|
xtar=round(myoutput.beta[1],2)
|
|
318
|
|
|
319
|
# Plot the fit
|
|
320
|
x_fit = np.linspace(-400, 50, 1000)
|
|
321
|
y_fit = f(myoutput.beta, x_fit)
|
|
322
|
ax1.plot(x_fit, y_fit, color='black')
|
|
323
|
|
|
324
|
#plt.xlabel('Distance from target (cm)',fontsize=15)
|
|
325
|
#ax1.text(-400,2,"X Pos @ tgt: "+str(xtar))
|
|
326
|
ax1.set_ylim([-2,2])
|
|
327
|
|
|
328
|
# Show Y Position
|
|
329
|
ax2.plot(NOMINAL_ZVEC, NOMINAL_YVEC, marker='s', color='black', markersize=8,
|
|
330
|
fillstyle='none', linestyle='none')
|
|
331
|
yraw = ax2.errorbar(ZVEC, YRAW, yerr=EX, fmt='o', color='blue', markersize=4)
|
|
332
|
ycor = ax2.errorbar(ZVEC, YVEC, yerr=EX, fmt='o', color='red', markersize=4)
|
|
333
|
linear = Model(f)
|
|
334
|
mydata = RealData(ZVEC, YVEC, sy=EX)
|
|
335
|
myodr = ODR(mydata, linear, beta0=[1., 2.])
|
|
336
|
myoutput = myodr.run()
|
|
337
|
# myoutput.pprint()
|
|
338
|
# get errors from covariance matrix - standard errors from ODR amplify by chi-squared
|
|
339
|
ytar=round(myoutput.beta[1],2)
|
|
340
|
|
|
341
|
# Plot the fit
|
|
342
|
x_fit = np.linspace(-400, 50, 1000)
|
|
343
|
y_fit = f(myoutput.beta, x_fit)
|
|
344
|
ax2.plot(x_fit, y_fit, color='black')
|
|
345
|
|
|
346
|
#ax2.text(-400,2,"Y Pos @ tgt: "+str(ytar));
|
|
347
|
ax2.set_ylim([-2,2])
|
|
348
|
ax1.set_ylabel('X (mm)',fontsize=15)
|
|
349
|
ax2.set_ylabel('Y (mm)',fontsize=15)
|
|
350
|
ax2.set_xlabel('Z (cm)',fontsize=15)
|
|
351
|
ax3.set_xlabel('Target X (mm)',fontsize=15)
|
|
352
|
ax3.set_ylabel('Target Y (mm)',fontsize=15)
|
|
353
|
|
|
354
|
# BPM monitoring-like Output
|
|
355
|
cPos, =ax3.plot([NOMINAL_POS['target']['XPOS']], [NOMINAL_POS['target']['YPOS']], marker='s', color='black', markersize=8, fillstyle='none', linestyle='none')
|
|
356
|
ax3.errorbar(xtar,ytar, yerr=0, fmt='o', color='red', markersize=4)
|
|
357
|
ax3.yaxis.tick_right()
|
|
358
|
ax3.yaxis.set_label_position('right')
|
|
359
|
ax3.yaxis.grid(color='grey')
|
|
360
|
ax3.xaxis.grid(color='grey')
|
|
361
|
ax3.text(-3,1.2,"Beam position on target:\n"+8*" "+str(xtar)+" , "+str(ytar));
|
|
362
|
ax3.set_xlim([-4,4])
|
|
363
|
ax3.set_ylim([-2,2])
|
|
364
|
# ax3.legend((yraw, ycor), ('Raw BPM', 'corrected'), loc='lower left')
|
|
365
|
ax3.legend((yraw,ycor,cPos), ('Raw BPM position', 'True position','Nominal position'), loc='lower left')
|
|
366
|
# print('xtar is', xtar, 'ytar', ytar)
|
|
367
|
|
|
368
|
ax3.text(-11.5, 2.5,"Nominal 3H07A: ({}, {}), 3H07C: ({}, {})".format(
|
|
369
|
NOMINAL_POS['3H07A']['XPOS'],
|
|
370
|
NOMINAL_POS['3H07A']['YPOS'],
|
|
371
|
NOMINAL_POS['3H07C']['XPOS'],
|
|
372
|
NOMINAL_POS['3H07C']['YPOS']),
|
|
373
|
size=10)
|
|
374
|
|
|
375
|
fig.canvas.draw()
|
|
376
|
fig.canvas.flush_events()
|
|
377
|
plt.pause(1)
|
|
378
|
ax1.clear()
|
|
379
|
ax2.clear()
|
|
380
|
ax3.clear()
|
|
381
|
gc.collect()
|