diff --git a/startup/00-base.py b/startup/00-base.py index 2d66176..f445bf9 100644 --- a/startup/00-base.py +++ b/startup/00-base.py @@ -4,35 +4,6 @@ from datetime import datetime from ophyd.signal import EpicsSignalBase, EpicsSignal, DEFAULT_CONNECTION_TIMEOUT -try: - from bluesky_queueserver import is_re_worker_active, parameter_annotation_decorator - -except ImportError: - # Remove the try..except once 'bluesky_queueserver' is included in the collection environment - - def is_re_worker_active(): - return False - - import functools - - def parameter_annotation_decorator(annotation): - def function_wrap(func): - if inspect.isgeneratorfunction(func): - - @functools.wraps(func) - def wrapper(*args, **kwargs): - return (yield from func(*args, **kwargs)) - - else: - - @functools.wraps(func) - def wrapper(*args, **kwargs): - return func(*args, **kwargs) - - return wrapper - - return function_wrap - def print_now(): return datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S.%f") @@ -76,10 +47,9 @@ def wait_for_connection(self, timeout=DEFAULT_CONNECTION_TIMEOUT): from datetime import datetime # Register bluesky IPython magics. -if not is_re_worker_active(): - from bluesky.magics import BlueskyMagics +from bluesky.magics import BlueskyMagics - get_ipython().register_magics(BlueskyMagics) +get_ipython().register_magics(BlueskyMagics) from bluesky.preprocessors import stage_decorator, run_decorator from databroker.v0 import Broker @@ -89,11 +59,6 @@ def wait_for_connection(self, timeout=DEFAULT_CONNECTION_TIMEOUT): nslsii.configure_base(get_ipython().user_ns, db, bec=True) -# The following plan stubs should not be imported directly in the global namespace. -# Otherwise Queue Server will not be able to load the startup files. -del one_1d_step -del one_nd_step -del one_shot # Make new RE.md storage available in old environments. from pathlib import Path diff --git a/startup/10-area-detector.py b/startup/10-area-detector.py index bd50206..292b7a9 100644 --- a/startup/10-area-detector.py +++ b/startup/10-area-detector.py @@ -144,7 +144,6 @@ class AndorKlass(SingleTriggerV33, DetectorBase): ) ac_period = Cpt(EpicsSignal, "cam1:AcquirePeriod") - binning = Cpt(EpicsSignal, "cam1:A3Binning") def stop(self): self.hdf5.capture.put(0) diff --git a/startup/11-txm_motor.py b/startup/11-txm_motor.py index e9c0860..0bda618 100644 --- a/startup/11-txm_motor.py +++ b/startup/11-txm_motor.py @@ -180,9 +180,6 @@ class Scint(Device): zps = TXMSampleStage("XF:18IDB-OP", name="zps") XEng = MyEpicsMotor("XF:18IDA-OP{Mono:DCM-Ax:En}Mtr", name="XEng") -zps_sy = zps.sy # Required by the Queue Server -zps_sz = zps.sz # Required by the Queue Server - th2_motor = MyEpicsMotor("XF:18IDA-OP{Mono:DCM-Ax:Th2}Mtr", name="th2_motor") th2_feedback = EpicsSignal("XF:18IDA-OP{Mono:DCM-Ax:Th2}PID", name="th2_feedback") th2_feedback_enable = EpicsSignal( diff --git a/startup/12-optics_motor.py b/startup/12-optics_motor.py index 9228bac..e8d8ed5 100644 --- a/startup/12-optics_motor.py +++ b/startup/12-optics_motor.py @@ -38,8 +38,6 @@ class PBSL(Device): dcm = DCM("XF:18IDA-OP{Mono:DCM", name="dcm") pbsl = PBSL("XF:18IDA-OP{PBSL:1", name="pbsl") -dcm_th2 = dcm.th2 # Required by the Queue Server - motor_optics = [ cm.x, cm.yaw, @@ -76,5 +74,5 @@ class PBSL(Device): pbsl.ib, ] -# get_ipython().register_magics(BlueskyMagics) +get_ipython().register_magics(BlueskyMagics) # BlueskyMagics.positioners = motor_txm + motor_optics diff --git a/startup/40-scan_pre_define.py b/startup/40-scan_pre_define.py index c8096a2..a72b370 100644 --- a/startup/40-scan_pre_define.py +++ b/startup/40-scan_pre_define.py @@ -49,7 +49,7 @@ def _take_image(detectors, motor, num, stream_name="primary"): def _set_Andor_chunk_size(detectors, chunk_size): for detector in detectors: yield from unstage(detector) - yield from bps.configure(Andor, {"cam.num_images": chunk_size}) + yield from mv(Andor.cam.num_images, chunk_size) for detector in detectors: yield from stage(detector) @@ -89,6 +89,8 @@ def _take_bkg_image( def _set_andor_param(exposure_time=0.1, period=0.1, chunk_size=1, binning=[1, 1]): yield from mv(Andor.cam.acquire, 0) yield from mv(Andor.cam.image_mode, 0) + if (not binning is None) and len(binning) == 2: + yield from mv(Andor.cam.bin_y, binning[0], Andor.cam.bin_x, binning[1]) yield from mv(Andor.cam.num_images, chunk_size) period_cor = period yield from mv(Andor.cam.acquire_time, exposure_time) diff --git a/startup/41-scans.py b/startup/41-scans.py index de5487d..f37c6b9 100644 --- a/startup/41-scans.py +++ b/startup/41-scans.py @@ -192,7 +192,6 @@ def fly_scan( binning=None, note="", md=None, - move_to_ini_pos=True, simu=False, ): """ @@ -327,8 +326,8 @@ def fly_inner_scan(): # open shutter, tomo_images true_period = yield from rd(Andor.cam.acquire_period) - rot_time = np.abs(relative_rot_angle) / np.abs(rs) - num_img = int(rot_time / true_period) + 2 + rot_time = relative_rot_angle / np.abs(rs) + num_img = int(rot_time / true_period) + 3 yield from _open_shutter(simu=simu) print("\nshutter opened, taking tomo images...") @@ -360,15 +359,13 @@ def fly_inner_scan(): simu=simu, ) yield from _close_shutter(simu=simu) - if move_to_ini_pos: - yield from _move_sample_in( - motor_x_ini, - motor_y_ini, - motor_z_ini, - motor_r_ini, - trans_first_flag=rot_first_flag, - repeat=3, - ) + yield from _move_sample_in( + motor_x_ini, + motor_y_ini, + motor_z_ini, + motor_r_ini, + trans_first_flag=rot_first_flag, + ) for flt in filters: yield from mv(flt, 0) @@ -508,10 +505,6 @@ def xanes_scan2( @stage_decorator(list(detectors) + motor) @run_decorator(md=_md) def xanes_inner_scan(): - if len(filters): - for filt in filters: - yield from mv(filt, 1) - yield from bps.sleep(0.5) yield from _set_rotation_speed(rs=30) # take dark image print(f"\ntake {chunk_size} dark images...") @@ -534,7 +527,10 @@ def xanes_inner_scan(): info_flag=0, stream_name="primary", ) - + if len(filters): + for filt in filters: + yield from mv(filt, 1) + yield from bps.sleep(0.5) yield from _take_bkg_image( motor_x_out, motor_y_out, @@ -556,10 +552,10 @@ def xanes_inner_scan(): repeat=2, trans_first_flag=rot_first_flag, ) - if len(filters): - for filt in filters: - yield from mv(filt, 0) - yield from bps.sleep(0.5) + if len(filters): + for filt in filters: + yield from mv(filt, 0) + yield from bps.sleep(0.5) yield from move_zp_ccd(eng_ini, move_flag=1, info_flag=0) print("closing shutter") yield from _close_shutter(simu=simu) @@ -601,7 +597,7 @@ def xanes_scan( energy in unit of keV exposure_time: float - unit of seconds + in unit of seconds chunk_size: int number of background images == num of dark images @@ -766,131 +762,6 @@ def xanes_inner_scan(): print(txt) -def xanes_scan_img_only( - eng_list, - exposure_time=0.1, - chunk_size=5, - simu=False, - note="", - md=None, -): - """ - Scan the energy and take 2D image, will take dark image, but will not move sample out to take background image) - - Inputs: - ------- - eng_list: list or numpy array, - energy in unit of keV - - exposure_time: float - unit of seconds - - chunk_size: int - number of background images == num of dark images - - note: string - adding note to the 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 - detectors = [Andor, ic3] - period = exposure_time if exposure_time >= 0.05 else 0.05 - yield from _set_andor_param(exposure_time, period, chunk_size) - motor_eng = XEng - eng_ini = XEng.position - - motor_x_ini = zps.sx.position - motor_y_ini = zps.sy.position - motor_z_ini = zps.sz.position - motor_r_ini = zps.pi_r.position - - rs_ini = yield from bps.rd(zps.pi_r.velocity) - motor = [motor_eng, zps.sx, zps.sy, zps.sz, zps.pi_r] - - _md = { - "detectors": [det.name for det in detectors], - "motors": [mot.name for mot in motor], - "num_eng": len(eng_list), - "chunk_size": chunk_size, - "exposure_time": exposure_time, - "eng_list": eng_list, - "XEng": XEng.position, - "plan_args": { - "eng_list": "eng_list", - "exposure_time": exposure_time, - "chunk_size": chunk_size, - "note": note if note else "None", - "zone_plate": ZONE_PLATE, - }, - "plan_name": "xanes_scan_img_only", - "hints": {}, - "operator": "FXI", - "zone_plate": ZONE_PLATE, - "note": note if note else "None", - #'motor_pos': wh_pos(print_on_screen=0), - } - _md.update(md or {}) - try: - dimensions = [(motor.hints["fields"], "primary")] - except (AttributeError, KeyError): - pass - else: - _md["hints"].setdefault("dimensions", dimensions) - - @stage_decorator(list(detectors) + motor) - @run_decorator(md=_md) - def xanes_inner_scan(): - print("\ntake {} dark images...".format(chunk_size)) - yield from _set_rotation_speed(rs=30) - yield from _take_dark_image( - detectors, motor, 1, chunk_size, stream_name="dark", simu=simu - ) - - print( - f"\nopening shutter, and start xanes scan: {chunk_size} images per each energy..." - ) - yield from _open_shutter(simu) - for eng in eng_list: - yield from _xanes_per_step( - eng, - detectors, - motor, - move_flag=1, - move_clens_flag=0, - info_flag=0, - stream_name="primary", - ) - - yield from _move_sample_in( - motor_x_ini, - motor_y_ini, - motor_z_ini, - motor_r_ini, - repeat=2, - trans_first_flag=1, - ) - yield from move_zp_ccd(eng_ini, info_flag=0) - - print("closing shutter") - yield from _close_shutter(simu) - - yield from xanes_inner_scan() - txt1 = get_scan_parameter() - eng_list = np.round(eng_list, 5) - if len(eng_list) > 10: - txt2 = f"eng_list: {eng_list[0:10]}, ... {eng_list[-5:]}\n" - else: - txt2 = f"eng_list: {eng_list}" - txt = txt1 + "\n" + txt2 - insert_text(txt) - print(txt) - - def mv_stage(motor, pos): grp = _short_uid("set") yield Msg("checkpoint") @@ -898,17 +769,6 @@ def mv_stage(motor, pos): yield Msg("wait", None, group=grp) -@parameter_annotation_decorator( - { - "parameters": { - "detectors": { - "annotation": "typing.List[DetectorType1]", - "devices": {"DetectorType1": ["ic3", "ic4"]}, - "default": ["ic3", "ic4"], - } - } - } -) def eng_scan( start, stop=None, num=1, detectors=[ic3, ic4], delay_time=1, note="", md=None ): @@ -936,11 +796,6 @@ def eng_scan( # detectors=[ic3, ic4] motor_x = XEng motor_x_ini = motor_x.position # initial position of motor_x - - # added by XH -- start - motor_y = dcm - # added by XH -- end - if isinstance(start, (list, np.ndarray)): steps = start num = len(start) @@ -954,8 +809,7 @@ def eng_scan( print(steps) _md = { "detectors": [det.name for det in detectors], - # "motors": [motor_x.name], - "motors": [motor_x.name, motor_y.name], + "motors": [motor_x.name], "XEng": XEng.position, "plan_name": "eng_scan_delay", "plan_args": { @@ -979,25 +833,19 @@ def eng_scan( } _md.update(md or {}) try: - # dimensions = [(motor_x.hints["fields"], "primary")] - dimensions = [ - (motor_x.hints["fields"], "primary"), - (motor_y.hints["fields"], "primary"), - ] + dimensions = [(motor_x.hints["fields"], "primary")] except (AttributeError, KeyError): pass else: _md["hints"].setdefault("dimensions", dimensions) - # @stage_decorator(list(detectors) + [motor_x]) - @stage_decorator(list(detectors) + [motor_x, motor_y]) + @stage_decorator(list(detectors) + [motor_x]) @run_decorator(md=_md) def eng_inner_scan(): for step in steps: yield from mv(motor_x, step) yield from bps.sleep(delay_time) - # yield from trigger_and_read(list(detectors) + [motor_x]) - yield from trigger_and_read(list(detectors) + [motor_x, motor_y]) + yield from trigger_and_read(list(detectors) + [motor_x]) yield from mv(motor_x, motor_x_ini) yield from eng_inner_scan() @@ -1148,7 +996,6 @@ def delay_count(detectors, num=1, delay=None, *, note="", plot_flag=0, md=None): @bpp.stage_decorator(detectors) @bpp.run_decorator(md=_md) def inner_count(): - yield from _open_shutter(simu=False) return ( yield from bps.repeat( partial(bps.trigger_and_read, detectors), num=num, delay=delay @@ -1304,7 +1151,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)) @@ -1458,15 +1305,9 @@ def raster_2D_scan( @stage_decorator(list(detectors) + motor) @run_decorator(md=_md) def raster_2D_inner(): - if len(filters): - for filt in filters: - yield from mv(filt, 1) - yield from bps.sleep(0.5) # take dark image print("take 5 dark image") - yield from _take_dark_image( - detectors, motor, num=5, stream_name="primary", simu=simu - ) + yield from _take_dark_image(detectors, motor, num_dark=5, simu=simu) print("open shutter ...") yield from _open_shutter(simu) @@ -1487,7 +1328,10 @@ def raster_2D_inner(): # yield from trigger_and_read(list(detectors) + motor) print("moving sample out to take 5 background image") - + if len(filters): + for filt in filters: + yield from mv(filt, 1) + yield from bps.sleep(0.5) yield from _take_bkg_image( motor_x_out, motor_y_out, @@ -1495,10 +1339,9 @@ def raster_2D_inner(): motor_r_out, detectors, motor, - num=5, - stream_name="primary", + num_bkg=5, simu=simu, - rot_first_flag=rot_first_flag, + traditional_sequence_flag=rot_first_flag, ) # move sample in @@ -1523,213 +1366,6 @@ def raster_2D_inner(): print(txt) -def raster_2D_scan_test( - x_range=[-1, 1], - y_range=[-1, 1], - exposure_time=0.1, - out_x=None, - out_y=None, - out_z=None, - out_r=None, - img_sizeX=2560, - img_sizeY=2160, - pxl=20, - simu=False, - relative_move_flag=1, - rot_first_flag=1, - note="", - scan_x_flag=1, - filters=[], - md=None, -): - """ - scanning large area by moving samples at different 2D block position, defined by x_range and y_range, only work for Andor camera at full resolution (2160 x 2560) - for example, set x_range=[-1,1] and y_range=[-2, 2] will totally take 3 x 5 = 15 images and stitch them together - - Inputs: - ------- - - 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 - - exposure_time: float - - out_x: float, default is 0 - relative movement of sample in "x" direction using zps.sx to move out sample (in unit of um) - NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z - - out_y: float, default is 0 - relative movement of sample in "y" direction using zps.sy to move out sample (in unit of um) - NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z - - out_z: float, default is 0 - relative movement of sample in "z" direction using zps.sz to move out sample (in unit of um) - NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z - - 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 - - pxl: float, pixel size, default is 17.2, in unit of nm/pix - - note: string - - scan_x_flag: 1 or 0 - if 1: scan x and y - if 0: scan z and y - - 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] - detectors = [Andor, ic3] - yield from _set_andor_param( - exposure_time=exposure_time, period=exposure_time, chunk_size=1 - ) - - motor_x_ini = zps.sx.position - motor_y_ini = zps.sy.position - motor_z_ini = zps.sz.position - motor_r_ini = zps.pi_r.position - - if relative_move_flag: - motor_x_out = motor_x_ini + out_x if not (out_x is None) else motor_x_ini - motor_y_out = motor_y_ini + out_y if not (out_y is None) else motor_y_ini - motor_z_out = motor_z_ini + out_z if not (out_z is None) else motor_z_ini - motor_r_out = motor_r_ini + out_r if not (out_r is None) else motor_r_ini - else: - motor_x_out = out_x if not (out_x is None) else motor_x_ini - motor_y_out = out_y if not (out_y is None) else motor_y_ini - motor_z_out = out_z if not (out_z is None) else motor_z_ini - motor_r_out = out_r if not (out_r is None) else motor_r_ini - - img_sizeX = np.int(img_sizeX) - img_sizeY = np.int(img_sizeY) - x_range = np.int_(x_range) - y_range = np.int_(y_range) - - print("hello1") - _md = { - "detectors": [det.name for det in detectors], - "motors": [mot.name for mot in motor], - "num_bkg_images": 5, - "num_dark_images": 5, - "x_range": x_range, - "y_range": y_range, - "out_x": out_x, - "out_y": out_y, - "out_z": out_z, - "exposure_time": exposure_time, - "XEng": XEng.position, - "plan_args": { - "x_range": x_range, - "y_range": y_range, - "exposure_time": exposure_time, - "out_x": out_x, - "out_y": out_y, - "out_z": out_z, - "out_r": out_r, - "img_sizeX": img_sizeX, - "img_sizeY": img_sizeY, - "pxl": pxl, - "note": note if note else "None", - "relative_move_flag": relative_move_flag, - "rot_first_flag": rot_first_flag, - "note": note if note else "None", - "scan_x_flag": scan_x_flag, - "zone_plate": ZONE_PLATE, - }, - "plan_name": "raster_2D", - "hints": {}, - "operator": "FXI", - "zone_plate": ZONE_PLATE, - "note": note if note else "None", - #'motor_pos': wh_pos(print_on_screen=0), - } - _md.update(md or {}) - try: - dimensions = [(motor.hints["fields"], "primary")] - except (AttributeError, KeyError): - pass - else: - _md["hints"].setdefault("dimensions", dimensions) - - @stage_decorator(list(detectors) + motor) - @run_decorator(md=_md) - def raster_2D_inner(): - - # take dark image - print("take 5 dark image") - yield from _take_dark_image( - detectors, motor, num=5, stream_name="primary", simu=simu - ) - - print("open shutter ...") - yield from _open_shutter(simu) - - print("taking mosaic image ...") - for ii in np.arange(x_range[0], x_range[1] + 1): - if scan_x_flag == 1: - yield from mv(zps.sx, motor_x_ini + ii * img_sizeX * pxl * 1.0 / 1000) - yield from mv(zps.sx, motor_x_ini + ii * img_sizeX * pxl * 1.0 / 1000) - else: - yield from mv(zps.sz, motor_z_ini + ii * img_sizeX * pxl * 1.0 / 1000) - yield from mv(zps.sz, motor_z_ini + ii * img_sizeX * pxl * 1.0 / 1000) - sleep_time = (x_range[-1] - x_range[0]) * img_sizeX * pxl * 1.0 / 1000 / 600 - yield from bps.sleep(sleep_time) - for jj in np.arange(y_range[0], y_range[1] + 1): - yield from mv(zps.sy, motor_y_ini + jj * img_sizeY * pxl * 1.0 / 1000) - yield from _take_image(detectors, motor, 1) - # yield from trigger_and_read(list(detectors) + motor) - - print("moving sample out to take 5 background image") - if len(filters): - for filt in filters: - yield from mv(filt, 1) - yield from bps.sleep(0.5) - yield from _take_bkg_image( - motor_x_out, - motor_y_out, - motor_z_out, - motor_r_out, - detectors, - motor, - num=5, - stream_name="primary", - simu=simu, - rot_first_flag=rot_first_flag, - ) - if len(filters): - for filt in filters: - yield from mv(filt, 0) - yield from bps.sleep(0.5) - # move sample in - yield from _move_sample_in( - motor_x_ini, - motor_y_ini, - motor_z_ini, - motor_r_ini, - repeat=1, - trans_first_flag=1 - rot_first_flag, - ) - - print("closing shutter") - yield from _close_shutter(simu) - - yield from raster_2D_inner() - txt = get_scan_parameter() - insert_text(txt) - print(txt) - - def raster_2D_scan2( x_range=[-1, 1], y_range=[-1, 1], @@ -1877,9 +1513,7 @@ def raster_2D_scan2( def raster_2D_inner(): # take dark image print("take 5 dark image") - yield from _take_dark_image( - detectors, motor, num=5, stream_name="primary", simu=simu - ) + yield from _take_dark_image(detectors, motor, num_dark=5, simu=simu) print("open shutter ...") yield from _open_shutter(simu) @@ -1912,10 +1546,9 @@ def raster_2D_inner(): motor_r_out, detectors, motor, - num=1, - stream_name="primary", + num_bkg=num_bkg, simu=simu, - rot_first_flag=rot_first_flag, + traditional_sequence_flag=rot_first_flag, ) # print('moving sample out to take 5 background image') @@ -2586,7 +2219,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) @@ -2878,14 +2511,6 @@ def multi_pos_xanes_3D( n = len(x_list) for rep in range(repeat): for i in range(n): - if x_list[i] is None: - x_list[i] = zps.sx.position - if y_list[i] is None: - y_list[i] = zps.sy.position - if z_list[i] is None: - z_list[i] = zps.sz.position - if r_list[i] is None: - r_list[i] = zps.pi_r.position yield from mv( zps.sx, x_list[i], @@ -2912,76 +2537,9 @@ def multi_pos_xanes_3D( rs=rs, simu=simu, relative_move_flag=relative_move_flag, - rot_first_flag=rot_first_flag, + rot_first_flag=traditional_sequence_flag, note=note, binning=[2, 2], ) print(f"sleep for {sleep_time} sec\n\n\n\n") yield from bps.sleep(sleep_time) - - -def tomo_mosaic( - x_ini, - y_ini, - z_ini, - x_num_steps, - y_num_steps, - z_num_steps, - x_step_size, - y_step_size, - z_step_size, - exposure_time, - period, - rs=4, - out_x=None, - out_y=None, - out_z=None, - out_r=None, - start_angle=None, - relative_rot_angle=180, - relative_move_flag=True, - simu=False, - note="", -): - - if x_ini is None: - x_ini = zps.sx.position - if y_ini is None: - y_ini = zps.sy.position - if z_ini is None: - z_ini = zps.sz.position - - y_list = np.arange(y_ini, y_ini + y_step_size * y_num_steps - 1, y_step_size) - x_list = np.arange(x_ini, x_ini + x_step_size * x_num_steps - 1, x_step_size) - z_list = np.arange(z_ini, z_ini + z_step_size * z_num_steps - 1, z_step_size) - txt1 = "\n###############################################" - txt2 = "\n####### start mosaic tomography scan ######" - txt3 = "\n###############################################" - txt = txt1 + txt2 + txt3 - print(txt) - insert_text(txt) - for y in y_list: - for z in z_list: - for x in x_list: - yield from mv(zps.sx, x, zps.sy, y, zps.sz, z) - yield from fly_scan( - exposure_time, - start_angle, - relative_rot_angle, - period, - out_x, - out_y, - out_z, - out_r, - rs=rs, - relative_move_flag=relative_move_flag, - note=note, - simu=simu, - rot_first_flag=True, - ) - txt4 = "\n###### mosaic tomogrpahy scan finished ######" - txt = txt1 + txt4 + txt3 - insert_text(txt) - - -# diff --git a/startup/43-scans_pzt.py b/startup/43-scans_pzt.py index ec0b861..800d285 100644 --- a/startup/43-scans_pzt.py +++ b/startup/43-scans_pzt.py @@ -1,14 +1,3 @@ -@parameter_annotation_decorator( - { - "parameters": { - "detectors": { - "annotation": "typing.List[DetectorType1]", - "devices": {"DetectorType1": ["Vout2"]}, - "default": ["Vout2"], - } - } - } -) def pzt_scan(pzt_motor, start, stop, steps, detectors=[Vout2], sleep_time=1, md=None): """ scan the pzt_motor (e.g., pzt_dcm_th2), detectors can be any signal or motor (e.g., Andor, dcm.th2) @@ -170,17 +159,6 @@ def pzt_inner_scan(): # return pzt_readout, motor_readout, signal_readout -@parameter_annotation_decorator( - { - "parameters": { - "detectors": { - "annotation": "typing.List[DetectorType1]", - "devices": {"DetectorType1": ["Vout2"]}, - "default": ["Vout2"], - } - } - } -) def pzt_scan_multiple( moving_pzt, start, @@ -294,17 +272,6 @@ def pzt_scan_multiple( ###################### -@parameter_annotation_decorator( - { - "parameters": { - "detectors": { - "annotation": "typing.List[DetectorType1]", - "devices": {"DetectorType1": ["dcm_th2", "Vout2"]}, - "default": ["dcm_th2", "Vout2"], - } - } - } -) def pzt_energy_scan( moving_pzt, start, @@ -375,17 +342,6 @@ def pzt_energy_scan( insert_text(txt_finish) -@parameter_annotation_decorator( - { - "parameters": { - "detectors": { - "annotation": "typing.List[DetectorType1]", - "devices": {"DetectorType1": ["dcm_th2", "Vout2"]}, - "default": ["dcm_th2", "Vout2"], - } - } - } -) def pzt_overnight_scan( moving_pzt, start, diff --git a/startup/44-scans_other.py b/startup/44-scans_other.py index 4d73976..20ebde0 100644 --- a/startup/44-scans_other.py +++ b/startup/44-scans_other.py @@ -13,7 +13,6 @@ def test_scan( num_img=10, num_bkg=10, note="", - simu=False, md=None, ): """ @@ -66,7 +65,7 @@ def test_scan( "hints": {}, "operator": "FXI", "note": note if note else "None", - # "motor_pos": wh_pos(print_on_screen=0), + "motor_pos": wh_pos(print_on_screen=0), } _md.update(md or {}) _md["hints"].setdefault("dimensions", [(("time",), "primary")]) @@ -74,13 +73,10 @@ def test_scan( @stage_decorator(list(detectors)) @run_decorator(md=_md) def inner_scan(): - yield from _open_shutter(simu=simu) - """ yield from abs_set(shutter_open, 1, wait=True) yield from bps.sleep(2) yield from abs_set(shutter_open, 1, wait=True) yield from bps.sleep(2) - """ for i in range(num_img): yield from trigger_and_read(list(detectors)) # taking out sample and take background image @@ -90,13 +86,10 @@ def inner_scan(): for i in range(num_bkg): yield from trigger_and_read(list(detectors)) # close shutter, taking dark image - yield from _close_shutter(simu=simu) - """ yield from abs_set(shutter_close, 1, wait=True) yield from bps.sleep(1) yield from abs_set(shutter_close, 1, wait=True) yield from bps.sleep(1) - """ for i in range(num_bkg): yield from trigger_and_read(list(detectors)) yield from mv(zps.sz, z_ini) @@ -219,19 +212,19 @@ def inner_scan(): yield from mv(zps.sx, x_out, zps.sy, y_out) yield from bps.sleep(0.5) yield from trigger_and_read(list(detectors) + [motor]) - yield from _close_shutter(simu=simu) - yield from bps.sleep(0.5) - yield from trigger_and_read(list(detectors) + [motor]) # dark images # yield from abs_set(shutter_close, 1, wait=True) # yield from bps.sleep(1) # yield from abs_set(shutter_close, 1) # yield from bps.sleep(1) + yield from _close_shutter(simu=simu) + yield from trigger_and_read(list(detectors) + [motor]) # move back zone_plate and sample y yield from mv(zps.sx, x_ini) yield from mv(zps.sy, y_ini) yield from mv(zp.z, z_ini) - # yield from abs_set(shutter_open, 1, wait=True) + + yield from abs_set(shutter_open, 1, wait=True) yield from mv(Andor.cam.image_mode, 1) uid = yield from inner_scan() @@ -295,7 +288,6 @@ def z_scan2( x_out = x_ini + out_x if not (out_x is None) else x_ini z_ini = zps.sz.position z_out = z_ini if not (out_z is None) else z_ini - period = max(exposure_time + 0.01, 0.05) yield from _set_andor_param( exposure_time=exposure_time, period=period, chunk_size=20 @@ -488,17 +480,6 @@ def z_inner_scan(): ##################### -@parameter_annotation_decorator( - { - "parameters": { - "detectors": { - "annotation": "typing.List[DetectorType1]", - "devices": {"DetectorType1": ["detA1"]}, - "default": ["detA1"], - } - } - } -) def cond_scan(detectors=[detA1], *, md=None): motor = clens.x @@ -549,113 +530,6 @@ def cond_inner_scan(): return (yield from cond_inner_scan()) -from bluesky.callbacks.mpl_plotting import QtAwareCallback -from bluesky.preprocessors import subs_wrapper - - -class LoadCellScanPlot(QtAwareCallback): - """ - Class for plotting data from 'load_cell_scan' plan. - """ - - def __init__(self, **kwargs): - super().__init__(use_teleporter=kwargs.pop("use_teleporter", None)) - - self._start_new_figure = False - self._show_axes_titles = False - - self._scan_id_start = 0 - self._scan_id_end = 0 - - self._fig = None - self._ax1 = None - self._ax2 = None - - # Parameters used in 'ax2' title - self._load_cell_force = None - self._bender_pos = None - - def start_new_figure(self): - """ - Create new figure when the next 'stop' document is received. The next plot - will be placed in the new figure. Call before the first scan in the series. - """ - self._start_new_figure = True - - def show_axes_titles(self, *, load_cell_force, bender_pos): - """ - Add subtitles to the current plot once the next stop document is received. - Call before the last scan in the series. - """ - self._show_axes_titles = True - self._load_cell_force = load_cell_force - self._bender_pos = bender_pos - - def stop(self, doc): - # Scan UID - uid = doc["run_start"] - - h = db[uid] - # Scan ID - scan_id = h.start["scan_id"] - - plan_args = h.start["plan_args"] - # Get values for some parameters used for plotting - eng_start = plan_args["start"] - eng_end = plan_args["stop"] - steps = plan_args["num"] - - if self._start_new_figure: - self._fig = plt.figure() - self._ax1 = self._fig.add_subplot(211) - self._ax2 = self._fig.add_subplot(212) - - # Save ID of the first scan - self._scan_id_start = scan_id - self._scan_id_end = scan_id - - self._start_new_figure = False - - y0 = np.array(list(h.data(ic3.name))) - y1 = np.array(list(h.data(ic4.name))) - r = np.log(y0 / y1) - x = np.linspace(eng_start, eng_end, steps) - self._ax1.plot(x, r, ".-") - r_dif = np.array([0] + list(np.diff(r))) - self._ax2.plot(x, r_dif, ".-") - - if self._show_axes_titles: - self._scan_id_end = scan_id - - self._ax1.title.set_text( - "scan_id: {}-{}, ratio of: {}/{}".format( - self._scan_id_start, - self._scan_id_end, - ic3.name, - ic4.name, - ) - ) - self._ax2.title.set_text( - "load_cell: {}, bender_pos: {}".format( - self._load_cell_force - if self._load_cell_force is not None - else "NOT SET", - self._bender_pos if self._bender_pos is not None else "NOT SET", - ) - ) - self._fig.subplots_adjust(hspace=0.5) - - self._load_cell_force = None - self._bender_pos = None - - self._show_axes_titles = False - - super().stop(doc) - - -lcs_plot = LoadCellScanPlot() - - def load_cell_scan( pzt_cm_bender_pos_list, pbsl_y_pos_list, @@ -700,95 +574,6 @@ def load_cell_scan( check_eng_range([eng_start, eng_end]) num_pbsl_pos = len(pbsl_y_pos_list) - yield from _open_shutter(simu=False) - - for bender_pos in pzt_cm_bender_pos_list: - yield from mv(pzt_cm.setpos, bender_pos) - yield from bps.sleep(5) - load_cell_force = yield from bps.rd(pzt_cm_loadcell) - - # Initiate creating of a new figure - lcs_plot.start_new_figure() - - for pbsl_pos in pbsl_y_pos_list: - yield from mv(pbsl.y_ctr, pbsl_pos) - for i in range(num): - - # If the scan is the last in the series, display axes titles and align the plot - if (pbsl_pos == pbsl_y_pos_list[-1]) and (i == num - 1): - lcs_plot.show_axes_titles( - load_cell_force=load_cell_force, bender_pos=bender_pos - ) - - eng_scan_with_plot = subs_wrapper( - eng_scan( - eng_start, - stop=eng_end, - num=steps, - detectors=[ic3, ic4], - delay_time=delay_time, - ), - [lcs_plot], - ) - - yield from eng_scan_with_plot - - yield from _close_shutter(simu=False) - yield from mv(pbsl.y_ctr, pbsl_y_ctr_ini) - print(f"moving pbsl.y_ctr back to initial position: {pbsl.y_ctr.position} mm") - txt_finish = '## "load_cell_scan()" finished' - insert_text(txt_finish) - - -# =============================================================================================== -# The following is the original version of the plan code before the update. -# DELETE THIS CODE AFTER IT IS VERIFIED THAT THE NEW VERSION OF 'load_cell_scan' works properly -# =============================================================================================== -def load_cell_scan_original( - pzt_cm_bender_pos_list, - pbsl_y_pos_list, - num, - eng_start, - eng_end, - steps, - delay_time=0.5, -): - """ - At every position in the pzt_cm_bender_pos_list, scan the pbsl.y_ctr under diffenent energies - Use as: - load_cell_scan(pzt_cm_bender_pos_list, pbsl_y_pos_list, num, eng_start, eng_end, steps, delay_time=0.5) - note: energies are in unit if keV - - Inputs: - -------- - pzt_cm_bender_pos_list: list of "CM_Bender Set Position" - PV: XF:18IDA-OP{Mir:CM-Ax:Bender}SET_POSITION - - pbsl_y_pos_list: list of PBSL_y Center Position - PV: XF:18IDA-OP{PBSL:1-Ax:YCtr}Mtr - - num: number of repeating scans (engergy scan) at each pzt_cm_bender position and each pbsl_y center position - - eng_start: float, start energy in unit of keV - - eng_end: float, end of energy in unit of keV - - steps: num of steps from eng_start to eng_end - - delay_time: delay_time between each energy step, in unit of sec - """ - - txt1 = f"load_cell_scan(pzt_cm_bender_pos_list, pbsl_y_pos_list, num={num}, eng_start={eng_start}, eng_end={eng_end}, steps={steps}, delay_time={delay_time})" - txt2 = f"pzt_cm_bender_pos_list = {pzt_cm_bender_pos_list}" - txt3 = f"pbsl_y_pos_list = {pbsl_y_pos_list}" - txt = "##" + txt1 + "\n" + txt2 + "\n" + txt3 + "\n Consisting of:\n" - insert_text(txt) - - pbsl_y_ctr_ini = pbsl.y_ctr.position - - check_eng_range([eng_start, eng_end]) - num_pbsl_pos = len(pbsl_y_pos_list) - yield from _open_shutter(simu=False) for bender_pos in pzt_cm_bender_pos_list: yield from mv(pzt_cm.setpos, bender_pos) @@ -829,7 +614,6 @@ def load_cell_scan_original( ) fig.subplots_adjust(hspace=0.5) plt.show() - yield from _close_shutter(simu=False) yield from mv(pbsl.y_ctr, pbsl_y_ctr_ini) print(f"moving pbsl.y_ctr back to initial position: {pbsl.y_ctr.position} mm") txt_finish = '## "load_cell_scan()" finished' @@ -1215,27 +999,6 @@ def inner_count(): return uid -@parameter_annotation_decorator( - { - "parameters": { - "det": { - "annotation": "typing.List[DetectorType1]", - "devices": {"DetectorType1": ["detA1"]}, - "default": ["detA1"], - }, - "mot1": { - "annotation": "MotorType1", - "devices": {"MotorType1": ["zps_sz"]}, - "default": "zps_sz", - }, - "mot2": { - "annotation": "MotorType2", - "devices": {"MotorType2": ["zps_sz"]}, - "default": "zps_sy", - }, - } - } -) def knife_edge_scan_for_condensor( det=[detA1], mot1=zps.sz, diff --git a/startup/50-save_log.py b/startup/50-save_log.py index de45637..f9aae7d 100644 --- a/startup/50-save_log.py +++ b/startup/50-save_log.py @@ -6,10 +6,8 @@ import subprocess import threading from datetime import datetime -from pathlib import Path -if not is_re_worker_active(): - BlueskyMagics.positioners = motor_txm + motor_optics + motor_pzt + motor_lakeshore +BlueskyMagics.positioners = motor_txm + motor_optics + motor_pzt + motor_lakeshore class Auto_Log_Save(object): diff --git a/startup/81-load_scan_legacy.py b/startup/81-load_scan_legacy.py index e60d83f..b2d5806 100644 --- a/startup/81-load_scan_legacy.py +++ b/startup/81-load_scan_legacy.py @@ -340,7 +340,7 @@ def fly_scan_repeat_legacy( export_pdf(1) -def export_multipos_2D_xanes_scan2_lagacy(h, fpath=None): +def export_multipos_2D_xanes_scan2_legacy(h, fpath=None): if fpath is None: fpath = "./" else: diff --git a/startup/91-functions.py b/startup/91-functions.py index ba7e50e..303dc56 100644 --- a/startup/91-functions.py +++ b/startup/91-functions.py @@ -803,7 +803,7 @@ def move_zp_ccd(eng_new, move_flag=1, info_flag=1, move_clens_flag=0, move_det_f Inputs: ------- - eng_new: float + eng_new: float User defined energy, in unit of keV flag: int 0: Do calculation without moving real stages @@ -816,12 +816,12 @@ def move_zp_ccd(eng_new, move_flag=1, info_flag=1, move_clens_flag=0, move_det_f eng_ini = XEng.position check_eng_range([eng_ini]) zp_ini, det_ini, zp_delta, det_delta, zp_final, det_final = cal_zp_ccd_position(eng_new, eng_ini, print_flag=0) - + assert ((det_final) > det.z.low_limit and (det_final) < det.z.high_limit), print ('Trying to move DetU to {0:2.2f}. Movement is out of travel range ({1:2.2f}, {2:2.2f})\nTry to move the bottom stage manually.'.format(det_final, det.z.low_limit, det.z.high_limit)) eng1 = CALIBER['XEng_pos1'] eng2 = CALIBER['XEng_pos2'] - + #pzt_dcm_th2_eng1 = CALIBER['th2_pos1'] dcm_chi2_eng1 = CALIBER['chi2_pos1'] zp_x_pos_eng1 = CALIBER['zp_x_pos1'] @@ -868,7 +868,7 @@ def move_zp_ccd(eng_new, move_flag=1, info_flag=1, move_clens_flag=0, move_det_f aper_y_target = (eng_new - eng2)*(aper_y_eng1 - aper_y_eng2)/(eng1 - eng2) + aper_y_eng2 #pzt_dcm_th2_ini = (yield from bps.rd(pzt_dcm_th2.pos)) pzt_dcm_chi2_ini = (yield from bps.rd(pzt_dcm_chi2.pos.value)) - zp_x_ini = zp.x.position + zp_x_ini = zp.x.position zp_y_ini = zp.y.position th2_motor_ini = th2_motor.position clens_x_ini = clens.x.position @@ -879,13 +879,13 @@ def move_zp_ccd(eng_new, move_flag=1, info_flag=1, move_clens_flag=0, move_det_f DetU_y_ini = DetU.y.position aper_x_ini = aper.x.position aper_y_ini = aper.y.position - + if move_flag: # move stages - print ('Now moving stages ....') - if info_flag: + print ('Now moving stages ....') + if info_flag: print ('Energy: {0:5.2f} keV --> {1:5.2f} keV'.format(eng_ini, eng_new)) print ('zone plate position: {0:2.4f} mm --> {1:2.4f} mm'.format(zp_ini, zp_final)) - print ('CCD position: {0:2.4f} mm --> {1:2.4f} mm'.format(det_ini, det_final)) + print ('CCD position: {0:2.4f} mm --> {1:2.4f} mm'.format(det_ini, det_final)) print ('move zp_x: ({0:2.4f} um --> {1:2.4f} um)'.format(zp_x_ini, zp_x_target)) print ('move zp_y: ({0:2.4f} um --> {1:2.4f} um)'.format(zp_y_ini, zp_y_target)) #print ('move pzt_dcm_th2: ({0:2.4f} um --> {1:2.4f} um)'.format(pzt_dcm_th2_ini, pzt_dcm_th2_target)) @@ -901,31 +901,31 @@ def move_zp_ccd(eng_new, move_flag=1, info_flag=1, move_clens_flag=0, move_det_f if move_det_flag: print ('move DetU_x: ({0:2.4f} um --> {1:2.4f} um)'.format(DetU_x_ini, DetU_x_target)) print ('move DetU_y: ({0:2.4f} um --> {1:2.4f} um)'.format(DetU_y_ini, DetU_y_target)) - + yield from mv(zp.x, zp_x_target, zp.y, zp_y_target) -# yield from mv(aper.x, aper_x_target, aper.y, aper_y_target) +# yield from mv(aper.x, aper_x_target, aper.y, aper_y_target) yield from mv(th2_feedback_enable, 0) yield from mv(th2_feedback, th2_motor_target) yield from mv(th2_feedback_enable, 1) yield from mv(zp.z, zp_final,det.z, det_final, XEng, eng_new) yield from mv(aper.x, aper_x_target, aper.y, aper_y_target) - if move_clens_flag: - yield from mv(clens.x, clens_x_target, clens.y1, clens_y1_target, clens.y2, clens_y2_target) + if move_clens_flag: + yield from mv(clens.x, clens_x_target, clens.y1, clens_y1_target, clens.y2, clens_y2_target) yield from mv(clens.p, clens_p_target) if move_det_flag: - yield from mv(DetU.x, DetU_x_target) - yield from mv(DetU.y, DetU_y_target) + yield from mv(DetU.x, DetU_x_target) + yield from mv(DetU.y, DetU_y_target) #yield from mv(pzt_dcm_th2.setpos, pzt_dcm_th2_target, pzt_dcm_chi2.setpos, pzt_dcm_chi2_target) - #yield from mv(pzt_dcm_chi2.setpos, pzt_dcm_chi2_target) - + #yield from mv(pzt_dcm_chi2.setpos, pzt_dcm_chi2_target) + yield from bps.sleep(0.1) if abs(eng_new - eng_ini) >= 0.005: t = 10 * abs(eng_new - eng_ini) t = min(t, 2) print(f'sleep for {t} sec') - yield from bps.sleep(t) + yield from bps.sleep(t) else: - print ('This is calculation. No stages move') + print ('This is calculation. No stages move') print ('Will move Energy: {0:5.2f} keV --> {1:5.2f} keV'.format(eng_ini, eng_new)) print ('will move zone plate down stream by: {0:2.4f} mm ({1:2.4f} mm --> {2:2.4f} mm)'.format(zp_delta, zp_ini, zp_final)) print ('will move CCD down stream by: {0:2.4f} mm ({1:2.4f} mm --> {2:2.4f} mm)'.format(det_delta, det_ini, det_final)) @@ -1341,7 +1341,7 @@ def get_scan_parameter(scan_id=-1, print_flag=0): return txt -def get_scan_timestamp(scan_id, return_flag=0): +def get_scan_timestamp(scan_id): h = db[scan_id] scan_id = h.start["scan_id"] timestamp = h.start["time"] @@ -1357,8 +1357,6 @@ def get_scan_timestamp(scan_id, return_flag=0): ) scan_time = f"scan#{scan_id}: {scan_year-20:04d}-{scan_mon:02d}-{scan_day:02d} {scan_hour:02d}:{scan_min:02d}:{scan_sec:02d}" print(scan_time) - if return_flag: - return scan_time.split("#")[-1] def get_scan_file_name(scan_id): diff --git a/startup/92-run_function_at_start.py b/startup/92-run_function_at_start.py index 1335877..148a3f6 100644 --- a/startup/92-run_function_at_start.py +++ b/startup/92-run_function_at_start.py @@ -1,6 +1,6 @@ import os -if not os.environ.get("AZURE_TESTING") and not is_re_worker_active(): +if not os.environ.get("AZURE_TESTING"): new_user() show_global_para() run_pdf() diff --git a/startup/94-tomo_recon.py b/startup/94-tomo_recon.py index 4c4a58b..9c21d64 100644 --- a/startup/94-tomo_recon.py +++ b/startup/94-tomo_recon.py @@ -1,5 +1,14 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + import numpy as np +import h5py +import tomopy +import os import tomopy +from scipy.signal import medfilt2d +from skimage import io +from PIL import Image +from scipy.interpolate import interp1d def find_nearest(data, value): @@ -7,30 +16,37 @@ def find_nearest(data, value): return np.abs(data - value).argmin() -def find_rot(fn, thresh=0.05, method=1): - from pystackreg import StackReg +def find_rot(fn, thresh=0.05, norm_flag=1): - sr = StackReg(StackReg.TRANSLATION) f = h5py.File(fn, "r") - ang = np.array(list(f["angle"])) img_bkg = np.squeeze(np.array(f["img_bkg_avg"])) - if np.abs(ang[0]) < np.abs(ang[0] - 90): # e.g, rotate from 0 - 180 deg - tmp = np.abs(ang - ang[0] - 180).argmin() - else: # e.g.,rotate from -90 - 90 deg - tmp = np.abs(ang - np.abs(ang[0])).argmin() - img0 = np.array(list(f["img_tomo"][0])) - img180_raw = np.array(list(f["img_tomo"][tmp])) + img_dark = np.squeeze(np.array(f["img_dark_avg"])) + ang = np.array(list(f["angle"])) + + idx0 = np.argmin(np.abs(ang)) + idx180 = np.abs(ang - 180).argmin() + img0 = np.array(list(f["img_tomo"][idx0])) + img180_raw = np.array(list(f["img_tomo"][idx180])) f.close() - img0 = img0 / img_bkg - img180_raw = img180_raw / img_bkg - img180 = img180_raw[:, ::-1] s = np.squeeze(img0.shape) - im1 = -np.log(img0) - im2 = -np.log(img180) + if norm_flag: + img0 = (img0 - img_dark) / (img_bkg - img_dark) + img180_raw = (img180_raw - img_dark) / (img_bkg - img_dark) + img180 = img180_raw[:, ::-1] + im1 = -np.log(img0) + im2 = -np.log(img180) + else: + img180 = img180_raw[:, ::-1] + im1 = img0.astype(np.float32) + im2 = img180.astype(np.float32) im1[np.isnan(im1)] = 0 + im1[np.isinf(im1)] = 0 im2[np.isnan(im2)] = 0 + im2[np.isinf(im2)] = 0 im1[im1 < thresh] = 0 im2[im2 < thresh] = 0 + im1 = im1[50:-50] + im2 = im2[50:-50] im1 = medfilt2d(im1, 3) im2 = medfilt2d(im2, 3) im1_fft = np.fft.fft2(im1) @@ -39,20 +55,10 @@ def find_rot(fn, thresh=0.05, method=1): row_shift = results[2] col_shift = results[3] rot_cen = s[1] / 2 + col_shift / 2 - 1 + return rot_cen - tmat = sr.register(im1, im2) - rshft = -tmat[1, 2] - cshft = -tmat[0, 2] - rot_cen0 = s[1] / 2 + cshft / 2 - 1 - print(f"rot_cen = {rot_cen} or {rot_cen0}") - if method: - return rot_cen - else: - return rot_cen0 - - -def rotcen_test( +def rotcen_test2( fn, start=None, stop=None, @@ -65,9 +71,22 @@ def rotcen_test( txm_normed_flag=0, denoise_flag=0, fw_level=9, + algorithm="gridrec", + n_iter=5, + circ_mask_ratio=0.95, + options={}, + atten=None, + clim=[], + dark_scale=1, + filter_name="None", ): import tomopy + if not atten is None: + ref_ang = atten[:, 0] + ref_atten = atten[:, 1] + fint = interp1d(ref_ang, ref_atten) + f = h5py.File(fn, "r") tmp = np.array(f["img_tomo"][0]) s = [1, tmp.shape[0], tmp.shape[1]] @@ -83,22 +102,26 @@ def rotcen_test( np.max([0, sli - addition_slice // 2]), np.min([sli + addition_slice // 2 + 1, s[1]]), ] - - theta = np.array(f["angle"]) / 180.0 * np.pi - + tomo_angle = np.array(f["angle"]) + theta = tomo_angle / 180.0 * np.pi img_tomo = np.array(f["img_tomo"][:, sli_exp[0] : sli_exp[1], :]) if txm_normed_flag: - prj = img_tomo + prj_norm = img_tomo else: img_bkg = np.array(f["img_bkg_avg"][:, sli_exp[0] : sli_exp[1], :]) - img_dark = np.array(f["img_dark_avg"][:, sli_exp[0] : sli_exp[1], :]) + img_dark = ( + np.array(f["img_dark_avg"][:, sli_exp[0] : sli_exp[1], :]) / dark_scale + ) prj = (img_tomo - img_dark) / (img_bkg - img_dark) + if not atten is None: + for i in range(len(tomo_angle)): + att = fint(tomo_angle[i]) + prj[i] = prj[i] / att + prj_norm = -np.log(prj) f.close() - prj = denoise(prj, denoise_flag) - - prj_norm = -np.log(prj) + prj_norm = denoise(prj_norm, denoise_flag) prj_norm[np.isnan(prj_norm)] = 0 prj_norm[np.isinf(prj_norm)] = 0 prj_norm[prj_norm < 0] = 0 @@ -122,7 +145,10 @@ def rotcen_test( prj_norm = prj_norm.reshape(s[0], 1, s[1]) s = prj_norm.shape - pos = find_nearest(theta, theta[0] + np.pi) + if theta[-1] > theta[1]: + pos = find_nearest(theta, theta[0] + np.pi) + else: + pos = find_nearest(theta, theta[0] - np.pi) block_list = list(block_list) + list(np.arange(pos + 1, len(theta))) if len(block_list): allow_list = list(set(np.arange(len(prj_norm))) - set(block_list)) @@ -137,43 +163,334 @@ def rotcen_test( for i in range(len(cen)): if print_flag: print("{}: rotcen {}".format(i + 1, cen[i])) - img[i] = tomopy.recon( - prj_norm[:, addition_slice : addition_slice + 1], - theta, - center=cen[i], - algorithm="gridrec", - ) + if algorithm == "gridrec": + img[i] = tomopy.recon( + prj_norm[:, addition_slice : addition_slice + 1], + theta, + center=cen[i], + algorithm="gridrec", + filter_name=filter_name, + ) + elif "astra" in algorithm: + img[i] = tomopy.recon( + prj_norm[:, addition_slice : addition_slice + 1], + theta, + center=cen[i], + algorithm=tomopy.astra, + options=options, + ) + else: + img[i] = tomopy.recon( + prj_norm[:, addition_slice : addition_slice + 1], + theta, + center=cen[i], + algorithm=algorithm, + num_iter=n_iter, + filter_name=filter_name, + ) fout = "center_test.h5" with h5py.File(fout, "w") as hf: hf.create_dataset("img", data=img) hf.create_dataset("rot_cen", data=cen) - img = tomopy.circ_mask(img, axis=0, ratio=0.8) - tracker = image_scrubber(img) + img = tomopy.circ_mask(img, axis=0, ratio=circ_mask_ratio) + tracker = image_scrubber(img, clim=clim) if return_flag: return img, cen -def img_variance(img): - import tomopy +def rotcen_test( + fn, start=None, stop=None, steps=None, sli=0, block_list=[], filter_name="none" +): + + f = h5py.File(fn) + tmp = np.array(f["img_bkg_avg"]) + s = tmp.shape + if sli == 0: + sli = int(s[1] / 2) + img_tomo = np.array(f["img_tomo"][:, sli, :]) + img_bkg = np.array(f["img_bkg_avg"][:, sli, :]) + img_dark = np.array(f["img_dark_avg"][:, sli, :]) + theta = np.array(f["angle"]) / 180.0 * np.pi + f.close() + prj = (img_tomo - img_dark) / (img_bkg - img_dark) + prj_norm = -np.log(prj) + prj_norm[np.isnan(prj_norm)] = 0 + prj_norm[np.isinf(prj_norm)] = 0 + prj_norm[prj_norm < 0] = 0 + s = prj_norm.shape + prj_norm = prj_norm.reshape(s[0], 1, s[1]) + if len(block_list): + allow_list = list(set(np.arange(len(prj_norm))) - set(block_list)) + prj_norm = prj_norm[allow_list] + theta = theta[allow_list] + if start == None or stop == None or steps == None: + start = int(s[1] / 2 - 50) + stop = int(s[1] / 2 + 50) + steps = 31 + cen = np.linspace(start, stop, steps) + img = np.zeros([len(cen), s[1], s[1]]) + for i in range(len(cen)): + print("{}: rotcen {}".format(i + 1, cen[i])) + img[i] = tomopy.recon( + prj_norm, theta, center=cen[i], algorithm="gridrec", filter_name=filter_name + ) + fout = "center_test.h5" + with h5py.File(fout, "w") as hf: + hf.create_dataset("img", data=img) + hf.create_dataset("rot_cen", data=cen) + + +def recon_sub( + img, + theta, + rot_cen, + block_list=[], + rm_stripe=False, + stripe_remove_level=9, + algorithm="gridrec", + num_iter=20, + options={}, + filter_name="none", +): + prj_norm = img + if len(block_list): + allow_list = list(set(np.arange(len(prj_norm))) - set(block_list)) + prj_norm = prj_norm[allow_list] + theta = theta[allow_list] + if rm_stripe: + prj_norm = tomopy.prep.stripe.remove_stripe_fw( + prj_norm, level=stripe_remove_level, wname="db5", sigma=1, pad=True + ) + # prj_norm = tomopy.prep.stripe.remove_all_stripe_tomo(prj_norm, 3, 81, 31) + + if algorithm == "gridrec": + rec = tomopy.recon( + prj_norm, + theta, + center=rot_cen, + algorithm="gridrec", + filter_name=filter_name, + ) + elif "astra" in algorithm: + rec = tomopy.recon( + prj_norm, theta, center=rot_cen, algorithm=tomopy.astra, options=options + ) + else: + rec = tomopy.recon( + prj_norm, + theta, + center=rot_cen, + algorithm=algorithm, + num_iter=num_iter, + filter_name=filter_name, + ) - s = img.shape - variance = np.zeros(s[0]) - img = tomopy.circ_mask(img, axis=0, ratio=0.8) - for i in range(s[0]): - img[i] = medfilt2d(img[i], 5) - img_ = img[i].flatten() - t = img_ > 0 - img_ = img_[t] - t = np.mean(img_) - variance[i] = np.sqrt(np.sum(np.power(np.abs(img_ - t), 2)) / len(img_ - 1)) - return variance + return rec def recon( fn, rot_cen, sli=[], + col=[], + binning=None, + zero_flag=0, + tiff_flag=0, + block_list=[], + rm_stripe=True, + stripe_remove_level=9, + filter_name="none", +): + """ + reconstruct 3D tomography + Inputs: + -------- + fn: string + filename of scan, e.g. 'fly_scan_0001.h5' + rot_cen: float + rotation center + algorithm: string + choose from 'gridrec' and 'mlem' + sli: list + a range of slice to recontruct, e.g. [100:300] + num_iter: int + iterations for 'mlem' algorithm + bingning: int + binning the reconstruted 3D tomographic image + zero_flag: bool + if 1: set negative pixel value to 0 + if 0: keep negative pixel value + + """ + import tomopy + from PIL import Image + + f = h5py.File(fn, "r") + tmp = np.array(f["img_bkg_avg"]) + s = tmp.shape + slice_info = "" + bin_info = "" + col_info = "" + + if len(sli) == 0: + sli = [0, s[1]] + elif len(sli) == 1 and sli[0] >= 0 and sli[0] <= s[1]: + sli = [sli[0], sli[0] + 1] + slice_info = "_slice_{}_".format(sli[0]) + elif len(sli) == 2 and sli[0] >= 0 and sli[1] <= s[1]: + slice_info = "_slice_{}_{}_".format(sli[0], sli[1]) + else: + print("non valid slice id, will take reconstruction for the whole object") + + if len(col) == 0: + col = [0, s[2]] + elif len(col) == 1 and col[0] >= 0 and col[0] <= s[2]: + col = [col[0], col[0] + 1] + col_info = "_col_{}_".format(col[0]) + elif len(col) == 2 and col[0] >= 0 and col[1] <= s[2]: + col_info = "col_{}_{}_".format(col[0], col[1]) + else: + col = [0, s[2]] + print("invalid col id, will take reconstruction for the whole object") + + rot_cen = rot_cen - col[0] + + scan_id = np.array(f["scan_id"]) + img_tomo = np.array(f["img_tomo"][:, sli[0] : sli[1], :]) + img_tomo = np.array(img_tomo[:, :, col[0] : col[1]]) + img_bkg = np.array(f["img_bkg_avg"][:, sli[0] : sli[1], col[0] : col[1]]) + img_dark = np.array(f["img_dark_avg"][:, sli[0] : sli[1], col[0] : col[1]]) + theta = np.array(f["angle"]) / 180.0 * np.pi + if theta[-1] > theta[1]: + pos_180 = find_nearest(theta, theta[0] + np.pi) + else: + pos_180 = find_nearest(theta, theta[0] - np.pi) + block_list = list(block_list) + list(np.arange(pos_180 + 1, len(theta))) + + eng = np.array(f["X_eng"]) + f.close() + + s = img_tomo.shape + if not binning == None: + img_tomo = bin_ndarray( + img_tomo, (s[0], int(s[1] / binning), int(s[2] / binning)), "sum" + ) + img_bkg = bin_ndarray( + img_bkg, (1, int(s[1] / binning), int(s[2] / binning)), "sum" + ) + img_dark = bin_ndarray( + img_dark, (1, int(s[1] / binning), int(s[2] / binning)), "sum" + ) + rot_cen = rot_cen * 1.0 / binning + bin_info = "bin{}".format(int(binning)) + + prj = (img_tomo - img_dark) / (img_bkg - img_dark) + prj_norm = -np.log(prj) + prj_norm[np.isnan(prj_norm)] = 0 + prj_norm[np.isinf(prj_norm)] = 0 + prj_norm[prj_norm < 0] = 0 + + if len(block_list): + allow_list = list(set(np.arange(len(prj_norm))) - set(block_list)) + prj_norm = prj_norm[allow_list] + theta = theta[allow_list] + + if rm_stripe: + prj_norm = tomopy.prep.stripe.remove_stripe_fw( + prj_norm, level=stripe_remove_level, wname="db5", sigma=1, pad=True + ) + fout = ( + "recon_scan_" + str(scan_id) + str(slice_info) + str(col_info) + str(bin_info) + ) + + if tiff_flag: + cwd = os.getcwd() + try: + os.mkdir(cwd + f"/{fout}") + except: + print(cwd + f"/{fout} existed") + for i in range(prj_norm.shape[1]): + print(f"recon slice: {i:04d}/{prj_norm.shape[1]-1}") + rec = tomopy.recon( + prj_norm[:, i : i + 1, :], theta, center=rot_cen, algorithm="gridrec" + ) + + if zero_flag: + rec[rec < 0] = 0 + fout_tif = cwd + f"/{fout}" + f"/{i+sli[0]:04d}.tiff" + io.imsave(fout_tif, rec[0]) + # img = Image.fromarray(rec[0]) + # img.save(fout_tif) + else: + rec = tomopy.recon( + prj_norm, + theta, + center=rot_cen, + algorithm="gridrec", + filter_name=filter_name, + ) + if zero_flag: + rec[rec < 0] = 0 + fout_h5 = fout + ".h5" + with h5py.File(fout_h5, "w") as hf: + hf.create_dataset("img", data=rec) + hf.create_dataset("scan_id", data=scan_id) + hf.create_dataset("X_eng", data=eng) + print("{} is saved.".format(fout)) + del rec + del img_tomo + del prj_norm + + +""" +def batch_recon(file_path='.', file_prefix='fly', file_type='.h5', sli=[], col=[], block_list=[], binning=1, rm_stripe=True, stripe_remove_level=9): + path = os.path.abspath(file_path) + files = pyxas.retrieve_file_type(file_path, file_prefix, file_type) + num_file = len(files) + for i in range(num_file): + fn = files[i].split('/')[-1] + tmp = pyxas.get_img_from_hdf_file(fn, 'angle') + angle = tmp['angle'] + pos_180 = pyxas.find_nearest(angle, angle[0]+180) + block_list = list(block_list) + list(np.arange(pos_180+1, len(angle))) + rotcen = pyxas.find_rot(fn) + pyxas.recon(fn, rotcen, binning=binning, sli=sli, col=col, block_list=block_list, rm_stripe=rm_stripe, stripe_remove_level=stripe_remove_level) +""" + + +def batch_find_rotcen(files, block_list, index=0): + img = [] + r = [] + for i in range(len(files)): + fn = files[i] + r.append(find_rot(fn)) + print(f"#{i} {fn}: rotcen = {r[-1]}") + tmp = recon( + fn, + r[-1], + sli=[index], + block_list=block_list, + binning=None, + tiff_flag=0, + h5_flag=0, + return_flag=1, + ) + img.append(np.squeeze(tmp)) + img = np.array(img, dtype=np.float32) + with h5py.File("batch_rotcen.h5", "w") as hf: + hf.create_dataset("img", data=img) + hf.create_dataset("rotcen", data=r) + return img, r + + +########### +def recon2( + fn, + rot_cen, + sli=[], + col=[], binning=None, + algorithm="gridrec", zero_flag=0, block_list=[], bkg_level=0, @@ -181,6 +498,17 @@ def recon( read_full_memory=0, denoise_flag=0, fw_level=9, + num_iter=20, + dark_scale=1, + atten=[], + norm_empty_sli=[], + options={ + "proj_type": "cuda", + "method": "SIRT_CUDA", + "num_iter": 200, + }, + filter_name="None", + ncore=4, ): """ reconstruct 3D tomography @@ -192,6 +520,10 @@ def recon( rotation center sli: list a range of slice to recontruct, e.g. [100:300] + col: + a range of column to reconstruct, e.g, [300,800] + algorithm: + if using astra, algorithm="astra", and will use "options" provided bingning: int binning the reconstruted 3D tomographic image zero_flag: bool @@ -226,28 +558,30 @@ def recon( else: print("non valid slice id, will take reconstruction for the whole object") - """ if len(col) == 0: col = [0, s[2]] - elif len(col) == 1 and col[0] >=0 and col[0] <= s[2]: - col = [col[0], col[0]+1] - col_info = '_col_{}'.format(col[0]) - elif len(col) == 2 and col[0] >=0 and col[1] <= s[2]: - col_info = '_col_{}_{}'.format(col[0], col[1]) + elif len(col) == 1 and col[0] >= 0 and col[0] <= s[2]: + col = [col[0], col[0] + 1] + col_info = "_col_{}".format(col[0]) + elif len(col) == 2 and col[0] >= 0 and col[1] <= s[2]: + col_info = "_col_{}_{}".format(col[0], col[1]) else: col = [0, s[2]] - print('invalid col id, will take reconstruction for the whole object') - """ - # rot_cen = rot_cen - col[0] + print("invalid col id, will take reconstruction for the whole object") + scan_id = np.array(f["scan_id"]) theta = np.array(f["angle"]) / 180.0 * np.pi eng = np.array(f["X_eng"]) - pos = find_nearest(theta, theta[0] + np.pi) + if theta[-1] > theta[1]: + pos = find_nearest(theta, theta[0] + np.pi) + else: + pos = find_nearest(theta, theta[0] - np.pi) block_list = list(block_list) + list(np.arange(pos + 1, len(theta))) allow_list = list(set(np.arange(len(theta))) - set(block_list)) theta = theta[allow_list] tmp = np.squeeze(np.array(f["img_tomo"][0])) + tmp = tmp[:, col[0] : col[1]] s = tmp.shape f.close() @@ -256,8 +590,10 @@ def recon( bin_info = f"_bin_{binning}" n_steps = int(len(sli_total) / sli_step) - rot_cen = rot_cen * 1.0 / binning + rot_cen = (rot_cen * 1.0 - col[0]) / binning + if n_steps == 0: + read_full_memory = 1 if read_full_memory: sli_step = sli[1] - sli[0] n_steps = 1 @@ -277,6 +613,7 @@ def recon( print("Cannot allocate memory") for i in range(n_steps): + time_s = time.time() if i == 0: sli_sub = [sli_total[0], sli_total[0] + sli_step] current_sli = sli_sub @@ -297,19 +634,50 @@ def recon( bkg_level, fw_level=fw_level, denoise_flag=denoise_flag, + dark_scale=dark_scale, + atten=atten, + norm_empty_sli=norm_empty_sli, ) - + prj_norm = prj_norm[:, :, col[0] // binning : col[1] // binning] if i != 0 and i != n_steps - 1: prj_norm = prj_norm[ :, add_slice // binning : sli_step // binning + add_slice // binning ] - rec_sub = tomopy.recon(prj_norm, theta, center=rot_cen, algorithm="gridrec") + if algorithm == "gridrec": + rec_sub = tomopy.recon( + prj_norm, + theta, + center=rot_cen, + algorithm="gridrec", + ncore=ncore, + filter_name=filter_name, + ) + elif "astra" in algorithm: + rec_sub = tomopy.recon( + prj_norm, + theta, + center=rot_cen, + algorithm=tomopy.astra, + options=options, + ncore=ncore, + ) + else: + rec_sub = tomopy.recon( + prj_norm, + theta, + center=rot_cen, + algorithm=algorithm, + num_iter=num_iter, + ncore=ncore, + filter_name=filter_name, + ) rec[ i * sli_step // binning : i * sli_step // binning + rec_sub.shape[0] ] = rec_sub - + time_e = time.time() + print(f"takeing {time_e-time_s:3.1f} sec") bin_info = f"_bin{int(binning)}" - fout = f"recon_scan_{str(scan_id)}{str(slice_info)}{str(bin_info)}" + fout = f"recon_scan_{str(scan_id)}{str(slice_info)}{str(col_info)}{str(bin_info)}" if zero_flag: rec[rec < 0] = 0 fout_h5 = f"{fout}.h5" @@ -321,7 +689,6 @@ def recon( hf.create_dataset("binning", data=binning) print(f"{fout} is saved.") del rec - # del img_tomo del prj_norm @@ -355,27 +722,55 @@ def proj_normalize( bkg_level=0, fw_level=9, denoise_flag=0, + dark_scale=1, + atten=[], + norm_empty_sli=[], ): f = h5py.File(fn, "r") img_tomo = np.array(f["img_tomo"][:, sli[0] : sli[1], :]) + tomo_angle = np.array(f["angle"]) + if len(norm_empty_sli) == 2: + print("norm_empty_sli") + t_tomo = np.array(f["img_tomo"][:, norm_empty_sli[0] : norm_empty_sli[1]]) + t_bkg = np.array(f["img_bkg_avg"][:, norm_empty_sli[0] : norm_empty_sli[1]]) + t_dark = ( + np.array(f["img_dark_avg"][:, norm_empty_sli[0] : norm_empty_sli[1]]) + / dark_scale + ) + t = (t_tomo - t_dark) / (t_bkg - t_dark) + t_mean = np.mean(t, axis=1) + t_mean = np.expand_dims(t_mean, 1) + else: + t_mean = 1 try: img_bkg = np.array(f["img_bkg_avg"][:, sli[0] : sli[1]]) except: img_bkg = [] try: - img_dark = np.array(f["img_dark_avg"][:, sli[0] : sli[1]]) + img_dark = np.array(f["img_dark_avg"][:, sli[0] : sli[1]]) / dark_scale except: img_dark = [] if len(img_dark) == 0 or len(img_bkg) == 0 or txm_normed_flag == 1: prj = img_tomo else: prj = (img_tomo - img_dark) / (img_bkg - img_dark) + prj = prj / t_mean + if len(atten): + fint = interp1d(atten[:, 0], atten[:, 1]) + atten_interp = fint(tomo_angle) + for i in range(len(tomo_angle)): + prj[i] = prj[i] / atten_interp[i] + prj = denoise(prj, denoise_flag) s = prj.shape + prj = bin_ndarray(prj, (s[0], int(s[1] / binning), int(s[2] / binning)), "mean") - prj_norm = -np.log(prj) - prj_norm[np.isnan(prj_norm)] = 0 - prj_norm[np.isinf(prj_norm)] = 0 + if not txm_normed_flag: + prj_norm = -np.log(prj) + prj_norm[np.isnan(prj_norm)] = 0 + prj_norm[np.isinf(prj_norm)] = 0 + else: + prj_norm = prj prj_norm[prj_norm < 0] = 0 prj_norm = prj_norm[allow_list] prj_norm = tomopy.prep.stripe.remove_stripe_fw( @@ -404,3 +799,57 @@ def show_image_slice(fn, sli=0): print("cannot display image") finally: f.close() + + +class IndexTracker(object): + def __init__(self, ax, X, clim): + self.ax = ax + self._indx_txt = ax.set_title(" ", loc="center") + self.X = X + self.slices, rows, cols = X.shape + self.ind = self.slices // 2 + if not len(clim): + im_min = np.min(self.X[self.ind, :, :]) + im_max = np.max(self.X[self.ind, :, :]) + else: + im_min, im_max = clim + + self.im = ax.imshow(self.X[self.ind, :, :], cmap="gray", clim=[im_min, im_max]) + self.update() + + def onscroll(self, event): + if event.button == "up": + self.ind = (self.ind + 1) % self.slices + else: + self.ind = (self.ind - 1) % self.slices + self.update() + + def update(self): + self.im.set_data(self.X[self.ind, :, :]) + # self.ax.set_ylabel('slice %s' % self.ind) + self._indx_txt.set_text(f"frame {self.ind + 1} of {self.slices}") + self.im.axes.figure.canvas.draw() + + +def image_scrubber(data, ax=None, clim=[]): + if ax is None: + fig, ax = plt.subplots() + else: + fig = ax.figure + tracker = IndexTracker(ax, data, clim) + # monkey patch the tracker onto the figure to keep it alive + fig._tracker = tracker + fig.canvas.mpl_connect("scroll_event", tracker.onscroll) + return tracker + + +def test(): + fn = "/home/mingyuan/Work/tomo_recon/data/fly_scan_id_66030.h5" + options = { + "proj_type": "cuda", + "method": "FBP_CUDA", + "num_iter": 80, + } + recon2( + fn, 647, sli=[500], col=[300, 900], algorithm="astra", ncore=8, options=options + ) diff --git a/startup/98-user_scan.py b/startup/98-user_scan.py index 3f04dcc..f9a7fc1 100644 --- a/startup/98-user_scan.py +++ b/startup/98-user_scan.py @@ -270,11 +270,11 @@ def user_fly_scan( motor_r_ini = zps.pi_r.position motor = [zps.sx, zps.sy, zps.sz, zps.pi_r, zps.pi_x] - dets = [Andor, ic3] - taxi_ang = -2.0 * rs - cur_rot_ang = zps.pi_r.position + detectors = [Andor, ic3] + offset_angle = -2.0 * rs + current_rot_angle = zps.pi_r.position - # tgt_rot_ang = cur_rot_ang + rel_rot_ang + # target_rot_angle = current_rot_angle + relative_rot_angle _md = { "detectors": ["Andor"], "motors": [mot.name for mot in motor], @@ -312,13 +312,13 @@ def user_fly_scan( print("set rotation speed: {} deg/sec".format(rs)) - @stage_decorator(list(dets) + motor) + @stage_decorator(list(detectors) + motor) @bpp.monitor_during_decorator([zps.pi_r]) @run_decorator(md=_md) def inner_scan(): # close shutter, dark images: numer=chunk_size (e.g.20) print("\nshutter closed, taking dark images...") - yield from _take_dark_image(dets, motor, num_dark=1, simu=simu) + yield from _take_dark_image(detectors, motor, num_dark=1, simu=simu) yield from mv(zps.pi_x, 0) yield from mv(zps.pi_r, -50) @@ -326,11 +326,11 @@ def inner_scan(): # open shutter, tomo_images yield from _open_shutter(simu=simu) print("\nshutter opened, taking tomo images...") - yield from mv(zps.pi_r, -50 + taxi_ang) + yield from mv(zps.pi_r, -50 + offset_angle) status = yield from abs_set(zps.pi_r, 50, wait=False) yield from bps.sleep(2) while not status.done: - yield from trigger_and_read(list(dets) + motor) + yield from trigger_and_read(list(detectors) + motor) # bkg images print("\nTaking background images...") yield from _set_rotation_speed(rs=30) @@ -338,7 +338,7 @@ def inner_scan(): yield from mv(zps.pi_x, 12) yield from mv(zps.pi_r, 70) - yield from trigger_and_read(list(dets) + motor) + yield from trigger_and_read(list(detectors) + motor) yield from _close_shutter(simu=simu) yield from mv(zps.pi_r, 0) @@ -385,7 +385,7 @@ def mosaic_fly_scan( z_list, r_list, exposure_time=0.1, - rel_rot_ang=150, + relative_rot_angle=150, period=0.1, chunk_size=20, out_x=None, @@ -480,7 +480,7 @@ def multi_pos_3D_xanes( z_list=[0], r_list=[0], exposure_time=0.05, - rel_rot_ang=182, + relative_rot_angle=182, rs=2, ): """ @@ -489,7 +489,7 @@ def multi_pos_3D_xanes( to run: - RE(multi_pos_3D_xanes(Ni_eng_list, x_list=[a, b, c], y_list=[aa,bb,cc], z_list=[aaa,bbb, ccc], r_list=[0, 0, 0], exposure_time=0.05, rel_rot_ang=185, rs=3, out_x=1500, out_y=-1500, out_z=-770, out_r=0, note='NC') + RE(multi_pos_3D_xanes(Ni_eng_list, x_list=[a, b, c], y_list=[aa,bb,cc], z_list=[aaa,bbb, ccc], r_list=[0, 0, 0], exposure_time=0.05, relative_rot_angle=185, rs=3, out_x=1500, out_y=-1500, out_z=-770, out_r=0, note='NC') """ num_pos = len(x_list) for i in range(num_pos): @@ -502,7 +502,7 @@ def multi_pos_3D_xanes( yield from xanes_3D( eng_list, exposure_time=exposure_time, - relative_rot_angle=rel_rot_ang, + relative_rot_angle=relative_rot_angle, period=exposure_time, out_x=out_x, out_y=out_y, @@ -517,40 +517,31 @@ def multi_pos_3D_xanes( insert_text(f"finished 3D xanes scan for {note_pos}") -def mk_eng_list(elem, bulk=False): - if bulk: +def mk_eng_list(elem): + if elem.split("_")[-1] == "wl": eng_list = np.genfromtxt( "/nsls2/data/fxi-new/shared/config/xanes_ref/" + elem.split("_")[0] + "/eng_list_" + elem.split("_")[0] - + "_xanes_standard_dense.txt" + + "_s_xanes_standard_21pnt.txt" + ) + elif elem.split("_")[-1] == "101": + eng_list = np.genfromtxt( + "/nsls2/data/fxi-new/shared/config/xanes_ref/" + + elem.split("_")[0] + + "/eng_list_" + + elem.split("_")[0] + + "_xanes_standard_101pnt.txt" + ) + elif elem.split("_")[-1] == "63": + eng_list = np.genfromtxt( + "/nsls2/data/fxi-new/shared/config/xanes_ref/" + + elem.split("_")[0] + + "/eng_list_" + + elem.split("_")[0] + + "_xanes_standard_63pnt.txt" ) - else: - if elem.split("_")[-1] == "wl": - eng_list = np.genfromtxt( - "/nsls2/data/fxi-new/shared/config/xanes_ref/" - + elem.split("_")[0] - + "/eng_list_" - + elem.split("_")[0] - + "_s_xanes_standard_21pnt.txt" - ) - elif elem.split("_")[-1] == "101": - eng_list = np.genfromtxt( - "/nsls2/data/fxi-new/shared/config/xanes_ref/" - + elem.split("_")[0] - + "/eng_list_" - + elem.split("_")[0] - + "_xanes_standard_101pnt.txt" - ) - elif elem.split("_")[-1] == "63": - eng_list = np.genfromtxt( - "/nsls2/data/fxi-new/shared/config/xanes_ref/" - + elem.split("_")[0] - + "/eng_list_" - + elem.split("_")[0] - + "_xanes_standard_63pnt.txt" - ) return eng_list @@ -560,1200 +551,183 @@ def sort_in_pos(in_pos_list): z_list = [] r_list = [] for ii in range(len(in_pos_list)): - x_list.append( - zps.sx.position if in_pos_list[ii][0] is None else in_pos_list[ii][0] - ) - y_list.append( - zps.sy.position if in_pos_list[ii][1] is None else in_pos_list[ii][1] - ) - z_list.append( - zps.sz.position if in_pos_list[ii][2] is None else in_pos_list[ii][2] - ) - r_list.append( - zps.pi_r.position if in_pos_list[ii][3] is None else in_pos_list[ii][3] - ) - # if in_pos_list[ii][0] is None: - # x_list.append(zps.sx.position) - # else: - # x_list.append(in_pos_list[ii][0]) - - # if in_pos_list[ii][1] is None: - # y_list.append(zps.sy.position) - # else: - # y_list.append(in_pos_list[ii][1]) - - # if in_pos_list[ii][2] is None: - # z_list.append(zps.sz.position) - # else: - # z_list.append(in_pos_list[ii][2]) - - # if in_pos_list[ii][3] is None: - # r_list.append(zps.pi_r.position) - # else: - # r_list.append(in_pos_list[ii][3]) - - return (x_list, y_list, z_list, r_list) - - -def multi_edge_xanes( - elements=["Ni_wl"], - scan_type="3D", - filters={"Ni_filters": [1, 2, 3]}, - exposure_time={"Ni_exp": 0.05}, - rel_rot_ang=185, - rs=1, - in_pos_list=[[None, None, None, None]], - out_pos=[None, None, None, None], - note="", - relative_move_flag=0, - binning=None, - simu=False, -): - yield from mv(Andor.cam.acquire, 0) - cam_bin = {0: "[1x1]", 1: "[2x2]", 2: "[3x3]", 3: "[4x4]", 4: "[8x8]"} - x_list, y_list, z_list, r_list = sort_in_pos(in_pos_list) - for elem in elements: - for key in filters.keys(): - if elem.split("_")[0] == key.split("_")[0]: - yield from select_filters(filters[key]) - break - else: - yield from select_filters([]) - for key in exposure_time.keys(): - if elem.split("_")[0] == key.split("_")[0]: - exposure = exposure_time[key] - print(elem, exposure) - break - else: - exposure = 0.05 - print("use default exposure time 0.05s") - eng_list = mk_eng_list(elem, bulk=False) - if scan_type == "2D": - if binning is None: - binning = 0 - ans = input( - f"You are going to conduct 2D XANES with camera binning of {cam_bin[binning]}. Proceed? (Y/n)" - ) - if ans.upper() == "N": - return - if int(binning) not in [0, 1, 2, 3, 4]: - raise ValueError("binnng must be in [0, 1, 2, 3, 4]") - yield from mv(Andor.binning, binning) - - yield from multipos_2D_xanes_scan2( - eng_list, - x_list, - y_list, - z_list, - r_list, - out_x=out_pos[0], - out_y=out_pos[1], - out_z=out_pos[2], - out_r=out_pos[3], - exposure_time=exposure, - chunk_size=5, - simu=simu, - relative_move_flag=relative_move_flag, - note=note, - md=None, - sleep_time=0, - repeat_num=1, - ) - elif scan_type == "3D": - if binning is None: - binning = 1 - ans = input( - f"You are going to conduct 3D XANES with camera binning of {cam_bin[binning]}. Proceed? (Y/n)" - ) - if ans.upper() == "N": - return - if int(binning) not in [0, 1, 2, 3, 4]: - raise ValueError("binnng must be in [0, 1, 2, 3, 4]") - yield from mv(Andor.binning, binning) - - yield from multi_pos_xanes_3D( - eng_list, - x_list, - y_list, - z_list, - r_list, - exposure_time=exposure, - relative_rot_angle=rel_rot_ang, - rs=rs, - out_x=out_pos[0], - out_y=out_pos[1], - out_z=out_pos[2], - out_r=out_pos[3], - note=note, - simu=simu, - relative_move_flag=relative_move_flag, - rot_first_flag=1, - sleep_time=0, - repeat=1, - ) + if in_pos_list[ii][0] is None: + x_list.append(zps.sx.position) else: - print("wrong scan type") - return - - -def multi_edge_xanes2( - elements=["Ni_wl"], - scan_type="3D", - filters={"Ni_filters": [1, 2, 3]}, - exposure_time={"Ni_exp": 0.05}, - rel_rot_ang=185, - rs=1, - in_pos_list=[[None, None, None, None]], - out_pos=[None, None, None, None], - note="", - relative_move_flag=0, - binning=None, - bulk=False, - bulk_intgr=10, - simu=False, - sleep=0, - repeat=None, -): - yield from mv(Andor.cam.acquire, 0) - cam_bin = {0: "[1x1]", 1: "[2x2]", 2: "[3x3]", 3: "[4x4]", 4: "[8x8]"} - if repeat is None: - repeat = 1 - repeat = int(repeat) - - for itr in range(repeat): - x_list, y_list, z_list, r_list = sort_in_pos(in_pos_list) - for elem in elements: - for key in filters.keys(): - if elem.split("_")[0] == key.split("_")[0]: - yield from select_filters(filters[key]) - else: - yield from select_filters([]) - for key in exposure_time.keys(): - if elem.split("_")[0] == key.split("_")[0]: - exposure = exposure_time[key] - print(elem, exposure) - else: - exposure = 0.05 - print("use default exposure time 0.05s") - eng_list = mk_eng_list(elem, bulk=False) - if scan_type == "2D": - if binning is None: - binning = 0 - ans = input( - f"You are going to conduct 2D XANES with camera binning of {cam_bin[binning]}. Proceed? (Y/n)" - ) - if ans.upper() == "N": - return - if int(binning) not in [0, 1, 2, 3, 4]: - raise ValueError("binnng must be in [0, 1, 2, 3, 4]") - yield from mv(Andor.binning, binning) - - yield from multipos_2D_xanes_scan2( - eng_list, - x_list, - y_list, - z_list, - r_list, - out_x=out_pos[0], - out_y=out_pos[1], - out_z=out_pos[2], - out_r=out_pos[3], - exposure_time=exposure, - chunk_size=5, - simu=simu, - relative_move_flag=relative_move_flag, - note=note, - md=None, - sleep_time=0, - repeat_num=1, - ) - elif scan_type == "3D": - if binning is None: - binning = 1 - ans = input( - f"You are going to conduct 3D XANES with camera binning of {cam_bin[binning]}. Proceed? (Y/n)" - ) - if ans.upper() == "N": - return - if int(binning) not in [0, 1, 2, 3, 4]: - raise ValueError("binnng must be in [0, 1, 2, 3, 4]") - yield from mv(Andor.binning, binning) - - yield from multi_pos_xanes_3D( - eng_list, - x_list, - y_list, - z_list, - r_list, - exposure_time=exposure, - relative_rot_angle=rel_rot_ang, - rs=rs, - out_x=out_pos[0], - out_y=out_pos[1], - out_z=out_pos[2], - out_r=out_pos[3], - note=note, - simu=simu, - relative_move_flag=relative_move_flag, - rot_first_flag=1, - sleep_time=0, - repeat=1, - ) - else: - print("wrong scan type") - - if bulk: - eng_list = mk_eng_list(elem, bulk=True) - zpx = zp.x.position - apx = aper.x.position - cdx = clens.x.position - yield from mv(zp.x, -6500 + zpx) - yield from mv(clens.x, 6500 + cds) - yield from mv(aper.x, -4000 + apx) - xxanes_scan(eng_list, delay_time=0.2, intgr=bulk_intgr, note=note) - yield from mv(clens.x, cds) - yield from mv(aper.x, apx) - yield from mv(zp.x, zpx) - if itr != repeat - 1: - yield from bps.sleep(sleep) - print(f"repeat # {itr} finished") - - -def fly_scan2( - exposure_time=0.05, - start_angle=None, - rel_rot_ang=180, - period=0.05, - out_x=None, - out_y=None, - out_z=None, - out_r=None, - rs=3, - relative_move_flag=1, - rot_first_flag=1, - filters=[], - rot_back_velo=30, - binning=None, - note="", - md=None, - move_to_ini_pos=True, - simu=False, -): - """ - Inputs: - ------- - exposure_time: float, in unit of sec - - start_angle: float - starting angle - - rel_rot_ang: float, - total rotation angles start from current rotary stage (zps.pi_r) position - - period: float, in unit of sec - period of taking images, "period" should >= "exposure_time" - - out_x: float, default is 0 - relative movement of sample in "x" direction using zps.sx to move out sample (in unit of um) - NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z - - out_y: float, default is 0 - relative movement of sample in "y" direction using zps.sy to move out sample (in unit of um) - NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z - - out_z: float, default is 0 - relative movement of sample in "z" direction using zps.sz to move out sample (in unit of um) - NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z - - 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 - - rs: float, default is 1 - rotation speed in unit of deg/sec - - note: string - adding note to the scan - - simu: Bool, default is False - True: will simulate closing/open shutter without really closing/opening - False: will really close/open shutter - - """ - yield from mv(Andor.cam.acquire, 0) - if binning is None: - binning = 0 - if int(binning) not in [0, 1, 2, 3, 4]: - raise ValueError("binnng must be in [0, 1, 2, 3, 4]") - yield from mv(Andor.binning, binning) - - global ZONE_PLATE - motor_x_ini = zps.sx.position - motor_y_ini = zps.sy.position - motor_z_ini = zps.sz.position - motor_r_ini = zps.pi_r.position + x_list.append(in_pos_list[ii][0]) - if not (start_angle is None): - yield from mv(zps.pi_r, start_angle) - - if relative_move_flag: - motor_x_out = motor_x_ini + out_x if not (out_x is None) else motor_x_ini - motor_y_out = motor_y_ini + out_y if not (out_y is None) else motor_y_ini - motor_z_out = motor_z_ini + out_z if not (out_z is None) else motor_z_ini - motor_r_out = motor_r_ini + out_r if not (out_r is None) else motor_r_ini - else: - motor_x_out = out_x if not (out_x is None) else motor_x_ini - motor_y_out = out_y if not (out_y is None) else motor_y_ini - motor_z_out = out_z if not (out_z is None) else motor_z_ini - motor_r_out = out_r if not (out_r is None) else motor_r_ini + if in_pos_list[ii][1] is None: + y_list.append(zps.sy.position) + else: + y_list.append(in_pos_list[ii][1]) - motor = [zps.sx, zps.sy, zps.sz, zps.pi_r] + if in_pos_list[ii][2] is None: + z_list.append(zps.sz.position) + else: + z_list.append(in_pos_list[ii][2]) - dets = [Andor, ic3] - taxi_ang = -1 * rs - cur_rot_ang = zps.pi_r.position - tgt_rot_ang = cur_rot_ang + rel_rot_ang - _md = { - "detectors": ["Andor"], - "motors": [mot.name for mot in motor], - "XEng": XEng.position, - "ion_chamber": ic3.name, - "plan_args": { - "exposure_time": exposure_time, - "start_angle": start_angle, - "relative_rot_angle": rel_rot_ang, - "period": period, - "out_x": out_x, - "out_y": out_y, - "out_z": out_z, - "out_r": out_r, - "rs": rs, - "relative_move_flag": relative_move_flag, - "rot_first_flag": rot_first_flag, - "filters": [t.name for t in filters] if filters else "None", - "binning": "None" if binning is None else binning, - "note": note if note else "None", - "zone_plate": ZONE_PLATE, - }, - "plan_name": "fly_scan", - "num_bkg_images": 20, - "num_dark_images": 20, - "plan_pattern": "linspace", - "plan_pattern_module": "numpy", - "hints": {}, - "operator": "FXI", - "note": note if note else "None", - "zone_plate": ZONE_PLATE, - #'motor_pos': wh_pos(print_on_screen=0), - } - _md.update(md or {}) - try: - dimensions = [(zps.pi_r.hints["fields"], "primary")] - except (AttributeError, KeyError): - pass - else: - _md["hints"].setdefault("dimensions", dimensions) - - yield from _set_andor_param( - exposure_time=exposure_time, period=period, chunk_size=20, binning=binning - ) - yield from _set_rotation_speed(rs=np.abs(rs)) - print("set rotation speed: {} deg/sec".format(rs)) - - @stage_decorator(list(dets) + motor) - @bpp.monitor_during_decorator([zps.pi_r]) - @run_decorator(md=_md) - def fly_inner_scan(): - for flt in filters: - yield from mv(flt, 1) - yield from mv(flt, 1) - yield from bps.sleep(1) - - # close shutter, dark images: numer=chunk_size (e.g.20) - print("\nshutter closed, taking dark images...") - yield from _take_dark_image( - dets, motor, num=1, chunk_size=20, stream_name="dark", simu=simu - ) - - # open shutter, tomo_images - true_period = yield from rd(Andor.cam.acquire_period) - rot_time = np.abs(rel_rot_ang) / np.abs(rs) - num_img = int(rot_time / true_period) + 2 - - yield from _open_shutter(simu=simu) - print("\nshutter opened, taking tomo images...") - yield from _set_Andor_chunk_size(dets, chunk_size=num_img) - # yield from mv(zps.pi_r, cur_rot_ang + taxi_ang) - status = yield from abs_set(zps.pi_r, tgt_rot_ang, wait=False) - # yield from bps.sleep(1) - yield from _take_image(dets, motor, num=1, stream_name="primary") - while not status.done: - yield from bps.sleep(0.01) - # yield from trigger_and_read(list(dets) + motor) - - # bkg images - print("\nTaking background images...") - yield from _set_rotation_speed(rs=rot_back_velo) - # yield from abs_set(zps.pi_r.velocity, rs) - - yield from _take_bkg_image( - motor_x_out, - motor_y_out, - motor_z_out, - motor_r_out, - dets, - [], - num=1, - chunk_size=20, - rot_first_flag=rot_first_flag, - stream_name="flat", - simu=simu, - ) - yield from _close_shutter(simu=simu) - if move_to_ini_pos: - yield from _move_sample_in( - motor_x_ini, - motor_y_ini, - motor_z_ini, - motor_r_ini, - trans_first_flag=rot_first_flag, - repeat=3, - ) - for flt in filters: - yield from mv(flt, 0) - - uid = yield from fly_inner_scan() - yield from mv(Andor.cam.image_mode, 1) - print("scan finished") - txt = get_scan_parameter(print_flag=0) - insert_text(txt) - print(txt) - return uid - - -def fly_scan3( - exposure_time=0.05, - start_angle=None, - rel_rot_ang=180, - period=0.05, - out_x=None, - out_y=None, - out_z=None, - out_r=None, - rs=3, - relative_move_flag=1, - rot_first_flag=1, - filters=[], - rot_back_velo=30, - binning=None, - note="", - md=None, - move_to_ini_pos=True, - simu=False, - noDark=False, - noFlat=False, -): - """ - Inputs: - ------- - exposure_time: float, in unit of sec - - start_angle: float - starting angle - - rel_rot_ang: float, - total rotation angles start from current rotary stage (zps.pi_r) position - - period: float, in unit of sec - period of taking images, "period" should >= "exposure_time" - - out_x: float, default is 0 - relative movement of sample in "x" direction using zps.sx to move out sample (in unit of um) - NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z - - out_y: float, default is 0 - relative movement of sample in "y" direction using zps.sy to move out sample (in unit of um) - NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z - - out_z: float, default is 0 - relative movement of sample in "z" direction using zps.sz to move out sample (in unit of um) - NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z - - 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 - - rs: float, default is 1 - rotation speed in unit of deg/sec - - note: string - adding note to the scan - - simu: Bool, default is False - True: will simulate closing/open shutter without really closing/opening - False: will really close/open shutter - - """ - yield from mv(Andor.cam.acquire, 0) - global ZONE_PLATE - - if binning is None: - binning = 0 - if int(binning) not in [0, 1, 2, 3, 4]: - raise ValueError("binnng must be in [0, 1, 2, 3, 4]") - yield from mv(Andor.binning, binning) - - motor_x_ini = zps.sx.position - motor_y_ini = zps.sy.position - motor_z_ini = zps.sz.position - motor_r_ini = zps.pi_r.position - - if not (start_angle is None): - yield from mv(zps.pi_r, start_angle) - - if relative_move_flag: - motor_x_out = motor_x_ini + out_x if not (out_x is None) else motor_x_ini - motor_y_out = motor_y_ini + out_y if not (out_y is None) else motor_y_ini - motor_z_out = motor_z_ini + out_z if not (out_z is None) else motor_z_ini - motor_r_out = motor_r_ini + out_r if not (out_r is None) else motor_r_ini - else: - motor_x_out = out_x if not (out_x is None) else motor_x_ini - motor_y_out = out_y if not (out_y is None) else motor_y_ini - motor_z_out = out_z if not (out_z is None) else motor_z_ini - motor_r_out = out_r if not (out_r is None) else motor_r_ini - - motor = [zps.sx, zps.sy, zps.sz, zps.pi_r] - - dets = [Andor, ic3] - taxi_ang = -1 * rs - cur_rot_ang = zps.pi_r.position - tgt_rot_ang = cur_rot_ang + rel_rot_ang - _md = { - "detectors": ["Andor"], - "motors": [mot.name for mot in motor], - "XEng": XEng.position, - "ion_chamber": ic3.name, - "plan_args": { - "exposure_time": exposure_time, - "start_angle": start_angle, - "relative_rot_angle": rel_rot_ang, - "period": period, - "out_x": out_x, - "out_y": out_y, - "out_z": out_z, - "out_r": out_r, - "rs": rs, - "relative_move_flag": relative_move_flag, - "rot_first_flag": rot_first_flag, - "filters": [t.name for t in filters] if filters else "None", - "binning": binning, - "note": note if note else "None", - "zone_plate": ZONE_PLATE, - "noDark": "True" if noDark else "False", - "noFlat": "True" if noFlat else "False", - }, - "plan_name": "fly_scan3", - "num_bkg_images": 20, - "num_dark_images": 20, - "plan_pattern": "linspace", - "plan_pattern_module": "numpy", - "hints": {}, - "operator": "FXI", - "note": note if note else "None", - "zone_plate": ZONE_PLATE, - #'motor_pos': wh_pos(print_on_screen=0), - } - _md.update(md or {}) - try: - dimensions = [(zps.pi_r.hints["fields"], "primary")] - except (AttributeError, KeyError): - pass - else: - _md["hints"].setdefault("dimensions", dimensions) - - yield from _set_andor_param( - exposure_time=exposure_time, period=period, chunk_size=20, binning=binning - ) - yield from _set_rotation_speed(rs=np.abs(rs)) - print("set rotation speed: {} deg/sec".format(rs)) - - @stage_decorator(list(dets) + motor) - @bpp.monitor_during_decorator([zps.pi_r]) - @run_decorator(md=_md) - def fly_inner_scan(): - for flt in filters: - yield from mv(flt, 1) - yield from mv(flt, 1) - yield from bps.sleep(1) - - # close shutter, dark images: numer=chunk_size (e.g.20) - if not noDark: - print("\nshutter closed, taking dark images...") - yield from _take_dark_image( - dets, motor, num=1, chunk_size=20, stream_name="dark", simu=simu - ) - - # open shutter, tomo_images - true_period = yield from rd(Andor.cam.acquire_period) - rot_time = np.abs(rel_rot_ang) / np.abs(rs) - num_img = int(rot_time / true_period) + 2 - - yield from _open_shutter(simu=simu) - print("\nshutter opened, taking tomo images...") - yield from _set_Andor_chunk_size(dets, chunk_size=num_img) - # yield from mv(zps.pi_r, cur_rot_ang + taxi_ang) - status = yield from abs_set(zps.pi_r, tgt_rot_ang, wait=False) - # yield from bps.sleep(1) - yield from _take_image(dets, motor, num=1, stream_name="primary") - while not status.done: - yield from bps.sleep(0.01) - # yield from trigger_and_read(list(dets) + motor) - - # bkg images - print("\nTaking background images...") - yield from _set_rotation_speed(rs=rot_back_velo) - # yield from abs_set(zps.pi_r.velocity, rs) - - if not noFlat: - yield from _take_bkg_image( - motor_x_out, - motor_y_out, - motor_z_out, - motor_r_out, - dets, - [], - num=1, - chunk_size=20, - rot_first_flag=rot_first_flag, - stream_name="flat", - simu=simu, - ) - - if not noDark: - yield from _close_shutter(simu=simu) - - if move_to_ini_pos: - yield from _move_sample_in( - motor_x_ini, - motor_y_ini, - motor_z_ini, - motor_r_ini, - trans_first_flag=rot_first_flag, - repeat=3, - ) - for flt in filters: - yield from mv(flt, 0) - - uid = yield from fly_inner_scan() - yield from mv(Andor.cam.image_mode, 1) - print("scan finished") - txt = get_scan_parameter(print_flag=0) - insert_text(txt) - print(txt) - return uid - - -def mosaic_fly_scan_xh( - x_ini=None, - y_ini=None, - z_ini=None, - x_num_steps=1, - y_num_steps=1, - z_num_steps=1, - x_step_size=0, - y_step_size=0, - z_step_size=0, - exposure_time=0.1, - period=0.1, - rs=4, - out_x=None, - out_y=None, - out_z=None, - out_r=None, - start_angle=None, - rel_rot_ang=180, - binning=0, - relative_move_flag=True, - simu=False, - note="", -): - if binning is None: - binning = 0 - if int(binning) not in [0, 1, 2, 3, 4]: - raise ValueError("binnng must be in [0, 1, 2, 3, 4]") - yield from mv(Andor.binning, binning) - - if x_ini is None: - x_ini = zps.sx.position - if y_ini is None: - y_ini = zps.sy.position - if z_ini is None: - z_ini = zps.sz.position - - y_list = y_ini + np.arange(y_num_steps) * y_step_size - x_list = x_ini + np.arange(x_num_steps) * x_step_size - z_list = z_ini + np.arange(z_num_steps) * z_step_size - txt1 = "\n###############################################" - txt2 = "\n####### start mosaic tomography scan ######" - txt3 = "\n###############################################" - txt = txt1 + txt2 + txt3 - print(txt) - for y in y_list: - for z in z_list: - for x in x_list: - yield from mv(zps.sx, x, zps.sy, y, zps.sz, z) - yield from fly_scan( - exposure_time=exposure_time, - start_angle=start_angle, - relative_rot_angle=rel_rot_ang, - period=period, - out_x=out_x, - out_y=out_y, - out_z=out_z, - out_r=out_r, - rs=rs, - relative_move_flag=relative_move_flag, - note=note, - simu=simu, - rot_first_flag=True, - ) - - -def grid_z_scan( - zstart=-0.03, - zstop=0.03, - zsteps=5, - gmesh=[[-5, 0, 5], [-5, 0, 5]], - out_x=-100, - out_y=-100, - chunk_size=10, - exposure_time=0.1, - note="", - md=None, - simu=False, -): - """ - scan the zone-plate to find best focus - use as: - z_scan(zstart=-0.03, zstop=0.03, zsteps=5, gmesh=[[-5, 0, 5], [-5, 0, 5]], out_x=-100, out_y=-100, chunk_size=10, exposure_time=0.1, fn='/home/xf18id/Documents/tmp/z_scan.h5', note='', md=None) - - Input: - --------- - zstart: float, relative starting position of zp_z - - zstop: float, relative zstop position of zp_z - - zsteps: int, number of zstep between [zstart, zstop] - - out_x: float, relative amount to move sample out for zps.sx - - out_y: float, relative amount to move sample out for zps.sy - - chunk_size: int, number of images per each subscan (for Andor camera) - - exposure_time: float, exposure time for each image - - note: str, experiment notes - - """ - yield from mv(Andor.cam.acquire, 0) - dets = [Andor] - motor = zp.z - z_ini = motor.position # zp.z intial position - z_start = z_ini + zstart - z_stop = z_ini + zstop - zp_x_ini = zp.x.position - zp_y_ini = zp.y.position - # dets = [Andor] - y_ini = zps.sy.position # sample y position (initial) - y_out = ( - y_ini + out_y if not (out_y is None) else y_ini - ) # sample y position (out-position) - x_ini = zps.sx.position - x_out = x_ini + out_x if not (out_x is None) else x_ini - yield from mv(Andor.cam.acquire, 0) - yield from mv(Andor.cam.image_mode, 0) - yield from mv(Andor.cam.num_images, chunk_size) - yield from mv(Andor.cam.acquire_time, exposure_time) - period_cor = max(exposure_time + 0.01, 0.05) - yield from mv(Andor.cam.acquire_period, period_cor) - - _md = { - "detectors": [det.name for det in dets], - "motors": [motor.name], - "XEng": XEng.position, - "plan_args": { - "zstart": zstart, - "zstop": zstop, - "zsteps": zsteps, - "gmesh": gmesh, - "out_x": out_x, - "out_y": out_y, - "chunk_size": chunk_size, - "exposure_time": exposure_time, - "note": note if note else "None", - }, - "plan_name": "grid_z_scan", - "plan_pattern": "linspace", - "plan_pattern_module": "numpy", - "hints": {}, - "operator": "FXI", - "motor_pos": wh_pos(print_on_screen=0), - } - _md.update(md or {}) - my_var = np.linspace(z_start, z_stop, zsteps) - try: - dimensions = [(motor.hints["fields"], "primary")] - except (AttributeError, KeyError): - pass - else: - _md["hints"].setdefault("dimensions", dimensions) - - @stage_decorator(list(dets) + [motor]) - @run_decorator(md=_md) - def inner_scan(): - yield from _open_shutter(simu=simu) - for xx in gmesh[0]: - for yy in gmesh[1]: - yield from mv(zp.x, zp_x_ini + xx, zp.y, zp_y_ini + yy, wait=True) - # yield from mv(zp.y, zp_y_ini+yy, wait=True) - yield from bps.sleep(1) - for x in my_var: - yield from mv(motor, x) - yield from trigger_and_read(list(dets) + [motor], name="primary") - # backgroud images - yield from mv(zps.sx, x_out, zps.sy, y_out, wait=True) - yield from bps.sleep(1) - yield from trigger_and_read(list(dets) + [motor], name="flat") - yield from mv(zps.sx, x_ini, zps.sy, y_ini, wait=True) - yield from bps.sleep(1) - # yield from mv(zps.sy, y_ini, wait=True) - yield from _close_shutter(simu=simu) - yield from bps.sleep(1) - yield from trigger_and_read(list(dets) + [motor], name="dark") - - yield from mv(zps.sx, x_ini) - yield from mv(zps.sy, y_ini) - yield from mv(zp.z, z_ini) - yield from mv(zp.x, zp_x_ini, zp.y, zp_y_ini, wait=True) - yield from mv(Andor.cam.image_mode, 1) - - uid = yield from inner_scan() - yield from mv(Andor.cam.image_mode, 1) - yield from _close_shutter(simu=simu) - txt = get_scan_parameter() - insert_text(txt) - print(txt) - - -def xxanes_scan( - eng_list, - delay_time=0.5, - intgr=1, - dets=[ic1, ic2, ic3], - note="", - md=None, - repeat=None, - sleep=1200, -): - """ - eng_list: energy list in keV - delay_time: delay_time between each energy step, in unit of sec - note: string; optional, description of the scan - """ - if repeat is None: - repeat = 1 - repeat = int(repeat) - - check_eng_range([eng_list[0], eng_list[-1]]) - print(0) - yield from _open_shutter(simu=False) - # dets=[ic1, ic2, ic3] - motor_x = XEng - motor_x_ini = motor_x.position # initial position of motor_x - - # added by XH -- start - motor_y = dcm - # added by XH -- end - - _md = { - "detectors": "".join(ii.name + " " for ii in dets), - "motors": [motor_x.name, motor_y.name], - "XEng": XEng.position, - "plan_name": "xxanes", - "plan_args": { - "eng": eng_list, - "detectors": "".join(ii.name + " " for ii in dets), - "delay_time": delay_time, - "repeat": intgr, - "note": note if note else "None", - }, - "plan_pattern": "linspace", - "plan_pattern_module": "numpy", - "hints": {}, - "operator": "FXI", - "note": note if note else "None", - } - _md.update(md or {}) - try: - dimensions = [ - (motor_x.hints["fields"], "primary"), - (motor_y.hints["fields"], "primary"), - ] - except (AttributeError, KeyError): - pass - else: - _md["hints"].setdefault("dimensions", dimensions) - - @stage_decorator(list(dets) + [motor_x, motor_y]) - @run_decorator(md=_md) - def eng_inner_scan(): - for eng in eng_list: - yield from mv(motor_x, eng) - yield from bps.sleep(delay_time) - yield from bps.repeat( - partial(bps.trigger_and_read, list(dets) + [motor_x, motor_y]), - num=intgr, - delay=0.01, - ) - # yield from trigger_and_read(list(dets) + [motor_x, motor_y]) - yield from mv(motor_x, motor_x_ini) - - for itr in range(repeat): - yield from _open_shutter(simu=False) - yield from eng_inner_scan() - yield from _close_shutter(simu=False) - if itr != (repeat - 1): - yield from bps.sleep(sleep) - print(f"repeat # {itr} finished") - - -def xxanes_scan2( - eng_list, dets=[ic1, ic2, ic3], note="", md=None, repeat=1, sleep=100, simu=False -): - """ - eng_list: energy list in keV - note: string; optional, description of the scan - """ - repeat = int(repeat) - - check_eng_range([eng_list[0], eng_list[-1]]) - print(0) - XEng_target = eng_list[-1] - # motor_x = dcm - # motor_y = XEng - XEng_ini = XEng.position # initial position of motor_x - dcm_vel_ini = dcm.th1.velocity.value - # yield from mv(dcm.th1.velocity, 0.1) - # yield from mv(XEng, eng_list[0]) - - ang0 = np.arcsin(12.398 / eng_list[0] / 2 / (5.43 / np.sqrt(3))) - ang1 = np.arcsin(12.398 / eng_list[-1] / 2 / (5.43 / np.sqrt(3))) - dcm_vel = ( - 10 - * 180 - * np.abs(ang1 - ang0) - / np.pi - / (4 * np.abs(eng_list[0] - eng_list[-1])) - / 1000 - ) - if dcm_vel < 0.00279: - dcm_vel = 0.00279 - intgr = int(np.ceil(10 * 180 * np.abs(ang1 - ang0) / np.pi / dcm_vel)) - - _md = { - "detectors": "".join(ii.name + " " for ii in dets), - "motors": [XEng.name, dcm.name], - "XEng": XEng.position, - "plan_name": "xxanes2", - "plan_args": { - "eng": eng_list, - "detectors": "".join(ii.name + " " for ii in dets), - "repeat": repeat, - "IC_rate": 10, - "dcm velocity": dcm_vel, - "note": note if note else "None", - }, - "plan_pattern": "linspace", - "plan_pattern_module": "numpy", - "hints": {}, - "operator": "FXI", - } - _md.update(md or {}) - try: - dimensions = [ - (XEng.hints["fields"], "primary"), - (dcm.hints["fields"], "primary"), - ] - except (AttributeError, KeyError): - pass - else: - _md["hints"].setdefault("dimensions", dimensions) - - @stage_decorator(list(dets) + [XEng, dcm]) - @bpp.monitor_during_decorator( - [XEng.user_readback, dcm.th1.user_readback] + list(dets) - ) - @run_decorator(md=_md) - def eng_inner_scan(): - while XEng.moving: - yield from bps.sleep(1) - status = yield from abs_set(XEng, XEng_target, wait=False) - # yield from trigger_and_read(dets + [dcm, XEng], name=stream_name) - yield from bps.repeat( - partial(bps.trigger_and_read, list(dets) + [XEng, dcm]), - num=intgr, - delay=0.1, - ) - while not status.done: - yield from bps.sleep(0.01) + if in_pos_list[ii][3] is None: + r_list.append(zps.pi_r.position) + else: + r_list.append(in_pos_list[ii][3]) - for itr in range(repeat): - yield from _open_shutter(simu=simu) - yield from mv(dcm.th1.velocity, 0.1) - yield from mv(XEng, eng_list[0]) - yield from mv(dcm.th1.velocity, dcm_vel) - yield from bps.sleep(1) - yield from eng_inner_scan() - yield from _close_shutter(simu=simu) - if itr != (repeat - 1): - yield from bps.sleep(sleep) - print(f"repeat # {itr} finished") - - yield from mv(dcm.th1.velocity, 0.1) - yield from mv(XEng, XEng_ini) - yield from mv(dcm.th1.velocity, dcm_vel_ini) - - -def mosaic_2D_rel_grid_xh( - mot1=zps.sx, - mot1_start=-100, - mot1_end=100, - mot1_points=6, - mot2=zps.sy, - mot2_start=-50, - mot2_end=50, - mot2_points=6, - mot2_snake=False, - out_x=100, - out_y=100, - exp_time=0.1, - chunk_size=1, + return (x_list, y_list, z_list, r_list) + + +def multi_edge_xanes( + elements=["Ni_wl"], + scan_type="3D", + filters={"Ni_filters": [1, 2, 3]}, + exposure_time={"Ni_exp": 0.05}, + relative_rot_angle=185, + rs=1, + in_pos_list=[[0, 0, 0, 0]], + out_pos=[0, 0, 0, 0], note="", - md=None, + relative_move_flag=0, + binning=[2, 2], simu=False, ): - yield from mv(Andor.cam.acquire, 0) - dets = [Andor] - y_ini = zps.sy.position # sample y position (initial) - y_out = ( - y_ini + out_y if not (out_y is None) else y_ini - ) # sample y position (out-position) - x_ini = zps.sx.position - x_out = x_ini + out_x if not (out_x is None) else x_ini - yield from mv(Andor.cam.acquire, 0) - yield from mv(Andor.cam.image_mode, 0) - yield from mv(Andor.cam.num_images, chunk_size) - yield from mv(Andor.cam.acquire_time, exp_time) - period_cor = max(exp_time + 0.01, 0.05) - yield from mv(Andor.cam.acquire_period, period_cor) - - _md = { - "detectors": [det.name for det in dets], - "motors": [mot1.name, mot2.name], - "XEng": XEng.position, - "plan_args": { - "mot1_start": mot1_start, - "mot1_stop": mot1_end, - "mot1_pnts": mot1_points, - "mot2_start": mot2_start, - "mot2_stop": mot2_end, - "mot2_pnts": mot2_points, - "mot2_snake": mot2_snake, - "out_x": out_x, - "out_y": out_y, - "exposure_time": exp_time, - "note": note if note else "", - }, - "plan_name": "raster_scan_xh", - "plan_pattern": "linspace", - "plan_pattern_module": "numpy", - "hints": {}, - "operator": "FXI", - "motor_pos": wh_pos(print_on_screen=0), - } - _md.update(md or {}) - - # @stage_decorator(list(dets) + [mot1, mot2]) - # @run_decorator(md=_md) - # def inner_scan(): - yield from _open_shutter(simu=simu) - yield from rel_grid_scan( - dets, - mot1, - mot1_start, - mot1_end, - mot1_points, - mot2, - mot2_start, - mot2_end, - mot2_points, - mot2_snake, - ) - yield from mv(zps.sx, x_out, zps.sy, y_out, wait=True) - yield from stage(Andor) - yield from bps.sleep(1) - yield from trigger_and_read(list(dets) + [mot1, mot2], name="flat") - yield from mv(zps.sx, x_ini, zps.sy, y_ini, wait=True) - yield from bps.sleep(1) - yield from _close_shutter(simu=simu) - yield from stage(Andor) - yield from bps.sleep(1) - yield from trigger_and_read(list(dets) + [mot1, mot2], name="dark") - yield from mv(zps.sx, x_ini) - yield from mv(zps.sy, y_ini) - yield from unstage(Andor) - yield from mv(Andor.cam.image_mode, 1) - yield from _close_shutter(simu=simu) + x_list, y_list, z_list, r_list = sort_in_pos(in_pos_list) + for elem in elements: + for key in filters.keys(): + if elem.split("_")[0] == key.split("_")[0]: + yield from select_filters(filters[key]) + break + else: + yield from select_filters([]) + for key in exposure_time.keys(): + if elem.split("_")[0] == key.split("_")[0]: + exposure = exposure_time[key] + print(elem, exposure) + break + else: + exposure = 0.05 + print("use default exposure time 0.05s") + eng_list = mk_eng_list(elem) + if scan_type == "2D": + yield from multipos_2D_xanes_scan2( + eng_list, + x_list, + y_list, + z_list, + r_list, + out_x=out_pos[0], + out_y=out_pos[1], + out_z=out_pos[2], + out_r=out_pos[3], + exposure_time=exposure, + chunk_size=5, + simu=simu, + relative_move_flag=relative_move_flag, + note=note, + md=None, + sleep_time=0, + binning=[2, 2], + repeat_num=1, + ) + elif scan_type == "3D": + yield from multi_pos_xanes_3D( + eng_list, + x_list, + y_list, + z_list, + r_list, + exposure_time=exposure, + relative_rot_angle=relative_rot_angle, + rs=rs, + out_x=out_pos[0], + out_y=out_pos[1], + out_z=out_pos[2], + out_r=out_pos[3], + note=note, + simu=simu, + relative_move_flag=relative_move_flag, + traditional_sequence_flag=1, + sleep_time=0, + binning=[2, 2], + repeat=1, + ) + else: + print("wrong scan type") + return -def mosaic_2D_xh( - x_range=[-1, 1], - y_range=[-1, 1], +def fly_scan2( exposure_time=0.1, + start_angle=None, + relative_rot_angle=180, + period=0.15, + chunk_size=20, out_x=None, - out_y=None, + out_y=2000, out_z=None, out_r=None, - img_sizeX=2560, - img_sizeY=2160, + rs=1, + note="", simu=False, relative_move_flag=1, rot_first_flag=1, - note="", - scan_x_flag=1, filters=[], + rot_back_velo=30, md=None, + binning=[1, 1], ): - yield from mv(Andor.cam.acquire, 0) - zp_z_pos = zps.sz.position - DetU_z_pos = DetU.z.position - M = (DetU_z_pos / zp_z_pos - 1) * 10.0 - pxl = 6.5 / M + """ + Inputs: + ------- + exposure_time: float, in unit of sec + + start_angle: float + starting angle + + relative_rot_angle: float, + total rotation angles start from current rotary stage (zps.pi_r) position + + period: float, in unit of sec + period of taking images, "period" should >= "exposure_time" + + chunk_size: int, default setting is 20 + number of images taken for each trigger of Andor camera + + out_x: float, default is 0 + relative movement of sample in "x" direction using zps.sx to move out sample (in unit of um) + NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z + + out_y: float, default is 0 + relative movement of sample in "y" direction using zps.sy to move out sample (in unit of um) + NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z + + out_z: float, default is 0 + relative movement of sample in "z" direction using zps.sz to move out sample (in unit of um) + NOTE: BE CAUSION THAT IT WILL ROTATE SAMPLE BY "out_r" FIRST, AND THEN MOVE X, Y, Z + + 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 + + rs: float, default is 1 + rotation speed in unit of deg/sec + + note: string + adding note to the 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] - dets = [Andor, ic3] - yield from _set_andor_param( - exposure_time=exposure_time, period=exposure_time, chunk_size=1 - ) motor_x_ini = zps.sx.position motor_y_ini = zps.sy.position motor_z_ini = zps.sz.position motor_r_ini = zps.pi_r.position + if not (start_angle is None): + yield from mv(zps.pi_r, start_angle) + if relative_move_flag: motor_x_out = motor_x_ini + out_x if not (out_x is None) else motor_x_ini motor_y_out = motor_y_ini + out_y if not (out_y is None) else motor_y_ini @@ -1765,131 +739,158 @@ def mosaic_2D_xh( motor_z_out = out_z if not (out_z is None) else motor_z_ini motor_r_out = out_r if not (out_r is None) else motor_r_ini - img_sizeX = np.int(img_sizeX) - img_sizeY = np.int(img_sizeY) - x_range = np.int_(x_range) - y_range = np.int_(y_range) + motors = [zps.sx, zps.sy, zps.sz, zps.pi_r] - print("hello1") + detectors = [Andor, ic3] + offset_angle = -2 * rs + current_rot_angle = zps.pi_r.position + + target_rot_angle = current_rot_angle + relative_rot_angle _md = { - "detectors": [det.name for det in dets], - "motors": [mot.name for mot in motor], - "num_bkg_images": 5, - "num_dark_images": 5, - "x_range": x_range, - "y_range": y_range, - "out_x": out_x, - "out_y": out_y, - "out_z": out_z, - "exposure_time": exposure_time, + "detectors": ["Andor"], + "motors": [mot.name for mot in motors], "XEng": XEng.position, + "ion_chamber": ic3.name, "plan_args": { - "x_range": x_range, - "y_range": y_range, "exposure_time": exposure_time, + "start_angle": start_angle, + "relative_rot_angle": relative_rot_angle, + "period": period, + "chunk_size": chunk_size, "out_x": out_x, "out_y": out_y, "out_z": out_z, "out_r": out_r, - "img_sizeX": img_sizeX, - "img_sizeY": img_sizeY, - "pxl": pxl, - "note": note if note else "None", + "rs": rs, "relative_move_flag": relative_move_flag, "rot_first_flag": rot_first_flag, + "filters": [filt.name for filt in filters] if filters else "None", "note": note if note else "None", - "scan_x_flag": scan_x_flag, "zone_plate": ZONE_PLATE, }, - "plan_name": "mosaic_2D_xh", + "plan_name": "fly_scan2", + "num_bkg_images": 20, + "num_dark_images": 20, + "chunk_size": chunk_size, + "plan_pattern": "linspace", + "plan_pattern_module": "numpy", "hints": {}, "operator": "FXI", - "zone_plate": ZONE_PLATE, "note": note if note else "None", - #'motor_pos': wh_pos(print_on_screen=0), + "zone_plate": ZONE_PLATE, + #'motor_pos': wh_pos(print_on_screen=0), } _md.update(md or {}) try: - dimensions = [(motor.hints["fields"], "primary")] + dimensions = [(zps.pi_r.hints["fields"], "primary")] except (AttributeError, KeyError): pass else: _md["hints"].setdefault("dimensions", dimensions) - @stage_decorator(list(dets) + motor) + yield from mv(Andor.cam.acquire, 0) + yield from mv(Andor.cam.bin_y, binning[0], Andor.cam.bin_x, binning[1]) + yield from mv(Andor.cam.acquire_time, exposure_time) + yield from mv(Andor.cam.acquire_period, max(period, exposure_time + 0.01)) + # Andor.cam.acquire_period.put(period) + + # yield from _set_andor_param( + # exposure_time=exposure_time, period=period, chunk_size=chunk_size + # ) + yield from _set_rotation_speed(rs=rs) + print("set rotation speed: {} deg/sec".format(rs)) + + # We manually stage the Andor detector below. See there for why.... + # Stage everything else here in the usual way. + @stage_decorator([ic3] + motors) + @bpp.monitor_during_decorator([zps.pi_r]) @run_decorator(md=_md) - def mosaic_2D_inner(): - if len(filters): - for filt in filters: - yield from mv(filt, 1) - yield from bps.sleep(0.5) - # take dark image - print("take 5 dark image") - yield from _take_dark_image(dets, motor, num=5, stream_name="dark", simu=simu) + def fly_inner_scan(): + # set filters + for flt in filters: + yield from mv(flt, 1) + yield from mv(flt, 1) + # yield from mv(Andor.cam.num_images, chunk_size, timeout=10) ## commented out by XH + + # Manually stage the Andor. This creates a Resource document that + # contains the path to the HDF5 file where the detector writes. It also + # encodes the so-called 'frame_per_point' which here is what this plan + # calls chunk_size. The chunk_size CANNOT BE CHANGED later in the scan + # unless we unstage and re-stage the detector and generate a new + # Resource document. + + # This approach imposes some unfortunate overhead (closing the HDF5 + # file, opening a new one, going through all the steps to set the Area + # Detector's filepath PV, etc.). A better approach has been sketched + # in https://github.com/bluesky/area-detector-handlers/pull/11. It + # allows a single HDF5 file to contain multiple chunk_sizes. + + yield from bps.stage(Andor) + yield from bps.sleep(1) + yield from mv(Andor.cam.num_images, chunk_size, timeout=10) ## added by XH - print("open shutter ...") - yield from _open_shutter(simu) + # open shutter, tomo_images + yield from _open_shutter(simu=simu) + print("\nshutter opened, taking tomo images...") + yield from mv(zps.pi_r, current_rot_angle + offset_angle) + status = yield from abs_set(zps.pi_r, target_rot_angle, wait=False) + yield from bps.sleep(2) + while not status.done: + yield from trigger_and_read(list(detectors) + motors) - print("taking mosaic image ...") - for ii in np.arange(x_range[0], x_range[1] + 1): - if scan_x_flag == 1: - # yield from mv(zps.sx, motor_x_ini + ii * img_sizeX * pxl * 1.0 / 1000) - yield from abs_set( - zps.sx, motor_x_ini + ii * img_sizeX * pxl, wait=True - ) - else: - # yield from mv(zps.sz, motor_z_ini + ii * img_sizeX * pxl * 1.0 / 1000) - yield from abs_set( - zps.sz, motor_z_ini + ii * img_sizeX * pxl, wait=True - ) - # sleep_time = (x_range[-1] - x_range[0]) * img_sizeX * pxl * 1.0 / 1000 / 600 - # yield from bps.sleep(sleep_time) - for jj in np.arange(y_range[0], y_range[1] + 1): - # yield from mv(zps.sy, motor_y_ini + jj * img_sizeY * pxl * 1.0 / 1000) - yield from abs_set( - zps.sy, motor_y_ini + jj * img_sizeY * pxl, wait=True - ) - yield from _take_image(dets, motor, 1) - # yield from trigger_and_read(list(dets) + motor) + # bkg images + print("\nTaking background images...") + yield from _set_rotation_speed(rs=rot_back_velo) + yield from mv(Andor.cam.num_images, 20) - print("moving sample out to take 5 background image") + # Now that the new chunk_size has been set (20) create a new Resource + # document by unstage and re-staging the detector. + yield from bps.unstage(Andor) + yield from bps.stage(Andor) + yield from bps.sleep(1) yield from _take_bkg_image( motor_x_out, motor_y_out, motor_z_out, motor_r_out, - dets, - motor, - num=5, - stream_name="flat", - simu=simu, - rot_first_flag=rot_first_flag, + detectors, + motors, + num_bkg=1, + simu=False, + traditional_sequence_flag=rot_first_flag, ) - # move sample in + # dark images + yield from _close_shutter(simu=simu) + print("\nshutter closed, taking dark images...") + yield from _take_dark_image(detectors, motors, num_dark=1, simu=simu) + + yield from bps.unstage(Andor) + + # restore fliters yield from _move_sample_in( motor_x_ini, motor_y_ini, motor_z_ini, motor_r_ini, - repeat=1, - trans_first_flag=1 - rot_first_flag, + trans_first_flag=rot_first_flag, ) - if len(filters): - for filt in filters: - yield from mv(filt, 0) - yield from bps.sleep(0.5) - print("closing shutter") - yield from _close_shutter(simu) + for flt in filters: + yield from mv(flt, 0) - yield from mosaic_2D_inner() + yield from fly_inner_scan() + yield from mv(Andor.cam.image_mode, 1) + print("scan finished") + txt = get_scan_parameter(print_flag=0) + insert_text(txt) + print(txt) def dummy_scan( exposure_time=0.1, start_angle=None, - rel_rot_ang=180, + relative_rot_angle=180, period=0.15, out_x=None, out_y=2000, @@ -1905,7 +906,6 @@ def dummy_scan( repeat=1, ): - yield from mv(Andor.cam.acquire, 0) motor_x_ini = zps.sx.position motor_y_ini = zps.sy.position motor_z_ini = zps.sz.position @@ -1927,11 +927,11 @@ def dummy_scan( motors = [zps.sx, zps.sy, zps.sz, zps.pi_r] - dets = [Andor, ic3] - taxi_ang = -2 * rs - cur_rot_ang = zps.pi_r.position + detectors = [Andor, ic3] + offset_angle = -2 * rs + current_rot_angle = zps.pi_r.position - tgt_rot_ang = cur_rot_ang + rel_rot_ang + target_rot_angle = current_rot_angle + relative_rot_angle _md = {"dummy scan": "dummy scan"} yield from mv(Andor.cam.acquire, 0) @@ -1947,13 +947,15 @@ def fly_inner_scan(): yield from _open_shutter(simu=simu) print("\nshutter opened, taking tomo images...") yield from _set_rotation_speed(rs=rs) - yield from mv(zps.pi_r, cur_rot_ang + taxi_ang) - status = yield from abs_set(zps.pi_r, tgt_rot_ang, wait=False) + yield from mv(zps.pi_r, current_rot_angle + offset_angle) + status = yield from abs_set(zps.pi_r, target_rot_angle, wait=False) while not status.done: yield from bps.sleep(1) yield from _set_rotation_speed(rs=30) print("set rotation speed: {} deg/sec".format(rs)) - status = yield from abs_set(zps.pi_r, cur_rot_ang + taxi_ang, wait=False) + status = yield from abs_set( + zps.pi_r, current_rot_angle + offset_angle, wait=False + ) while not status.done: yield from bps.sleep(1) yield from abs_set(zps.sx, motor_x_out, wait=True) @@ -1989,7 +991,6 @@ def radiographic_record( rot_first_flag=1, relative_move_flag=1, ): - yield from mv(Andor.cam.acquire, 0) motor_x_ini = zps.sx.position motor_y_ini = zps.sy.position motor_z_ini = zps.sz.position @@ -2008,7 +1009,7 @@ def radiographic_record( motors = [zps.sx, zps.sy, zps.sz, zps.pi_r] - dets = [Andor, ic3] + detectors = [Andor, ic3] _md = { "detectors": ["Andor"], # "motors": [mot.name for mot in motors], @@ -2042,7 +1043,7 @@ def radiographic_record( yield from _set_andor_param(exposure_time=exp_t, period=period) yield from mv(Andor.cam.image_mode, 0) - @stage_decorator(list(dets)) + @stage_decorator(list(detectors)) # @bpp.monitor_during_decorator([Andor.cam.num_images_counter]) @run_decorator(md=_md) def rad_record_inner(): @@ -2053,7 +1054,7 @@ def rad_record_inner(): yield from bps.sleep(1) yield from mv(Andor.cam.num_images, int(t_span / period)) - yield from trigger_and_read([Andor], name="primary") + yield from trigger_and_read([Andor]) yield from mv( zps.sx, @@ -2066,7 +1067,7 @@ def rad_record_inner(): motor_r_out, ) yield from mv(Andor.cam.num_images, 20) - yield from trigger_and_read([Andor], name="flat") + yield from trigger_and_read([Andor]) yield from _close_shutter(simu=simu) yield from mv( zps.sx, @@ -2078,7 +1079,7 @@ def rad_record_inner(): zps.pi_r, motor_r_ini, ) - yield from trigger_and_read([Andor], name="dark") + yield from trigger_and_read([Andor]) yield from mv(Andor.cam.image_mode, 1) for flt in filters: yield from mv(flt, 0) @@ -2086,7 +1087,7 @@ def rad_record_inner(): yield from rad_record_inner() -# def multi_pos_2D_and_3D_xanes(elements=['Ni'], sam_in_pos_list_2D=[[[0, 0, 0, 0],]], sam_out_pos_list_2D=[[[0, 0, 0, 0],]], sam_in_pos_list_3D=[[[0, 0, 0, 0],]], sam_out_pos_list_3D=[[[0, 0, 0, 0],]], exposure_time=[0.05], rel_rot_ang=182, relative_move_flag=False, rs=1, note=''): +# def multi_pos_2D_and_3D_xanes(elements=['Ni'], sam_in_pos_list_2D=[[[0, 0, 0, 0],]], sam_out_pos_list_2D=[[[0, 0, 0, 0],]], sam_in_pos_list_3D=[[[0, 0, 0, 0],]], sam_out_pos_list_3D=[[[0, 0, 0, 0],]], exposure_time=[0.05], relative_rot_angle=182, relative_move_flag=False, rs=1, note=''): # sam_in_pos_list_2D = np.asarray(sam_in_pos_list_2D) # sam_out_pos_list_2D = np.asarray(sam_out_pos_list_2D) # sam_in_pos_list_3D = np.asarray(sam_in_pos_list_3D) @@ -2128,7 +1129,7 @@ def rad_record_inner(): # out_z = sam_out_pos_list_3D[ii, :, 2] # out_r = sam_out_pos_list_3D[ii, :, 3] # yield from multi_pos_3D_xanes(eng_list[jj], x_list, y_list, z_list, r_list, -# exposure_time=exposure_time[jj], relative_rot_angle=rel_rot_ang, rs=rs, +# exposure_time=exposure_time[jj], relative_rot_angle=relative_rot_angle, rs=rs, # out_x=out_x, out_y=out_y, out_z=out_z, out_r=out_r, note=note, simu=False, # relative_move_flag=relative_move_flag, traditional_sequence_flag=1, sleep_time=0, repeat=1) @@ -2191,7 +1192,7 @@ def rad_record_inner(): # out_z = sam_out_pos_list_3D[ii, 2] # out_r = sam_out_pos_list_3D[ii, 3] # yield from multi_pos_xanes_3D(eng_3D, x_list, y_list, z_list, r_list, -# exposure_time=exposure_time_3D[jj], relative_rot_angle=rel_rot_ang, rs=rs, +# exposure_time=exposure_time_3D[jj], relative_rot_angle=relative_rot_angle, rs=rs, # out_x=out_x, out_y=out_y, out_z=out_z, out_r=out_r, note=note, simu=False, # relative_move_flag=relative_move_flag, traditional_sequence_flag=1, sleep_time=0, repeat=1) @@ -2303,7 +1304,7 @@ def rad_record_inner(): # out_r = sam_out_pos_list_3D[ii, :, 3] # print(x_list, out_x, out_y, out_z, out_r) # yield from multi_pos_xanes_3D(eng_list[jj], x_list, y_list, z_list, r_list, -# exposure_time=exposure_time_3D[jj], relative_rot_angle=rel_rot_ang, rs=rs, +# exposure_time=exposure_time_3D[jj], relative_rot_angle=relative_rot_angle, rs=rs, # out_x=out_x, out_y=out_y, out_z=out_z, out_r=out_r, note=note, simu=simu, # relative_move_flag=relative_move_flag, traditional_sequence_flag=1, sleep_time=0, repeat=1) # if kk != (repeat_num-1): @@ -2321,7 +1322,7 @@ def multi_pos_2D_and_3D_xanes( sam_out_pos_list_3D={"Ni_3D_out_pos_list": [[0, 0, 0, 0]]}, exposure_time_2D={"Ni_2D_exp": 0.05}, exposure_time_3D={"Ni_3D_exp": 0.05}, - rel_rot_ang=185, + relative_rot_angle=185, rs=1, sleep_time=0, repeat_num=1, @@ -2330,7 +1331,6 @@ def multi_pos_2D_and_3D_xanes( simu=False, ): - yield from mv(Andor.cam.acquire, 0) xanes2D = {} xanes3D = {} for kk in range(repeat_num): @@ -2517,7 +1517,7 @@ def multi_pos_2D_and_3D_xanes( z_list_3D, r_list_3D, exposure_time == elem3D["exposure"], - relative_rot_angle=rel_rot_ang, + relative_rot_angle=relative_rot_angle, rs=rs, out_x=out_x_3D, out_y=out_y_3D, @@ -2725,7 +1725,7 @@ def multi_pos_2D_and_3D_xanes( # z_list_3D, # r_list_3D, # exposure_time=exp_3D, -# relative_rot_angle=rel_rot_ang, +# relative_rot_angle=relative_rot_angle, # rs=rs, # out_x=out_x_3D, # out_y=out_y_3D, @@ -2942,7 +1942,7 @@ def multi_pos_2D_and_3D_xanes( # z_list_3D, # r_list_3D, # exposure_time=exp_3D, -# relative_rot_angle=rel_rot_ang, +# relative_rot_angle=relative_rot_angle, # rs=rs, # out_x=out_x_3D, # out_y=out_y_3D, @@ -2971,14 +1971,13 @@ def multi_pos_2D_xanes_and_3D_tomo( sam_out_pos_list_3D=[[[0, 0, 0, 0]]], exposure_time_2D=[0.05], exposure_time_3D=[0.05], - rel_rot_ang=0, + relative_rot_angle=0, rs=1, eng_3D=[10, 60], note="", relative_move_flag=0, simu=False, ): - yield from mv(Andor.cam.acquire, 0) sam_in_pos_list_2D = np.asarray(sam_in_pos_list_2D) sam_out_pos_list_2D = np.asarray(sam_out_pos_list_2D) sam_in_pos_list_3D = np.asarray(sam_in_pos_list_3D) @@ -3069,7 +2068,7 @@ def multi_pos_2D_xanes_and_3D_tomo( z_list, r_list, exposure_time=exposure_time_3D[jj], - relative_rot_angle=rel_rot_ang, + relative_rot_angle=relative_rot_angle, rs=rs, out_x=out_x, out_y=out_y, @@ -3103,7 +2102,7 @@ def zps_motor_scan_with_Andor( md=None, ): global ZONE_PLATE - dets = [Andor, ic3] + detectors = [Andor, ic3] # if len(out_x) != len(motors): # out_x = [out_x[0]] * len(motors) @@ -3160,7 +2159,7 @@ def _set_andor_param(): print("hello1") _md = { - "detectors": [det.name for det in dets], + "detectors": [det.name for det in detectors], "motors": [mot.name for mot in motors], "num_bkg_images": 5, "num_dark_images": 5, @@ -3205,12 +2204,12 @@ def _set_andor_param(): else: _md["hints"].setdefault("dimensions", dimensions) - @stage_decorator(list(dets) + motors) + @stage_decorator(list(detectors) + motors) @run_decorator(md=_md) def zps_motor_scan_inner(): # take dark image print("take 5 dark image") - yield from _take_dark_image(dets, motors, num_dark=5) + yield from _take_dark_image(detectors, motors, num_dark=5) print("open shutter ...") yield from _open_shutter(simu) @@ -3259,7 +2258,7 @@ def zps_motor_scan_inner(): # yield from mv(motors, mot_pos[:, jj]) for ii in range(len(motors)): yield from mv(motors[ii], mot_pos[ii, jj]) - yield from _take_image(dets, motors, 1) + yield from _take_image(detectors, motors, 1) print("moving sample out to take 5 background image") yield from _take_bkg_image( @@ -3267,7 +2266,7 @@ def zps_motor_scan_inner(): motor_y_out, motor_z_out, motor_r_out, - dets, + detectors, motors, num_bkg=5, simu=simu, @@ -3304,7 +2303,7 @@ def diff_tomo( ], exposure=[0.05], period=[0.05], - rel_rot_ang=182, + relative_rot_angle=182, rs=1, eng=None, note="", @@ -3341,7 +2340,7 @@ def diff_tomo( yield from mv(zps.pi_r, sam_in_pos_list[jj, 3]) yield from fly_scan( exposure_time=exposure[jj], - relative_rot_angle=rel_rot_ang, + relative_rot_angle=relative_rot_angle, period=period[jj], chunk_size=20, out_x=sam_out_pos_list[jj, 0], @@ -3453,7 +2452,7 @@ def damon_scan( def user_fly_scan( exposure_time=0.1, - rel_rot_ang=180, + relative_rot_angle=180, period=0.15, chunk_size=20, out_x=None, @@ -3473,7 +2472,7 @@ def user_fly_scan( ------- exposure_time: float, in unit of sec - rel_rot_ang: float, + relative_rot_angle: float, total rotation angles start from current rotary stage (zps.pi_r) position period: float, in unit of sec @@ -3528,11 +2527,11 @@ def user_fly_scan( motor = [zps.sx, zps.sy, zps.sz, zps.pi_r] - dets = [Andor, ic3] - taxi_ang = -0.5 * rs - cur_rot_ang = zps.pi_r.position + detectors = [Andor, ic3] + offset_angle = -0.5 * rs + current_rot_angle = zps.pi_r.position - tgt_rot_ang = cur_rot_ang + rel_rot_ang + target_rot_angle = current_rot_angle + relative_rot_angle _md = { "detectors": ["Andor"], "motors": [mot.name for mot in motor], @@ -3540,7 +2539,7 @@ def user_fly_scan( "ion_chamber": ic3.name, "plan_args": { "exposure_time": exposure_time, - "relative_rot_angle": rel_rot_ang, + "relative_rot_angle": relative_rot_angle, "period": period, "chunk_size": chunk_size, "out_x": out_x, @@ -3578,7 +2577,7 @@ def user_fly_scan( yield from _set_rotation_speed(rs=rs) print("set rotation speed: {} deg/sec".format(rs)) - @stage_decorator(list(dets) + motor) + @stage_decorator(list(detectors) + motor) @bpp.monitor_during_decorator([zps.pi_r]) @run_decorator(md=_md) def fly_inner_scan(): @@ -3587,7 +2586,7 @@ def fly_inner_scan(): yield from _set_andor_param( exposure_time=exposure_time, period=period, chunk_size=20 ) - yield from _take_dark_image(dets, motor, num_dark=1, simu=simu) + yield from _take_dark_image(detectors, motor, num_dark=1, simu=simu) yield from bps.sleep(1) yield from _set_andor_param( exposure_time=exposure_time, period=period, chunk_size=chunk_size @@ -3596,11 +2595,11 @@ def fly_inner_scan(): # open shutter, tomo_images yield from _open_shutter(simu=simu) print("\nshutter opened, taking tomo images...") - yield from mv(zps.pi_r, cur_rot_ang + taxi_ang) - status = yield from abs_set(zps.pi_r, tgt_rot_ang, wait=False) + yield from mv(zps.pi_r, current_rot_angle + offset_angle) + status = yield from abs_set(zps.pi_r, target_rot_angle, wait=False) yield from bps.sleep(1) while not status.done: - yield from trigger_and_read(list(dets) + motor) + yield from trigger_and_read(list(detectors) + motor) # bkg images print("\nTaking background images...") yield from _set_rotation_speed(rs=30) @@ -3617,7 +2616,7 @@ def fly_inner_scan(): motor_y_out, motor_z_out, motor_r_out, - dets, + detectors, motor, num_bkg=1, simu=False, @@ -3664,11 +2663,11 @@ def user_fly_only( motor = [zps.sx, zps.sy, zps.sz, zps.pi_r] - dets = [Andor, ic3] - # taxi_ang = 0 #-0.5 * rs * np.sign(rel_rot_ang) - cur_rot_ang = zps.pi_r.position + detectors = [Andor, ic3] + # offset_angle = 0 #-0.5 * rs * np.sign(relative_rot_angle) + current_rot_angle = zps.pi_r.position - tgt_rot_ang = end_rot_angle + target_rot_angle = end_rot_angle _md = { "detectors": ["Andor"], "motors": [mot.name for mot in motor], @@ -3709,14 +2708,14 @@ def user_fly_only( yield from _set_rotation_speed(rs=rs) print("set rotation speed: {} deg/sec".format(rs)) - @stage_decorator(list(dets) + motor) + @stage_decorator(list(detectors) + motor) @bpp.monitor_during_decorator([zps.pi_r]) @run_decorator(md=_md) def fly_inner_scan(): yield from _open_shutter(simu=simu) - status = yield from abs_set(zps.pi_r, tgt_rot_ang, wait=False) + status = yield from abs_set(zps.pi_r, target_rot_angle, wait=False) while not status.done: - yield from trigger_and_read(list(dets) + motor) + yield from trigger_and_read(list(detectors) + motor) uid = yield from fly_inner_scan() yield from mv(Andor.cam.image_mode, 1) @@ -3749,7 +2748,7 @@ def user_dark_only(exposure_time=0.1, chunk_size=20, note="", simu=False, md=Non """ global ZONE_PLATE period = exposure_time # default to exposure time for backgrounds - dets = [Andor, ic3] + detectors = [Andor, ic3] motor = [] _md = { @@ -3784,13 +2783,13 @@ def user_dark_only(exposure_time=0.1, chunk_size=20, note="", simu=False, md=Non exposure_time=exposure_time, period=period, chunk_size=chunk_size ) - @stage_decorator(list(dets) + motor) + @stage_decorator(list(detectors) + motor) @run_decorator(md=_md) def inner_scan(): yield from _set_andor_param( exposure_time=exposure_time, period=period, chunk_size=chunk_size ) - yield from _take_dark_image(dets, motor, num_dark=1, simu=simu) + yield from _take_dark_image(detectors, motor, num_dark=1, simu=simu) uid = yield from inner_scan() yield from mv(Andor.cam.image_mode, 1) @@ -3868,8 +2867,8 @@ def user_bkg_only( motor = [zps.sx, zps.sy, zps.sz, zps.pi_r] - dets = [Andor, ic3] - cur_rot_ang = zps.pi_r.position + detectors = [Andor, ic3] + current_rot_angle = zps.pi_r.position _md = { "detectors": ["Andor"], @@ -3908,7 +2907,7 @@ def user_bkg_only( # yield from _set_andor_param(exposure_time=exposure_time, period=period, chunk_size=chunk_size) - @stage_decorator(list(dets) + motor) + @stage_decorator(list(detectors) + motor) @bpp.monitor_during_decorator([zps.pi_r]) @run_decorator(md=_md) def fly_inner_scan(): @@ -3921,7 +2920,7 @@ def fly_inner_scan(): motor_y_out, motor_z_out, motor_r_out, - dets, + detectors, motor, num_bkg=1, simu=False, @@ -4263,7 +3262,7 @@ def qingchao_scan( relative_move_flag=True, note="622_filter4", ) - print(f"sleep for {sleep_time} sec ...") + print(f"slepp for {sleep_time} sec ...") yield from bps.sleep(sleep_time) @@ -4482,7 +3481,7 @@ def scan_change_expo_time( motor_z_ini = zps.sz.position motor_r_ini = zps.pi_r.position - dets = [Andor, ic3] + detectors = [Andor, ic3] if relative_move_flag: motor_x_out = motor_x_ini + out_x if out_x else motor_x_ini @@ -4498,7 +3497,7 @@ def scan_change_expo_time( motor = [motor_eng, zps.sx, zps.sy, zps.sz, zps.pi_r] _md = { - "detectors": [det.name for det in dets], + "detectors": [det.name for det in detectors], "x_ray_energy": XEng.position, "plan_args": { "x_range": x_range, @@ -4529,16 +3528,16 @@ def scan_change_expo_time( else: _md["hints"].setdefault("dimensions", dimensions) - @stage_decorator(list(dets) + motor) + @stage_decorator(list(detectors) + motor) @run_decorator(md=_md) def inner(): # take dark image print(f"take 5 dark image with exposure = {t1}") yield from _set_andor_param(exposure_time=t1, period=t1, chunk_size=1) - yield from _take_dark_image(dets, motor, num_dark=5, simu=simu) + yield from _take_dark_image(detectors, motor, num_dark=5, simu=simu) print(f"take 5 dark image with exposure = {t2}") yield from _set_andor_param(exposure_time=t2, period=t2, chunk_size=1) - yield from _take_dark_image(dets, motor, num_dark=5, simu=simu) + yield from _take_dark_image(detectors, motor, num_dark=5, simu=simu) print("open shutter ...") yield from _open_shutter(simu) @@ -4550,11 +3549,11 @@ def inner(): print(f"set exposure time = {t1}") yield from _set_andor_param(exposure_time=t1, period=t1, chunk_size=1) yield from bps.sleep(sleep_time) - yield from _take_image(dets, motor, 1) + yield from _take_image(detectors, motor, 1) print(f"set exposure time = {t2}") yield from _set_andor_param(exposure_time=t2, period=t2, chunk_size=1) yield from bps.sleep(sleep_time) - yield from _take_image(dets, motor, 1) + yield from _take_image(detectors, motor, 1) print(f"take bkg image with exposure time = {t1}") yield from _set_andor_param(exposure_time=t1, period=t1, chunk_size=1) yield from bps.sleep(sleep_time) @@ -4563,7 +3562,7 @@ def inner(): motor_y_out, motor_z_out, motor_r_out, - dets, + detectors, motor, num_bkg=5, simu=simu, @@ -4576,7 +3575,7 @@ def inner(): motor_y_out, motor_z_out, motor_r_out, - dets, + detectors, motor, num_bkg=5, simu=simu,