From 9d104173bd9aecf0bb98f18e1591b2b08ecc3a43 Mon Sep 17 00:00:00 2001 From: gac-x05la Date: Tue, 18 Feb 2025 18:50:04 +0100 Subject: [PATCH] Work on fede scans --- tomcat_bec/devices/gigafrost/stddaq_client.py | 5 + tomcat_bec/scans/tutorial_fly_scan.py | 103 +++++++++--------- tomcat_bec/scripts/scans_fede.py | 36 +++++- 3 files changed, 91 insertions(+), 53 deletions(-) diff --git a/tomcat_bec/devices/gigafrost/stddaq_client.py b/tomcat_bec/devices/gigafrost/stddaq_client.py index 34006b2..8bb8209 100644 --- a/tomcat_bec/devices/gigafrost/stddaq_client.py +++ b/tomcat_bec/devices/gigafrost/stddaq_client.py @@ -49,6 +49,10 @@ class StdDaqMixin(CustomDeviceMixin): d["image_height"] = scanargs["image_height"] if "nr_writers" in scanargs and scanargs["nr_writers"] is not None: d["nr_writers"] = scanargs["nr_writers"] + if "system_config" in scanargs and scanargs["system_config"] is not None: + if scanargs['system_config']['file_directory']: + file_directory = scanargs['system_config']['file_directory'] + ### to be used in the future to substitute the procedure using file path if "file_path" in scanargs and scanargs["file_path"] is not None: self.parent.file_path.set(scanargs["file_path"].replace("data", "gpfs")).wait() print(scanargs["file_path"]) @@ -428,6 +432,7 @@ class StdDaqClient(PSIDeviceBase): return result status = SubscriptionStatus(self.runstatus, is_running, settle_time=0.5) + # status.set_finished() return status def get_daq_config(self, update=False) -> dict: diff --git a/tomcat_bec/scans/tutorial_fly_scan.py b/tomcat_bec/scans/tutorial_fly_scan.py index 0f1b63f..2672f4b 100644 --- a/tomcat_bec/scans/tutorial_fly_scan.py +++ b/tomcat_bec/scans/tutorial_fly_scan.py @@ -57,7 +57,6 @@ class AcquireDark(Acquire): class AcquireWhite(Acquire): scan_name = "acquire_white" - required_kwargs = ["exp_burst", "sample_position_out", "sample_angle_out", "motor"] gui_config = {"Acquisition parameters": ["exp_burst"]} def __init__(self, exp_burst: int, sample_position_out: float, sample_angle_out: float, motor: DeviceBase, **kwargs): @@ -111,20 +110,20 @@ class AcquireWhite(Acquire): def scan_core(self): - # open the shutter and move the sample stage to the out position - self.scan_motors = [self.motor_sample, "es1_roty"] # change to the correct shutter device - yield from self._move_scan_motors_and_wait([self.sample_position_out, self.sample_angle_out]) - self.scan_motors = ["eyex"] # change to the correct shutter device - yield from self._move_scan_motors_and_wait([self.dark_shutter_pos_out]) + # move the sample stage to the out position and correct angular position + status_sample_out_angle = yield from self.stubs.set(device=[self.motor_sample, "es1_roty"], value=[self.sample_position_out, self.sample_angle_out], wait=False) + # open the main shutter (TODO change to the correct shutter device) + yield from self.stubs.set(device=["eyex"], value=[self.dark_shutter_pos_out]) + status_sample_out_angle.wait() # TODO add opening of fast shutter + yield from super().scan_core() # TODO add closing of fast shutter - yield from self._move_scan_motors_and_wait([self.dark_shutter_pos_in]) + yield from self.stubs.set(device=["eyex"], value=[self.dark_shutter_pos_in]) class AcquireProjections(AsyncFlyScanBase): scan_name = "acquire_projections" - required_kwargs = ["motor", "exp_burst", "sample_position_in", "start_angle", "angular_range"] gui_config = {"Acquisition parameters": ["exp_burst"]} def __init__(self, @@ -138,8 +137,6 @@ class AcquireProjections(AsyncFlyScanBase): Acquire projection images. Args: - motor : - motor : DeviceBase Motor to move continuously from start to stop position exp_burst : int @@ -174,83 +171,69 @@ class AcquireProjections(AsyncFlyScanBase): >>> scans.acquire_projections() """ - super().__init__(**kwargs) self.motor = motor + super().__init__(**kwargs) + self.burst_at_each_point = 1 self.sample_position_in = sample_position_in self.start_angle = start_angle self.angular_range = angular_range - #self.scan_motors = ["eyex", "eyez", "es1_roty"] # change to the correct shutter device self.dark_shutter_pos_out = 1 ### change with a variable self.dark_shutter_pos_in = 0 ### change with a variable + def update_scan_motors(self): + return [self.motor] + def prepare_positions(self): self.positions = np.array([[self.start_angle], [self.start_angle+self.angular_range]]) self.num_pos = None yield from self._set_position_offset() - def scan_core(self): - # move to in position and go to start position - self.scan_motors = ["eyez", self.motor] - yield from self._move_scan_motors_and_wait([self.sample_position_in, self.positions[0][0]]) + # move to in position and go to start angular position + yield from self.stubs.set(device=["eyez", self.motor], value=[self.sample_position_in, self.positions[0][0]]) # open the shutter - self.scan_motors = ["eyex"] # change to the correct shutter device - yield from self._move_scan_motors_and_wait([self.dark_shutter_pos_out]) + yield from self.stubs.set(device="eyex", value=self.dark_shutter_pos_out) # TODO add opening of fast shutter # start the flyer - # flyer_request = yield from self.stubs.set_with_response( - # device=self.motor, value=self.positions[1][0] - # ) flyer_request = yield from self.stubs.set( - device=self.motor, value=self.positions[1][0], wait=True + device=self.motor, value=self.positions[1][0], wait=False ) self.connector.send_client_info( "Starting the scan", show_asap=True, rid=self.metadata.get("RID") - ) - - # send a trigger -# yield from self.stubs.trigger(group="trigger", point_id=self.point_id) - yield from self.stubs.trigger(wait=False) - while True: - # read the data - # yield from self.stubs.read_and_wait( - # group="primary", wait_group="readout_primary", point_id=self.point_id - # ) + ) + + yield from self.stubs.trigger() + while not flyer_request.done: + yield from self.stubs.read( - device=self.motor, point_id=self.point_id, wait=True + group="monitored", point_id=self.point_id ) time.sleep(1) - if self.stubs.request_is_completed(flyer_request): - # stop the scan if the motor has reached the stop position - break - # increase the point id self.point_id += 1 - def finalize(self): - yield from super().finalize() - self.num_pos = self.point_id + 1 + self.num_pos = self.point_id class AcquireRefs(Acquire): scan_name = "acquire_refs" - required_kwargs = [] gui_config = {} def __init__( self, + motor: DeviceBase, num_darks: int = 0, num_flats: int = 0, sample_angle_out: float = 0, sample_position_in: float = 0, - sample_position_out: float = 5000, + sample_position_out: float = 1, file_prefix_dark: str = 'tmp_dark', file_prefix_white: str = 'tmp_white', **kwargs @@ -262,24 +245,30 @@ class AcquireRefs(Acquire): the sample is returned to the sample_in_position afterwards. Args: + motor : DeviceBase + Motor to be moved to move the sample out of beam num_darks : int , optional Number of dark field images to acquire num_flats : int , optional Number of white field images to acquire + sample_angle_out : float , optional + Angular position where to take the flat field images sample_position_in : float , optional Sample stage X position for sample in beam [um] sample_position_out : float ,optional Sample stage X position for sample out of the beam [um] - sample_angle_out : float , optional - Angular position where to take the flat field images exp_time : float, optional - Exposure time [ms]. If not specified, the currently configured value on the camera will be used + Exposure time [ms]. If not specified, the currently configured value + on the camera will be used exp_period : float, optional - Exposure period [ms]. If not specified, the currently configured value on the camera will be used + Exposure period [ms]. If not specified, the currently configured value + on the camera will be used image_width : int, optional - ROI size in the x-direction [pixels]. If not specified, the currently configured value on the camera will be used + ROI size in the x-direction [pixels]. If not specified, the currently + configured value on the camera will be used image_height : int, optional - ROI size in the y-direction [pixels]. If not specified, the currently configured value on the camera will be used + ROI size in the y-direction [pixels]. If not specified, the currently + configured value on the camera will be used acq_mode : str, optional Predefined acquisition mode (default= 'default') file_path : str, optional @@ -292,6 +281,7 @@ class AcquireRefs(Acquire): >>> scans.acquire_refs(sample_angle_out=90, sample_position_in=10, num_darks=5, num_flats=5, exp_time=0.1) """ + self.motor = motor super().__init__(**kwargs) self.sample_position_in = sample_position_in self.sample_position_out = sample_position_out @@ -303,24 +293,30 @@ class AcquireRefs(Acquire): def scan_core(self): - ## TODO move sample in position and do not wait - ## TODO move angle in position and do not wait + status_sample_out_angle = yield from self.stubs.set(device=[self.motor, "es1_roty"], value=[self.sample_position_out, self.sample_angle_out], wait=False) + if self.num_darks: self.connector.send_client_info( f"Acquiring {self.num_darks} dark images", show_asap=True, rid=self.metadata.get("RID"), ) + + # to set signals on a device + yield from self.stubs.send_rpc_and_wait("gfdaq", "file_prefix.set", self.file_prefix_dark) + yield from self.stubs.send_rpc_and_wait("gfdaq", "num_images.set", self.num_darks) darks = AcquireDark( exp_burst=self.num_darks, - file_prefix=self.file_prefix_dark, device_manager=self.device_manager, metadata=self.metadata, + instruction_handler=self.stubs._instruction_handler, + **self.caller_kwargs, ) yield from darks.scan_core() self.point_id = darks.point_id - + + status_sample_out_angle.wait() if self.num_flats: self.connector.send_client_info( f"Acquiring {self.num_flats} flat field images", @@ -331,9 +327,12 @@ class AcquireRefs(Acquire): exp_burst=self.num_flats, sample_position_out=self.sample_position_out, sample_angle_out=self.sample_angle_out, + motor=self.motor, file_prefix=self.file_prefix_white, device_manager=self.device_manager, metadata=self.metadata, + instruction_handler=self.stubs._instruction_handler, + **self.caller_kwargs, ) flats.point_id = self.point_id yield from flats.scan_core() diff --git a/tomcat_bec/scripts/scans_fede.py b/tomcat_bec/scripts/scans_fede.py index 77d77ab..5cb4abc 100644 --- a/tomcat_bec/scripts/scans_fede.py +++ b/tomcat_bec/scripts/scans_fede.py @@ -44,6 +44,10 @@ class Measurement: self.exposure_period = self.det.cfgFramerate.get() self.roix = self.det.cfgRoiX.get() self.roiy = self.det.cfgRoiY.get() + + self.get_position_rb() + #self.position_rb = False + #self.disable_position_rb_device() def build_filename(self, acquisition_type='data'): @@ -75,7 +79,8 @@ class Measurement: exposure_period=None, roix=None, roiy=None,nimages=None, nimages_dark=None, nimages_white=None, start_angle=None, sample_angle_out=None, - sample_position_in=None, sample_position_out=None): + sample_position_in=None, sample_position_out=None, + position_rb=None): """ Reconfigure the measurement with any number of new parameter @@ -111,6 +116,8 @@ class Measurement: sample_position_out : float, optional Sample stage X position for sample out of the beam [um] (default = None) + position_rb : bool, optional + Enable position readback (default = None) """ if sample_name != None: @@ -139,6 +146,13 @@ class Measurement: self.sample_position_in = sample_position_in if sample_position_out != None: self.sample_position_out = sample_position_out + if position_rb != None: + if position_rb == True: + self.enable_position_rb_device() + elif position_rb == False: + self.disable_position_rb_device() + else: + print("WARNING! Position readback should be either True, False or None") self.build_filename() @@ -169,6 +183,12 @@ class Measurement: self.device_name = self.enabled_detectors[0].name self.build_filename() + def disable_position_rb_device(self): + + "Disable position readback device" + + dev.es1_ddaq.enabled= False + self.position_rb = False def enable_detector(self, detector_name): """ @@ -198,7 +218,12 @@ class Measurement: self.device_name = self.enabled_detectors[0].name self.build_filename() + def enable_position_rb_device(self): + "Enable position readback device" + + dev.es1_ddaq.enabled= True + self.position_rb = True def get_available_detectors(self): """ @@ -216,6 +241,14 @@ class Measurement: """ self.enabled_detectors = [obj for obj in dev.get_devices_with_tags('camera') if obj.enabled] + def get_position_rb(self): + """ + Get position rb + """ + if dev.es1_ddaq.enabled == True: + self.position_rb = True + else: + self.position_rb = False def show_available_detectors(self): """ @@ -273,6 +306,7 @@ class Measurement: print("Sample angle out: " + str(self.sample_angle_out)) print("Sample position in: " + str(self.sample_position_in)) print("Sample position out: " + str(self.sample_position_out)) + print("Position readback: " + str(self.position_rb)) def acquire_darks(self,nimages_dark=None, exposure_time=None, exposure_period=None,