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])