diff --git a/cfel_fabio.py b/cfel_fabio.py new file mode 100644 index 0000000000000000000000000000000000000000..7edc689eab8b36da91ad536a790858df059a0d9b --- /dev/null +++ b/cfel_fabio.py @@ -0,0 +1,88 @@ +# This file is part of cfelpyutils. +# +# cfelpyutils is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cfelpyutils is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cfelpyutils. If not, see <http://www.gnu.org/licenses/>. +""" +Utilities based on the fabio python module. + +This module contains utilities based on the fabio python module. +files. +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import numpy +import fabio.cbfimage + + +def read_cbf_from_stream(stream): + """Reads a cbfimage object out of a data string buffer. + + Read a data string buffer received as a payload from the PETRAIII P11 sender, and creates a cbfimage object from + it (See the documentation of the fabio python module). + + Args: + + stream (str): a data string buffer received from the PETRAIII P11 sender. + + Returns: + + cbf_obj (fabio.cbfimage): a cbfimage object containing the data extracted + from the string buffer. + """ + + cbf_obj = fabio.cbfimage.cbfimage() + + cbf_obj.header = {} + cbf_obj.resetvals() + + infile = stream + cbf_obj._readheader(infile) + if fabio.cbfimage.CIF_BINARY_BLOCK_KEY not in cbf_obj.cif: + err = "Not key %s in CIF, no CBF image in stream" % fabio.cbfimage.CIF_BINARY_BLOCK_KEY + logger.error(err) + for kv in cbf_obj.cif.items(): + print("%s: %s" % kv) + raise RuntimeError(err) + if cbf_obj.cif[fabio.cbfimage.CIF_BINARY_BLOCK_KEY] == "CIF Binary Section": + cbf_obj.cbs += infile.read(len(fabio.cbfimage.STARTER) + int(cbf_obj.header["X-Binary-Size"]) + - len(cbf_obj.cbs) + cbf_obj.start_binary) + else: + if len(cbf_obj.cif[fabio.cbfimage.CIF_BINARY_BLOCK_KEY]) > int( + cbf_obj.header["X-Binary-Size"]) + cbf_obj.start_binary + len(fabio.cbfimage.STARTER): + cbf_obj.cbs = cbf_obj.cif[fabio.cbfimage.CIF_BINARY_BLOCK_KEY][:int(cbf_obj.header["X-Binary-Size"]) + + cbf_obj.start_binary + + len(fabio.cbfimage.STARTER)] + else: + cbf_obj.cbs = cbf_obj.cif[fabio.cbfimage.CIF_BINARY_BLOCK_KEY] + binary_data = cbf_obj.cbs[cbf_obj.start_binary + len(fabio.cbfimage.STARTER):] + + if "Content-MD5" in cbf_obj.header: + ref = numpy.string_(cbf_obj.header["Content-MD5"]) + obt = fabio.cbfimage.md5sum(binary_data) + if ref != obt: + logger.error("Checksum of binary data mismatch: expected %s, got %s" % (ref, obt)) + + if cbf_obj.header["conversions"] == "x-CBF_BYTE_OFFSET": + cbf_obj.data = cbf_obj._readbinary_byte_offset(binary_data).astype(cbf_obj.bytecode).reshape( + (cbf_obj.dim2, cbf_obj.dim1)) + else: + raise Exception(IOError, "Compression scheme not yet supported, please contact the author") + + cbf_obj.resetvals() + # ensure the PIL image is reset + cbf_obj.pilimage = None + return cbf_obj diff --git a/cfelgeom.py b/cfel_geom.py similarity index 73% rename from cfelgeom.py rename to cfel_geom.py index 9711c1b8b085381dd43f2519a3571167f33701f2..0f5937e69ceded764be1da63bd84ad6a8e9f6acf 100644 --- a/cfelgeom.py +++ b/cfel_geom.py @@ -19,15 +19,20 @@ This module contains utilities for the processing of CrystFEL-style geometry files. """ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals import numpy def apply_geometry_from_file(data_as_slab, geometry_filename): - """Parse a geometry file and applies the geometry to detector data in 'slab' format. - Turns a 2d array of pixel values into an array containing a representation of the - physical layout of the detector, keeping the origin of the reference system at the - beam interaction point. + """Parses a geometry file and applies the geometry to data. + + Parses a geometry file and applies the geometry to detector data in 'slab' format. Turns a 2d array of pixel + values into an array containing a representation of the physical layout of the detector, keeping the origin of + the reference system at the beam interaction point. Args: @@ -37,9 +42,8 @@ def apply_geometry_from_file(data_as_slab, geometry_filename): Returns: - im_out (numpy.ndarray data_as_slab.dtype): Array containing a representation of the - physical layout of the detector, with the origin of the reference system at the - beam interaction point. + im_out (numpy.ndarray data_as_slab.dtype): Array containing a representation of the physical layout of the + 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) @@ -50,10 +54,11 @@ def apply_geometry_from_file(data_as_slab, geometry_filename): def apply_geometry_from_pixel_maps(data_as_slab, yx, im_out=None): - """Applies geometry, in the form of pixel maps, to detector data in 'slab' format. - Turns a 2d array of pixel values into an array containing a representation of the - physical layout of the detector, keeping the origin of the reference system at the - beam interaction point. + """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 + into an array containing a representation of the physical layout of the detector, keeping the origin of the + reference system at the beam interaction point. Args: @@ -61,15 +66,15 @@ def apply_geometry_from_pixel_maps(data_as_slab, yx, im_out=None): yx (tuple): the yx pixel maps describing the geometry of the detector; each map is a numpy.ndarray. - im_out (Optional[numpy.ndarray]): array to hold the output; if not provided, one will be generated automatically. - + im_out (Optional[numpy.ndarray]): array to hold the output; if not provided, one will be generated + automatically. Returns: - im_out (numpy.ndarray data_as_slab.dtype): Array containing a representation of the - physical layout of the detector, with the origin of the reference system at the - beam interaction point. + im_out (numpy.ndarray data_as_slab.dtype): Array containing a representation of the physical layout of the + detector, with the origin of the reference system at the beam interaction point. """ + if im_out is None: im_out = numpy.zeros(data_as_slab.shape, dtype=data_as_slab.dtype) @@ -78,11 +83,12 @@ def apply_geometry_from_pixel_maps(data_as_slab, yx, im_out=None): def pixel_maps_for_image_view(geometry_filename): - """Parse the geometry file and 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). + """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 + 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). Args: @@ -92,12 +98,13 @@ def pixel_maps_for_image_view(geometry_filename): (y, x) (numpy.ndarray int, numpy.ndarray int): pixel maps - slab_shape tuple (int, int): shape of the original geometry uncorrected array - (the pixel values in "slab" format). + slab_shape tuple (int, int): shape of the original geometry uncorrected array (the pixel values in "slab" + format). - img_shape tuple (int, int): shape of the array needed to contain the - representation of the physical layout of the detector. + 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 @@ -117,8 +124,9 @@ def pixel_maps_for_image_view(geometry_filename): def parse_xy(string): - """Parse the x, y values from strings that have the format: - '1x + 2.0y'. + """Extracts x and y values from strings in a geometry file. + + Parse the x, y values from strings in that have the format: '1x + 2.0y'. Args: @@ -128,6 +136,7 @@ def parse_xy(string): x, y (float, float): the values of x and y. """ + x = y = 0 if string.find('x') is not -1: @@ -147,9 +156,10 @@ def parse_xy(string): def pixel_maps_from_geometry_file(fnam): - """Extracts pixel maps from a CrystFEL-style geometry file. The pixel maps - can be used to create a representation of the physical layout of the - detector, keeping the origin of the reference system at the beam interaction + """Parses a geometry file and creates pixel maps. + + Extracts pixel maps from a CrystFEL-style geometry file. The pixel maps can be used to create a representation of + the physical layout of the detector, keeping the origin of the reference system at the beam interaction point. Args: @@ -158,9 +168,8 @@ def pixel_maps_from_geometry_file(fnam): Returns: - x,y,r (numpy.ndarray float, numpy.ndarray float, numpy.ndarray float): - slab-like pixel maps with respectively x, y coordinates of the pixel - and distance of the pixel from the center of the reference system + x,y,r (numpy.ndarray float, numpy.ndarray float, numpy.ndarray float): slab-like pixel maps with + respectively x, y coordinates of the pixel and distance of the pixel from the center of the reference system. """ f = open(fnam, 'r') @@ -231,8 +240,9 @@ def pixel_maps_from_geometry_file(fnam): def coffset_from_geometry_file(fnam): - """Extracts detector distance offset information from a CrystFEL-style - geometry file. + """Extracts detector distance information from a geometry file. + + Extracts detector distance offset information from a CrystFEL-style geometry file. Args: @@ -242,6 +252,7 @@ def coffset_from_geometry_file(fnam): coffset (float): the detector distance offset """ + f = open(fnam, 'r') f_lines = f.readlines() f.close() @@ -256,8 +267,9 @@ def coffset_from_geometry_file(fnam): def res_from_geometry_file(fnam): - """Extracts pixel resolution information from a CrystFEL-style - geometry file. + """Extracts pixel resolution information from a geometry file. + + Extracts pixel resolution information from a CrystFEL-style geometry file. Args: @@ -267,6 +279,7 @@ def res_from_geometry_file(fnam): res (float): the pixel resolution """ + f = open(fnam, 'r') f_lines = f.readlines() f.close() diff --git a/cfelhdf5.py b/cfel_hdf5.py similarity index 73% rename from cfelhdf5.py rename to cfel_hdf5.py index 76946ae893549650b22a1cb95dd3640e30da1259..a789c314dc4746bbec49fbb0569ee8468520f655 100644 --- a/cfelhdf5.py +++ b/cfel_hdf5.py @@ -19,9 +19,13 @@ This module contains utilities for the processing of HDF5. This module builds on what the h5py module already provides. """ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals -import numpy import h5py +import numpy def load_nparray_from_hdf5_file(data_filename, data_group): @@ -37,8 +41,11 @@ def load_nparray_from_hdf5_file(data_filename, data_group): nparray (numpy.ndarray): numpy array with the data read from the file. """ - - hdfile = h5py.File(data_filename, 'r') - nparray = numpy.array(hdfile[data_group]) - hdfile.close() - return nparray + try: + with h5py.File(data_filename, 'r') as hdfile: + nparray = numpy.array(hdfile[data_group]) + hdfile.close() + except: + raise RuntimeError('Error reading file {0} (data block: {1}).'.format(data_filename, data_group)) + else: + return nparray diff --git a/cfeloptarg.py b/cfel_optarg.py similarity index 81% rename from cfeloptarg.py rename to cfel_optarg.py index e3746d3c50ca023759e9090f8cc9f92afd4b156b..40ec42061321e1b21f2b6390b3d7459a284d5a35 100644 --- a/cfeloptarg.py +++ b/cfel_optarg.py @@ -14,6 +14,12 @@ # along with cfelpyutils. If not, see <http://www.gnu.org/licenses/>. +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + + """ Utilities for parsing command line options and configuration files. @@ -22,30 +28,20 @@ configuration files. """ -import argparse -import os - - def parse_parameters(config): """Sets correct types for parameter dictionaries. - Reads a parameter dictionary returned by the ConfigParser python modue, - and assigns correct types to parameters, without changing the structure of - the dictionary. + Reads a parameter dictionary returned by the ConfigParser python module, and assigns correct types to parameters, + without changing the structure of the dictionary. - The parser tries to interpret each entry in the dictionary according to the - following rules: + The parser tries to interpret each entry in the dictionary according to the following rules: - - If the entry starts and ends with a single quote, it is interpreted as a - string. - - If the entry is the word None, without quotes, then the entry is - interpreted as NoneType. - - If the entry is the word False, without quotes, then the entry is - interpreted as a boolean False. - - If the entry is the word True, without quotes, then the entry is - interpreted as a boolean True. - - If non of the previous options match the content of the entry, - the parser tries to interpret the entry in order as: + - If the entry starts and ends with a single quote, it is interpreted as a string. + - If the entry is the word None, without quotes, then the entry is interpreted as NoneType. + - If the entry is the word False, without quotes, then the entry is interpreted as a boolean False. + - If the entry is the word True, without quotes, then the entry is interpreted as a boolean True. + - If non of the previous options match the content of the entry, the parser tries to interpret the entry in order + as: - An integer number. - A float number. @@ -59,8 +55,8 @@ def parse_parameters(config): Returns: - monitor_params (dict): dictionary with the same structure as the input - dictionary, but with correct types assigned to each entry. + monitor_params (dict): dictionary with the same structure as the input dictionary, but with correct types + assigned to each entry. """ monitor_params = {} @@ -84,11 +80,11 @@ def parse_parameters(config): try: monitor_params[sect][op] = int(monitor_params[sect][op]) continue - except: + except ValueError: try: monitor_params[sect][op] = float(monitor_params[sect][op]) continue - except: + except ValueError: pass return monitor_params diff --git a/cfelpsana.py b/cfel_psana.py similarity index 76% rename from cfelpsana.py rename to cfel_psana.py index bdead5d49ecefdd5f3de2916d04aba176ca08b55..f17d8e9f73bfff48878b53effddb1020894b27d1 100644 --- a/cfelpsana.py +++ b/cfel_psana.py @@ -17,11 +17,16 @@ """ Utilities based on the psana python module. -This module provides utilities that build on the functionality provided by the -psana python module. +This module provides utilities that build on the functionality provided by the psana python module. """ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + + def psana_obj_from_string(name): """Converts a string into a psana object type. @@ -46,9 +51,8 @@ def psana_obj_from_string(name): def psana_event_inspection(source): """Prints the structure of psana events. - Takes a psana source string (e.g. exp=CXI/cxix....) and inspects the - structure of the first event in the data, printing information about - the the content of the event. + Takes a psana source string (e.g. exp=CXI/cxix....) and inspects the structure of the first event in the data, + printing information about the the content of the event. Args: @@ -57,22 +61,8 @@ def psana_event_inspection(source): import psana - def my_import(name): - mod = __import__(name) - components = name.split('.') - for comp in components[1:]: - mod = getattr(mod, comp) - return mod - - def my_psana_from_string(name): - components = name.split('.') - mod = __import__(components[0]) - for comp in components[1:]: - mod = getattr(mod, comp) - return mod - print('\n\n') - print('data source : %s' % source) + print('data source :', source) print('\n') print('Opening dataset...') @@ -91,8 +81,8 @@ def psana_event_inspection(source): itr = ds.events() evt = itr.next() for k in evt.keys(): - print('Type: %s Source: %s Alias: %s Key: %s') % (k.type(), k.src(), k.alias(), k.key()) - print('\n') + print('Type: {0} Source: {1} Alias: {2} Key: {3}'.format(k.type(), k.src(), k.alias(), k.key())) + print('') for k in evt.keys(): print(k) @@ -104,9 +94,8 @@ def psana_event_inspection(source): def dirname_from_source_runs(source): """Returns a directory name based on a psana source string. - Takes a psana source string (e.g exp=CXI/cxix....) and returns - a string that can be used as a subdirectory name or a prefix for files and - directories. + Takes a psana source string (e.g exp=CXI/cxix....) and returns a string that can be used as a subdirectory name or + a prefix for files and directories. Args: @@ -125,5 +114,5 @@ def dirname_from_source_runs(source): nums = runs.split(',') if len(nums) == 0: nums = runs - dirname = 'run_' + "_".join(nums) + dirname = 'run_' + '_'.join(nums) return dirname diff --git a/cfelfabio.py b/cfelfabio.py deleted file mode 100644 index ac7a46d951c2c851e216e443b28c378cc7197b6f..0000000000000000000000000000000000000000 --- a/cfelfabio.py +++ /dev/null @@ -1,57 +0,0 @@ -import numpy -import fabio.cbfimage - -def read_cbf_from_stream(stream): - """Reads a cbfimage object out of a data string buffer. - - Read a data string buffer received as a payload from the PETRAIII P11 sender, - and creates a cbfimage object from it (See the documentation of the fabio - python module). - - Args: - - stream (str): a data string buffer received from the PETRAIII P11 sender. - - Returns: - - cbf_obj (fabio.cbfimage): a cbfimage object containing the data extracted - from the string buffer. - """ - - cbf_obj = fabio.cbfimage.cbfimage() - - cbf_obj.header = {} - cbf_obj.resetvals() - - infile = stream - cbf_obj._readheader(infile) - if fabio.cbfimage.CIF_BINARY_BLOCK_KEY not in cbf_obj.cif: - err = "Not key %s in CIF, no CBF image in stream" % (fabio.cbfimage.CIF_BINARY_BLOCK_KEY) - logger.error(err) - for kv in cbf_obj.cif.items(): - print("%s: %s" % kv) - raise RuntimeError(err) - if cbf_obj.cif[fabio.cbfimage.CIF_BINARY_BLOCK_KEY] == "CIF Binary Section": - cbf_obj.cbs += infile.read(len(fabio.cbfimage.STARTER) + int(cbf_obj.header["X-Binary-Size"]) - len(cbf_obj.cbs) + cbf_obj.start_binary) - else: - if len(cbf_obj.cif[fabio.cbfimage.CIF_BINARY_BLOCK_KEY]) > int(cbf_obj.header["X-Binary-Size"]) + cbf_obj.start_binary + len(fabio.cbfimage.STARTER): - cbf_obj.cbs = cbf_obj.cif[fabio.cbfimage.CIF_BINARY_BLOCK_KEY][:int(cbf_obj.header["X-Binary-Size"]) + cbf_obj.start_binary + len(fabio.cbfimage.STARTER)] - else: - cbf_obj.cbs = cbf_obj.cif[fabio.cbfimage.CIF_BINARY_BLOCK_KEY] - binary_data = cbf_obj.cbs[cbf_obj.start_binary + len(fabio.cbfimage.STARTER):] - - if "Content-MD5" in cbf_obj.header: - ref = numpy.string_(cbf_obj.header["Content-MD5"]) - obt = fabio.cbfimage.md5sum(binary_data) - if ref != obt: - logger.error("Checksum of binary data mismatch: expected %s, got %s" % (ref, obt)) - - if cbf_obj.header["conversions"] == "x-CBF_BYTE_OFFSET": - cbf_obj.data = cbf_obj._readbinary_byte_offset(binary_data).astype(cbf_obj.bytecode).reshape((cbf_obj.dim2, cbf_obj.dim1)) - else: - raise Exception(IOError, "Compression scheme not yet supported, please contact the author") - - cbf_obj.resetvals() - # ensure the PIL image is reset - cbf_obj.pilimage = None - return cbf_obj