Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: multi stream help #3

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
38 changes: 36 additions & 2 deletions startup/10-area-detector.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from ophyd import Component as Cpt
from ophyd.areadetector.filestore_mixins import FileStoreHDF5IterativeWrite
from ophyd.areadetector.filestore_mixins import (
FileStoreHDF5IterativeWrite,
FileStoreIterativeWrite,
FileStorePluginBase,
)
from ophyd import EpicsSignal, AreaDetector
from ophyd import (
ImagePlugin,
Expand Down Expand Up @@ -40,9 +44,22 @@ def ensure_nonblocking(self):
cpt.ensure_nonblocking()


class HDF5PluginWithFileStore(HDF5Plugin, FileStoreHDF5IterativeWrite):
class HDF5PluginWithFileStore(HDF5Plugin, FileStorePluginBase):
# AD v2.2.0 (at least) does not have this. It is present in v1.9.1.
file_number_sync = None
filestore_spec = "AD_HDF5_v1"

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# can not be class level because parent sets this in __init__ :(
self.stage_sigs.update(
[
("file_template", "%s%s_%6.6d.h5"),
("file_write_mode", "Stream"),
("capture", 1),
]
)
self._current_index = 0

def get_frames_per_point(self):
return self.parent.cam.num_images.get()
Expand All @@ -52,6 +69,22 @@ def make_filename(self):
self._ret = super().make_filename()
return self._ret

def stage(self):
super().stage()
self._current_index = 0
res_kwargs = {}
self._generate_resource(res_kwargs)

def generate_datum(self, key, timestamp, datum_kwargs):
step = self.get_frames_per_point()

datum_kwargs = datum_kwargs or {}
datum_kwargs.update({"offset": self._current_index, "num_frames": step})

self._current_index += step

return super().generate_datum(key, timestamp, datum_kwargs)


class AndorKlass(SingleTriggerV33, DetectorBase):
cam = Cpt(AndorCam, "cam1:")
Expand Down Expand Up @@ -267,6 +300,7 @@ def resume(self):


for det in [detA1, Andor]:
det.cam.num_images.kind = 'config'
det.stats1.total.kind = "hinted"
# It does not work since it's not defined in the class, commenting out:
# det.stats5.total.kind = 'hinted'
2 changes: 1 addition & 1 deletion startup/20-global_param.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# ZONE_DIAMETER = 200 # 200 um ### xridia zone plate
OUT_ZONE_WIDTH = ZONE_PLATE["OUT_ZONE_WIDTH"] # 30 nm
ZONE_DIAMETER = ZONE_PLATE["ZONE_DIAMETER"] # new commercial zone plate

zp.wait_for_connection()
GLOBAL_VLM_MAG = 10 # vlm magnification
GLOBAL_MAG = np.round((DetU.z.position / zp.z.position - 1) * GLOBAL_VLM_MAG, 2)
CURRENT_MAG_1 = GLOBAL_MAG
Expand Down
53 changes: 30 additions & 23 deletions startup/40-scans.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,16 @@ def _set_andor_param(exposure_time=0.1, period=0.1, chunk_size=1):

yield from abs_set(Andor.cam.acquire, 0, wait=True)
yield from abs_set(Andor.cam.image_mode, 0, wait=True)
yield from abs_set(Andor.cam.num_images, chunk_size, wait=True)
yield from abs_set(Andor.cam.acquire_time, exposure_time, wait=True)
Andor.cam.acquire_period.put(period)

yield from bps.configure(
Andor.cam,
{
Andor.cam.num_images.attr_name: chunk_size,
# Andor.cam.acquire_time.attr_name: exposure_time,
# Andor.cam.acquire_period.attr_name: period,
},
)
yield from bps.configure(Andor, {})


def _set_rotation_speed(rs=1):
Expand Down Expand Up @@ -914,7 +921,7 @@ def eng_scan(
detectors: list, detector list, e.g.[ic3, ic4, Andor]

delay_time: float, delay time after moving motors, in sec

"""

det = [det.name for det in detectors]
Expand Down Expand Up @@ -992,7 +999,7 @@ def eng_scan_delay(

delay_time: float, delay time after moving motors, in sec

note: string
note: string

"""
global ZONE_PLATE
Expand Down Expand Up @@ -1234,7 +1241,7 @@ def fly_scan(
-------
exposure_time: float, in unit of sec

relative_rot_angle: float,
relative_rot_angle: float,
total rotation angles start from current rotary stage (zps.pi_r) position

period: float, in unit of sec
Expand Down Expand Up @@ -1268,7 +1275,7 @@ def fly_scan(
simu: Bool, default is False
True: will simulate closing/open shutter without really closing/opening
False: will really close/open shutter

"""
global ZONE_PLATE
motor_x_ini = zps.sx.position
Expand Down Expand Up @@ -1497,7 +1504,7 @@ def grid2D_rel_inner():

def delay_count(detectors, num=1, delay=None, *, note="", plot_flag=0, md=None):
"""
same function as the default "count",
same function as the default "count",
re_write it in order to add auto-logging
"""
global ZONE_PLATE
Expand Down Expand Up @@ -1591,7 +1598,7 @@ def delay_scan(
if 0: not plot

note: string

"""
global ZONE_PLATE
if Andor in detectors:
Expand Down Expand Up @@ -1683,7 +1690,7 @@ def xanes_3d_scan(eng_list, exposure_time, relative_rot_angle, period, chunk_siz
insert_text(txt)
print(txt)


for eng in eng_list:
RE(move_zp_ccd(eng))
RE(fly_scan(exposure_time, relative_rot_angle, period, chunk_size, out_x, out_y, rs, parkpos, note))
Expand Down Expand Up @@ -1721,7 +1728,7 @@ def raster_2D_scan(
Inputs:
-------

x_range: two-elements list, e.g., [-1, 1], in unit of horizontal screen size
x_range: two-elements list, e.g., [-1, 1], in unit of horizontal screen size

y_range: two-elements list, e.g., [-1, 1], in unit of horizontal screen size

Expand All @@ -1742,7 +1749,7 @@ def raster_2D_scan(
out_r: float, default is 0
relative movement of sample by rotating "out_r" degrees, using zps.pi_r to move out sample
NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z

img_sizeX: int, default is 2560, it is the pixel number for Andor camera horizontal

img_sizeY: int, default is 2160, it is the pixel number for Andor camera vertical
Expand All @@ -1758,7 +1765,7 @@ def raster_2D_scan(
simu: Bool, default is False
True: will simulate closing/open shutter without really closing/opening
False: will really close/open shutter

"""
global ZONE_PLATE
motor = [zps.sx, zps.sy, zps.sz, zps.pi_r]
Expand Down Expand Up @@ -1926,7 +1933,7 @@ def raster_2D_scan2(
Inputs:
-------

x_range: two-elements list, e.g., [-1, 1], in unit of horizontal screen size
x_range: two-elements list, e.g., [-1, 1], in unit of horizontal screen size

y_range: two-elements list, e.g., [-1, 1], in unit of horizontal screen size

Expand All @@ -1947,7 +1954,7 @@ def raster_2D_scan2(
out_r: float, default is 0
relative movement of sample by rotating "out_r" degrees, using zps.pi_r to move out sample
NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z

img_sizeX: int, default is 2560, it is the pixel number for Andor camera horizontal

img_sizeY: int, default is 2160, it is the pixel number for Andor camera vertical
Expand All @@ -1963,7 +1970,7 @@ def raster_2D_scan2(
simu: Bool, default is False
True: will simulate closing/open shutter without really closing/opening
False: will really close/open shutter

"""
global ZONE_PLATE
motor = [zps.sx, zps.sy, zps.sz, zps.pi_r]
Expand Down Expand Up @@ -2188,7 +2195,7 @@ def multipos_2D_xanes_scan2(

For example:
RE(multipos_2D_xanes_scan2(Ni_eng_list, x_list=[0,1,2], y_list=[2,3,4], z_list=[0,0,0], r_list=[0,0,0], out_x=1000, out_y=0, out_z=0, out_r=90, repeat_num=2, exposure_time=0.1, sleep_time=60, chunk_size=5, relative_move_flag=True, note='sample')

Inputs:
--------
eng_list: list or numpy array,
Expand Down Expand Up @@ -2221,7 +2228,7 @@ def multipos_2D_xanes_scan2(
out_r: float, default is 0
relative movement of sample by rotating "out_r" degrees, using zps.pi_r to move out sample
NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z

repeat_num: integer, default is 1
repeating multiposition xanes scans

Expand All @@ -2233,13 +2240,13 @@ def multipos_2D_xanes_scan2(

chunk_size: int
number of background images == num of dark images == num of image for each energy

relative_move_flag:
if 1: relative movement of out_x, out_y, out_z, and out_r
if 0: set absolute position of x, y, z, r to move out sample

note: string

"""
print(eng_list)
print(x_list)
Expand Down Expand Up @@ -2427,7 +2434,7 @@ def multipos_2D_xanes_scan3(

For example:
RE(multipos_2D_xanes_scan3(Ni_eng_list, x_list=[0,1,2], y_list=[2,3,4], z_list=[0,0,0], r_list=[0,0,0], out_x=1000, out_y=0, out_z=0, out_r=90, repeat_num=2, sleep_time=60, note='sample')

Inputs:
--------
eng_list: list or numpy array,
Expand Down Expand Up @@ -2471,7 +2478,7 @@ def multipos_2D_xanes_scan3(
number of background images == num of dark images == num of image for each energy

note: string

"""
global ZONE_PLATE
txt = "starting multipos_2D_xanes_scan3"
Expand Down Expand Up @@ -2736,7 +2743,7 @@ def repeat_multipos_2D_xanes_scan2(eng_list, x_list, y_list, z_list, r_list, out

txt = f'starting "repeat_multipos_2D_xanes_scan2", consists of following scans:'
print(txt)
insert_text(txt)
insert_text(txt)
for i in range(repeat_num):
print(f'repeat #{i}:\n ')
yield from multipos_2D_xanes_scan2(eng_list, x_list, y_list, z_list, r_list, out_x, out_y, out_z, out_r, exposure_time, chunk_size, simu, relative_move_flag, note, md)
Expand Down
5 changes: 3 additions & 2 deletions startup/93-load_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,9 @@ def export_fly_scan(h):
imgs = imgs[1:-1]
s1 = imgs.shape
imgs = imgs.reshape([s1[0] * s1[1], s1[2], s1[3]])

with db.reg.handler_context({"AD_HDF5": AreaDetectorHDF5TimestampHandler}):
from area_detector_handlers.handlers import HDF5VariableFramesHandlerTS
with db.reg.handler_context({"AD_HDF5": AreaDetectorHDF5TimestampHandler,
"AD_HDF5_v1": HDF5VariableFramesHandlerTS}):
chunked_timestamps = list(h.data("Andor_image"))

chunked_timestamps = chunked_timestamps[1:-1]
Expand Down