Added flat acquisition

This commit is contained in:
gac-x05la
2025-02-10 16:41:31 +01:00
parent 0dc6412ed8
commit c729d67763
4 changed files with 184 additions and 64 deletions

View File

@@ -10,30 +10,20 @@ eyex:
enabled: true
readOnly: false
softwareTrigger: false
# eyey:
# readoutPriority: baseline
# description: X-ray eye axis Y
# deviceClass: tomcat_bec.devices.psimotor.EpicsMotorEC
# deviceConfig:
# prefix: MTEST-X05LA-ES2-XRAYEYE:M2
# deviceTags:
# - xray-eye
# onFailure: buffer
# enabled: true
# readOnly: false
# softwareTrigger: false
# eyez:
# readoutPriority: baseline
# description: X-ray eye axis Z
# deviceClass: tomcat_bec.devices.psimotor.EpicsMotorEC
# deviceConfig:
# prefix: MTEST-X05LA-ES2-XRAYEYE:M3
# deviceTags:
# - xray-eye
# onFailure: buffer
# enabled: true
# readOnly: false
# softwareTrigger: false
eyez:
readoutPriority: baseline
description: X-ray eye axis Z
deviceClass: tomcat_bec.devices.psimotor.EpicsMotorEC
deviceConfig:
prefix: MTEST-X05LA-ES2-XRAYEYE:M3
deviceTags:
- xray-eye
onFailure: buffer
enabled: true
readOnly: false
softwareTrigger: false
femto_mean_curr:
readoutPriority: monitored
description: Femto mean current

View File

@@ -1,2 +1,2 @@
from .tutorial_fly_scan import AcquireDark, AcquireFlat, TutorialFlyScanContLine
from .tutorial_fly_scan import AcquireDark, AcquireWhite, TutorialFlyScanContLine
from .tomcat_scans import TomcatStepScan, TomcatSnapNStep, TomcatSimpleSequence

View File

@@ -27,7 +27,7 @@ class AcquireDark(Acquire):
image_height : int, optional
ROI size in the y-direction [pixels]
acq_mode : str, optional
Predefined acquisition mode (default=)
Predefined acquisition mode (default= 'default')
file_path : str, optional
File path for standard daq
@@ -51,39 +51,58 @@ class AcquireDark(Acquire):
yield from super().scan_core()
class AcquireFlat(Acquire):
scan_name = "acquire_flat"
required_kwargs = ["num"]
gui_config = {"Acquisition parameters": ["num"]}
class AcquireWhite(Acquire):
scan_name = "acquire_white"
required_kwargs = ["exp_burst", "sample_position_out", "sample_angle_out"]
gui_config = {"Acquisition parameters": ["exp_burst"]}
def __init__(self, num: int, out_position: float, **kwargs):
def __init__(self, exp_burst: int, sample_position_out: float, sample_angle_out: float, **kwargs):
"""
Acquire a flat field image. This scan is used to acquire a flat field image. The flat field image is an image taken
with the shutter open but the sample out of the beam. The flat field image is used to correct the data images for
Acquire flat field images. This scan is used to acquire flat field images. The flat field image is an image taken
with the shutter open but the sample out of the beam. Flat field images are used to correct the data images for
non-uniformity in the detector.
Args:
num (int): number of flat field images to acquire
out_position (float): position to move the sample stage to take the flat field image
exp_burst : int
Number of flat field images to acquire (no default)
sample_position_out : float
Position to move the sample stage to position the sample out of beam and take flat field images
sample_angle_out : float
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
exp_period : float, optional
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
image_height : int, optional
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
File path for standard daq
Returns:
ScanReport
Examples:
>>> scans.acquire_flat(5, 20)
>>> scans.acquire_white(5, 20)
"""
super().__init__(**kwargs)
self.burst_at_each_point = num
self.out_position = out_position
self.sample_stage = "samy" # change to the correct sample stage device
self.shutter = "hx" # change to the correct shutter device
self.burst_at_each_point = 1
self.sample_position_out = sample_position_out
self.sample_angle_out = sample_angle_out
self.scan_motors = ["eyex", "eyez", "es1_roty"] # change to the correct shutter device
# self.scan_motors = ["eyex", "eyez"] # change to the correct shutter device
self.dark_shutter_pos = 1 ### change with a variable
def scan_core(self):
# open the shutter and move the sample stage to the out position
yield from self.stubs.set_and_wait(
device=[self.shutter, self.sample_stage], positions=[1, self.out_position]
)
yield from self._move_scan_motors_and_wait([self.dark_shutter_pos, self.sample_position_out, self.sample_angle_out])
# yield from self._move_scan_motors_and_wait([self.dark_shutter_pos, self.sample_position_out])
yield from super().scan_core()
@@ -168,7 +187,7 @@ class TutorialFlyScanContLine(AsyncFlyScanBase):
show_asap=True,
rid=self.metadata.get("RID"),
)
flats = AcquireFlat(
flats = AcquireWhite(
num=self.num_flats,
exp_time=self.exp_time,
out_position=self.sample_out,

View File

@@ -12,6 +12,11 @@ class Measurement:
self.nimages_dark = 50
self.nimages_white = 100
self.start_angle = 0
self.sample_angle_out = 0
self.sample_position_in = 0
self.sample_position_out = 1
# To be able to keep what is already set on the camera
self.exposure_time = None
self.exposure_period = None
@@ -29,12 +34,20 @@ class Measurement:
self.build_filename()
def build_filename(self):
def build_filename(self, acquisition_type='data'):
"""
Build and set filepath for bec
Build filepath and file prefix for stddaq
acquisition_type : string, optional
Type of images: a choice between dark, white, or data (default = data)
"""
if acquisition_type != "data" and acquisition_type != "dark" and acquisition_type != "white":
print("WARNING: chosen acquisition type not permitted! \n")
print("The chosen acquitisition type as been set to \"data\"!")
acquisition_type == "data"
self.scan_sample_name = 'S' + str(bec.queue.next_scan_number) + '_' + self.sample_name
# File path for bec
@@ -44,11 +57,13 @@ class Measurement:
self.file_path = os.path.join('/data/test/test-beamline',bec.system_config.file_directory, '_device_dat', self.device_name) # _device_dat does not work for now.
# A hack for now to create the right permissions
self.base_path = os.path.join('/data/test/test-beamline',self.data_path)
self.file_prefix = self.scan_sample_name + '_' + self.device_name + '_data_dark_'
self.file_prefix = self.scan_sample_name + '_' + self.device_name + '_' + acquisition_type + '_'
def configure(self,sample_name=None, data_path=None, exposure_time=None,
exposure_period=None, roix=None, roiy=None,nimages=None,
nimages_dark=None, nimages_white=None):
nimages_dark=None, nimages_white=None,
start_angle=None, sample_angle_out=None,
sample_position_in=None, sample_position_out=None):
"""
Reconfigure the measurement with any number of new parameter
@@ -56,24 +71,34 @@ class Measurement:
----------
sample_name : string, optional
Name of the sample or measurement. This name will be used to construct
the name of the measurement directory (default=None)
the name of the measurement directory (default = None)
data_path : string, optional
Information used to build the data directory for the measurement
(default=None)
(default = None)
exposure_time : float, optional
Exposure time [ms] (default=None)
Exposure time [ms] (default = None)
exposure_period : float, optional
Exposure period [ms] (default=None)
Exposure period [ms] (default = None)
roix : int, optional
ROI size in the x-direction [pixels] (default=None)
ROI size in the x-direction [pixels] (default = None)
roiy : int, optional
ROI size in the y-direction [pixels] (default=None)
ROI size in the y-direction [pixels] (default = None)
nimages : int, optional
Number of images to acquire (default=None)
Number of images to acquire (default = None)
nimages_dark : int, optional
Number of dark images to acquire (default=None)
Number of dark images to acquire (default = None)
nimages_white : int, optional
Number of white images to acquire (default=None)
Number of white images to acquire (default = None)
start_angle : float, optional
The start angle for the scan [deg] (default = None)
sample_angle_out : float, optional
Sample rotation angle for sample out of the beam [deg]
(default = None)
sample_position_in : float, optional
Sample stage X position for sample in beam [um] (default = None)
sample_position_out : float, optional
Sample stage X position for sample out of the beam [um]
(default = None)
"""
if sample_name != None:
@@ -94,6 +119,14 @@ class Measurement:
self.roix = roix
if roiy != None:
self.roiy = roiy
if start_angle != None:
self.start_angle = start_angle
if sample_angle_out != None:
self.sample_angle_out = sample_angle_out
if sample_position_in != None:
self.sample_position_in = sample_position_in
if sample_position_out != None:
self.sample_position_out = sample_position_out
self.build_filename()
@@ -102,7 +135,7 @@ class Measurement:
"""
Show configuration
TODO: check active devices, write the config for each device and if none read from device
TODO: make it work for multiple devices
"""
print("Sample name: " + self.sample_name)
@@ -110,11 +143,28 @@ class Measurement:
print("Number of images: " + str(self.nimages))
print("Number of darks: " + str(self.nimages_dark))
print("Number of flats: " + str(self.nimages_white))
print("Exposure time: " + str(self.exposure_time))
print("Exposure period: " + str(self.exposure_period))
print("Roix: " + str(self.roix))
print("Roiy: " + str(self.roiy))
if self.exposure_time == None:
print("Exposure time: " + str(self.det.cfgExposure.get()))
else:
print("Exposure time: " + str(self.exposure_time))
if self.exposure_period == None:
print("Exposure peirod: " + str(self.det.cfgFramerate.get()))
else:
print("Exposure period: " + str(self.exposure_period))
if self.roix == None:
print("Roix: " + str(self.det.cfgRoiX.get()))
else:
print("Roix: " + str(self.roix))
if self.roiy == None:
print("Roiy: " + str(self.det.cfgRoiY.get()))
else:
print("Roiy: " + str(self.roiy))
print("Start angle: " + str(self.start_angle))
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))
def acquire_darks(self,nimages_dark, exposure_time=None, exposure_period=None,
roix=None, roiy=None, acq_mode=None):
"""
@@ -137,7 +187,7 @@ class Measurement:
Example:
--------
fede_darks(100, exposure_time=5)
m.acquire_darks(100, exposure_time=5)
"""
# dev.es1_tasks.enabled = False
# dev.es1_psod.enabled = False
@@ -158,10 +208,71 @@ class Measurement:
if roiy != None:
self.roiy = roiy
self.build_filename()
self.build_filename(acquisition_type='dark')
### TODO: camera reset
print("Handing over to 'scans.acquire_dark")
scans.acquire_dark(exp_burst=nimages_dark, exp_time=self.exposure_time, exp_period=self.exposure_period, image_width=self.roix,
image_height=self.roiy, acq_mode=acq_mode, file_path=self.file_path, nr_writers=2, base_path=self.base_path,
file_prefix=self.file_prefix)
file_prefix=self.file_prefix)
def acquire_whites(self,nimages_whites, sample_angle_out=None, sample_position_out=None,
exposure_time=None, exposure_period=None,
roix=None, roiy=None, acq_mode=None):
"""
Acquire a set of whites images with shutters open and sample out of beam.
Parameters
----------
nimages_whites : int
Number of white images to acquire (no default)
sample_angle_out : float, optional
Sample rotation angle for sample out of the beam [deg]
sample_position_out : float, optional
Sample stage X position for sample out of the beam [um]
exposure_time : float, optional
Exposure time [ms]. If not specified, the currently configured value on the camera will be used
exposure_period : float, optional
Exposure period [ms]
roix : int, optional
ROI size in the x-direction [pixels]
roiy : int, optional
ROI size in the y-direction [pixels]
acq_mode : str, optional
Predefined acquisition mode (default=None)
Example:
--------
m.acquire_whites(100, exposure_time=5)
"""
# dev.es1_tasks.enabled = False
# dev.es1_psod.enabled = False
# dev.es1_ddaq.enabled = False
# dev.es1_ismc.enabled = False
# dev.es1_roty.enabled = False
dev.gfcam.enabled = True
dev.gfdaq.enabled = True
dev.daq_stream0.enabled = True
dev.daq_stream1.enabled = False
if sample_angle_out != None:
self.sample_angle_out = sample_angle_out
if sample_position_out != None:
self.sample_position_out = sample_position_out
if exposure_time != None:
self.exposure_time = exposure_time
if exposure_period != None:
self.exposure_period = exposure_period
if roix != None:
self.roix = roix
if roiy != None:
self.roiy = roiy
self.build_filename(acquisition_type='white')
### TODO: camera reset
print("Handing over to 'scans.acquire_whites")
scans.acquire_white(exp_burst=nimages_whites, sample_angle_out=self.sample_angle_out, sample_position_out= self.sample_position_out,
exp_time=self.exposure_time, exp_period=self.exposure_period, image_width=self.roix,
image_height=self.roiy, acq_mode=acq_mode, file_path=self.file_path, nr_writers=2, base_path=self.base_path,
file_prefix=self.file_prefix)