diff --git a/configuration/pipeline_config/SARBD02-DSCR051_sp.json b/configuration/pipeline_config/SARBD02-DSCR051_sp.json new file mode 100644 index 0000000..afe3f01 --- /dev/null +++ b/configuration/pipeline_config/SARBD02-DSCR051_sp.json @@ -0,0 +1,11 @@ +{ + "image_background_enable": false, + "image_background": null, + "image_threshold": null, + "image_region_of_interest": null, + "image_good_region": null, + "image_slices": null, + "pipeline_type": "processing", + "camera_name": "SARBD02-DSCR051", + "name": "SARBD02-DSCR051_sp" +} \ No newline at end of file diff --git a/configuration/pipeline_config/X01DD-SC-CAM1_proc.json b/configuration/pipeline_config/X01DD-SC-CAM1_proc.json new file mode 100644 index 0000000..136ede6 --- /dev/null +++ b/configuration/pipeline_config/X01DD-SC-CAM1_proc.json @@ -0,0 +1,13 @@ +{ + "name": "X01DD-SC-CAM1_proc", + "pipeline_type": "stream", + "input_pipeline": "X01DD-SC-CAM1_sp", + "mode": "PUB", + "block": false, + "function": "temp_epics_forwarder_sp.py", + "_max_frame_rate": 10.1, + "throw_epics_errors": true, + "abort_on_timeout": true, + "stream_timeout": 60, + "reload": true +} \ No newline at end of file diff --git a/configuration/user_scripts/epics_forwarder_gr.py b/configuration/user_scripts/epics_forwarder_gr.py new file mode 100644 index 0000000..c2bfab3 --- /dev/null +++ b/configuration/user_scripts/epics_forwarder_gr.py @@ -0,0 +1,108 @@ +import sys +import os +from cam_server.pipeline.data_processing import functions, processor +from collections import OrderedDict +from cam_server.pipeline.data_processing import functions +from cam_server.utils import create_thread_pvs, epics_lock +from logging import getLogger +import math + +_logger = getLogger(__name__) + +throw_epics_errors = True + +mean_x_pv, mean_y_pv, sig_x_pv, sig_y_pv = None, None, None, None +mean_x_name, mean_y_name, sig_x_name, sig_y_name = None, None, None, None +ampl_x_pv, ampl_y_pv, integ_x_pv, integ_y_pv = None, None, None, None +ampl_x_name, ampl_y_name, integ_x_name, integ_y_name = None, None, None, None +sent_pid = -1 + +initialized = False +def initialize(parameters): + global initialized + global mean_x_name, mean_y_name, sig_x_name, sig_y_name, ampl_x_name, ampl_y_name, integ_x_name, integ_y_name + prefix = parameters["camera_name"] + mean_x_name = prefix + ":POS-X" + mean_y_name = prefix + ":POS-Y" + sig_x_name = prefix + ":SIG-X" + sig_y_name = prefix + ":SIG-Y" + ampl_x_name = prefix + ":AMPL-X" + ampl_y_name = prefix + ":AMPL-Y" + integ_x_name = prefix + ":INTEG-X" + integ_y_name = prefix + ":INTEG-Y" + initialized = True + + +def process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata): + global initialized, sent_pid + global mean_x_pv, mean_y_pv, sig_x_pv, sig_y_pv, ampl_x_pv, ampl_y_pv, integ_x_pv, integ_y_pv + global mean_x_name, mean_y_name, sig_x_name, sig_y_name, ampl_x_name, ampl_y_name, integ_x_name, integ_y_name + prefix = parameters["camera_name"] + if not initialized: + initialize(parameters) + initialized = True + r = processor.process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata) + ret = OrderedDict() + + x_fit_integ = r["gr_x_fit_amplitude"] * r["gr_x_fit_standard_deviation"] * math.sqrt(2*math.pi) + y_fit_integ = r["gr_y_fit_amplitude"] * r["gr_y_fit_standard_deviation"] * math.sqrt(2*math.pi) + + + ret[prefix+":intensity"] = r["intensity"] + ret[prefix+":x_fit_mean"] = r["x_fit_mean"] + ret[prefix+":y_fit_mean"] = r["y_fit_mean"] + ret[prefix+":x_fit_standard_deviation"] = r["x_fit_standard_deviation"] + ret[prefix+":y_fit_standard_deviation"] = r["y_fit_standard_deviation"] + ret[prefix+":x_center_of_mass"] = r["x_center_of_mass"] + ret[prefix+":y_center_of_mass"] = r["y_center_of_mass"] + ret[prefix+":x_rms"] = r["x_rms"] + ret[prefix+":y_rms"] = r["y_rms"] + ret[prefix+":x_fwhm"] = r["x_fwhm"] + ret[prefix+":y_fwhm"] = r["y_fwhm"] + ret[prefix+":x_fit_amplitude"] = r["x_fit_amplitude"] + ret[prefix+":y_fit_amplitude"] = r["y_fit_amplitude"] + ret[prefix+":x_fit_integ"] = x_fit_integ + ret[prefix+":y_fit_integ"] = y_fit_integ + ret[prefix+":gr_x_fit_mean"] = r["gr_x_fit_mean"] + ret[prefix+":gr_y_fit_mean"] = r["gr_y_fit_mean"] + ret[prefix+":gr_x_fit_standard_deviation"] = r["gr_x_fit_standard_deviation"] + ret[prefix+":gr_y_fit_standard_deviation"] = r["gr_y_fit_standard_deviation"] + + mean_x_pv, mean_y_pv, sig_x_pv, sig_y_pv, ampl_x_pv, ampl_y_pv, integ_x_pv, integ_y_pv = create_thread_pvs([mean_x_name, mean_y_name, sig_x_name, sig_y_name, ampl_x_name, ampl_y_name, integ_x_name, integ_y_name]) + epics_error = None + + if pulse_id > sent_pid: + sent_pid = pulse_id + if epics_lock.acquire(False): + try: + for (pv, value) in [ (mean_x_pv, r["gr_x_fit_mean"]), \ + (mean_y_pv, r["gr_y_fit_mean"]), \ + (sig_x_pv, r["gr_x_fit_standard_deviation"]), \ + (sig_y_pv, r["gr_y_fit_standard_deviation"]), \ + (ampl_x_pv, r["gr_x_fit_amplitude"]), \ + (ampl_y_pv, r["gr_y_fit_amplitude"]), \ + (integ_x_pv, x_fit_integ), \ + (integ_y_pv, y_fit_integ) \ + ]: + if pv and pv.connected: + pv.put(value) + else: + _logger.warning("PV not connected: %s" % (str(pv),)) + #epics_error = "PV not connected: %s" % (str(pv),) + except Exception as e: + epics_error = "Error writing PVs: %s" % (str(e),) + finally: + epics_lock.release() + else: + _logger.warning("Cannot aquire EPICS lock") + + if epics_error: + _logger.warning(epics_error) + if throw_epics_errors: + raise Exception(epics_error) + + return ret + else: + _logger.warning("Invalid PID: %s last:%s"% (str(pulse_id), str(sent_pid),)) + sent_pid = 0 # It should be single threaded, assumes the camera instance restarted + diff --git a/configuration/user_scripts/streakcam.py b/configuration/user_scripts/streakcam.py new file mode 100644 index 0000000..b44c847 --- /dev/null +++ b/configuration/user_scripts/streakcam.py @@ -0,0 +1,40 @@ +import sys +import os + +from cam_server.pipeline.data_processing import functions + +# Bunch length measurement using the streak camera + +import numpy as np +from scipy import interpolate +from scipy.signal import find_peaks +import math +from logging import getLogger + +_logger = getLogger(__name__) + +class PpolPeakValley(): + def __init__(self): + self.x, self.y = self.lensrms() + + def lenrms(image, x_axis=None, row_range=(60, 80), offset=2100, plot=False): + row_start, row_end = row_range + if row_end >= image.shape[0]: + raise ValueError("Row range exceeds image height") + + # Sum over selected rows to get horizontal profile + averaged_row = np.sum(image[row_start:row_end + 1, :], axis=0) + + # Subtract offset and clip to zero + data = np.maximum(averaged_row - offset, 0) + + # Use pixel index as x_axis if not provided + if x_axis is None: + x_axis = np.arange(data.shape[0]) + + # Compute moments + mx1 = np.sum(x_axis * data) / np.sum(data) + mx2 = np.sum((x_axis ** 2) * data) / np.sum(data) + lenrms = np.sqrt(mx2 - mx1 ** 2) + + return ret \ No newline at end of file diff --git a/configuration/user_scripts/temp_epics_forwarder_sp.py b/configuration/user_scripts/temp_epics_forwarder_sp.py new file mode 100644 index 0000000..467f78c --- /dev/null +++ b/configuration/user_scripts/temp_epics_forwarder_sp.py @@ -0,0 +1,92 @@ +from collections import OrderedDict +from cam_server.utils import create_thread_pvs, epics_lock +from logging import getLogger +import json +import math + +_logger = getLogger(__name__) + +mean_x_name, mean_y_name, sig_x_name, sig_y_name = None, None, None, None +ampl_x_name, ampl_y_name, integ_x_name, integ_y_name = None, None, None, None +camera_name = None +sent_pid = -1 + +initialized = False +throw_epics_errors = False + + +def initialize(parameters, data): + global initialized, camera_name + global mean_x_name, mean_y_name, sig_x_name, sig_y_name, ampl_x_name, ampl_y_name, integ_x_name, integ_y_name + processing_parameters = json.loads(data["processing_parameters"]) + camera_name = processing_parameters["camera_name"] + mean_x_name = camera_name + ":POS-X" + mean_y_name = camera_name + ":POS-Y" + sig_x_name = camera_name + ":SIG-X" + sig_y_name = camera_name + ":SIG-Y" + ampl_x_name = camera_name + ":AMPL-X" + ampl_y_name = camera_name + ":AMPL-Y" + integ_x_name = camera_name + ":INTEG-X" + integ_y_name = camera_name + ":INTEG-Y" + initialized = True + + +def process(data, pulse_id, timestamp, parameters): + global initialized, sent_pid, camera_name + global mean_x_name, mean_y_name, sig_x_name, sig_y_name + + if not initialized: + initialize(parameters, data) + initialized = True + + mean_x_pv, mean_y_pv, sig_x_pv, sig_y_pv, ampl_x_pv, ampl_y_pv, integ_x_pv, integ_y_pv = create_thread_pvs([mean_x_name, mean_y_name, sig_x_name, sig_y_name, ampl_x_name, ampl_y_name, integ_x_name, integ_y_name]) + + ret = OrderedDict() + throw_epics_errors = parameters.get("throw_epics_errors", True) + + x_fit_integ = data["x_fit_amplitude"] * data["x_fit_standard_deviation"] * math.sqrt(2*math.pi) + y_fit_integ = data["y_fit_amplitude"] * data["y_fit_standard_deviation"] * math.sqrt(2*math.pi) + + channels = ["intensity", "x_fit_mean", "y_fit_mean", "x_fit_standard_deviation", "y_fit_standard_deviation", + "x_center_of_mass", "y_center_of_mass", "x_rms", "y_rms", "x_fwhm", "y_fwhm","x_fit_amplitude", "y_fit_amplitude"] + + for c in channels: + ret[camera_name + ":" + c] = data[c] + ret[camera_name + ":x_fit_integ"] = x_fit_integ + ret[camera_name + ":y_fit_integ"] = y_fit_integ + + epics_error = None + + if pulse_id > sent_pid: + sent_pid = pulse_id + if epics_lock.acquire(False): + try: + for (pv, value) in [(mean_x_pv, data["x_center_of_mass"]), \ + (mean_y_pv, data["y_center_of_mass"]), \ + (sig_x_pv, data["x_rms"]), \ + (sig_y_pv, data["y_rms"]), \ + (ampl_x_pv, data["x_fit_amplitude"]), \ + (ampl_y_pv, data["y_fit_amplitude"]), \ + (integ_x_pv, x_fit_integ), \ + (integ_y_pv, y_fit_integ) \ + ]: + if pv and pv.connected: + pv.put(value) + else: + _logger.warning("PV not connected: %s" % (str(pv),)) + # epics_error = "PV not connected: %s" % (str(pv),) + except Exception as e: + epics_error = "Error writing PVs: %s" % (str(e),) + finally: + epics_lock.release() + else: + _logger.warning("Cannot aquire EPICS lock") + + if epics_error: + _logger.warning(epics_error) + if throw_epics_errors: + raise Exception(epics_error) + return ret + else: + _logger.warning("Invalid PID: %s last:%s" % (str(pulse_id), str(sent_pid),)) + sent_pid = 0 # It should be single threaded, assumes the camera instance restarted \ No newline at end of file