diff --git a/cfel_cxi.py b/cfel_cxi.py index 33f27720e3beeecb0447b91525d53101c0ca3a08..f3174b2d39c6ac15845cdd992e9829c4c0b3e3b3 100644 --- a/cfel_cxi.py +++ b/cfel_cxi.py @@ -273,8 +273,7 @@ class CXIWriter: if self._initialized is True: raise RuntimeError('Adding stacks to the writer is not possible after initialization.') - for entry in self._cxi_stacks: - if path == entry.path: + if name in self._cxi_stacks: if overwrite is True: del (self._cxi_stacks[name]) else: diff --git a/cfel_geom.py b/cfel_geom.py index 41ef64482e2ee9c9d3827134cabd40876ea3f203..4048220a9174bf42bd5aa859649a8578277f50d0 100644 --- a/cfel_geom.py +++ b/cfel_geom.py @@ -24,9 +24,23 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals +from collections import namedtuple import numpy + from cfelpyutils.cfel_crystfel import load_crystfel_geometry +PixelMaps = namedtuple('PixelMaps', ['x', 'y', 'r']) +ImageShape = namedtuple('ImageShape', ['ss', 'fs']) + + +def _find_minimum_image_shape(x, y): + + # find the smallest size of cspad_geom that contains all + # xy values but is symmetric about the origin + n = 2 * int(max(abs(y.max()), abs(y.min()))) + 2 + m = 2 * int(max(abs(x.max()), abs(x.min()))) + 2 + + return n, m def apply_geometry_from_file(data_as_slab, geometry_filename): """Parses a geometry file and applies the geometry to data. @@ -47,14 +61,14 @@ def apply_geometry_from_file(data_as_slab, geometry_filename): detector, with the origin of the reference system at the beam interaction point. """ - yx, slab_shape, img_shape = pixel_maps_for_image_view(geometry_filename) + x, y, slab_shape, img_shape = pixel_maps_for_image_view(geometry_filename) im_out = numpy.zeros(img_shape, dtype=data_as_slab.dtype) - im_out[yx[0], yx[1]] = data_as_slab.ravel() + im_out[y, x] = data_as_slab.ravel() return im_out -def apply_geometry_from_pixel_maps(data_as_slab, yx, im_out=None): +def apply_geometry_from_pixel_maps(data_as_slab, y, x, im_out=None): """Applies geometry in pixel map format to data. Applies geometry, in the form of pixel maps, to detector data in 'slab' format. Turns a 2d array of pixel values @@ -65,7 +79,9 @@ def apply_geometry_from_pixel_maps(data_as_slab, yx, im_out=None): data_as_slab (numpy.ndarray): the pixel values to which geometry is to be applied. - yx (tuple): the yx pixel maps describing the geometry of the detector; each map is a numpy.ndarray. + y (numpy.ndarray): the y pixel map describing the geometry of the detector + + x (numpy.ndarray): the x pixel map describing the geometry of the detector im_out (Optional[numpy.ndarray]): array to hold the output; if not provided, one will be generated automatically. @@ -79,17 +95,18 @@ def apply_geometry_from_pixel_maps(data_as_slab, yx, im_out=None): if im_out is None: im_out = numpy.zeros(data_as_slab.shape, dtype=data_as_slab.dtype) - im_out[yx[0], yx[1]] = data_as_slab.ravel() + im_out[y, x] = data_as_slab.ravel() return im_out def pixel_maps_for_image_view(geometry_filename): """Parses a geometry file and creates pixel maps for pyqtgraph visualization. - Parse the geometry file and creates pixel maps for an array in 'slab' format containing pixel values. The pixel + Parses the geometry file and creates pixel maps for an array in 'slab' format containing pixel values. The pixel maps can be used to create a representation of the physical layout of the detector in a pyqtgraph ImageView widget (i.e. they apply the detector geometry setting the origin of the reference system is in the top left corner - of the output array). + of the output array). The representation is centered at the point where the beam hits the detector according to + the geometry in the file. Args: @@ -97,31 +114,52 @@ def pixel_maps_for_image_view(geometry_filename): Returns: - (y, x) (numpy.ndarray int, numpy.ndarray int): pixel maps + x (numpy.ndarray int): pixel map for x coordinate + + y (numpy.ndarray int): pixel map for x coordinate + """ + + pixm = pixel_maps_from_geometry_file(geometry_filename) + x, y = pixm.x, pixm.y + + n, m = _find_minimum_image_shape(x, y) + + # convert y x values to i j values + i = numpy.array(y, dtype=numpy.int) + n // 2 - 1 + j = numpy.array(x, dtype=numpy.int) + m // 2 - 1 - slab_shape tuple (int, int): shape of the original geometry uncorrected array (the pixel values in "slab" - format). + y = i.flatten() + x = j.flatten() + + return PixelMaps(x, y, None) + + +def get_image_shape(geometry_filename): + """Parses a geometry file and returns the minimum size of an image that can represent the detector. + + Parses the geometry file and return a numpy shape object representing the minimum size of an image that + can contain the physical representation of the detector. The representation is centered at the point where the beam + hits the detector according to the geometry in the file. + + Args: + + geometry_filename (str): geometry filename. + + Returns: img_shape tuple (int, int): shape of the array needed to contain the representation of the physical layout of the detector. """ pixm = pixel_maps_from_geometry_file(geometry_filename) - x, y = pixm[0], pixm[1] - slab_shape = x.shape + x, y = pixm.x, pixm.y - # find the smallest size of cspad_geom that contains all - # xy values but is symmetric about the origin - n = 2 * int(max(abs(y.max()), abs(y.min()))) + 2 - m = 2 * int(max(abs(x.max()), abs(x.min()))) + 2 + n, m = _find_minimum_image_shape(x, y) + + img_shape = ImageShape(n, m) + return img_shape - # convert y x values to i j values - i = numpy.array(y, dtype=numpy.int) + n//2 - 1 - j = numpy.array(x, dtype=numpy.int) + m//2 - 1 - yx = (i.flatten(), j.flatten()) - img_shape = (n, m) - return yx, slab_shape, img_shape def pixel_maps_from_geometry_file(fnam): @@ -146,8 +184,8 @@ def pixel_maps_from_geometry_file(fnam): max_slab_fs = numpy.array([detector['panels'][k]['max_fs'] for k in detector['panels']]).max() max_slab_ss = numpy.array([detector['panels'][k]['max_ss'] for k in detector['panels']]).max() - x = numpy.zeros((max_slab_ss+1, max_slab_fs+1), dtype=numpy.float32) - y = numpy.zeros((max_slab_ss+1, max_slab_fs+1), dtype=numpy.float32) + x = numpy.zeros((max_slab_ss + 1, max_slab_fs + 1), dtype=numpy.float32) + y = numpy.zeros((max_slab_ss + 1, max_slab_fs + 1), dtype=numpy.float32) for p in detector['panels']: # get the pixel coords for this asic @@ -163,12 +201,11 @@ def pixel_maps_from_geometry_file(fnam): r = i * dy + j * dx + r_0 # y[detector['panels'][p]['min_ss']: detector['panels'][p]['max_ss'] + 1, - detector['panels'][p]['min_fs']: detector['panels'][p]['max_fs'] + 1] = r.real + detector['panels'][p]['min_fs']: detector['panels'][p]['max_fs'] + 1] = r.real x[detector['panels'][p]['min_ss']: detector['panels'][p]['max_ss'] + 1, - detector['panels'][p]['min_fs']: detector['panels'][p]['max_fs'] + 1] = r.imag + detector['panels'][p]['min_fs']: detector['panels'][p]['max_fs'] + 1] = r.imag r = numpy.sqrt(numpy.square(x) + numpy.square(y)) - return x, y, r - + return PixelMaps(x, y, r) diff --git a/cfel_hdf5.py b/cfel_hdf5.py index a789c314dc4746bbec49fbb0569ee8468520f655..e961a6657dd1fe2b4ae3eedf7f5c5fc63e890885 100644 --- a/cfel_hdf5.py +++ b/cfel_hdf5.py @@ -42,6 +42,7 @@ def load_nparray_from_hdf5_file(data_filename, data_group): nparray (numpy.ndarray): numpy array with the data read from the file. """ try: + with h5py.File(data_filename, 'r') as hdfile: nparray = numpy.array(hdfile[data_group]) hdfile.close()