From bfc51f059d29712884e9a62c3ba85eea8c8f7c05 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 18 Mar 2022 15:27:50 -0400 Subject: [PATCH 1/3] MNT: updates to tomo_recon --- startup/94-tomo_recon.py | 603 ++++++++++++++++++++++++++++++++++----- 1 file changed, 526 insertions(+), 77 deletions(-) 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 + ) From 330796e8aede4788eb743a95213f82b55bcba1d4 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 18 Mar 2022 15:29:36 -0400 Subject: [PATCH 2/3] MNT: undoing changes for QS Probably will want to revert or drop this commit --- startup/00-base.py | 39 ++------------------------------- startup/11-txm_motor.py | 3 --- startup/12-optics_motor.py | 4 +--- startup/43-scans_pzt.py | 44 -------------------------------------- 4 files changed, 3 insertions(+), 87 deletions(-) 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/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/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, From 6d5e21849cace6b8a997c7d673b05e8bde80e526 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 18 Mar 2022 15:30:31 -0400 Subject: [PATCH 3/3] WIP: accumulated changes between the main and profile_default Due to work being done on a literal copy of the profile it is impossible to tell which of these changes are intentional changes on this branch vs which are changes to the version controlled version that were inadvertently reverted. --- startup/10-area-detector.py | 1 - startup/40-scan_pre_define.py | 4 +- startup/41-scans.py | 512 +------- startup/44-scans_other.py | 247 +--- startup/50-save_log.py | 4 +- startup/81-load_scan_legacy.py | 2 +- startup/91-functions.py | 40 +- startup/92-run_function_at_start.py | 2 +- startup/98-user_scan.py | 1705 ++++++--------------------- 9 files changed, 417 insertions(+), 2100 deletions(-) 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/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/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/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,