Source code for xpdsim.area_det

""" Spoof detectors """
##############################################################################
#
# xpdsim            by Billinge Group
#                   Simon J. L. Billinge sb2896@columbia.edu
#                   (c) 2016 trustees of Columbia University in the City of
#                        New York.
#                   All rights reserved
#
# File coded by:    Christopher J. Wright, Timothy Liu
#
# See AUTHORS.txt for a list of people who contributed.
# See LICENSE.txt for license information.
#
##############################################################################

from pathlib import Path
from tempfile import mkdtemp

import numpy as np
from cycler import cycler
from ophyd import Device, sim
from pkg_resources import resource_filename as rs_fn
from tifffile import imread

# extra config
XPD_SHUTTER_CONF = {"open": 60, "close": 0}
DATA_DIR_STEM = "xpdsim.data"
# image size
PE_IMG_SIZE = (2048, 2048)
DEXELA_IMG_SIZE = (3072, 3088)
BLACKFLY_IMG_SIZE = (20, 24)
# package filepath
nsls_ii_path = rs_fn(DATA_DIR_STEM + ".XPD", "ni")
xpd_wavelength = 0.1823
chess_path = rs_fn(DATA_DIR_STEM, "chess")


[docs]def build_image_cycle(path, key="pe1_image"): """Build image cycles, essentially generators with endless images Parameters ---------- path: str Path to the files to be used as the base for the cycle. key: str, optional key of the entire image sequence. Default to ``'pe1_image'``. Returns ------- Cycler: The iterable like object to cycle through the images """ p = Path(path) imgs = [imread(str(fp)) for fp in p.glob("*.tif*")] return cycler(key, imgs)
[docs]class SimulatedCam(Device): acquire_time = sim.SynSignal(name="acquire_time") acquire = sim.SynSignal(name="acquire")
[docs]def add_fake_cam(det): """Adding simulated cam device signals to the detector Parameters ---------- det: SimulatedPE1C instance The detector Returns ------- det: SimulatedPE1C instance The detector """ # plug-ins det.images_per_set = sim.SynSignal(name="images_per_set") det.number_of_sets = sim.SynSignal(name="number_of_sets") det.cam = SimulatedCam(name="cam") # set default values det.cam.acquire_time.put(0.1) det.cam.acquire.put(1) det.images_per_set.put(1) return det
[docs]def img_gen(cycle=None, size=PE_IMG_SIZE, shutter=None, noise=None): """Generator of diffraction images from 2D detector. The output images is determined by ``cycle`` argument. Parameters ---------- cycle: cycler.Cycler, optional The iterable like object to cycle through the images. Default to images with standard Gaussian noise in input size. size : tuple, optional Tuple to specify image size from the simulated detector. Default to ``(2048, 2048)`` (PE detector). Overridden when ``cycle`` argument is passed. shutter : settable, optional Ophyd objects to represent the shutter associated with with the detector. If it is not passed, assuming shutter is always open. If shutter is passed, assuming it follows the same configuration as XPD beamline (60 means open). noise : callable, optional function to generate noise based on absolute scale of image. Default to noise-free. Returns ------- img : ndarray simulated 2D diffraction image with specified size. """ if cycle is None: cycle = cycler(pe1_image=[np.random.random(size)]) # check data keys keys = cycle.keys if not len(keys) == 1: raise RuntimeError("Only support single data key") key = keys.pop() gen = cycle() next(gen) # kick-off cycler gen = cycle() # instantiate again img = next(gen)[key].copy() # if shutter, consider more realistic situation if shutter: status = shutter.get() if np.allclose(status.readback, XPD_SHUTTER_CONF["close"]): img = np.zeros(img.shape) elif np.allclose(status.readback, XPD_SHUTTER_CONF["open"]): if noise: img += noise(np.abs(img)) return img.astype(np.float32)
[docs]def det_factory( cycle=None, img_gen_func=img_gen, data_key="pe1_image", *args, **kwargs ): """Build a simulated detector yielding input image sequence Parameters ---------- cycle: cycler.Cycler, optional The iterable like object to cycle through the images. Default to output images in (2048, 2048) dimension with Gaussian(0, 1) noise. img_gen_func : callable, optional function to return image sequence will be output from this detector. The function signature is expected to be ``f(cycler, *args, **kwargs)``. Default to ``xpdsim.img_gen`` function where simulated shutter and noise can be included. data_key : str, optional data key will be shown in Descriptor. Default to ``'pe1_image'``. args : extra arguments will be passed to ``img_gen_func``. kwargs : extra keyword arguments will be passed to ``img_gen_func``. Returns ------- det: SimulatedPE1C instance The detector See also -------- ``xpdsim.img_gen`` """ det = sim.SynSignalWithRegistry( name=data_key, func=lambda: img_gen_func(cycle, *args, **kwargs), save_path=mkdtemp(prefix="xpdsim"), ) return add_fake_cam(det)