Dailiy commit

This commit is contained in:
Unknown MX Person
2024-09-18 18:26:54 +02:00
parent 23aadabfd1
commit 2563471ac8
+284 -234
View File
@@ -48,6 +48,9 @@ class AerotechFlyscanBase(AsyncFlyScanBase):
Low-level base class for standard scans at the PX beamlines at SLS. Theese scans use the Low-level base class for standard scans at the PX beamlines at SLS. Theese scans use the
A3200 rotation stage and the actual experiment is performed using an AeroBasic script A3200 rotation stage and the actual experiment is performed using an AeroBasic script
controlled via global variables. controlled via global variables.
IMPORTANT: The AeroBasic scripts take care of the PSO configuration.
""" """
scan_report_hint = "table" scan_report_hint = "table"
arg_input = {} arg_input = {}
@@ -126,17 +129,17 @@ class AerotechFlyscanBase(AsyncFlyScanBase):
class MeasureStandardWedge(AerotechFlyscanBase): class MeasureStandardWedge(AerotechFlyscanBase):
""" Standard wedge scan """ Standard wedge scan using the OMEGA motor
Measure a standard continous line scan from `start` to `start` + `range` Measure an absolute continous line scan from `start` to `start` + `range`
during `scan_time` on the Omega axis. during `move_time` on the Omega axis with PSO output.
The scan itself is executed by the scan service running on the Aerotech The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion. controller. Ophyd just configures, launches it and waits for completion.
Example Example
------- -------
>>> scans.standard_wedge(start=42, range=10, scan_time=20) >>> scans.standard_wedge(start=42, range=10, move_time=20)
Parameters Parameters
---------- ----------
@@ -144,26 +147,26 @@ class MeasureStandardWedge(AerotechFlyscanBase):
Scan start position of the axis. Scan start position of the axis.
range : (float, float) range : (float, float)
Scan range of the axis. Scan range of the axis.
scan_time : (float) move_time : (float)
Total fly time for the movement [s]. Total travel time for the movement [s].
ready_rate : float, optional ready_rate : float, optional
No clue what is this... (default=500) No clue what is this... (default=500)
""" """
scan_name = "standard_wedge" scan_name = "standard_wedge"
required_kwargs = ["start", "range", "scan_time"] required_kwargs = ["start", "range", "move_time"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ['omega'] self.axis = ['abr.omega']
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.scan_start = parameter['kwargs'].get("start") self.scan_start = parameter['kwargs'].get("start")
self.scan_range = parameter['kwargs'].get("range") self.scan_range = parameter['kwargs'].get("range")
self.scan_scan_time = parameter['kwargs'].get("scan_time") self.scan_move_time = parameter['kwargs'].get("move_time")
self.scan_ready_rate = parameter['kwargs'].get("ready_rate", 500) self.scan_ready_rate = parameter['kwargs'].get("ready_rate", 500)
self.abr_command = AbrCmd.MEASURE_STANDARD self.abr_command = AbrCmd.MEASURE_STANDARD
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_start, "var_1" : self.scan_start,
"var_2" : self.scan_range, "var_2" : self.scan_range,
"var_3" : self.scan_scan_time, "var_3" : self.scan_move_time,
"var_4" : self.scan_ready_rate, "var_4" : self.scan_ready_rate,
} }
# Call base class # Call base class
@@ -171,40 +174,88 @@ class MeasureStandardWedge(AerotechFlyscanBase):
class MeasureScanSlits(AerotechFlyscanBase):
""" Slit scan
Measure a standard slit scan. class MeasureVerticalLine(AerotechFlyscanBase):
""" Vertical line scan using the GMY motor
Simple relative continous line scan that records a single vertical line
with PSO output. There's no actual stepping, it's only used for velocity
calculation.
The scan itself is executed by the scan service running on the Aerotech The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion. controller. Ophyd just configures, launches it and waits for completion.
Example Example
------- -------
>>> scans.slit_scan(start=42, range=10, scan_time=20) >>> scans.measure_vline(range_y=12, steps_y=40, exp_time=0.1)
Parameters Parameters
---------- ----------
delta_x : (float, float) range_y : float
Scan range with slit in x. Step size [mm].
delta_y : (float, float) steps_y : int
Scan range with slit in y. Scan range of the axis.
velocity : (float) exp_time : float
Scan velocity [mm/s]. Eeffective exposure time per step [s]
""" """
scan_name = "slit_scan" scan_name = "measure_vline"
required_kwargs = ["delta_x", "delta_y", "velocity"] required_kwargs = ["exp_time", "range_y", "steps_y"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = [] self.axis = ['abr.gmy']
# Set parameters from meaningful inputs
self.scan_exp_time = parameter['kwargs'].get("exp_time")
self.scan_range_y = parameter['kwargs'].get("range_y")
self.scan_stepnum_y = parameter['kwargs'].get("steps_y")
self.scan_stepsize_y = self.scan_range_y / self.scan_stepnum_y
self.abr_command = AbrCmd.VERTICAL_LINE_SCAN
self.abr_globals = {
'var_1': self.scan_exp_time,
'var_2': self.scan_stepsize_y,
'var_3': self.scan_stepnum_y,
}
# Call base class
super().__init__(parameter=parameter, **kwargs)
class MeasureScanSlits(AerotechFlyscanBase):
""" Coordinated scan
Measure a hardware coordinated relative line scan with the X- and Y axes.
This is used to accurately track solid supports with long linear grooves,
as theese might be slightly rotated.
The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion.
Example
-------
>>> scans.slit_scan(range=[10, 0.3], scan_time=20)
Parameters
----------
range_x : float
Move distance in X [mm].
range_y : float
Move distance in Y [mm].
velocity : float
Effective movement velocity [mm/s].
"""
scan_name = "slit_scan"
required_kwargs = ["range", "velocity"]
def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ["abr.gmx", "abr.gmy"]
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.abr_command = AbrCmd.SLIT_SCAN self.abr_command = AbrCmd.SLIT_SCAN
self.scan_delta_x = parameter['kwargs'].get("delta_x") self.scan_range_x = parameter['kwargs'].get("range_x")
self.scan_delta_y = parameter['kwargs'].get("delta_y") self.scan_range_y = parameter['kwargs'].get("range_y")
self.scan_velocity = parameter['kwargs'].get("velocity") self.scan_velocity = parameter['kwargs'].get("velocity")
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_delta_x, "var_1" : self.scan_range_x,
"var_2" : self.scan_delta_y, "var_2" : self.scan_range_y,
"var_3" : self.scan_velocity, "var_3" : self.scan_velocity,
} }
# Call base class # Call base class
@@ -215,40 +266,45 @@ class MeasureScanSlits(AerotechFlyscanBase):
class MeasureRasterSimple(AerotechFlyscanBase): class MeasureRasterSimple(AerotechFlyscanBase):
""" Simple raster scan """ Simple raster scan
Measure a simplified raster scan, assuming the goniometer is currently Measure a simplified relative zigzag raster scan in the X-Y plane.
at the CENTER of TOP-LEFT CELL. The scan is relative assumes the goniometer is currently at the CENTER of
the first cell (i.e. TOP-LEFT). Each line is executed as a single continous
movement, i.e. there's no actual stepping in the X direction.
The scan itself is executed by the scan service running on the Aerotech The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion. controller. Ophyd just configures, launches it and waits for completion.
Example Example
------- -------
>>> scans.raster_simple(exp_time=0.5, cell_width=0.2, cell_height=0.2, ncols=10, nrows=10) >>> scans.raster_simple(exp_time=0.1, range_x=4, range_y=4, steps_x=80, steps_y=80)
Parameters Parameters
---------- ----------
exp_time : (float) exp_time : float
Exposure time per point [s]. Effective exposure time for each cell along the X axis [s].
cell_width : (float) range_x : float
Scan step size [mm]. Scan step size [mm].
cell_height : (float) range_y : float
Scan step size [mm]. Scan step size [mm].
ncols : (int) steps_x : int
Number of scan steps. Number of scan steps in X (fast). Only used for velocity calculation.
nrows : (int) steps_y : int
Number of scan steps. Number of scan steps in Y (slow).
""" """
scan_name = "raster_simple" scan_name = "raster_simple"
required_kwargs = ["exp_time", "cell_width", "cell_height", "ncols", "nrows"] required_kwargs = ["exp_time", "range_x", "range_y", "steps_x", "steps_y"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = [] self.axis = ['abr.gmx', 'abr.gmy']
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.scan_exp_time = parameter['kwargs'].get("exp_time") self.scan_exp_time = parameter['kwargs'].get("exp_time")
self.scan_stepsize_x = parameter['kwargs'].get("cell_width") self.scan_range_x = parameter['kwargs'].get("range_x")
self.scan_stepsize_y = parameter['kwargs'].get("cell_height") self.scan_range_y = parameter['kwargs'].get("range_y")
self.scan_stepnum_x = parameter['kwargs'].get("ncols") self.scan_stepnum_x = parameter['kwargs'].get("steps_x")
self.scan_stepnum_y = parameter['kwargs'].get("nrows") self.scan_stepnum_y = parameter['kwargs'].get("steps_y")
self.scan_stepsize_x = self.scan_range_x / self.scan_stepnum_x
self.scan_stepsize_y = self.scan_range_y / self.scan_stepnum_y
self.abr_command = AbrCmd.RASTER_SCAN_SIMPLE self.abr_command = AbrCmd.RASTER_SCAN_SIMPLE
self.abr_raster_reset = True self.abr_raster_reset = True
self.abr_globals = { self.abr_globals = {
@@ -269,29 +325,33 @@ class MeasureRasterSimple(AerotechFlyscanBase):
class MeasureSASTT(AerotechFlyscanBase): class MeasureSASTT(AerotechFlyscanBase):
""" Small angle scanning tensor tomography scan """ Small angle scanning tensor tomography scan
Measure a Small Angle Scanning Tensor Tomography scan on the specified Measure a single projection for Small Angle Scanning Tensor Tomography.
grid assuming the goniometer is currently at the CENTER of the required It's essentially a separate grid scan, that can be modified independently.
grid. The scan is relative and assumes the goniometer is currently at the CENTER
of the first cell (i.e. TOP-LEFT). Each line is executed as a single
continous movement, there's no actual stepping in the X direction.
NOTE: Not all beamlines have all SASTT modes implemented.
The scan itself is executed by the scan service running on the Aerotech The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion. controller. Ophyd just configures, launches it and waits for completion.
Example Example
------- -------
>>> scans.measure_sastt(exp_time=1.0, cell_width=0.01, cell_height=0.01, ncols=100, nrows=100) >>> scans.measure_sastt(exp_time=0.01, range_x=1, range_y=1, steps_x=200, steps_y=200)
Parameters Parameters
---------- ----------
exp_time : (float) exp_time : float
Exposure time per point [s]. Effective exposure time for each cell along the X axis [s].
cell_width : (float) range_x : float
Scan step size [mm]. Scan step size [mm].
cell_height : (float) range_y : float
Scan step size [mm]. Scan step size [mm].
ncols : (int) steps_x : int
Number of scan steps. Number of scan steps in X (fast). Only used for velocity calculation.
nrows : (int) steps_y : int
Number of scan steps. Number of scan steps in Y (slow).
odd_tweak : (float) odd_tweak : (float)
Distance to be added before the open shutter command [mm]. Distance to be added before the open shutter command [mm].
Used only in scan version=3. Should be small (default: 0)! Used only in scan version=3. Should be small (default: 0)!
@@ -305,10 +365,10 @@ class MeasureSASTT(AerotechFlyscanBase):
3 = snake scan alternating PSO window for even/odd rows 3 = snake scan alternating PSO window for even/odd rows
""" """
scan_name = "measure_sastt" scan_name = "measure_sastt"
required_kwargs = ["exp_time", "cell_width", "cell_height", "ncols", "nrows"] required_kwargs = ["exp_time", "range_x", "range_y", "steps_x", "steps_y"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = [] self.axis = ['abr.gmx', 'abr.gmy']
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.scan_version = int(parameter['kwargs'].get("version", 1)) self.scan_version = int(parameter['kwargs'].get("version", 1))
if self.scan_version==1: if self.scan_version==1:
@@ -319,14 +379,18 @@ class MeasureSASTT(AerotechFlyscanBase):
self.abr_command = AbrCmd.SCAN_SASTT_V3 self.abr_command = AbrCmd.SCAN_SASTT_V3
else: else:
raise RuntimeError(f"Non existing SAS-TT scan mode: {self.scan_version}") raise RuntimeError(f"Non existing SAS-TT scan mode: {self.scan_version}")
# Set parameters from meaningful inputs
self.scan_exp_time = parameter['kwargs'].get("exp_time") self.scan_exp_time = parameter['kwargs'].get("exp_time")
self.scan_stepsize_x = parameter['kwargs'].get("cell_width") self.scan_range_x = parameter['kwargs'].get("range_x")
self.scan_stepsize_y = parameter['kwargs'].get("cell_height") self.scan_range_y = parameter['kwargs'].get("range_y")
self.scan_stepnum_x = parameter['kwargs'].get("ncols") self.scan_stepnum_x = parameter['kwargs'].get("steps_x")
self.scan_stepnum_y = parameter['kwargs'].get("nrows") self.scan_stepnum_y = parameter['kwargs'].get("steps_y")
self.scan_even_tweak = parameter['kwargs'].get("even_tweak", 0) self.scan_even_tweak = parameter['kwargs'].get("even_tweak", 0)
self.scan_odd_tweak = parameter['kwargs'].get("odd_tweak", 0) self.scan_odd_tweak = parameter['kwargs'].get("odd_tweak", 0)
self.scan_stepsize_x = self.scan_range_x / self.scan_stepnum_x
self.scan_stepsize_y = self.scan_range_y / self.scan_stepnum_y
self.abr_globals = { self.abr_globals = {
'var_1': self.scan_exp_time, 'var_1': self.scan_exp_time,
'var_2': self.scan_stepsize_x, 'var_2': self.scan_stepsize_x,
@@ -342,90 +406,57 @@ class MeasureSASTT(AerotechFlyscanBase):
class MeasureVerticalLine(AerotechFlyscanBase):
""" Vertical line scan using the GMY motor
Simple fly scan that records a single vertical line.
The line is nummCells * cellHeight long and the exposureTime is per cell.
The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion.
Example
-------
>>> scans.measure_vline(cell_height=12, cell_num=10, cell_time=20)
Parameters
----------
cell_height : (float)
Step size [mm].
cell_num : (int)
Scan range of the axis.
cell_time : (float)
Exposure time per cell [s]
"""
scan_name = "measure_vline"
required_kwargs = ["cell_time", "cell_height", "cell_num"]
def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ['gmy']
# Set parameters from meaningful inputs
self.scan_cell_time = parameter['kwargs'].get("cell_time")
self.scan_stepsize_y = parameter['kwargs'].get("cell_height")
self.scan_stepnum_y = parameter['kwargs'].get("cell_num")
self.abr_command = AbrCmd.VERTICAL_LINE_SCAN
self.abr_globals = {
'var_1': self.scan_cell_time,
'var_2': self.scan_stepsize_y,
'var_3': self.scan_stepnum_y,
}
# Call base class
super().__init__(parameter=parameter, **kwargs)
class MeasureScreening(AerotechFlyscanBase): class MeasureScreening(AerotechFlyscanBase):
""" Sample screening scan """ Sample screening scan
Sample screening scan that scans intervals on the rotation axis taking
1 image/interval. This makes sure that we hit diffraction peaks if there
are any crystals.
The scan itself is executed by the scan service running on the Aerotech The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion. controller. Ophyd just configures, launches it and waits for completion.
Example Example
------- -------
>>> scans.measure_screening(start=42, range=10, scan_time=20, degrees=180, frames=1800) >>> scans.measure_screening(start=42, range=180, steps=18, exp_time=0.1, oscrange=2.0)
Parameters Parameters
---------- ----------
start : float start : float
Scan start position of the axis. Absolute scan start position of the omega axis [deg].
range : float range : float
Scan range of the axis. Total screened range of the omega axis relative to 'start' [deg].
scan_time : float steps : int
Total scan time for the movement [s]. Number of blurred intervals.
degrees : (???) exp_time : float
frames : (???) Exposure time per blurred interval [s].
delta : (???) oscrange : float
(default: 0.5). Motion blurring of each interval [deg]
delta : float
Safety margin for sub-range movements (default: 0.5) [deg].
""" """
scan_name = "measure_screening" scan_name = "measure_screening"
required_kwargs = ["start", "range", "scan_time", "degrees", "frames"] required_kwargs = ["start", "range", "steps", "exp_time", "oscrange"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ['gmy'] self.axis = ['gmy']
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.scan_start = parameter['kwargs'].get("start") self.scan_start = parameter['kwargs'].get("start")
self.scan_range = parameter['kwargs'].get("range") self.scan_range_o = parameter['kwargs'].get("range")
self.scan_scan_time = parameter['kwargs'].get("scan_time") self.scan_stepnum_o = parameter['kwargs'].get("steps")
self.scan_degrees = parameter['kwargs'].get("degrees") self.scan_exp_time = parameter['kwargs'].get("exp_time")
self.scan_frames = parameter['kwargs'].get("frames") self.scan_oscrange = parameter['kwargs'].get("oscrange")
self.scan_delta = parameter['kwargs'].get("delta", 0.5) self.scan_delta = parameter['kwargs'].get("delta", 0.5)
self.scan_stepsize_o = self.scan_range_o / self.scan_stepnum_o
self.abr_command = AbrCmd.SCREENING self.abr_command = AbrCmd.SCREENING
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_start, "var_1" : self.scan_start,
"var_2" : self.scan_range, "var_2" : self.scan_oscrange,
"var_3" : self.scan_scan_time, "var_3" : self.scan_exp_time,
"var_4" : self.scan_degrees, "var_4" : self.scan_stepsize_o,
"var_5" : self.scan_frames, "var_5" : self.scan_stepnum_o,
"var_6" : self.scan_delta, "var_6" : self.scan_delta,
} }
# Call base class # Call base class
@@ -436,28 +467,32 @@ class MeasureScreening(AerotechFlyscanBase):
class MeasureFastOmega(AerotechFlyscanBase): class MeasureFastOmega(AerotechFlyscanBase):
""" Fast omega scan """ Fast omega scan
MEasures a fast rotational scan with the rotation stage (omega). Performs a fast rotational scan with the rotation stage (omega). It ramps
up to constant speed and sets off PSO for the expected travel time. I.e.
not really a PSO output (as it ignores acceleration distance) but it's
expected to trigger at-speed for 'range' distance.
The scan itself is executed by the scan service running on the Aerotech The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion. controller. Ophyd just configures, launches it and waits for completion.
Example Example
------- -------
>>> scans.measure_fast_omega(start=42, range=180, scan_time=20) >>> scans.measure_fast_omega(start=42, range=180, move_time=1.0)
Parameters Parameters
---------- ----------
start : float start : float
Scan start position of the axis. Scan start position of the axis [deg].
range : float range : float
Scan range of the axis. At-speed range of the axis relative to 'start' + acceleration
scan_time : float distance [deg].
Total scan time for the movement [s]. move_time : float
Total time for the at-speed movement and trigger [s].
rate : (???) rate : (???)
(default: 200). (default: 200).
""" """
scan_name = "measure_fast_omega" scan_name = "measure_fast_omega"
required_kwargs = ["start", "range", "scan_time"] required_kwargs = ["start", "range", "move_time"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ['omega'] self.axis = ['omega']
@@ -465,14 +500,14 @@ class MeasureFastOmega(AerotechFlyscanBase):
logger.info(parameter) logger.info(parameter)
self.scan_start = parameter['kwargs'].get("start") self.scan_start = parameter['kwargs'].get("start")
self.scan_range = parameter['kwargs'].get("range") self.scan_range = parameter['kwargs'].get("range")
self.scan_scan_time = parameter['kwargs'].get("scan_time") self.scan_move_time = parameter['kwargs'].get("move_time")
self.scan_rate = parameter['kwargs'].get("rate", 200) self.scan_acceleration = parameter['kwargs'].get("acceleration", 200)
self.abr_command = AbrCmd.SUPER_FAST_OMEGA self.abr_command = AbrCmd.SUPER_FAST_OMEGA
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_start, "var_1" : self.scan_start,
"var_2" : self.scan_range, "var_2" : self.scan_range,
"var_3" : self.scan_scan_time, "var_3" : self.scan_move_time,
"var_4" : self.scan_rate, "var_4" : self.scan_acceleration,
} }
# Call base class # Call base class
super().__init__(parameter=parameter, **kwargs) super().__init__(parameter=parameter, **kwargs)
@@ -482,42 +517,47 @@ class MeasureFastOmega(AerotechFlyscanBase):
class MeasureStillWedge(AerotechFlyscanBase): class MeasureStillWedge(AerotechFlyscanBase):
""" Still wedge scan """ Still wedge scan
Measure a simple step scan with the omega stage with PSO triggering.
The scan is similar to the continous wedge scan.
The scan itself is executed by the scan service running on the Aerotech The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion. controller. Ophyd just configures, launches it and waits for completion.
Example Example
------- -------
>>> scans.measure_still_wedge(start=42, range=90, scan_time=20, oscrange=15) >>> scans.measure_still_wedge(start=42, range=180, exp_time=0.1, steps=60)
Parameters Parameters
---------- ----------
start : (float) start : (float)
Scan start position of the axis. Scan start position of the axis [mm].
range : (float) range : (float)
Scan range of the axis. Scan range of the omega axis [mm].
scan_time : (float) exp_time : (float)
Total scan time for the movement [s]. Exposure time per point [s].
oscrange : (float) steps : int
Number of actual steps.
sleep_after_shutter_close : (float) sleep_after_shutter_close : (float)
[s] (default: 0.01). [s] (default: 0.01).
""" """
scan_name = "measure_still_wedge" scan_name = "measure_still_wedge"
required_kwargs = ["start", "range", "exp_time", "oscrange"] required_kwargs = ["start", "range", "exp_time", "steps"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ['omega'] self.axis = ['abr.omega']
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.scan_start = parameter['kwargs'].get("start") self.scan_start = parameter['kwargs'].get("start")
self.scan_range = parameter['kwargs'].get("range") self.scan_range = parameter['kwargs'].get("range")
self.scan_scan_time = parameter['kwargs'].get("scan_time") self.scan_stepnum_o = parameter['kwargs'].get("steps")
self.scan_oscrange = parameter['kwargs'].get("oscrange") self.scan_exp_time = parameter['kwargs'].get("exp_time")
self.scan_shutter_sleep = parameter['kwargs'].get("sleep_after_shutter_close", 0.01) self.scan_shutter_sleep = parameter['kwargs'].get("sleep_after_shutter_close", 0.01)
self.scan_stepsize_o = self.scan_stepnum_o / self.scan_stepnum_o
self.abr_command = AbrCmd.STILL_WEDGE self.abr_command = AbrCmd.STILL_WEDGE
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_start, "var_1" : self.scan_start,
"var_2" : self.scan_range, "var_2" : self.scan_range,
"var_3" : self.scan_scan_time, "var_3" : self.scan_exp_time,
"var_4" : self.scan_oscrange, "var_4" : self.scan_stepsize_o,
"var_5" : self.scan_shutter_sleep, "var_5" : self.scan_shutter_sleep,
} }
# Call base class # Call base class
@@ -528,37 +568,37 @@ class MeasureStillWedge(AerotechFlyscanBase):
class MeasureStills(AerotechFlyscanBase): class MeasureStills(AerotechFlyscanBase):
""" Still image sequence scan """ Still image sequence scan
Measures a series of still images without any motor movement. Measures a series of PSO triggered images without any motor movement.
IMPORTANT: use idle_time=0.0 to prevent shutter open/close NOTE: Use idle_time=0.0 to prevent shutter open/close.
The scan itself is executed by the scan service running on the Aerotech The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion. controller. Ophyd just configures, launches it and waits for completion.
Example Example
------- -------
>>> scans.measure_stills(nframes=100, exp_time=0.1, idle_time=30) >>> scans.measure_stills(steps=100, exp_time=0.1, idle_time=3)
Parameters Parameters
---------- ----------
nframes : int steps : int
Total number of frames to be recorded. Total number of frames to be recorded.
exposure_time : float exp_time : float
Exposure time of each frame [s]. Exposure time of each frame [s].
idle_time : float idle_time : float
Sleep time between the frames [s]. Sleep time between the frames [s].
""" """
scan_name = "measure_stills" scan_name = "measure_stills"
required_kwargs = ["exp_time", "nframes", "idle_time"] required_kwargs = ["exp_time", "steps", "idle_time"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = [] self.axis = []
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.scan_exp_time = parameter['kwargs'].get("exp_time") self.scan_exp_time = parameter['kwargs'].get("exp_time")
self.scan_num_frames = parameter['kwargs'].get("nframes") self.scan_numsteps = parameter['kwargs'].get("steps")
self.scan_idle_time = parameter['kwargs'].get("idle_time") self.scan_idle_time = parameter['kwargs'].get("idle_time")
self.abr_command = AbrCmd.STILLS self.abr_command = AbrCmd.STILLS
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_num_frames, "var_1" : self.scan_numsteps,
"var_2" : self.scan_exp_time, "var_2" : self.scan_exp_time,
"var_3" : self.scan_idle_time, "var_3" : self.scan_idle_time,
} }
@@ -570,42 +610,44 @@ class MeasureStills(AerotechFlyscanBase):
class MeasureSingleOscillation(AerotechFlyscanBase): class MeasureSingleOscillation(AerotechFlyscanBase):
""" Single oscillation scan """ Single oscillation scan
Short line scan with the omega axis with PSO trigger.
The scan itself is executed by the scan service running on the Aerotech The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion. controller. Ophyd just configures, launches it and waits for completion.
Example Example
------- -------
>>> scans.measure_single_osc(start=42, range=180, scan_time=20) >>> scans.measure_single_osc(start=42, range=180, move_time=20)
Parameters Parameters
---------- ----------
start : float start : float
Scan start position of the axis. Scan start position of the omegaaxis [mm].
range : float range : float
Oscillation range of the axis. Oscillation range of the axis [mm].
scan_time : float move_time : float
Total scan time for the movement [s]. Total scan time for the movement [s].
delta : (???) delta : (???)
(default: 0). Safety margin for movement (default: 0).
settle : (???) settle : (???)
(default: 0.5). (default: 0.5).
""" """
scan_name = "measure_single_osc" scan_name = "measure_single_osc"
required_kwargs = ["start", "range", "scan_time"] required_kwargs = ["start", "range", "move_time"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ['omega'] self.axis = ['abr.omega']
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.scan_start = parameter['kwargs'].get("start") self.scan_start = parameter['kwargs'].get("start")
self.scan_range = parameter['kwargs'].get("range") self.scan_range = parameter['kwargs'].get("range")
self.scan_scan_time = parameter['kwargs'].get("scan_time") self.scan_move_time = parameter['kwargs'].get("move_time")
self.scan_delta = parameter['kwargs'].get("delta", 0) self.scan_delta = parameter['kwargs'].get("delta", 0)
self.scan_settle = parameter['kwargs'].get("settle", 0.5) self.scan_settle = parameter['kwargs'].get("settle", 0.5)
self.abr_command = AbrCmd.SINGLE_OSCILLATION self.abr_command = AbrCmd.SINGLE_OSCILLATION
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_start, "var_1" : self.scan_start,
"var_2" : self.scan_range, "var_2" : self.scan_range,
"var_3" : self.scan_scan_time, "var_3" : self.scan_move_time,
"var_4" : self.scan_delta, "var_4" : self.scan_delta,
"var_5" : self.scan_settle, "var_5" : self.scan_settle,
} }
@@ -617,41 +659,44 @@ class MeasureSingleOscillation(AerotechFlyscanBase):
class MeasureRepeatedOscillation(AerotechFlyscanBase): class MeasureRepeatedOscillation(AerotechFlyscanBase):
""" Repeated oscillation scan """ Repeated oscillation scan
Repeated relative line scans with the omega axis with PSO enable trigger.
The lines are performed in zigzag mode with PSO triggering.
The scan itself is executed by the scan service running on the Aerotech The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion. controller. Ophyd just configures, launches it and waits for completion.
Example Example
------- -------
>>> scans.measure_multi_osc(start=42, range=180, scan_time=20) >>> scans.measure_multi_osc(steps=50, range=30, move_time=3)
Parameters Parameters
---------- ----------
nframes : int steps : int
??? Number of cycles to repeat the scan
scan_time : float move_time : float
Total scan time for the movement [s]. Total scan time for the movement [s].
range : float range : float
Oscillation range of the axis. Relative oscillation range of the omega axis [deg].
settle : (???) settle : (???)
(default: 0). Movement settle time after each line (default: 0) [s].
delta : (???) delta : (???)
(default: 0.5). Safety margin for movement (default: 0.5) [deg].
""" """
scan_name = "measure_multi_osc" scan_name = "measure_multi_osc"
required_kwargs = ["nframes", "range", "scan_time"] required_kwargs = ["steps", "range", "scan_time"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ['omega'] self.axis = ['omega']
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.scan_num_frames = parameter['kwargs'].get("nframes") self.scan_stepnum = parameter['kwargs'].get("steps")
self.scan_range = parameter['kwargs'].get("range") self.scan_range = parameter['kwargs'].get("range")
self.scan_scan_time = parameter['kwargs'].get("scan_time") self.scan_move_time = parameter['kwargs'].get("move_time")
self.scan_sleep = parameter['kwargs'].get("sleep", 0) self.scan_sleep = parameter['kwargs'].get("sleep", 0)
self.scan_delta = parameter['kwargs'].get("delta", 0.5) self.scan_delta = parameter['kwargs'].get("delta", 0.5)
self.abr_command = AbrCmd.REPEAT_SINGLE_OSCILLATION self.abr_command = AbrCmd.REPEAT_SINGLE_OSCILLATION
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_num_frames, "var_1" : self.scan_stepnum,
"var_2" : self.scan_scan_time, "var_2" : self.scan_move_time,
"var_3" : self.scan_range, "var_3" : self.scan_range,
"var_4" : self.scan_sleep, "var_4" : self.scan_sleep,
"var_5" : self.scan_delta, "var_5" : self.scan_delta,
@@ -664,12 +709,15 @@ class MeasureRepeatedOscillation(AerotechFlyscanBase):
class MeasureMSOX(AerotechFlyscanBase): class MeasureMSOX(AerotechFlyscanBase):
""" Standard MSOX scan """ Standard MSOX scan
MSOX experiment for Florian, i.e. a glorified oscillation scan this time
with absolute positions. The lines are unidirectional with PSO triggering.
The scan itself is executed by the scan service running on the Aerotech The scan itself is executed by the scan service running on the Aerotech
controller. Ophyd just configures, launches it and waits for completion. controller. Ophyd just configures, launches it and waits for completion.
Example Example
------- -------
>>> scans.measure_msox(start=42, range=10, exp_time=0.1) >>> scans.measure_msox(start=42, range=30, move_time=3.0)
Parameters Parameters
---------- ----------
@@ -677,32 +725,32 @@ class MeasureMSOX(AerotechFlyscanBase):
Scan start position of the axis. Scan start position of the axis.
range : float range : float
Scan range of the axis. Scan range of the axis.
exp_time : float move_time : float
Exposure time for each point [s]. Exposure time for each point [s].
num_datasets : int steps : int
??? Number of repeats.
rest_time : float settle_time : float
??? Settle time before line start (default=0) [s].
""" """
scan_name = "measure_msox" scan_name = "measure_msox"
required_kwargs = ["start", "range", "exp_time"] required_kwargs = ["start", "range", "move_time"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ['omega'] self.axis = ['abr.omega']
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.scan_start = parameter['kwargs'].get("start") self.scan_start = parameter['kwargs'].get("start")
self.scan_range = parameter['kwargs'].get("range") self.scan_range = parameter['kwargs'].get("range")
self.scan_exp_time = parameter['kwargs'].get("exp_time") self.scan_move_time = parameter['kwargs'].get("move_time")
self.scan_num_datasets = parameter['kwargs'].get("num_datasets", 1) self.scan_stepnum = parameter['kwargs'].get("steps", 1)
self.scan_rest_time = parameter['kwargs'].get("rest_time", 0) self.scan_settle_time = parameter['kwargs'].get("settle_time", 0)
self.abr_command = AbrCmd.MSOX self.abr_command = AbrCmd.MSOX
self.abr_reset = True self.abr_reset = True
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_start, "var_1" : self.scan_start,
"var_2" : self.scan_range, "var_2" : self.scan_range,
"var_3" : self.scan_exp_time, "var_3" : self.scan_move_time,
"var_4" : self.scan_num_datasets, "var_4" : self.scan_stepnum,
"var_5" : self.scan_rest_time, "var_5" : self.scan_settle_time,
"var_6" : 0, "var_6" : 0,
"var_7" : 0, "var_7" : 0,
"var_8" : 0, "var_8" : 0,
@@ -717,6 +765,11 @@ class MeasureMSOX(AerotechFlyscanBase):
class MeasureGrid(AerotechFlyscanBase): class MeasureGrid(AerotechFlyscanBase):
""" General grid scan """ General grid scan
Performs an X-Y-Omega coordinated grid scan:
X axis is absolute (fast axis)
Y axis is relative to start
Omega starts at the current value and is synchronized to X
Note: This was probably never used in its current form, because the Note: This was probably never used in its current form, because the
code had an undefined variable 'self.position' code had an undefined variable 'self.position'
@@ -731,12 +784,14 @@ class MeasureGrid(AerotechFlyscanBase):
---------- ----------
positions : 2D-array positions : 2D-array
Scan position of each axis, i.e. (N, 3) shaped array. Scan position of each axis, i.e. (N, 3) shaped array.
ncols : int steps_x : int
Nmber of columns. Number of points along the X axis (fast).
steps_y : int
Number of points in the Y axis (slow).
angle: angle:
??? Triggered angular range on the synchronized omega [deg]
exp_time : (float) exp_time : (float)
Exposure time for each point [s]. Exposure time for each point, only used for number of points and velocity [s].
""" """
scan_name = "measure_raster" scan_name = "measure_raster"
required_kwargs = ["positions", "ncols", "angle", "exp_time"] required_kwargs = ["positions", "ncols", "angle", "exp_time"]
@@ -750,16 +805,19 @@ class MeasureGrid(AerotechFlyscanBase):
scan_gmy_step = 0.010 scan_gmy_step = 0.010
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ['omega'] self.axis = ['abr.omega', 'abr.gmx', 'abr.gmy']
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.abr_command = AbrCmd.RASTER_SCAN self.abr_command = AbrCmd.RASTER_SCAN
self.abr_reset = True self.abr_reset = True
self.scan_positions = parameter['kwargs'].get("positions") self.scan_positions = parameter['kwargs'].get("positions")
self.scan_stepnum_x = parameter['kwargs'].get("ncols") self.scan_stepnum_x = parameter['kwargs'].get("steps_x")
self.scan_stepnum_y = self.scan_positions / self.scan_stepnum_x self.scan_stepnum_y = parameter['kwargs'].get("steps_y")
self.scan_angle = parameter['kwargs'].get("angle") self.scan_anglerange = parameter['kwargs'].get("angle")
self.scan_exp_time = parameter['kwargs'].get("exp_time") self.scan_exp_time = parameter['kwargs'].get("exp_time")
if len(self.scan_positions) != self.scan_stepnum_x * self.scan_stepnum_y:
raise RuntimeError("Number of points and positions do not match")
if len(self.scan_positions)==1: if len(self.scan_positions)==1:
raise RuntimeWarning("Raster scan with one cell makes no sense") raise RuntimeWarning("Raster scan with one cell makes no sense")
@@ -784,26 +842,17 @@ class MeasureGrid(AerotechFlyscanBase):
self.scan_gmy_step = np.linalg.norm([self.scan_ystep, self.scan_zstep]) self.scan_gmy_step = np.linalg.norm([self.scan_ystep, self.scan_zstep])
# ToDo: Check with Zac what are theese parameters # ToDo: Check with Zac what are theese parameters
self.scan_omega_position = yield from self.stubs.send_rpc_and_wait("abs", "omega.readback.get") self.scan_start_o = yield from self.stubs.send_rpc_and_wait("abs", "omega.readback.get")
self.scan_gmx_offset = yield from self.stubs.send_rpc_and_wait("abs", "gmx.readback.get") self.scan_gmx_offset = yield from self.stubs.send_rpc_and_wait("abs", "gmx.readback.get")
# ToDo : This was left out
# self._raster_starting_x = start_x
# self._raster_starting_y = y1
# self._raster_starting_z = z1
# self._raster_step_y = ystep
# self._raster_step_z = zstep
# self._raster_current_row = 0
# self._raster_num_rows = rows
# Configure the global variables # Configure the global variables
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_omega_position, "var_1" : self.scan_start_o,
"var_2" : self.scan_start_x, "var_2" : self.scan_start_x,
"var_3" : self.scan_end_x, "var_3" : self.scan_end_x,
"var_4" : self.scan_stepnum_x, "var_4" : self.scan_stepnum_x,
"var_5" : self.scan_stepnum_y, "var_5" : self.scan_stepnum_y,
"var_6" : self.scan_angle, "var_6" : self.scan_anglerange,
"var_7" : self.scan_exp_time, "var_7" : self.scan_exp_time,
"var_8" : HALF_PERIOD, "var_8" : HALF_PERIOD,
"var_9" : self.scan_gmx_offset, "var_9" : self.scan_gmx_offset,
@@ -815,6 +864,11 @@ class MeasureGrid(AerotechFlyscanBase):
class MeasureGridStill(AerotechFlyscanBase): class MeasureGridStill(AerotechFlyscanBase):
""" Still grid scan """ Still grid scan
Performs an X-Y-Omega coordinated grid scan in stepping mode:
X axis is absolute
Y axis is relative to start
Omega starts at the current value and is synchronized to X
Note: This was probably never used in its current form, because the Note: This was probably never used in its current form, because the
code had an undefined variable 'self.position' code had an undefined variable 'self.position'
@@ -823,7 +877,7 @@ class MeasureGridStill(AerotechFlyscanBase):
Example Example
------- -------
>>> scans.measure_raster(positions=[[11, 2, 3.4], [11, 2, 3.5], ...], columns=20, exp_time=0.1, delay=0.05) >>> scans.measure_raster(positions=[[11, 2, 3.4], [11, 2, 3.5], ...], steps_x=20, steps_y=20, exp_time=0.1, delay=0.05)
Parameters Parameters
---------- ----------
@@ -839,7 +893,7 @@ class MeasureGridStill(AerotechFlyscanBase):
??? ???
""" """
scan_name = "measure_raster_still" scan_name = "measure_raster_still"
required_kwargs = ["positions", "columns", "exp_time", "delay"] required_kwargs = ["positions", "steps_x", "steps_y", "exp_time", "delay"]
# Default values # Default values
scan_start_x = None scan_start_x = None
@@ -850,16 +904,19 @@ class MeasureGridStill(AerotechFlyscanBase):
scan_gmy_step = 0.010 scan_gmy_step = 0.010
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ['omega'] self.axis = ['abr.gmx', 'abr.gmy', 'abr.omega']
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.abr_command = AbrCmd.RASTER_SCAN_STILL self.abr_command = AbrCmd.RASTER_SCAN_STILL
self.abr_reset = True self.abr_reset = True
self.scan_positions = parameter['kwargs'].get("positions") self.scan_positions = parameter['kwargs'].get("positions")
self.scan_stepnum_x = parameter['kwargs'].get("columns") self.scan_stepnum_x = parameter['kwargs'].get("steps_x")
self.scan_stepnum_y = self.scan_positions / self.scan_stepnum_x self.scan_stepnum_y = parameter['kwargs'].get("steps_y")
self.scan_exp_time = parameter['kwargs'].get("exp_time") self.scan_exp_time = parameter['kwargs'].get("exp_time")
self.scan_delay = parameter['kwargs'].get("delay") self.scan_delay = parameter['kwargs'].get("delay")
if len(self.scan_positions) != self.scan_stepnum_x * self.scan_stepnum_y:
raise RuntimeError("Number of points and positions do not match")
if len(self.scan_positions)==1: if len(self.scan_positions)==1:
raise RuntimeWarning("Raster scan with one cell makes no sense") raise RuntimeWarning("Raster scan with one cell makes no sense")
# Call base class # Call base class
@@ -886,15 +943,6 @@ class MeasureGridStill(AerotechFlyscanBase):
self.scan_omega_position = yield from self.stubs.send_rpc_and_wait("abs", "omega.readback.get") self.scan_omega_position = yield from self.stubs.send_rpc_and_wait("abs", "omega.readback.get")
self.scan_gmx_offset = yield from self.stubs.send_rpc_and_wait("abs", "gmx.readback.get") self.scan_gmx_offset = yield from self.stubs.send_rpc_and_wait("abs", "gmx.readback.get")
# ToDo : This was left out
# self._raster_starting_x = start_x
# self._raster_starting_y = y1
# self._raster_starting_z = z1
# self._raster_step_y = ystep
# self._raster_step_z = zstep
# self._raster_current_row = 0
# self._raster_num_rows = rows
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_omega_position, "var_1" : self.scan_omega_position,
"var_2" : self.scan_start_x, "var_2" : self.scan_start_x,
@@ -922,13 +970,13 @@ class MeasureJungfrau(AerotechFlyscanBase):
Parameters Parameters
---------- ----------
columns : int steps_x : int
??? ???
rows : int steps_y : int
??? ???
width : int range_x : int
??? ???
height : int range_y : int
??? ???
exp_time : float exp_time : float
Exposure time per point [s]. Exposure time per point [s].
@@ -936,15 +984,17 @@ class MeasureJungfrau(AerotechFlyscanBase):
(default: 0.1). (default: 0.1).
""" """
scan_name = "measure_jungfrau" scan_name = "measure_jungfrau"
required_kwargs = ["columns", "rows", "width", "height", "exp_time"] required_kwargs = ["steps_x", "steps_y", "range_x", "range_y", "exp_time"]
def __init__(self, *args, parameter: dict = None, **kwargs): def __init__(self, *args, parameter: dict = None, **kwargs):
self.axis = ['omega'] self.axis = ['omega']
# Set parameters from meaningful inputs # Set parameters from meaningful inputs
self.scan_num_cols = parameter['kwargs'].get("columns") self.scan_stepnum_x = parameter['kwargs'].get("steps_x")
self.scan_num_rows = parameter['kwargs'].get("rows") self.scan_stepnum_y = parameter['kwargs'].get("steps_y")
self.scan_width = parameter['kwargs'].get("width") self.scan_range_x = parameter['kwargs'].get("range_x")
self.scan_height = parameter['kwargs'].get("height") self.scan_range_y = parameter['kwargs'].get("range_y")
self.scan_stepsize_x = self.scan_range_x / self.scan_stepnum_x
self.scan_stepsize_y = self.scan_range_y / self.scan_stepnum_y
self.scan_exp_time = parameter['kwargs'].get("exp_time") self.scan_exp_time = parameter['kwargs'].get("exp_time")
self.scan_sleep = parameter['kwargs'].get("sleep", 0.1) self.scan_sleep = parameter['kwargs'].get("sleep", 0.1)
self.abr_timeout = None if self.scan_sleep <= 0 else 5.0 + (self.scan_num_rows * self.scan_sleep) + (self.scan_num_cols * self.scan_num_rows * self.scan_exp_time) self.abr_timeout = None if self.scan_sleep <= 0 else 5.0 + (self.scan_num_rows * self.scan_sleep) + (self.scan_num_cols * self.scan_num_rows * self.scan_exp_time)
@@ -952,10 +1002,10 @@ class MeasureJungfrau(AerotechFlyscanBase):
self.abr_reset = True self.abr_reset = True
self.abr_complete = True self.abr_complete = True
self.abr_globals = { self.abr_globals = {
"var_1" : self.scan_num_cols, "var_1" : self.scan_stepnum_x,
"var_2" : self.scan_num_rows, "var_2" : self.scan_stepnum_y,
"var_3" : self.scan_width, "var_3" : self.scan_stepsize_x,
"var_4" : self.scan_height, "var_4" : self.scan_stepsize_y,
"var_5" : self.scan_exp_time, "var_5" : self.scan_exp_time,
"var_6" : self.scan_sleep, "var_6" : self.scan_sleep,
"var_7" : 0, "var_7" : 0,