262 lines
11 KiB
Python
262 lines
11 KiB
Python
import ch.psi.pshell.epics.Positioner as Positioner
|
|
from mathutils import fit_polynomial
|
|
|
|
#Parameters
|
|
dry_run = False
|
|
do_elog = True
|
|
USE_SCREEN_PANEL = True
|
|
MO_FREQ = 142.8e6 # MO = 142.8 MHz
|
|
is_panel = get_exec_pars().source != CommandSource.ui # run from panel
|
|
if is_panel:
|
|
start = args[0]
|
|
stop = args[1] + 0.001 # needed to get the last point
|
|
step = args[2]
|
|
nb = int(args[3])
|
|
lat = args[4]
|
|
thr = args[5]
|
|
tds = args[6]
|
|
bunch = args[7]
|
|
plt11 = args[8]
|
|
plt12 = args[9]
|
|
plt21 = args[10]
|
|
plt22 = args[11]
|
|
else:
|
|
start = -0.1
|
|
stop = 0.1 + 0.001
|
|
step = 0.05
|
|
nb = 5
|
|
lat = 2.0
|
|
thr = 250
|
|
tds = "S30CB14"
|
|
bunch = "Bunch1"
|
|
plt11 = plot(None, title="Output")[0]
|
|
plt12 = plot(None, title="Output")[0]
|
|
plt21 = plot(None, title="Output")[0]
|
|
plt22 = plot(None, title="Output")[0]
|
|
run("Tools/BunchLengthTDSdata.py")
|
|
|
|
#Record callback: update of output plot
|
|
def update_plot(record, scan, plt):
|
|
com_mean, com_stdev = record[0].mean, record[0].stdev
|
|
rms_mean, rms_stdev = record[1].mean, record[1].stdev
|
|
fw_mean, fw_stdev = record[2].mean, record[2].stdev
|
|
fit_mean, fit_stdev = record[3].mean, record[3].stdev
|
|
phase = record.positions[0]
|
|
plt.getSeries(0).appendData(phase, com_mean, com_stdev)
|
|
plt.getSeries(1).appendData(phase, rms_mean, rms_stdev)
|
|
plt.getSeries(2).appendData(phase, fw_mean, fw_stdev)
|
|
plt.getSeries(3).appendData(phase, fit_mean, fit_stdev)
|
|
|
|
def update_plot_1(record, scan):
|
|
global plt11
|
|
update_plot(record, scan, plt11)
|
|
|
|
def update_plot_2(record, scan):
|
|
global plt12
|
|
update_plot(record, scan, plt12)
|
|
|
|
#Plot setup
|
|
def init_plots(plt1, plt2):
|
|
plt1.clear()
|
|
plt1.removeMarker(None)
|
|
plt1.setStyle(plt1.Style.ErrorY)
|
|
plt1.addSeries(LinePlotErrorSeries("Bunch center of mass", Color.red))
|
|
plt1.addSeries(LinePlotErrorSeries("Bunch length rms", Color.yellow, 2))
|
|
plt1.addSeries(LinePlotErrorSeries("Bunch length fw", Color.green, 2))
|
|
plt1.addSeries(LinePlotErrorSeries("Bunch length gauss fit", Color.blue, 2))
|
|
plt1.getAxis(plt1.AxisId.X).setLabel("TDS Phase (deg)")
|
|
plt1.getAxis(plt1.AxisId.Y).setLabel("Bunch center of mass (um)")
|
|
plt1.getAxis(plt1.AxisId.Y2).setLabel("Bunch length (um)")
|
|
plt1.setLegendVisible(True)
|
|
plt2.clear()
|
|
plt2.removeMarker(None)
|
|
plt2.setStyle(plt2.Style.Normal)
|
|
plt2.getAxis(plt2.AxisId.X).setLabel("Time (fs)")
|
|
plt2.getAxis(plt2.AxisId.Y).setLabel("Current (kA)")
|
|
plt2.setLegendVisible(False)
|
|
|
|
init_plots(plt11, plt21)
|
|
init_plots(plt12, plt22)
|
|
|
|
#Creating Phase positioner
|
|
if dry_run:
|
|
phase = DummyPositioner("TDS Phase")
|
|
camera_name = "simulation"
|
|
else:
|
|
phase = Positioner("TDS Phase", tds + "-RSYS:SET-BEAM-PHASE", tds + "-RSYS:SET-BEAM-PHASE")
|
|
camera_name = tds_data[tds]["screen"]
|
|
phase.config.minValue = -90.0
|
|
phase.config.maxValue = 270.0
|
|
phase.config.precision = 4
|
|
phase.config.resolution = 0.05
|
|
phase.config.rotation = True
|
|
phase.config.save()
|
|
phase.initialize()
|
|
phase0 = phase.read() % 360
|
|
|
|
#Camera setup
|
|
if USE_SCREEN_PANEL:
|
|
cam_server.start(camera_name+"_sp1", True) # shared pipeline
|
|
else:
|
|
cam_server.start(camera_name) # generic pipeline
|
|
cam_server.setFunction("beam_full_width")
|
|
cam_server.setInstanceConfigValue("fw_threshold", 0.3)
|
|
cam_server.setThreshold(thr)
|
|
cam_server.setBackgroundSubtraction(False)
|
|
cam_server.setGoodRegion(0.1, 3.0)
|
|
print "Waiting for y_fw and y_fit"
|
|
timeout = 1.0
|
|
start_time = time.time()
|
|
while (True):
|
|
wait_cam_server_message()
|
|
y_fw = cam_server.stream.getChild("y_fw")
|
|
y_fit = cam_server.stream.getChild("gr_y_fit_standard_deviation")
|
|
if (y_fw is not None) and (y_fit is not None):
|
|
break
|
|
if time.time() - start_time > timeout:
|
|
if y_fw is None:
|
|
raise Exception("y_fw not in camera stream")
|
|
if y_fit is None:
|
|
raise Exception("y_fit not in camera stream")
|
|
y_center_of_mass = cam_server.stream.getChild("y_center_of_mass")
|
|
y_rms = cam_server.stream.getChild("y_rms")
|
|
y_profile = cam_server.stream.getChild("y_profile")
|
|
y_axis = cam_server.stream.getChild("y_axis")
|
|
|
|
#Creating averagers
|
|
com_averager = create_averager(y_center_of_mass, nb, -1) # -1 event based, waits for the next value
|
|
rms_averager = create_averager(y_rms, nb, -1)
|
|
fw_averager = create_averager(y_fw, nb, -1)
|
|
fit_averager = create_averager(y_fit, nb, -1)
|
|
rms_averager.monitored = True # not blocking, will return last nb values
|
|
fw_averager.monitored = True
|
|
fit_averager.monitored = True
|
|
|
|
#switch BLMs off
|
|
blm = tds_data[tds]["BLM"]
|
|
strg = ":B1_ROI_ACTIVE_OP" if bunch == "Bunch1" else ":B2_ROI_ACTIVE_OP"
|
|
for i in range(len(blm)):
|
|
if dry_run:
|
|
print(blm[i] + strg, 0)
|
|
else:
|
|
caput(blm[i] + strg, 0)
|
|
|
|
#The scan loop
|
|
try:
|
|
bunch1_charge = caget("SINEG01-DBPM340:Q1")
|
|
bunch2_charge = caget("SINEG01-DBPM340:Q2")
|
|
bunch_charge = bunch1_charge if bunch == "Bunch1" else bunch2_charge
|
|
sensor_list = [com_averager, rms_averager, fw_averager, fit_averager, y_axis, y_profile, y_center_of_mass]
|
|
phase.write(start)
|
|
time.sleep(1.0)
|
|
# get bs phase-jitter / screen position data for SATMA02 calib
|
|
r1 = lscan(phase, sensor_list, start, stop, step , latency=lat, after_read = update_plot_1)
|
|
start, stop = start + 180.0, stop + 180.0
|
|
phase.write(start)
|
|
time.sleep(10.0)
|
|
r2 = lscan(phase, sensor_list, start, stop, step , latency=lat, after_read = update_plot_2)
|
|
finally:
|
|
phase.write(phase0)
|
|
phase.close()
|
|
cam_server.stop() # stops cam_server but does not close it cam_server is a global object
|
|
|
|
# stop the beam
|
|
if dry_run:
|
|
print("SIN-TIMAST-TMA:Beam-RF-OnDelay-Sel", 1)
|
|
print("SIN-TIMAST-TMA:Beam-Apply-Cmd.PROC", 1)
|
|
else:
|
|
caput("SIN-TIMAST-TMA:Beam-RF-OnDelay-Sel", 1)
|
|
caput("SIN-TIMAST-TMA:Beam-Apply-Cmd.PROC", 1)
|
|
|
|
#switch BLMs on
|
|
for i in range(len(blm)):
|
|
if dry_run:
|
|
print(blm[i] + strg, 1)
|
|
else:
|
|
caput(blm[i] + strg, 1)
|
|
|
|
#output
|
|
def write_output(r, plt):
|
|
phase_pos = r.getPositions(0)
|
|
rf_period = 1 / MO_FREQ / tds_data[tds]["harm"]
|
|
time_pos = [val / 360.0 * rf_period * 1e15 for val in phase_pos] # in fs
|
|
bunch_center = [val.mean for val in r.getReadable(0)]
|
|
bunch_center_stdev = [val.stdev for val in r.getReadable(0)]
|
|
a0, a1 = fit_polynomial(time_pos, bunch_center, 1)
|
|
calib = abs(a1) # in fs/um
|
|
#calib = 1
|
|
bunch_length_rms = [val.mean * calib for val in r.getReadable(1)]
|
|
bunch_length_rms_average = sum(bunch_length_rms) / len(bunch_length_rms)
|
|
bunch_length_fw = [val.mean * calib for val in r.getReadable(2)]
|
|
bunch_length_fw_average = sum(bunch_length_fw) / len(bunch_length_fw)
|
|
bunch_length_fit = [val.mean * calib for val in r.getReadable(3)]
|
|
bunch_length_fit_average = sum(bunch_length_fit) / len(bunch_length_fit)
|
|
profiles_um = r[y_axis]
|
|
profiles_dig = r[y_profile]
|
|
profiles_com = r[y_center_of_mass]
|
|
com = sum(profiles_com) / len(profiles_com)
|
|
profiles_fs = []
|
|
profiles_kA = []
|
|
for i in range(len(r[y_axis])):
|
|
delta_um = profiles_com[i] - com
|
|
profiles_fs.append([(val - delta_um) * calib for val in profiles_um[i]])
|
|
step_fs = (max(profiles_fs[i]) - min(profiles_fs[i])) / (len(profiles_fs[i]) - 1)
|
|
total_dig = float(sum(profiles_dig[i]))
|
|
profiles_kA.append([val / total_dig * bunch_charge / step_fs for val in profiles_dig[i]]) # pC / fs = kA
|
|
for i in range(len(profiles_um)):
|
|
plt.addSeries(LinePlotSeries("Bunch current " + str(i), Color.red))
|
|
plt.getSeries(i).setData(profiles_fs[i], profiles_kA[i])
|
|
return bunch_length_rms_average, bunch_length_fw_average, bunch_length_fit_average, calib
|
|
|
|
bunch_length_rms_average1, bunch_length_fw_average1, bunch_length_fit_average1, calib1 = write_output(r1, plt21)
|
|
bunch_length_rms_average2, bunch_length_fw_average2, bunch_length_fit_average2, calib2 = write_output(r2, plt22)
|
|
bunch_length_rms = (bunch_length_rms_average1 + bunch_length_rms_average2) / 2
|
|
bunch_length_fw = (bunch_length_fw_average1 + bunch_length_fw_average2) / 2
|
|
bunch_length_fit = (bunch_length_fit_average1 + bunch_length_fit_average2) / 2
|
|
calib = (calib1 + calib2) / 2
|
|
|
|
#archiver channels
|
|
if bunch == "Bunch1":
|
|
caput(tds + "-RTDS100:BD-BUNCH1-DURATION", bunch_length_fw)
|
|
caput(tds + "-RTDS100:BD-BUNCH1-CALIBRATION", 1 / calib)
|
|
else:
|
|
caput(tds + "-RTDS100:BD-BUNCH2-DURATION", bunch_length_fw)
|
|
caput(tds + "-RTDS100:BD-BUNCH2-CALIBRATION", 1 / calib)
|
|
|
|
#Elog entry
|
|
if do_elog:
|
|
if get_option("Generated data file:\n" + get_exec_pars().path +"\n\n" + "Save to ELOG?", "YesNo") == "Yes":
|
|
title = "Bunch length Scan"
|
|
log_msg = "Data file: " + get_exec_pars().path + "\n\n"
|
|
log_msg = log_msg + "TDS: " + tds + "\n"
|
|
log_msg = log_msg + "Bunch: " + bunch + "\n\n"
|
|
log_msg = log_msg + "#### 0 deg ####\n"
|
|
log_msg = log_msg + "Bunch length rms: %0.1f" % bunch_length_rms_average1 + " fs\n"
|
|
log_msg = log_msg + "Bunch length fw: %0.1f" % bunch_length_fw_average1 + " fs\n"
|
|
log_msg = log_msg + "Bunch length fit: %0.1f" % bunch_length_fit_average1 + " fs\n"
|
|
log_msg = log_msg + "Calibration: %0.4f" % calib1 + " fs/um\n\n"
|
|
log_msg = log_msg + "#### 180 deg ####\n"
|
|
log_msg = log_msg + "Bunch length rms: %0.1f" % bunch_length_rms_average2 + " fs\n"
|
|
log_msg = log_msg + "Bunch length fw: %0.1f" % bunch_length_fw_average2 + " fs\n"
|
|
log_msg = log_msg + "Bunch length fit: %0.1f" % bunch_length_fit_average2 + " fs\n"
|
|
log_msg = log_msg + "Calibration: %0.4f" % calib2 + " fs/um\n\n"
|
|
log_msg = log_msg + "#### mean ####\n"
|
|
log_msg = log_msg + "Bunch length rms: %0.1f" % bunch_length_rms + " fs\n"
|
|
log_msg = log_msg + "Bunch length fw: %0.1f" % bunch_length_fw + " fs\n"
|
|
log_msg = log_msg + "Bunch length fit: %0.1f" % bunch_length_fit + " fs\n"
|
|
log_msg = log_msg + "Calibration: %0.4f" % calib + " fs/um"
|
|
sleep(0.1) #Give some time to plot to be finished - it is not sync with acquisition
|
|
file_name1 = os.path.abspath(get_context().setup.getContextPath() + "/BunchLengthScanPlot1.png")
|
|
plt11.saveSnapshot(file_name1, "png")
|
|
file_name2 = os.path.abspath(get_context().setup.getContextPath() + "/BunchLengthCurrent1.png")
|
|
plt21.saveSnapshot(file_name2, "png")
|
|
file_name3 = os.path.abspath(get_context().setup.getContextPath() + "/BunchLengthScanPlot2.png")
|
|
plt12.saveSnapshot(file_name3, "png")
|
|
file_name4 = os.path.abspath(get_context().setup.getContextPath() + "/BunchLengthCurrent2.png")
|
|
plt22.saveSnapshot(file_name4, "png")
|
|
elog(title, log_msg, [file_name1, file_name2, file_name3, file_name4])
|
|
|
|
set_return([bunch_length_rms_average1, bunch_length_fw_average1, bunch_length_fit_average1, calib1,
|
|
bunch_length_rms_average2, bunch_length_fw_average2, bunch_length_fit_average2, calib2,
|
|
bunch_length_rms, bunch_length_fw, bunch_length_fit, calib])
|