WIP acquire_refs

This commit is contained in:
gac-x05la
2025-02-11 17:12:21 +01:00
parent a36c8237da
commit 6db73b366b
3 changed files with 402 additions and 46 deletions

View File

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

View File

@@ -46,7 +46,7 @@ class AcquireDark(Acquire):
def scan_core(self):
# close the shutter
yield from self._move_scan_motors_and_wait(self.dark_shutter_pos)
# yield from self._move_scan_motors_and_wait(self.dark_shutter_pos)
#yield from self.stubs.set_and_wait(device=[self.shutter], positions=[0])
yield from super().scan_core()
@@ -95,15 +95,205 @@ class AcquireWhite(Acquire):
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
self.dark_shutter_pos_out = 1 ### change with a variable
self.dark_shutter_pos_in = 0 ### change with a variable
def scan_core(self):
# open the shutter and move the sample stage to the 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])
self.scan_motors = ["eyez", "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])
# 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])
class AcquireProjectins(Acquire):
scan_name = "acquire_projections"
required_kwargs = ["exp_burst", "sample_position_in", "start_position", "angular_range"]
gui_config = {"Acquisition parameters": ["exp_burst"]}
def __init__(self,
exp_burst: int,
sample_position_in: float,
start_position: float,
angular_range: float,
**kwargs):
"""
Acquire projection images.
Args:
exp_burst : int
Number of flat field images to acquire (no default)
sample_position_in : float
Position to move the sample stage to position the sample in the beam
start_position : float
Angular start position for the scan
angular_range : float
Angular range
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_white(5, 20)
"""
super().__init__(**kwargs)
self.burst_at_each_point = 1
self.sample_position_in = sample_position_in
self.start_position = start_position
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 scan_core(self):
# open the shutter and move the sample stage to the out position
self.scan_motors = ["eyez", "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])
# 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])
class AcquireRefs(Acquire):
scan_name = "acquire_refs"
required_kwargs = []
gui_config = {}
def __init__(
self,
num_darks: int = 0,
num_flats: int = 0,
sample_angle_out: float = 0,
sample_position_in: float = 0,
sample_position_out: float = 5000,
file_prefix_dark: str = 'tmp_dark',
file_prefix_white: str = 'tmp_white',
exp_time: float = 0,
exp_period: float = 0,
image_width: int = 2016,
image_height: int = 2016,
acq_mode: str = 'default',
file_path: str = 'tmp',
nr_writers: int = 2,
base_path: str = 'tmp',
**kwargs
):
"""
Acquire reference images (darks + whites) and return to beam position.
Reference images are acquired automatically in an optimized sequence and
the sample is returned to the sample_in_position afterwards.
Args:
num_darks : int , optional
Number of dark field images to acquire
num_flats : int , optional
Number of white field images to acquire
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
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_refs(sample_angle_out=90, sample_position_in=10, num_darks=5, num_flats=5, exp_time=0.1)
"""
super().__init__(**kwargs)
self.sample_position_in = sample_position_in
self.sample_position_out = sample_position_out
self.sample_angle_out = sample_angle_out
self.num_darks = num_darks
self.num_flats = num_flats
self.file_prefix_dark = file_prefix_dark
self.file_prefix_white = file_prefix_white
self.exp_time = exp_time,
self.exp_period = exp_period,
self.image_width = image_width,
self.image_height = image_height,
self.acq_mode = acq_mode,
self.file_path = file_path,
self.nr_writers = nr_writers,
self.base_path = base_path,
def scan_core(self):
## TODO move sample in position and do not wait
## TODO move angle in position and do not wait
if self.num_darks:
self.connector.send_client_info(
f"Acquiring {self.num_darks} dark images",
show_asap=True,
rid=self.metadata.get("RID"),
)
darks = AcquireDark(
exp_burst=self.num_darks,
file_prefix=self.file_prefix_dark,
device_manager=self.device_manager,
metadata=self.metadata
)
yield from darks.scan_core()
self.point_id = darks.point_id
if self.num_flats:
self.connector.send_client_info(
f"Acquiring {self.num_flats} flat field images",
show_asap=True,
rid=self.metadata.get("RID"),
)
flats = AcquireWhite(
exp_burst=self.num_flats,
sample_position_out=self.sample_position_out,
sample_angle_out=self.sample_angle_out,
file_prefix=self.file_prefix_white,
device_manager=self.device_manager,
metadata=self.metadata,
)
flats.point_id = self.point_id
yield from flats.scan_core()
self.point_id = flats.point_id
## TODO move sample in beam and do not wait
## TODO move rotation to angle and do not wait
class TutorialFlyScanContLine(AsyncFlyScanBase):

View File

@@ -8,6 +8,9 @@ class Measurement:
def __init__(self):
self.sample_name = 'tmp'
self.data_path = 'disk_test'
bec.system_config.file_suffix = None
bec.system_config.file_directory = os.path.join(self.data_path,self.sample_name)
self.nimages = 1000
self.nimages_dark = 50
self.nimages_white = 100
@@ -23,16 +26,24 @@ class Measurement:
self.roix = None
self.roiy = None
enabled_detectors = [obj for obj in dev.get_devices_with_tags('camera') if obj.enabled]
if len(enabled_detectors) != 1:
print('WARNING! More than 1 detector active')
self.det = enabled_detectors[0]
self.device_name = enabled_detectors[0].name
bec.system_config.file_suffix = None
bec.system_config.file_directory = os.path.join(self.data_path,self.sample_name)
self.build_filename()
self.get_available_detectors()
self.get_enabled_detectors()
if len(self.enabled_detectors) > 1:
print('WARNING! More than 1 detector enabled')
self.show_enabled_detectors()
elif len(self.enabled_detectors) == 0:
print("WARNING! No detector enabled!!")
self.show_available_detectors()
else:
self.show_enabled_detectors()
self.det = self.enabled_detectors[0]
self.device_name = self.enabled_detectors[0].name
self.build_filename()
self.exposure_time = self.det.cfgExposure.get()
self.exposure_period = self.det.cfgFramerate.get()
self.roix = self.det.cfgRoiX.get()
self.roiy = self.det.cfgRoiY.get()
def build_filename(self, acquisition_type='data'):
"""
@@ -130,6 +141,99 @@ class Measurement:
self.build_filename()
def disable_detector(self, detector_name):
"""
Disable detector
"""
if detector_name not in self.available_detectors_names:
print("WARNING! The detector " + str(detector_name + " is not available!"))
print("You can check the available detectors with the command dev.show_all()")
devices_to_be_disabled = [obj for obj in dev.get_devices_with_tags(detector_name)]
for i in range(len(devices_to_be_disabled)):
devices_to_be_disabled[i].enabled = False
self.get_enabled_detectors()
if len(self.enabled_detectors) > 1:
print('WARNING! More than 1 detector enabled')
self.show_enabled_detectors()
elif len(self.enabled_detectors) == 0:
print("WARNING! No detector enabled!!")
self.show_available_detectors()
else:
self.show_enabled_detectors()
self.det = self.enabled_detectors[0]
self.device_name = self.enabled_detectors[0].name
self.build_filename()
def enable_detector(self, detector_name):
"""
Enable detector
"""
if detector_name not in self.available_detectors_names:
print("WARNING! The detector " + str(detector_name + " is not available!"))
print("You can check the available detectors with the command dev.show_all()")
devices_to_be_enabled = [obj for obj in dev.get_devices_with_tags(detector_name)]
for i in range(len(devices_to_be_enabled)):
devices_to_be_enabled[i].enabled = True
dev.daq_stream1.enabled = False
self.get_enabled_detectors()
if len(self.enabled_detectors) > 1:
print('WARNING! More than 1 detector enabled')
self.show_enabled_detectors()
elif len(self.enabled_detectors) == 0:
print("WARNING! No detector enabled!!")
self.show_available_detectors()
else:
self.show_enabled_detectors()
self.det = self.enabled_detectors[0]
self.device_name = self.enabled_detectors[0].name
self.build_filename()
def get_available_detectors(self):
"""
Check available detectors
"""
self.available_detectors = [obj for obj in dev.get_devices_with_tags('camera')]
self.available_detectors_names = []
for i in range(len(self.available_detectors)):
self.available_detectors_names.append(self.available_detectors[i].name)
def get_enabled_detectors(self):
"""
Get enabled detectors
"""
self.enabled_detectors = [obj for obj in dev.get_devices_with_tags('camera') if obj.enabled]
def show_available_detectors(self):
"""
Show available detectors
"""
print("Available detectors:")
for i in range(len(self.available_detectors)):
print(self.available_detectors[i].name + '\tenabled ' + str(self.available_detectors[i].enabled))
def show_enabled_detectors(self):
"""
List enabled detectors
"""
print("Enabled detectors:")
for i in range(len(self.enabled_detectors)):
print(self.enabled_detectors[i].name)
def show_all(self):
"""
@@ -145,18 +249,22 @@ class Measurement:
print("Number of flats: " + str(self.nimages_white))
if self.exposure_time == None:
print("Exposure time: " + str(self.det.cfgExposure.get()))
self.exposure_time = 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()))
print("Exposure period: " + str(self.det.cfgFramerate.get()))
self.exposure_period = self.det.cfgFramerate.get()
else:
print("Exposure period: " + str(self.exposure_period))
if self.roix == None:
print("Roix: " + str(self.det.cfgRoiX.get()))
self.roix = self.det.cfgRoiX.get()
else:
print("Roix: " + str(self.roix))
if self.roiy == None:
print("Roiy: " + str(self.det.cfgRoiY.get()))
self.roiy = self.det.cfgRoiY.get()
else:
print("Roiy: " + str(self.roiy))
print("Start angle: " + str(self.start_angle))
@@ -165,14 +273,14 @@ class Measurement:
print("Sample position out: " + str(self.sample_position_out))
def acquire_darks(self,nimages_dark, exposure_time=None, exposure_period=None,
def acquire_darks(self,nimages_dark=None, exposure_time=None, exposure_period=None,
roix=None, roiy=None, acq_mode=None):
"""
Acquire a set of dark images with shutters closed.
Parameters
----------
nimages_dark : int
nimages_dark : int, optional
Number of dark images to acquire (no default)
exposure_time : float, optional
Exposure time [ms]. If not specified, the currently configured value on the camera will be used
@@ -187,18 +295,11 @@ class Measurement:
Example:
--------
m.acquire_darks(100, exposure_time=5)
m.acquire_darks(nimages_darks=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 nimages_dark != None:
self.nimages_dark = nimages_dark
if exposure_time != None:
self.exposure_time = exposure_time
if exposure_period != None:
@@ -212,11 +313,12 @@ class Measurement:
### 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,
scans.acquire_dark(exp_burst=self.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)
def acquire_whites(self,nimages_whites, sample_angle_out=None, sample_position_out=None,
def acquire_whites(self,nimages_white=None, sample_angle_out=None, sample_position_out=None,
exposure_time=None, exposure_period=None,
roix=None, roiy=None, acq_mode=None):
"""
@@ -224,7 +326,7 @@ class Measurement:
Parameters
----------
nimages_whites : int
nimages_whites : int, optional
Number of white images to acquire (no default)
sample_angle_out : float, optional
Sample rotation angle for sample out of the beam [deg]
@@ -243,18 +345,11 @@ class Measurement:
Example:
--------
m.acquire_whites(100, exposure_time=5)
m.acquire_whites(nimages_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 nimages_white != None:
self.nimages_white = nimages_white
if sample_angle_out != None:
self.sample_angle_out = sample_angle_out
if sample_position_out != None:
@@ -272,7 +367,78 @@ class Measurement:
### 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,
scans.acquire_white(exp_burst=self.nimages_white, 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)
file_prefix=self.file_prefix)
def acquire_refs(self,nimages_dark=None, nimages_white=None, sample_angle_out=None,
sample_position_in=None, sample_position_out=None,
exposure_time=None, exposure_period=None,
roix=None, roiy=None, acq_mode=None):
"""
Acquire reference images (darks + whites) and return to beam position.
Reference images are acquired automatically in an optimized sequence and
the sample is returned to the sample_in_position afterwards.
Parameters
----------
darks : int, optional
Number of dark images to acquire (no default)
nimages_whites : int, optional
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_in : float, optional
Sample stage X position for sample in of the beam [um]
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_refs(nimages_whites=100, exposure_time=5)
"""
if nimages_dark != None:
self.nimages_dark = nimages_dark
if nimages_white != None:
self.nimages_white = nimages_white
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
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='dark')
file_prefix_dark = self.file_prefix
self.build_filename(acquisition_type='white')
file_prefix_white = self.file_prefix
### TODO: camera reset
print("Handing over to 'scans.acquire_refs")
scans.acquire_refs(num_darks=self.nimages_dark, num_flats=self.nimages_white, sample_angle_out=self.sample_angle_out,
sample_position_in=self.sample_position_in, 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='default', file_path=self.file_path, nr_writers=2, base_path=self.base_path,
file_prefix_dark=file_prefix_dark, file_prefix_white=file_prefix_white)