def rebin_axis_1D(obj, axis_out): """ This function rebins the primary axis for a C{SOM} or a C{SO} based on the given C{NessiList} axis. @param obj: Object to be rebinned @type obj: C{SOM.SOM} or C{SOM.SO} @param axis_out: The axis to rebin the C{SOM} or C{SO} to @type axis_out: C{NessiList} @return: Object that has been rebinned according to the provided axis @rtype: C{SOM.SOM} or C{SOM.SO} @raise TypeError: The rebinning axis given is not a C{NessiList} @raise TypeError: The object being rebinned is not a C{SOM} or a C{SO} """ # import the helper functions import hlr_utils # set up for working through data try: axis_out.__type__ except AttributeError: raise TypeError("Rebinning axis must be a NessiList!") o_descr = hlr_utils.get_descr(obj) if o_descr == "number" or o_descr == "list": raise TypeError("Do not know how to handle given type: %s" % \ o_descr) else: pass (result, res_descr) = hlr_utils.empty_result(obj) result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) # iterate through the values import axis_manip for i in xrange(hlr_utils.get_length(obj)): axis_in = hlr_utils.get_value(obj, i, o_descr, "x", 0) val = hlr_utils.get_value(obj, i, o_descr) err2 = hlr_utils.get_err2(obj, i, o_descr) value = axis_manip.rebin_axis_1D(axis_in, val, err2, axis_out) xvals = [] xvals.append(axis_out) map_so = hlr_utils.get_map_so(obj, None, i) hlr_utils.result_insert(result, res_descr, value, map_so, "all", 0, xvals) return result
def subtract_time_indep_bkg(obj, B_list): """ This function takes spectrum object(s) and time-independent background value(s) and subtracts the numbers from the appropriate spectrum. The time-independent background number(s) are assumed to be in the same order as the spectrum object(s). @param obj: Object from which to subtract the individual background numbers @type obj: C{SOM.SOM} or C{SOM.SO} @param B_list: The time-independent backgrounds to subtract from the individual spectra. @type B_list: C{list} of C{tuple}s or C{tuple} @return: Object with the time-independent backgrounds subtracted @rtype: C{SOM.SOM} or C{SOM.SO} @raise IndexError: The B_list object is empty @raise TypeError: The first argument is not a C{SOM} or C{SO} @raise RuntimeError: The C{SOM} and list are not the same length """ if len(B_list) <= 0: raise IndexError("List of time-independent background cannot be empty") # List is correct size, go on else: pass # import the helper functions import hlr_utils (o_descr, l_descr) = hlr_utils.get_descr(obj, B_list) if o_descr == "number" or o_descr == "list": raise TypeError("First argument must be a SOM or a SO!") # Have a SOM or SO, go on else: pass (result, res_descr) = hlr_utils.empty_result(obj) result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) import common_lib # iterate through the values for i in xrange(hlr_utils.get_length(obj)): val1 = hlr_utils.get_value(obj, i, o_descr, "all") val2 = hlr_utils.get_value(B_list, i, l_descr, "all") value = common_lib.sub_ncerr(val1, val2) hlr_utils.result_insert(result, res_descr, value, None, "all") return result
def filter_normalization(obj, lothreshold, hithreshold, config=None): """ This function takes an object with normalization integration information and a threshold and creates a mask file containing the pixel IDs that do not make it above the threshold. @param obj: The object containing the normalization information @type obj: C{SOM.SOM} @param lothreshold: The value below which a pixel will be masked. @type lothreshold: C{float} @param hithreshold: The value above which a pixel will be masked. @type hithreshold: C{float} @param config: The object holding the DR configuration @type config: L{hlr_utils.Configure} @raise TypeError: The incoming object is not a C{SOM}. """ import hlr_utils o_descr = hlr_utils.get_descr(obj) if o_descr != "SOM": raise TypeError("Only SOMs are allowed in this function!") if config is None: # Make mask file name from object information instname = obj.attr_list.inst.get_name() runnum = obj.attr_list["run_number"] outfile = "%s_%s_mask.dat" % (instname, str(runnum)) else: # Make mask file name from configuration information outfile = hlr_utils.ext_replace(config.output, config.ext_replacement, "dat") outfile = hlr_utils.add_tag(outfile, "mask") ofile = open(outfile, "w") import SOM import utils len_obj = hlr_utils.get_length(obj) for i in xrange(len_obj): norm = hlr_utils.get_value(obj, i, o_descr) if utils.compare(norm, lothreshold) <= 0 or \ utils.compare(norm, hithreshold) >= 0: map_so = hlr_utils.get_map_so(obj, None, i) pix_id = SOM.NeXusId.fromString(str(map_so.id)).toJoinedStr() print >> ofile, pix_id ofile.close()
def filter_normalization(obj, lothreshold, hithreshold, config=None): """ This function takes an object with normalization integration information and a threshold and creates a mask file containing the pixel IDs that do not make it above the threshold. @param obj: The object containing the normalization information @type obj: C{SOM.SOM} @param lothreshold: The value below which a pixel will be masked. @type lothreshold: C{float} @param hithreshold: The value above which a pixel will be masked. @type hithreshold: C{float} @param config: The object holding the DR configuration @type config: L{hlr_utils.Configure} @raise TypeError: The incoming object is not a C{SOM}. """ import hlr_utils o_descr = hlr_utils.get_descr(obj) if o_descr != "SOM": raise TypeError("Only SOMs are allowed in this function!") if config is None: # Make mask file name from object information instname = obj.attr_list.inst.get_name() runnum = obj.attr_list["run_number"] outfile = "%s_%s_mask.dat" % (instname, str(runnum)) else: # Make mask file name from configuration information outfile = hlr_utils.ext_replace(config.output, config.ext_replacement, "dat") outfile = hlr_utils.add_tag(outfile, "mask") ofile = open(outfile, "w") import SOM import utils len_obj = hlr_utils.get_length(obj) for i in xrange(len_obj): norm = hlr_utils.get_value(obj, i, o_descr) if utils.compare(norm, lothreshold) <= 0 or utils.compare(norm, hithreshold) >= 0: map_so = hlr_utils.get_map_so(obj, None, i) pix_id = SOM.NeXusId.fromString(str(map_so.id)).toJoinedStr() print >> ofile, pix_id ofile.close()
def reverse_array_cp(obj): """ This function reverses the y and var_y values of all the C{SO}s in a C{SOM} or an individual C{SO}. This is assuming that there was a previous transformation on the x-axis of the C{SO} or C{SOM}. @param obj: Object that needs to have its y and var_y values reversed @type obj: C{SOM.SOM} or C{SOM.SO} @return: Object containing the results of the reversal process @rtype: C{SOM.SOM} or C{SOM.SO} @raise TypeError: A C{tuple} or C{list} of C{tuple}s is presented to the function """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) if o_descr == "number" or o_descr == "list": raise TypeError("Do not know how to handle given type: %s" % \ o_descr) else: pass result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) # iterate through the values import axis_manip for i in xrange(hlr_utils.get_length(obj)): val = hlr_utils.get_value(obj, i, o_descr) err2 = hlr_utils.get_err2(obj, i, o_descr) value1 = axis_manip.reverse_array_cp(val) value2 = axis_manip.reverse_array_cp(err2) map_so = hlr_utils.get_map_so(obj, None, i) hlr_utils.result_insert(result, res_descr, (value1, value2), map_so) return result
def calculate_ref_background(obj, no_bkg, inst, peak_excl, **kwargs): """ This function takes a set of reflectometer data spectra in TOF, slices the data along TOF channels, fits a linear function to the slice to determine the background and then reassembles the slice back into TOF spectra. @param obj: Object containing data spectra @type obj: C{SOM.SOM} or C{SOM.SO} @param no_bkg: Flag for actually requesting a background calculation @type no_bkg: C{boolean} @param inst: String containing the reflectometer short name @type inst: C{string} (I{REF_L} or I{REF_M}) @param peak_excl: The bounding pixel IDs for peak exclusion from fit @type peak_excl: C{tuple} containging the minimum and maximum pixel ID @param kwargs: A list of keyword arguments that the function accepts: @keyword aobj: An alternate data object containing the sizing information for the constructed background spectra. @type aobj: C{SOM.SOM} or C{SOM.SO} @return: Background spectra @rtype: C{SOM.SOM} """ if obj is None: return None if no_bkg: return None # import the helper functions import hlr_utils # Setup instrument specific stuff if inst == "REF_L": inst_pix_id = 1 elif inst == "REF_M": inst_pix_id = 0 else: raise RuntimeError("Do not know how to deal with instrument %s" % inst) # Check keywords try: aobj = kwargs["aobj"] except KeyError: aobj = None # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) # Set spectrum object to obtain background SOs from if aobj is None: bobj = obj else: bobj = aobj # Get the number of spectra for background calculation len_som = len(obj) # Get the number of spectra for final background object if aobj is None: len_bsom = len(obj) else: len_bsom = len(aobj) # Get the number of TOF channels len_tof = len(obj[0]) # Create blank SOs for background spectra so_list = [] import nessi_list import SOM import utils # Setup pixel axes pix_axis = nessi_list.NessiList() if peak_excl is not None: pix_axis_no_peak = nessi_list.NessiList() # Fill pixel axes and background SOs for k in xrange(len_bsom): map_so = hlr_utils.get_map_so(bobj, None, k) cur_pix_id = map_so.id[1][inst_pix_id] pix_axis.append(cur_pix_id) if peak_excl is not None: if cur_pix_id < peak_excl[0] or cur_pix_id > peak_excl[1]: pix_axis_no_peak.append(cur_pix_id) so = SOM.SO() hlr_utils.result_insert(so, "SO", map_so, None, "all") so_list.append(so) # Slice data, calculate weighted average and repackage spectra for i in xrange(len_tof): sliced_data = nessi_list.NessiList() sliced_data_err2 = nessi_list.NessiList() for j in xrange(len_som): obj1 = hlr_utils.get_value(obj, j, o_descr, "all") cur_pix_id = obj1.id[1][inst_pix_id] if peak_excl is None: filter_pixel = False else: if cur_pix_id < peak_excl[0] or cur_pix_id > peak_excl[1]: filter_pixel = False else: filter_pixel = True if not filter_pixel: if not (utils.compare(obj1.var_y[i], 0.0) == 0 and \ utils.compare(obj1.y[i], 0.0) == 0): sliced_data.append(obj1.y[i]) sliced_data_err2.append(obj1.var_y[i]) len_fit = len(sliced_data) if not len_fit: value = (0.0, 0.0) else: value = utils.weighted_average(sliced_data, sliced_data_err2, 0, len_fit-1) for j in xrange(len_bsom): so_list[j].y[i] = value[0] so_list[j].var_y[i] = value[1] for m in xrange(len_bsom): hlr_utils.result_insert(result, res_descr, so_list[m], None, "all") return result
def wavelength_to_velocity(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from wavelength to velocity. The wavelength axis for a C{SOM} must be in units of I{Angstroms}. The primary axis of a C{SO} is assumed to be in units of I{Angstroms}. A C{tuple} of C{(wavelength, wavelength_err2)} (assumed to be in units of I{Angstroms}) can be converted to C{(velocity, velocity_err)}. @param obj: Object to be converted @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword lojac: A flag that allows one to turn off the calculation of the linear-order Jacobian. The default action is True for histogram data. @type lojac: C{boolean} @keyword units: The expected units for this function. The default for this function is I{Angstroms} @type units: C{string} @return: Object with a primary axis in wavelength converted to velocity @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise TypeError: The incoming object is not a type the function recognizes @raise RuntimeError: The C{SOM} x-axis units are not I{Angstroms} """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) if o_descr == "list": raise TypeError("Do not know how to handle given type: %s" % \ o_descr) else: pass # Setup keyword arguments try: units = kwargs["units"] except KeyError: units = "Angstroms" try: lojac = kwargs["lojac"] except KeyError: lojac = hlr_utils.check_lojac(obj) # Primary axis for transformation. If a SO is passed, the function, will # assume the axis for transformation is at the 0 position if o_descr == "SOM": axis = hlr_utils.one_d_units(obj, units) else: axis = 0 result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, "meters/microseconds", axis) result.setAxisLabel(axis, "velocity") result.setYUnits("Counts/meters/microseconds") result.setYLabel("Intensity") else: pass # iterate through the values import axis_manip if lojac: import utils len_obj = hlr_utils.get_length(obj) for i in xrange(len_obj): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) value = axis_manip.wavelength_to_velocity(val, err2) if lojac: y_val = hlr_utils.get_value(obj, i, o_descr, "y") y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y") counts = utils.linear_order_jacobian(val, value[0], y_val, y_err2) else: pass if o_descr != "number": value1 = axis_manip.reverse_array_cp(value[0]) value2 = axis_manip.reverse_array_cp(value[1]) rev_value = (value1, value2) else: rev_value = value if map_so is not None: if not lojac: map_so.y = axis_manip.reverse_array_cp(map_so.y) map_so.var_y = axis_manip.reverse_array_cp(map_so.var_y) else: map_so.y = axis_manip.reverse_array_cp(counts[0]) map_so.var_y = axis_manip.reverse_array_cp(counts[1]) else: pass hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x", axis) return result
def d_spacing_to_tof_focused_det(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from d-spacing to a focused time-of-flight. The focusing is done using the geometry information from a single detector pixel. The d-spacing axis for a C{SOM} must be in units of I{Angstroms}. The primary axis of a C{SO} is assumed to be in units of I{Angstroms}. @param obj: Object to be converted @type obj: C{SOM.SOM} or C{SOM.SO} @param kwargs: A list of keyword arguments that the function accepts: @keyword polar: The polar angle and its associated error^2 @type polar: C{tuple} or C{list} of C{tuple}s @keyword pathlength: The total pathlength and its associated error^2 @type pathlength: C{tuple} or C{list} of C{tuple}s @keyword pixel_id: The pixel ID from which the geometry information will be retrieved from the instrument @type pixel_id: C{tuple}=(\"bankN\", (x, y)) @keyword verbose: This determines if the pixel geometry information is printed. The default is False @type verbose: C{boolean} @keyword units: The expected units for this function. The default for this function is I{microseconds}. @type units: C{string} @return: Object with a primary axis in d-spacing converted to time-of-flight @rtype: C{SOM.SOM} or C{SOM.SO} @raise RuntimeError: A C{SOM} or C{SO} is not provided to the function @raise RuntimeError: No C{SOM.Instrument} is provided in a C{SOM} @raise RuntimeError: No C{SOM} is given and both the pathlength and polar angle are not provided @raise RuntimeError: No C{SOM} is given and the pathlength is not provided @raise RuntimeError: No C{SOM} is given and the polar angle is not provided """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) if o_descr == "number" or o_descr == "list": raise RuntimeError("Must provide a SOM of a SO to the function.") # Go on else: pass # Setup keyword arguments try: polar = kwargs["polar"] except KeyError: polar = None try: pathlength = kwargs["pathlength"] except KeyError: pathlength = None try: pixel_id = kwargs["pixel_id"] except KeyError: pixel_id = None try: verbose = kwargs["verbose"] except KeyError: verbose = False try: units = kwargs["units"] except KeyError: units = "Angstroms" # Primary axis for transformation. If a SO is passed, the function, will # assume the axis for transformation is at the 0 position if o_descr == "SOM": axis = hlr_utils.one_d_units(obj, units) else: axis = 0 result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, "microseconds", axis) result.setAxisLabel(axis, "time-of-flight") result.setYUnits("Counts/usec") result.setYLabel("Intensity") else: pass if pathlength is None or polar is None: if o_descr == "SOM": try: obj.attr_list.instrument.get_primary() inst = obj.attr_list.instrument except RuntimeError: raise RuntimeError("An instrument was not provided") else: if pathlength is None and polar is None: raise RuntimeError("If no SOM is provided, then pathlength "\ +"and polar angle information must be provided") elif pathlength is None: raise RuntimeError("If no SOM is provided, then pathlength "\ +"information must be provided") elif polar is None: raise RuntimeError("If no SOM is provided, then polar angle "\ +"information must be provided") else: raise RuntimeError("If you get here, see Steve Miller for "\ +"your mug.") else: pass if pathlength is not None: p_descr = hlr_utils.get_descr(pathlength) if polar is not None: a_descr = hlr_utils.get_descr(polar) # iterate through the values if pixel_id is not None: tmp_so = SOM.SO() tmp_so.id = pixel_id (pl, pl_err2) = hlr_utils.get_parameter("total", tmp_so, inst) (angle, angle_err2) = hlr_utils.get_parameter("polar", tmp_so, inst) if verbose: format_str = "Pixel ID %s has polar angle: (%f,%f) and " format_str += "pathlength: (%f,%f)" print format_str % (str(pixel_id), angle, angle_err2, pl, pl_err2) else: pass else: pl = hlr_utils.get_value(pathlength, 0, p_descr) pl_err2 = hlr_utils.get_err2(pathlength, 0, p_descr) angle = hlr_utils.get_value(polar, 0, a_descr) angle_err2 = hlr_utils.get_err2(polar, 0, a_descr) # iterate through the values import axis_manip for i in xrange(hlr_utils.get_length(obj)): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) value = axis_manip.d_spacing_to_tof_focused_det(val, err2, pl, pl_err2, angle, angle_err2) hlr_utils.result_insert(result, res_descr, value, map_so, "x", axis) return result
def shift_spectrum(obj, shift_point, min_ext, max_ext, scale_const=None): """ This function takes a given spectrum and a central value and creates a spectrum that is shifted about that point. Values greater than the point are moved to the beginning of the new spectrum and values less than the point are move towards the end of the new spectrum. @param obj: Monitor object that will be shifted @type obj: C{SOM.SOM} or C{SOM.SO} @param shift_point: The point in the spectrum about which to shift the data. @type shift_point: C{list} of C{floats} @param min_ext: The minimum extent of the axis to shift. @type min_ext: C{list} of C{floats} @param max_ext: The maximum extent of the axis to shift. @type max_ext: C{list} of C{floats} @param scale_const: A scaling constant to apply (multiply) to the newly shifted spectrum. The default is I{None}. @type scale_const: C{float} @return: Monitor spectrum that have been shifted @rtype: C{SOM.SOM} or C{SOM.SO} """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) s_descr = hlr_utils.get_descr(shift_point) ie_descr = hlr_utils.get_descr(min_ext) ae_descr = hlr_utils.get_descr(max_ext) result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) import array_manip import utils len_obj = hlr_utils.get_length(obj) for i in xrange(len_obj): val = hlr_utils.get_value(obj, i, o_descr, "y") err2 = hlr_utils.get_err2(obj, i, o_descr, "y") x_axis = hlr_utils.get_value(obj, i, o_descr, "x", 0) x_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", 0) map_so = hlr_utils.get_map_so(obj, None, i) bin_center = utils.calc_bin_centers(x_axis, x_err2) # Get shift point and extents sp = hlr_utils.get_value(shift_point, i, s_descr, "y") ie = hlr_utils.get_value(min_ext, i, ie_descr, "y") ae = hlr_utils.get_value(max_ext, i, ae_descr, "y") # Make shifted spectrum value0 = utils.shift_spectrum(val, err2, x_axis, bin_center[0], sp, ie, ae) # Scale spectrum if necessary if scale_const is not None: value1 = array_manip.mult_ncerr(value0[0], value0[1], scale_const, 0.0) else: value1 = value0 hlr_utils.result_insert(result, res_descr, value1, map_so, "y") return result
def create_X_vs_pixpos(som, *args, **kwargs): """ This function takes a group of single spectrum with any given axes (wavelength, energy etc.) and rebins those axes to the given axis and converts the spectra into a single I{I(X, pixel)} spectrum. @param som: The input object with arbitrary (but same) axis spectra @type som: C{SOM.SOM} @param args: A mandatory list of axes for rebinning. There is a particular order to them. They should be present in the following order: Without errors 1. Axis With errors 1. Axis 2. Axis error^2 @type args: C{nessi_list.NessiList}s @param kwargs: A list of keyword arguments that the function accepts: @keyword withXVar: A flag for whether the function should be expecting the associated axes to have errors. The default value will be I{False}. @type withXVar: C{boolean} @keyword data_type: The name of the data type which can be either I{histogram}, I{density} or I{coordinate}. The default value will be I{histogram}. @type data_type: C{string} @keyword so_id: The identifier represents a number, string, tuple or other object that describes the resulting C{SO}. @type so_id: C{int}, C{string}, C{tuple}, C{pixel ID} @keyword y_label: The dependent axis label @type y_label: C{string} @keyword y_units: The dependent axis units @type y_units: C{string} @keyword x_label: The second primary axis label @type x_label: C{string} @keyword x_units: The second primary axis units @type x_units: C{string} @keyword rebin: A flag for turning rebin on or off. The default is I{True}. @type rebin: C{boolean} @return: Object with a single 2D C{SO} with the given axis and global pixel position @rtype: C{SOM.SOM} @raise RuntimeError: The parameter given to the keyword argument withXVar is not I{True} or I{False} @raise RuntimeError: The parameter given to the keyword argument data_type is not I{histogram} or I{density} or I{coordinate}. @raise RuntimeError: The number of given arguments (x-axes) is not either 2 (no errors) or 4 (with errors) """ import common_lib import nessi_list # Setup some variables dim = 2 N_y = [] N_tot = 1 N_args = len(args) # Check withXVar keyword argument and also check number of given args. # Set xvar to the appropriate value try: value = kwargs["withXVar"] if value.lower() == "true": if N_args != 2: raise RuntimeError("Since you have requested x errors, 2 x "\ +"axes must be provided.") else: xvar = True elif value.lower() == "false": if N_args != 2: raise RuntimeError("Since you did not requested x errors, 2 "\ +"x axes must be provided.") else: xvar = False else: raise RuntimeError("Do not understand given parameter %s" % \ value) except KeyError: if N_args != 1: raise RuntimeError("Since you did not requested x errors, 1 "\ +"x axes must be provided.") else: xvar = False # Check dataType keyword argument. An offset will be set to 1 for the # histogram type and 0 for either density or coordinate try: data_type = kwargs["data_type"] if data_type.lower() == "histogram": offset = 1 elif data_type.lower() == "density" or \ data_type.lower() == "coordinate": offset = 0 else: raise RuntimeError("Do not understand data type given: %s" % \ data_type) # Default is offset for histogram except KeyError: offset = 1 so_dim = SOM.SO(dim) arb_axis = 1 pixel_axis = 0 # Set the x-axis arguments from the *args list into the new SO if not xvar: so_dim.axis[arb_axis].val = args[0] else: so_dim.axis[arb_axis].val = args[0] so_dim.axis[arb_axis].var = args[1] # Set individual value axis sizes (not x-axis size) N_y.append(len(args[0]) - offset) # Calculate total 2D array size N_som = len(som) N_tot = N_som * N_y[-1] # Make second axis on total number of pixels so_dim.axis[pixel_axis].val = hlr_utils.make_axis(0, N_som, 1) if xvar: so_dim.axis[pixel_axis].var = nessi_list.NessiList(N_som+1) # Create y and var_y lists from total 2D size so_dim.y = nessi_list.NessiList(N_tot) so_dim.var_y = nessi_list.NessiList(N_tot) # Check for rebinning try: rebin = kwargs["rebin"] except KeyError: rebin = True # Rebin data to X axis if rebin: som_1 = common_lib.rebin_axis_1D(som, args[0]) else: som_1 = som del som import array_manip for i in xrange(hlr_utils.get_length(som_1)): val = hlr_utils.get_value(som_1, i, "SOM", "y") err2 = hlr_utils.get_err2(som_1, i, "SOM", "y") start = i * N_y[0] (so_dim.y, so_dim.var_y) = array_manip.add_ncerr(so_dim.y, so_dim.var_y, val, err2, a_start=start) # Check for so_id keyword argument try: so_dim.id = kwargs["so_id"] except KeyError: so_dim.id = 0 comb_som = SOM.SOM() comb_som.copyAttributes(som_1) del som_1 # Check for y_label keyword argument try: comb_som.setYLabel(kwargs["y_label"]) except KeyError: comb_som.setYLabel("Counts") # Check for y_units keyword argument try: comb_som.setYUnits(kwargs["y_units"]) except KeyError: comb_som.setYUnits("Counts / Arb") # Check for x_label keyword argument try: comb_som.setAllAxisLabels(["Pixel Number", kwargs["x_label"]]) except KeyError: comb_som.setAllAxisLabels(["Pixel Number", "Arbitrary"]) # Check for x_units keyword argument try: comb_som.setAllAxisUnits(["Pixel#", kwargs["x_units"]]) except KeyError: comb_som.setAllAxisUnits(["Pixel#", "Arb"]) comb_som.append(so_dim) del so_dim return comb_som
def tof_to_wavelength_lin_time_zero(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from time-of-flight to wavelength incorporating a linear time zero which is a described as a linear function of the wavelength. The time-of-flight axis for a C{SOM} must be in units of I{microseconds}. The primary axis of a C{SO} is assumed to be in units of I{microseconds}. A C{tuple} of C{(tof, tof_err2)} (assumed to be in units of I{microseconds}) can be converted to C{(wavelength, wavelength_err2)}. @param obj: Object to be converted @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword pathlength: The pathlength and its associated error^2 @type pathlength: C{tuple} or C{list} of C{tuple}s @keyword time_zero_slope: The time zero slope and its associated error^2 @type time_zero_slope: C{tuple} @keyword time_zero_offset: The time zero offset and its associated error^2 @type time_zero_offset: C{tuple} @keyword inst_param: The type of parameter requested from an associated instrument. For this function the acceptable parameters are I{primary}, I{secondary} and I{total}. Default is I{primary}. @type inst_param: C{string} @keyword lojac: A flag that allows one to turn off the calculation of the linear-order Jacobian. The default action is I{True} for histogram data. @type lojac: C{boolean} @keyword units: The expected units for this function. The default for this function is I{microseconds}. @type units: C{string} @keyword cut_val: Specify a wavelength to cut the spectra at. @type cut_val: C{float} @keyword cut_less: A flag that specifies cutting the spectra less than C{cut_val}. The default is C{True}. @type cut_less: C{boolean} @return: Object with a primary axis in time-of-flight converted to wavelength @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise TypeError: The incoming object is not a type the function recognizes @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds} @raise RuntimeError: A C{SOM} does not contain an instrument and no pathlength was provided @raise RuntimeError: No C{SOM} is provided and no pathlength given """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) # Setup keyword arguments try: inst_param = kwargs["inst_param"] except KeyError: inst_param = "primary" try: pathlength = kwargs["pathlength"] except KeyError: pathlength = None try: time_zero_slope = kwargs["time_zero_slope"] except KeyError: time_zero_slope = None # Current constants for Time Zero Slope TIME_ZERO_SLOPE = (float(0.0), float(0.0)) try: time_zero_offset = kwargs["time_zero_offset"] except KeyError: time_zero_offset = None # Current constants for Time Zero Offset TIME_ZERO_OFFSET = (float(0.0), float(0.0)) try: lojac = kwargs["lojac"] except KeyError: lojac = hlr_utils.check_lojac(obj) try: units = kwargs["units"] except KeyError: units = "microseconds" try: cut_val = kwargs["cut_val"] except KeyError: cut_val = None try: cut_less = kwargs["cut_less"] except KeyError: cut_less = True # Primary axis for transformation. If a SO is passed, the function, will # assume the axis for transformation is at the 0 position if o_descr == "SOM": axis = hlr_utils.one_d_units(obj, units) else: axis = 0 result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, "Angstroms", axis) result.setAxisLabel(axis, "wavelength") result.setYUnits("Counts/A") result.setYLabel("Intensity") else: pass if pathlength is not None: p_descr = hlr_utils.get_descr(pathlength) else: if o_descr == "SOM": try: obj.attr_list.instrument.get_primary() inst = obj.attr_list.instrument except RuntimeError: raise RuntimeError("A detector was not provided") else: raise RuntimeError("If no SOM is provided, then pathlength "\ +"information must be provided") if time_zero_slope is not None: t_0_slope_descr = hlr_utils.get_descr(time_zero_slope) else: if o_descr == "SOM": try: t_0_slope = obj.attr_list["Time_zero_slope"][0] t_0_slope_err2 = obj.attr_list["Time_zero_slope"][1] except KeyError: t_0_slope = TIME_ZERO_SLOPE[0] t_0_slope_err2 = TIME_ZERO_SLOPE[1] else: t_0_slope = TIME_ZERO_SLOPE[0] t_0_slope_err2 = TIME_ZERO_SLOPE[1] if time_zero_offset is not None: t_0_offset_descr = hlr_utils.get_descr(time_zero_offset) else: if o_descr == "SOM": try: t_0_offset = obj.attr_list["Time_zero_offset"][0] t_0_offset_err2 = obj.attr_list["Time_zero_offset"][1] except KeyError: t_0_offset = TIME_ZERO_OFFSET[0] t_0_offset_err2 = TIME_ZERO_OFFSET[1] else: t_0_offset = TIME_ZERO_OFFSET[0] t_0_offset_err2 = TIME_ZERO_OFFSET[1] # iterate through the values import axis_manip if lojac or cut_val is not None: import utils for i in xrange(hlr_utils.get_length(obj)): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) if pathlength is None: (pl, pl_err2) = hlr_utils.get_parameter(inst_param, map_so, inst) else: pl = hlr_utils.get_value(pathlength, i, p_descr) pl_err2 = hlr_utils.get_err2(pathlength, i, p_descr) if time_zero_slope is not None: t_0_slope = hlr_utils.get_value(time_zero_slope, i, t_0_slope_descr) t_0_slope_err2 = hlr_utils.get_err2(time_zero_slope, i, t_0_slope_descr) else: pass if time_zero_offset is not None: t_0_offset = hlr_utils.get_value(time_zero_offset, i, t_0_offset_descr) t_0_offset_err2 = hlr_utils.get_err2(time_zero_offset, i, t_0_offset_descr) else: pass value = axis_manip.tof_to_wavelength_lin_time_zero( val, err2, pl, pl_err2, t_0_slope, t_0_slope_err2, t_0_offset, t_0_offset_err2) if cut_val is not None: index = utils.bisect_helper(value[0], cut_val) if cut_less: # Need to cut at this index, so increment by one index += 1 value[0].__delslice__(0, index) value[1].__delslice__(0, index) map_so.y.__delslice__(0, index) map_so.var_y.__delslice__(0, index) if lojac: val.__delslice__(0, index) err2.__delslice__(0, index) else: len_data = len(value[0]) # All axis arrays need starting index adjusted by one since # they always carry one more bin than the data value[0].__delslice__(index + 1, len_data) value[1].__delslice__(index + 1, len_data) map_so.y.__delslice__(index, len_data) map_so.var_y.__delslice__(index, len_data) if lojac: val.__delslice__(index + 1, len_data) err2.__delslice__(index + 1, len_data) if lojac: counts = utils.linear_order_jacobian(val, value[0], map_so.y, map_so.var_y) hlr_utils.result_insert(result, res_descr, counts, map_so, "all", axis, [value[0]]) else: hlr_utils.result_insert(result, res_descr, value, map_so, "x", axis) return result
def filter_ref_data(som, **kwargs): """ This function takes in an object containing reflectometer data, scans it for bad data and removes that data from the arrays. The following criteria are what is considered bad data: - R or dR^2 is nan, inf, -inf - R < 0 - dR^2 >= R^2 @param som: Object containing a single spectrum to be cleaned @type som: C{SOM.SOM} @param kwargs: A list of keyword arguments that the function accepts: @keyword zero_mode: A flag that tells the function to zero the bad values instead of removing them @type zero_mode: C{boolean} @return: Object containing a spectrum that has been cleaned of all bad data @rtype: C{SOM.SOM} @raise RuntimeError: The incoming object is not a C{SOM}. """ import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(som) o_descr = hlr_utils.get_descr(som) if o_descr != "SOM": raise RuntimeError("Must provide a SOM to the function.") # Go on else: pass result = hlr_utils.copy_som_attr(result, res_descr, som, o_descr) try: dtot = result.attr_list["extra_som"] except KeyError: dtot = None # Check keyword arguments try: zero_mode = kwargs["zero_mode"] except KeyError: zero_mode = False import copy import itertools import utils index_map = {} len_som = hlr_utils.get_length(som) if dtot is not None: # Deal with delta t / t information len_dtot = len(dtot) if len_dtot == 1 and len_som > 1: # If the delta t / t information has only one spectrum and the som # data has more than one, we'll need to clone that delta t / t # spectrum multiple_dtot = True (res_dtot, resd_descr) = hlr_utils.empty_result(dtot) res_dtot = hlr_utils.copy_som_attr(res_dtot, resd_descr, dtot, "SOM") else: # Everything should be on equal footing with respect to the number # of spectra, so we don't have to do anything. res_dtot = dtot multiple_dtot = False else: len_dtot = 0 res_dtot = None multiple_dtot = False # Parse through the data to find the bad data locations. for i in xrange(len_som): counter = 0 indicies = [] so = hlr_utils.get_value(som, i, o_descr, "all") if multiple_dtot: if i > 0: dso = hlr_utils.get_value(dtot, 0, resd_descr, "all") dtot.append(copy.deepcopy(dso)) for (yval, yerr2) in itertools.izip(so.y, so.var_y): tofilter = False yval2 = yval * yval syval = str(yval) syerr2 = str(yerr2) if syval == "nan" or syval == "inf" or syval == "-inf": tofilter = True if syerr2 == "nan" or syerr2 == "inf" or syerr2 == "-inf": tofilter = True if yval < 0: tofilter = True if yerr2 > yval2 or not utils.compare(yerr2, yval2): tofilter = True if tofilter: indicies.append(counter) counter += 1 index_map[so.id] = indicies # Parse through data to remove bad data at requested indicies for j in xrange(len_som): map_so = hlr_utils.get_map_so(som, None, j) y_val = hlr_utils.get_value(som, j, o_descr, "y") y_err2 = hlr_utils.get_err2(som, j, o_descr, "y") x_val = hlr_utils.get_value(som, j, o_descr, "x", 0) x_err2 = hlr_utils.get_err2(som, j, o_descr, "x", 0) y_val_new = copy.deepcopy(y_val) y_err2_new = copy.deepcopy(y_err2) x_val_new = copy.deepcopy(x_val) x_err2_new = copy.deepcopy(x_err2) if dtot is not None: dso = hlr_utils.get_value(dtot, j, "SOM", "all") dso_new = copy.deepcopy(dso) offset = 0 for index in index_map[map_so.id]: if not zero_mode: # Index arithmetic since list length get shorter with every # element deleted dindex = index - offset del y_val_new[dindex] del y_err2_new[dindex] del x_val_new[dindex] del x_err2_new[dindex] if dtot is not None: del dso_new.y[dindex] offset += 1 else: y_val_new[index] = 0.0 y_err2_new[index] = 0.0 if dtot is not None and multiple_dtot: hlr_utils.result_insert(res_dtot, resd_descr, dso_new, None, "all") hlr_utils.result_insert(result, res_descr, (y_val_new, y_err2_new), map_so, "all", 0, [x_val_new]) if dtot is not None: result.attr_list["extra_som"] = res_dtot return result
def data_filter(obj, **kwargs): """ This function takes in an object containing data, scans it for bad data and removes that data from the arrays. The criteria is instrument dependent and subfunctions will be written that handle the instrument dependent criteria. This function will operate in a zeroing mode. This means that bins with bad data will have their value and error^2 set to zero. @param obj: Object containing a single spectrum to be cleaned @type obj: C{SOM.SOM} @param kwargs: A list of keyword arguments that the function accepts: @keyword clean_axis: A flag that tells the function to check for I{inf} of I{-inf} values (normally at the ends of the axis) and remove those bins. The default behavior is I{False}. @type clean_axis: C{boolean} @keyword axis_index: The index on the axis to check for bad_values. This is assumed to be a single value and the default is -1 (last bin) @type axis_index: C{int} @keyword axis_pos: The position of the axis within the data object. This is necessary for greater than 1D spectra. The default value is 0. @type axis_pos: C{int} @return: Object containing a spectrum that has been cleaned of all bad data @rtype: C{SOM.SOM} @raise RuntimeError: The incoming object is not a C{SOM}. @raise AttributeError: 1D or 2D data passed is clean_axis is I{True}. @raise AttributeError: Axis position not 0 or 1 for 2D data. """ import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) if o_descr != "SOM": raise RuntimeError("Must provide a SOM to the function.") # Go on else: pass result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) # See if there is extra information present try: extra_som = result.attr_list["extra_som"] except KeyError: extra_som = None # Get instrument name inst_name = obj.attr_list.instrument.get_name() # Get dimension of incoming data data_dims = obj.getDimension() # Check keyword arguments try: clean_axis = kwargs["clean_axis"] except KeyError: clean_axis = False try: axis_index = kwargs["axis_index"] except KeyError: axis_index = -1 try: axis_pos = kwargs["axis_pos"] except KeyError: axis_pos = 0 if clean_axis: # Can only support 1D and 2D data axis cleaning for now if data_dims not in [1, 2]: raise AttributeError("Do not know how to clean %d-dimensional " + "data" % data_dims) if data_dims == 2: if axis_pos not in [0, 1]: raise AttributeError("2D data cannot have axis position %d!" \ % axis_pos) if axis_pos: other_axis = 0 else: other_axis = 1 axis_lengths = (len(obj[0].axis[0].val) - 1, len(obj[0].axis[1].val) - 1) else: axis_lengths = None if obj[0].axis[0].var is None: with_x_var = False else: with_x_var = True else: axis_lengths = None import copy import itertools len_som = hlr_utils.get_length(obj) if extra_som is not None: # Deal with extra information len_extra_som = len(extra_som) if len_extra_som == 1 and len_som > 1: # If the extra information has only one spectrum and the som # data has more than one, we'll need to clone that spectrum multiple_extra_som = True (res_extra_som, resd_descr) = hlr_utils.empty_result(extra_som) res_extra_som = hlr_utils.copy_som_attr(res_extra_som, resd_descr, extra_som, "SOM") else: # Everything should be on equal footing with respect to the number # of spectra, so we don't have to do anything. res_extra_som = extra_som multiple_extra_som = False else: len_extra_som = 0 res_extra_som = None multiple_extra_som = False # Parse through the data to find the bad data locations. for i in xrange(len_som): so = hlr_utils.get_value(obj, i, o_descr, "all") map_so = hlr_utils.get_map_so(obj, None, i) y_val = hlr_utils.get_value(obj, i, o_descr, "y") y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y") y_val_new = copy.deepcopy(y_val) y_err2_new = copy.deepcopy(y_err2) if extra_som is not None: eso = hlr_utils.get_value(extra_som, i, "SOM", "all") eso_new = copy.deepcopy(eso) else: eso_new = None if multiple_extra_som: if i > 0: eso = hlr_utils.get_value(extra_som, 0, resd_descr, "all") extra_som.append(copy.deepcopy(eso)) counter = 0 for (yval, yerr2) in itertools.izip(so.y, so.var_y): to_filter = False if inst_name == "BSS": to_filter = __filter_sns_bss(yval, yerr2) elif inst_name == "REF_L" or inst_name == "REF_M": to_filter = __filter_sns_ref(yval, yerr2) elif inst_name == "SANS": to_filter = __filter_ieee(str(yval), str(yerr2)) if to_filter: y_val_new[counter] = 0.0 y_err2_new[counter] = 0.0 counter += 1 if clean_axis: x_val = hlr_utils.get_value(obj, i, o_descr, "x", axis_pos) x_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis_pos) x_val_new = copy.deepcopy(x_val) x_err2_new = copy.deepcopy(x_err2) (y_val_new, y_err2_new, x_val_new, x_err2_new, eso_new) = __clean_axis(data_dims, axis_pos, axis_index, x_val_new, x_err2_new, y_val_new, y_err2_new, ext_so=eso_new, axis_len=axis_lengths) if extra_som is not None and multiple_extra_som: hlr_utils.result_insert(res_extra_som, resd_descr, eso_new, None, "all") if not clean_axis: hlr_utils.result_insert(result, res_descr, (y_val_new, y_err2_new), map_so, "y") else: if data_dims == 1: xvals = [x_val_new, x_err2_new] if not with_x_var: del xvals[-1] hlr_utils.result_insert(result, res_descr, (y_val_new, y_err2_new), map_so, "all", axis_pos, xvals) elif data_dims == 2: ox_val = hlr_utils.get_value(obj, i, o_descr, "x", other_axis) ox_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", other_axis) if axis_pos == 0: xvals = [ x_val_new, x_err2_new, copy.deepcopy(ox_val), copy.deepcopy(ox_err2) ] else: xvals = [ copy.deepcopy(ox_val), copy.deepcopy(ox_err2), x_val_new, x_err2_new ] if not with_x_var: del xvals[1::2] hlr_utils.result_insert(result, res_descr, (y_val_new, y_err2_new), map_so, "all", axis_pos, xvals) if extra_som is not None: result.attr_list["extra_som"] = res_extra_som return result
def tof_to_initial_wavelength_igs(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from time-of-flight to initial_wavelength_igs. The time-of-flight axis for a C{SOM} must be in units of I{microseconds}. The primary axis of a C{SO} is assumed to be in units of I{microseconds}. A C{tuple} of C{(tof, tof_err2)} (assumed to be in units of I{microseconds}) can be converted to C{(initial_wavelength_igs, initial_wavelength_igs_err2)}. @param obj: Object to be converted @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword lambda_f:The final wavelength and its associated error^2 @type lambda_f: C{tuple} @keyword time_zero: The time zero offset and its associated error^2 @type time_zero: C{tuple} @keyword dist_source_sample: The source to sample distance information and its associated error^2 @type dist_source_sample: C{tuple} or C{list} of C{tuple}s @keyword dist_sample_detector: The sample to detector distance information and its associated error^2 @type dist_sample_detector: C{tuple} or C{list} of C{tuple}s @keyword run_filter: This determines if the filter on the negative wavelengths is run. The default setting is True. @type run_filter: C{boolean} @keyword units: The expected units for this function. The default for this function is I{microseconds} @type units: C{string} @return: Object with a primary axis in time-of-flight converted to initial_wavelength_igs @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise TypeError: The incoming object is not a type the function recognizes @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds} """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) # Setup keyword arguments try: lambda_f = kwargs["lambda_f"] except KeyError: lambda_f = None try: time_zero = kwargs["time_zero"] except KeyError: time_zero = None try: dist_source_sample = kwargs["dist_source_sample"] except KeyError: dist_source_sample = None try: dist_sample_detector = kwargs["dist_sample_detector"] except KeyError: dist_sample_detector = None try: units = kwargs["units"] except KeyError: units = "microseconds" try: run_filter = kwargs["run_filter"] except KeyError: run_filter = True # Primary axis for transformation. If a SO is passed, the function, will # assume the axis for transformation is at the 0 position if o_descr == "SOM": axis = hlr_utils.one_d_units(obj, units) else: axis = 0 result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, "Angstroms", axis) result.setAxisLabel(axis, "wavelength") result.setYUnits("Counts/A") result.setYLabel("Intensity") else: pass # Where to get instrument information if dist_source_sample is None or dist_sample_detector is None: if o_descr == "SOM": try: obj.attr_list.instrument.get_primary() inst = obj.attr_list.instrument except RuntimeError: raise RuntimeError("A detector was not provided!") else: if dist_source_sample is None and dist_sample_detector is None: raise RuntimeError("If a SOM is not passed, the "\ +"source-sample and sample-detector "\ +"distances must be provided.") elif dist_source_sample is None: raise RuntimeError("If a SOM is not passed, the "\ +"source-sample distance must be provided.") elif dist_sample_detector is None: raise RuntimeError("If a SOM is not passed, the "\ +"sample-detector distance must be "\ +"provided.") else: raise RuntimeError("If you get here, see Steve Miller for "\ +"your mug.") else: pass if lambda_f is not None: l_descr = hlr_utils.get_descr(lambda_f) else: if o_descr == "SOM": try: som_l_f = obj.attr_list["Wavelength_final"] except KeyError: raise RuntimeError("Please provide a final wavelength "\ +"parameter either via the function call "\ +"or the SOM") else: raise RuntimeError("You need to provide a final wavelength") if time_zero is not None: t_descr = hlr_utils.get_descr(time_zero) else: if o_descr == "SOM": try: t_0 = obj.attr_list["Time_zero"][0] t_0_err2 = obj.attr_list["Time_zero"][1] except KeyError: raise RuntimeError("Please provide a time-zero "\ +"parameter either via the function call "\ +"or the SOM") else: t_0 = 0.0 t_0_err2 = 0.0 if dist_source_sample is not None: ls_descr = hlr_utils.get_descr(dist_source_sample) # Do nothing, go on else: pass if dist_sample_detector is not None: ld_descr = hlr_utils.get_descr(dist_sample_detector) # Do nothing, go on else: pass # iterate through the values import axis_manip for i in xrange(hlr_utils.get_length(obj)): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) if dist_source_sample is None: (L_s, L_s_err2) = hlr_utils.get_parameter("primary", map_so, inst) else: L_s = hlr_utils.get_value(dist_source_sample, i, ls_descr) L_s_err2 = hlr_utils.get_err2(dist_source_sample, i, ls_descr) if dist_sample_detector is None: (L_d, L_d_err2) = hlr_utils.get_parameter("secondary", map_so, inst) else: L_d = hlr_utils.get_value(dist_sample_detector, i, ld_descr) L_d_err2 = hlr_utils.get_err2(dist_sample_detector, i, ld_descr) if lambda_f is not None: l_f = hlr_utils.get_value(lambda_f, i, l_descr) l_f_err2 = hlr_utils.get_err2(lambda_f, i, l_descr) else: l_f_tuple = hlr_utils.get_special(som_l_f, map_so) l_f = l_f_tuple[0] l_f_err2 = l_f_tuple[1] if time_zero is not None: t_0 = hlr_utils.get_value(time_zero, i, t_descr) t_0_err2 = hlr_utils.get_err2(time_zero, i, t_descr) else: pass value = axis_manip.tof_to_initial_wavelength_igs( val, err2, l_f, l_f_err2, t_0, t_0_err2, L_s, L_s_err2, L_d, L_d_err2) # Remove all wavelengths < 0 if run_filter: index = 0 for val in value[0]: if val >= 0: break index += 1 value[0].__delslice__(0, index) value[1].__delslice__(0, index) map_so.y.__delslice__(0, index) map_so.var_y.__delslice__(0, index) else: pass hlr_utils.result_insert(result, res_descr, value, map_so, "x", axis) return result
def tof_to_ref_scalar_Q(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from time-of-flight to reflectometer scalar Q. This means that a single angle and a single flightpath is used. The time-of-flight axis for a C{SOM} must be in units of I{microseconds}. The primary axis of a C{SO} is assumed to be in units of I{microseconds}. A C{tuple} of C{(time-of-flight, time-of-flight_err2)} (assumed to be in units of I{microseconds}) can be converted to C{(scalar_Q, scalar_Q_err2)}. @param obj: Object to be converted @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword polar: The polar angle and its associated error^2 @type polar: C{tuple} @keyword pathlength: The pathlength and its associated error^2 @type pathlength: C{tuple} @keyword angle_offset: A constant offset for the polar angle and its associated error^2. The units of the offset should be in radians. @type angle_offset: C{tuple} @keyword lojac: A flag that allows one to turn off the calculation of the linear-order Jacobian. The default action is True for histogram data. @type lojac: C{boolean} @keyword units: The expected units for this function. The default for this function is I{microseconds}. @type units: C{string} @keyword configure: This is the object containing the driver configuration. This will signal the function to write out the counts and fractional area to files. @type configure: C{Configure} @return: Object with a primary axis in time-of-flight converted to reflectometer scalar Q @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise TypeError: The incoming object is not a type the function recognizes @raise RuntimeError: A C{SOM} is not passed and no polar angle is provided @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds} """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) if o_descr == "list": raise TypeError("Do not know how to handle given type: %s" % \ o_descr) else: pass # Setup keyword arguments polar = kwargs.get("polar") pathlength = kwargs.get("pathlength") units = kwargs.get("units", "microseconds") lojac = kwargs.get("lojac", hlr_utils.check_lojac(obj)) angle_offset = kwargs.get("angle_offset") config = kwargs.get("configure") if config is None: beamdiv_corr = False else: beamdiv_corr = config.beamdiv_corr # Primary axis for transformation. If a SO is passed, the function, will # assume the axis for transformation is at the 0 position if o_descr == "SOM": axis = hlr_utils.one_d_units(obj, units) else: axis = 0 result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, "1/Angstroms", axis) result.setAxisLabel(axis, "scalar wavevector transfer") result.setYUnits("Counts/A-1") result.setYLabel("Intensity") else: pass if pathlength is None or polar is None: if o_descr == "SOM": try: obj.attr_list.instrument.get_primary() inst = obj.attr_list.instrument except RuntimeError: raise RuntimeError("A detector was not provided") else: if pathlength is None and polar is None: raise RuntimeError("If no SOM is provided, then pathlength "\ +"and polar angle information must be "\ +"provided") elif pathlength is None: raise RuntimeError("If no SOM is provided, then pathlength "\ +"information must be provided") elif polar is None: raise RuntimeError("If no SOM is provided, then polar angle "\ +"information must be provided") else: raise RuntimeError("If you get here, see Steve Miller for "\ +"your mug.") else: pass if pathlength is None: (pl, pl_err2) = obj.attr_list.instrument.get_total_path(obj[0].id, det_secondary=True) else: (pl, pl_err2) = pathlength if polar is None: angle = hlr_utils.get_special(obj.attr_list["data-theta"], obj[0])[0] angle_err2 = 0.0 else: (angle, angle_err2) = polar if angle_offset is not None: angle += angle_offset[0] angle_err2 += angle_offset[1] # Need to multiply angle by 2.0 in order to make it be Theta to # underlying conversion function angle *= 2.0 angle_err2 *= 4.0 # iterate through the values import axis_manip if lojac: import utils if beamdiv_corr: import dr_lib for i in xrange(hlr_utils.get_length(obj)): skip_pixel = False val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) if beamdiv_corr: dangle = dr_lib.ref_beamdiv_correct(obj.attr_list, map_so.id, config.det_spat_res, config.center_pix) # We subtract due to the inversion of the z coordinates from the # mirror reflection of the beam at the sample. if dangle is not None: pangle = angle - (2.0 * dangle) else: pangle = angle skip_pixel = True else: pangle = angle value = axis_manip.tof_to_scalar_Q(val, err2, pl, pl_err2, pangle, angle_err2) if lojac: y_val = hlr_utils.get_value(obj, i, o_descr, "y") y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y") counts = utils.linear_order_jacobian(val, value[0], y_val, y_err2) else: pass if o_descr != "number": value1 = axis_manip.reverse_array_cp(value[0]) value2 = axis_manip.reverse_array_cp(value[1]) rev_value = (value1, value2) else: rev_value = value if map_so is not None: if not lojac: map_so.y = axis_manip.reverse_array_cp(map_so.y) map_so.var_y = axis_manip.reverse_array_cp(map_so.var_y) else: map_so.y = axis_manip.reverse_array_cp(counts[0]) map_so.var_y = axis_manip.reverse_array_cp(counts[1]) else: pass if not skip_pixel: hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x", axis) return result
def integrate_axis(obj, **kwargs): """ This function takes a spectrum and integrates the given axis. The function assumes that the incoming data is in the histogram form. @param obj: Spectrum to be integrated @type obj: C{SOM.SOM} or C{SOM.SO} @param kwargs: A list of keyword arguments that the function accepts: @keyword start: Value for the start range of the integration. @type start: C{float} @keyword end: Value for the end range of the integration. @type end: C{float} @keyword width: This is a flag to turn on the multiplication of the individual bin contents with the bins corresponding width. @type width: C{boolean} @keyword width_pos: This is the position of the x-axis in the axis array from which to calculate the bin widths in support of the width flag. If no argument is given, the default value is I{0}. @type width_pos: C{int} @return: The integration value and its associated error @rtype: C{tuple} @raise RuntimError: A C{SOM} or C{SO} is not given to the function. """ # import the helper functions import hlr_utils # set up for working through data o_descr = hlr_utils.get_descr(obj) if o_descr == "number" or o_descr == "list": raise RuntimeError("Must provide a SOM of a SO to the function.") # Go on else: pass # Check for starting bin try: start = kwargs["start"] except KeyError: start = float("inf") # Check for ending bin try: end = kwargs["end"] except KeyError: end = float("inf") # Check for width keyword argument try: width = kwargs["width"] except KeyError: width = False if width: # Check for width_pos keyword argument try: width_pos = kwargs["width_pos"] except KeyError: width_pos = 0 else: width_pos = 0 import array_manip import utils integration = float(0) integration_error2 = float(0) len_obj = hlr_utils.get_length(obj) for i in xrange(len_obj): value = hlr_utils.get_value(obj, i, o_descr, "y") error = hlr_utils.get_err2(obj, i, o_descr, "y") x_axis = hlr_utils.get_value(obj, i, o_descr, "x", width_pos) (int_val) = utils.integrate_1D_hist(value, error, x_axis, width=width, min_int=start, max_int=end) (integration, integration_error2) = array_manip.add_ncerr(int_val[0], int_val[1], integration, integration_error2) return (integration, integration_error2)
def energy_transfer(left, right, **kwargs): """ This function takes a C{tuple} and a C{SOM}, a C{tuple} and a C{SO} or two C{tuple}s and calculates the energy transfer in units of I{THz}. The C{SOM} principle axis must be in units of I{meV}. The C{SO} and C{tuple}s are assumed to be in units of I{meV}. @param left: Object on the left side of the subtraction @type left: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param right: Object on the right side of the subtraction @type right: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword units: The expected units for this function. The default for this function is I{meV} @type units: C{string} @return: Object based on left - right in units of I{THz} @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise RuntimeError: The x-axis units are not I{meV} @raise TypeError: C{SOM}-C{SOM} operation not supported @raise TypeError: C{SOM}-C{SO} operation not supported @raise TypeError: C{SO}-C{SOM} operation not supported @raise TypeError: C{SO}-C{SO} operation not supported """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(left, right) (l_descr, r_descr) = hlr_utils.get_descr(left, right) # error checking for types if l_descr == "SOM" and r_descr == "SOM": raise TypeError("SOM-SOM operation not supported") elif l_descr == "SOM" and r_descr == "SO": raise TypeError("SOM-SO operation not supported") elif l_descr == "SO" and r_descr == "SOM": raise TypeError("SO-SOM operation not supported") elif l_descr == "SO" and r_descr == "SO": raise TypeError("SO-SO operation not supported") else: pass # Setup keyword arguments try: units = kwargs["units"] except KeyError: units = "meV" result = hlr_utils.copy_som_attr(result, res_descr, left, l_descr, right, r_descr) if res_descr == "SOM": index = hlr_utils.one_d_units(result, units) result = hlr_utils.force_units(result, "THz", index) result.setAxisLabel(index, "energy transfer") result.setYUnits("Counts/THz") result.setYLabel("Intensity") else: pass # iterate through the values import axis_manip for i in xrange(hlr_utils.get_length(left, right)): val1 = hlr_utils.get_value(left, i, l_descr, "x") err2_1 = hlr_utils.get_err2(left, i, l_descr, "x") val2 = hlr_utils.get_value(right, i, r_descr, "x") err2_2 = hlr_utils.get_err2(right, i, r_descr, "x") value = axis_manip.energy_transfer(val1, err2_1, val2, err2_2) map_so = hlr_utils.get_map_so(left, right, i) hlr_utils.result_insert(result, res_descr, value, map_so, "x") return result
def wavelength_to_scalar_k(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from wavelength to scalar k. The wavelength axis for a C{SOM} must be in units of I{Angstroms}. The primary axis of a C{SO} is assumed to be in units of I{Angstroms}. A C{tuple} of C{(wavelength, wavelength_err2)} (assumed to be in units of I{Angstroms}) can be converted to C{(scalar_k, scalar_k_err2)}. @param obj: Object to be converted @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword units: The expected units for this function. The default for this function is I{Angstroms}. @type units: C{string} @return: Object with a primary axis in wavelength converted to scalar k @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise TypeError: The incoming object is not a type the function recognizes @raise RuntimeError: The C{SOM} x-axis units are not I{Angstroms} """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) if o_descr == "list": raise TypeError("Do not know how to handle given type: %s" % \ o_descr) else: pass # Setup keyword arguments try: units = kwargs["units"] except KeyError: units = "Angstroms" # Primary axis for transformation. If a SO is passed, the function, will # assume the axis for transformation is at the 0 position if o_descr == "SOM": axis = hlr_utils.one_d_units(obj, units) else: axis = 0 result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, "1/Angstroms", axis) result.setAxisLabel(axis, "scalar wavevector") result.setYUnits("Counts/A-1") result.setYLabel("Intensity") else: pass # iterate through the values import axis_manip for i in xrange(hlr_utils.get_length(obj)): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) value = axis_manip.wavelength_to_scalar_k(val, err2) if o_descr != "number": value1 = axis_manip.reverse_array_cp(value[0]) value2 = axis_manip.reverse_array_cp(value[1]) rev_value = (value1, value2) else: rev_value = value map_so = hlr_utils.get_map_so(obj, None, i) if map_so is not None: map_so.y = axis_manip.reverse_array_cp(map_so.y) map_so.var_y = axis_manip.reverse_array_cp(map_so.var_y) else: pass hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x", axis) return result
def create_Qvec_vs_E_dgs(som, E_i, conf, **kwargs): """ This function starts with the energy transfer axis from DGS reduction and turns this into a 4D spectra with Qx, Qy, Qz and Et axes. @param som: The input object with initial IGS wavelength axis @type som: C{SOM.SOM} @param E_i: The initial energy for the given data. @type E_i: C{tuple} @param conf: Object that contains the current setup of the driver. @type conf: L{hlr_utils.Configure} @param kwargs: A list of keyword arguments that the function accepts: @keyword timer: Timing object so the function can perform timing estimates. @type timer: C{sns_timer.DiffTime} @keyword corner_angles: The object that contains the corner geometry information. @type corner_angles: C{dict} @keyword make_fixed: A flag that turns on writing the fixed grid mesh information to a file. @type make_fixed: C{boolean} @keyword output: The output filename and or directory. @type output: C{string} """ import array_manip import axis_manip import common_lib import hlr_utils import os # Check keywords try: t = kwargs["timer"] except KeyError: t = None corner_angles = kwargs["corner_angles"] try: make_fixed = kwargs["make_fixed"] except KeyError: make_fixed = False try: output = kwargs["output"] except KeyError: output = None # Convert initial energy to initial wavevector l_i = common_lib.energy_to_wavelength(E_i) k_i = common_lib.wavelength_to_scalar_k(l_i) # Since all the data is rebinned to the same energy transfer axis, we can # calculate the final energy axis once E_t = som[0].axis[0].val if som[0].axis[0].var is not None: E_t_err2 = som[0].axis[0].var else: import nessi_list E_t_err2 = nessi_list.NessiList(len(E_t)) E_f = array_manip.sub_ncerr(E_i[0], E_i[1], E_t, E_t_err2) # Check for negative final energies which will cause problems with # wavelength conversion due to square root if E_f[0][-1] < 0: E_f[0].reverse() E_f[1].reverse() index = 0 for E in E_f[0]: if E >= 0: break index += 1 E_f[0].__delslice__(0, index) E_f[1].__delslice__(0, index) E_f[0].reverse() E_f[1].reverse() len_E = len(E_f[0]) - 1 # Now we can get the final wavevector l_f = axis_manip.energy_to_wavelength(E_f[0], E_f[1]) k_f = axis_manip.wavelength_to_scalar_k(l_f[0], l_f[1]) # Grab the instrument from the som inst = som.attr_list.instrument if make_fixed: import SOM fixed_grid = {} for key in corner_angles: so_id = SOM.NeXusId.fromString(key).toTuple() try: pathlength = inst.get_secondary(so_id)[0] points = [] for j in range(4): points.extend( __calc_xyz(pathlength, corner_angles[key].getPolar(j), corner_angles[key].getAzimuthal(j))) fixed_grid[key] = points except KeyError: # Pixel ID is not in instrument geometry pass CNT = {} ERR2 = {} V1 = {} V2 = {} V3 = {} V4 = {} # Output positions for Qx, Qy, Qz coordinates X = 0 Y = 2 Z = 4 if t is not None: t.getTime(False) # Iterate though the data len_som = hlr_utils.get_length(som) for i in xrange(len_som): map_so = hlr_utils.get_map_so(som, None, i) yval = hlr_utils.get_value(som, i, "SOM", "y") yerr2 = hlr_utils.get_err2(som, i, "SOM", "y") CNT[str(map_so.id)] = yval ERR2[str(map_so.id)] = yerr2 cangles = corner_angles[str(map_so.id)] Q1 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1], k_f[0], k_f[1], cangles.getAzimuthal(0), 0.0, cangles.getPolar(0), 0.0) V1[str(map_so.id)] = {} V1[str(map_so.id)]["x"] = Q1[X] V1[str(map_so.id)]["y"] = Q1[Y] V1[str(map_so.id)]["z"] = Q1[Z] Q2 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1], k_f[0], k_f[1], cangles.getAzimuthal(1), 0.0, cangles.getPolar(1), 0.0) V2[str(map_so.id)] = {} V2[str(map_so.id)]["x"] = Q2[X] V2[str(map_so.id)]["y"] = Q2[Y] V2[str(map_so.id)]["z"] = Q2[Z] Q3 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1], k_f[0], k_f[1], cangles.getAzimuthal(2), 0.0, cangles.getPolar(2), 0.0) V3[str(map_so.id)] = {} V3[str(map_so.id)]["x"] = Q3[X] V3[str(map_so.id)]["y"] = Q3[Y] V3[str(map_so.id)]["z"] = Q3[Z] Q4 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1], k_f[0], k_f[1], cangles.getAzimuthal(3), 0.0, cangles.getPolar(3), 0.0) V4[str(map_so.id)] = {} V4[str(map_so.id)]["x"] = Q4[X] V4[str(map_so.id)]["y"] = Q4[Y] V4[str(map_so.id)]["z"] = Q4[Z] if t is not None: t.getTime(msg="After calculating verticies ") # Form the messages if t is not None: t.getTime(False) jobstr = 'MR' + hlr_utils.create_binner_string(conf) + 'JH' num_lines = len(CNT) * len_E linestr = str(num_lines) if output is not None: outdir = os.path.dirname(output) if outdir != '': if outdir.rfind('.') != -1: outdir = "" else: outdir = "" value = str(som.attr_list["data-run_number"].getValue()).split('/') topdir = os.path.join(outdir, value[0].strip() + "-mesh") try: os.mkdir(topdir) except OSError: pass outtag = os.path.basename(output) if outtag.rfind('.') == -1: outtag = "" else: outtag = outtag.split('.')[0] if outtag != "": filehead = outtag + "_bmesh" if make_fixed: filehead1 = outtag + "_fgrid" filehead2 = outtag + "_conf" else: filehead = "bmesh" if make_fixed: filehead1 = "fgrid" filehead2 = "conf" hfile = open(os.path.join(topdir, "%s.in" % filehead2), "w") print >> hfile, jobstr print >> hfile, linestr hfile.close() import utils use_zero_supp = not conf.no_zero_supp for k in xrange(len_E): ofile = open(os.path.join(topdir, "%s%04d.in" % (filehead, k)), "w") if make_fixed: ofile1 = open(os.path.join(topdir, "%s%04d.in" % (filehead1, k)), "w") for pid in CNT: if use_zero_supp: write_value = not utils.compare(CNT[pid][k], 0.0) == 0 else: write_value = True if write_value: result = [] result.append(str(k)) result.append(str(E_t[k])) result.append(str(E_t[k + 1])) result.append(str(CNT[pid][k])) result.append(str(ERR2[pid][k])) __get_coords(V1, pid, k, result) __get_coords(V2, pid, k, result) __get_coords(V3, pid, k, result) __get_coords(V4, pid, k, result) __get_coords(V1, pid, k + 1, result) __get_coords(V2, pid, k + 1, result) __get_coords(V3, pid, k + 1, result) __get_coords(V4, pid, k + 1, result) print >> ofile, " ".join(result) if make_fixed: result1 = [] result1.append(str(k)) result1.append(str(E_t[k])) result1.append(str(E_t[k + 1])) result1.append(str(CNT[pid][k])) result1.append(str(ERR2[pid][k])) result1.extend([str(x) for x in fixed_grid[pid]]) print >> ofile1, " ".join(result1) ofile.close() if make_fixed: ofile1.close() if t is not None: t.getTime(msg="After creating messages ")
def rebin_efficiency(obj1, obj2, **kwargs): """ This function takes two objects and rebins the data for obj1 onto the axis provided by obj2. The units on the x-axes needs to be I{Angstroms}, since this is what the efficiencies will be present as. @param obj1: Object that will be rebinned @type obj1: C{SOM.SOM} or C{SOM.SO} @param obj2: Object that will provide the axis for rebinning @type obj2: C{SOM.SOM} or C{SOM.SO} @param kwargs: A list of keyword arguments that the function accepts: @keyword units: The expected units for this function. The default for this function is I{Angstroms}. @type units: C{string} @return: Object that has been rebinned @rtype: C{SOM.SOM} or C{SOM.SO} @raise TypeError: The C{SOM}-C{SO} operation is attempted @raise TypeError: The C{SO}-C{SOM} operation is attempted @raise TypeError: obj1 not a C{SOM} or C{SO} @raise TypeError: obj2 not a C{SOM} or C{SO} @raise IndexError: The C{SOM}s do not have the same number of C{SO}s @raise RuntimeError: The C{SOM} x-axis units are not I{Angstroms} @raise RuntimeError: The x-axis units of the C{SOM}s do not match """ # import the helper functions import hlr_utils # Kickout if monitor object is None if obj1 is None: return obj1 # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj1, obj2) (o1_descr, o2_descr) = hlr_utils.get_descr(obj1, obj2) # error checking for types if o1_descr == "SOM" and o2_descr == "SO": raise TypeError, "SOM-SO operation not supported" elif o1_descr == "SO" and o2_descr == "SOM": raise TypeError("SO-SOM operation not supported") # Have the right object combination, go on else: pass # Setup keyword arguments try: units = kwargs["units"] except KeyError: units = "Angstroms" if o1_descr == "SOM" and o2_descr == "SOM": hlr_utils.math_compatible(obj1, o1_descr, obj2, o2_descr) # If both objects are not SOMs, do nothing else: pass result = hlr_utils.copy_som_attr( result, res_descr, obj2, o2_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, units) # Can't force units on anything other than a SOM else: pass # iterate through the values import common_lib for i in xrange(hlr_utils.get_length(obj1, obj2)): val1 = hlr_utils.get_value(obj1, i, o1_descr, "all") val2 = hlr_utils.get_value(obj2, i, o2_descr, "x") value = common_lib.rebin_axis_1D(val1, val2) hlr_utils.result_insert(result, res_descr, value, None, "all") return result
def sumw_ncerr(obj1, obj2, **kwargs): """ This function sums by weighting errors of two objects (C{SOM} or C{SO}) and returns the result of that action in an C{SOM}. The function does not handle the cases of C{SOM}+C{tuple}, C{SO}+C{tuple} or C{tuple}+C{tuple}. @param obj1: First object in the weighted sum @type obj1: C{SOM.SOM} or C{SOM.SO} or C{tuple} @param obj2: Second object in the the weighted sum @type obj2: C{SOM.SOM} or C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword axis: This is the axis one wishes to manipulate. If no argument is given the default value is y @type axis: C{string}=<y or x> @keyword axis_pos: This is position of the axis in the axis array. If no argument is given, the default value is 0 @type axis_pos: C{int} @keyword length_one_som: This is a flag that lets the function know it is dealing with a length 1 C{SOM} so that attributes may be passed along. The length 1 C{SOM} will be turned into a C{SO}. The default value is False. @type length_one_som: C{boolean} @keyword length_one_som_pos: This is the argument position of the length 1 C{SOM} since the check is done before the arguments are swapped. The default value is 2. @type length_one_som_pos: C{int}=<1 or 2> @return: Object containing the results of the addition @rtype: C{SOM.SOM} or C{SOM.SO} @raise TypeError: The C{SOM}+C{tuple}, C{SO}+C{tuple} or C{tuple}+C{tuple} cases are presented to the function @raise IndexError: The two C{SOM}s do not contain the same number of spectra @raise RunTimeError: The x-axis units of the C{SOM}s do not match @raise RunTimeError: The y-axis units of the C{SOM}s do not match @raise RunTimeError: The x-axes of the two C{SO}s are not equal """ # import the helper functions import hlr_utils # Check to see if we are working with a length 1 SOM try: length_one_som = kwargs["length_one_som"] except KeyError: length_one_som = False try: length_one_som_pos = kwargs["length_one_som_pos"] if length_one_som_pos != 1 or length_one_som_pos != 2: raise RuntimeError("length_one_som_pos must be either 1 or 2 and "\ +"%d" % length_one_som_pos) except KeyError: length_one_som_pos = 2 if length_one_som: if length_one_som_pos == 1: som_copy = obj1 obj1 = obj1[0] else: som_copy = obj2 obj2 = obj2[0] else: # Not working with a length 1 SOM, do nothing pass # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj1, obj2) (o1_descr, o2_descr) = hlr_utils.get_descr(obj1, obj2) # error check information if o1_descr == "number" or o2_descr == "number": raise RuntimeError("Operations with tuples are not supported!") elif o2_descr == "SOM" and o1_descr == "SO": (obj1, obj2) = hlr_utils.swap_args(obj1, obj2) (o1_descr, o2_descr) = hlr_utils.swap_args(o1_descr, o2_descr) elif o2_descr == "SOM" and o1_descr == "SOM": hlr_utils.math_compatible(obj1, o1_descr, obj2, o2_descr) else: pass # Check for axis keyword argument try: axis = kwargs["axis"] except KeyError: axis = "y" # Check for axis_pos keyword argument try: axis_pos = kwargs["axis_pos"] except KeyError: axis_pos = 0 if length_one_som: if length_one_som_pos == 1: result = hlr_utils.copy_som_attr(result, res_descr, som_copy, "SOM", obj2, o2_descr) else: result = hlr_utils.copy_som_attr(result, res_descr, obj1, o1_descr, som_copy, "SOM") else: result = hlr_utils.copy_som_attr(result, res_descr, obj1, o1_descr, obj2, o2_descr) # iterate through the values import array_manip for i in xrange(hlr_utils.get_length(obj1, obj2)): val1 = hlr_utils.get_value(obj1, i, o1_descr, axis, axis_pos) err2_1 = hlr_utils.get_err2(obj1, i, o1_descr, axis, axis_pos) val2 = hlr_utils.get_value(obj2, i, o2_descr, axis, axis_pos) err2_2 = hlr_utils.get_err2(obj2, i, o2_descr, axis, axis_pos) (descr_1, descr_2) = hlr_utils.get_descr(val1, val2) hlr_utils.math_compatible(val1, descr_1, val2, descr_2) value = array_manip.sumw_ncerr(val1, err2_1, val2, err2_2) map_so = hlr_utils.get_map_so(obj1, None, i) hlr_utils.result_insert(result, res_descr, value, map_so, axis, axis_pos) return result
def sum_by_rebin_frac(obj, axis_out, **kwargs): """ This function uses the C{axis_manip.rebin_axis_1D_frac} function from the SCL to perform the rebinning. The function tracks the counts and fractional area from all spectra separately. The counts and fractional area are divided after all spectra have been parsed. @param obj: Object to be rebinned and summed @type obj: C{SOM.SOM} or C{SOM.SO} @param axis_out: The axis to rebin the C{SOM} or C{SO} to @type axis_out: C{NessiList} @param kwargs: A list of keyword arguments that the function accepts: @keyword configure: This is the object containing the driver configuration. This will signal the function to write out the counts and fractional area to files. @type configure: C{Configure} @return: Object that has been rebinned and summed according to the provided axis @rtype: C{SOM.SOM} or C{SOM.SO} @raise TypeError: The rebinning axis given is not a C{NessiList} @raise TypeError: The object being rebinned is not a C{SOM} or a C{SO} @raise TypeError: The dimension of the input object is not 1D """ # import the helper functions import hlr_utils # set up for working through data try: axis_out.__type__ except AttributeError: raise TypeError("Rebinning axis must be a NessiList!") o_descr = hlr_utils.get_descr(obj) if o_descr == "number" or o_descr == "list": raise TypeError("Do not know how to handle given type: %s" % \ o_descr) else: pass try: if obj.getDimension() != 1: raise TypeError("The input object must be 1D!. This one is "\ +"%dD." % obj.getDimension()) except AttributeError: # obj is a SO if obj.dim() != 1: raise TypeError("The input object must be 1D!. This one is "\ +"%dD." % obj.dim()) # Check for keywords try: config = kwargs["configure"] except KeyError: config = None (result, res_descr) = hlr_utils.empty_result(obj) result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) import array_manip import axis_manip len_data = len(axis_out) - 1 counts = nessi_list.NessiList(len_data) counts_err2 = nessi_list.NessiList(len_data) frac_area = nessi_list.NessiList(len_data) frac_area_err2 = nessi_list.NessiList(len_data) for i in xrange(hlr_utils.get_length(obj)): axis_in = hlr_utils.get_value(obj, i, o_descr, "x", 0) val = hlr_utils.get_value(obj, i, o_descr) err2 = hlr_utils.get_err2(obj, i, o_descr) value = axis_manip.rebin_axis_1D_frac(axis_in, val, err2, axis_out) (counts, counts_err2) = array_manip.add_ncerr(counts, counts_err2, value[0], value[1]) (frac_area, frac_area_err2) = array_manip.add_ncerr(frac_area, frac_area_err2, value[2], frac_area_err2) # Divide the total counts by the total fractional area value1 = array_manip.div_ncerr(counts, counts_err2, frac_area, frac_area_err2) xvals = [] xvals.append(axis_out) map_so = hlr_utils.get_map_so(obj, None, 0) hlr_utils.result_insert(result, res_descr, value1, map_so, "all", 0, xvals) if config is not None: if o_descr == "SOM": import SOM o_som = SOM.SOM() o_som.copyAttributes(obj) so = hlr_utils.get_map_so(obj, None, 0) so.axis[0].val = axis_out so.y = counts so.var_y = counts_err2 o_som.append(so) # Write out summed counts into file hlr_utils.write_file(config.output, "text/Spec", o_som, output_ext="cnt", verbose=config.verbose, data_ext=config.ext_replacement, path_replacement=config.path_replacement, message="summed counts") # Replace counts data with fractional area. The axes remain the # same o_som[0].y = frac_area o_som[0].var_y = frac_area_err2 # Write out summed fractional area into file hlr_utils.write_file(config.output, "text/Spec", o_som, output_ext="fra", verbose=config.verbose, data_ext=config.ext_replacement, path_replacement=config.path_replacement, message="fractional area") return result
def create_E_vs_Q_dgs(som, E_i, Q_final, **kwargs): """ This function starts with the rebinned energy transfer and turns this into a 2D spectra with E and Q axes for DGS instruments. @param som: The input object with initial IGS wavelength axis @type som: C{SOM.SOM} @param E_i: The initial energy for the given data. @type E_i: C{tuple} @param Q_final: The momentum transfer axis to rebin the data to @type Q_final: C{nessi_list.NessiList} @param kwargs: A list of keyword arguments that the function accepts: @keyword corner_angles: The object that contains the corner geometry information. @type corner_angles: C{dict} @keyword so_id: The identifier represents a number, string, tuple or other object that describes the resulting C{SO} @type so_id: C{int}, C{string}, C{tuple}, C{pixel ID} @keyword y_label: The y axis label @type y_label: C{string} @keyword y_units: The y axis units @type y_units: C{string} @keyword x_labels: This is a list of names that sets the individual x axis labels @type x_labels: C{list} of C{string}s @keyword x_units: This is a list of names that sets the individual x axis units @type x_units: C{list} of C{string}s @keyword split: This flag causes the counts and the fractional area to be written out into separate files. @type split: C{boolean} @keyword configure: This is the object containing the driver configuration. @type configure: C{Configure} @return: Object containing a 2D C{SO} with E and Q axes @rtype: C{SOM.SOM} """ import array_manip import axis_manip import common_lib import hlr_utils import nessi_list import SOM import utils # Check for keywords corner_angles = kwargs["corner_angles"] configure = kwargs.get("configure") split = kwargs.get("split", False) # Setup output object so_dim = SOM.SO(2) so_dim.axis[0].val = Q_final so_dim.axis[1].val = som[0].axis[0].val # E_t # Calculate total 2D array size N_tot = (len(so_dim.axis[0].val) - 1) * (len(so_dim.axis[1].val) - 1) # Create y and var_y lists from total 2D size so_dim.y = nessi_list.NessiList(N_tot) so_dim.var_y = nessi_list.NessiList(N_tot) # Create area sum and errors for the area sum lists from total 2D size area_sum = nessi_list.NessiList(N_tot) area_sum_err2 = nessi_list.NessiList(N_tot) # Convert initial energy to initial wavevector l_i = common_lib.energy_to_wavelength(E_i) k_i = common_lib.wavelength_to_scalar_k(l_i) # Since all the data is rebinned to the same energy transfer axis, we can # calculate the final energy axis once E_t = som[0].axis[0].val if som[0].axis[0].var is not None: E_t_err2 = som[0].axis[0].var else: E_t_err2 = nessi_list.NessiList(len(E_t)) # Get the bin width arrays from E_t (E_t_bw, E_t_bw_err2) = utils.calc_bin_widths(E_t) E_f = array_manip.sub_ncerr(E_i[0], E_i[1], E_t, E_t_err2) # Now we can get the final wavevector l_f = axis_manip.energy_to_wavelength(E_f[0], E_f[1]) k_f = axis_manip.wavelength_to_scalar_k(l_f[0], l_f[1]) # Output position for Q X = 0 # Iterate though the data len_som = hlr_utils.get_length(som) for i in xrange(len_som): map_so = hlr_utils.get_map_so(som, None, i) yval = hlr_utils.get_value(som, i, "SOM", "y") yerr2 = hlr_utils.get_err2(som, i, "SOM", "y") cangles = corner_angles[str(map_so.id)] avg_theta1 = (cangles.getPolar(0) + cangles.getPolar(1)) / 2.0 avg_theta2 = (cangles.getPolar(2) + cangles.getPolar(3)) / 2.0 Q1 = axis_manip.init_scatt_wavevector_to_scalar_Q(k_i[0], k_i[1], k_f[0][:-1], k_f[1][:-1], avg_theta2, 0.0) Q2 = axis_manip.init_scatt_wavevector_to_scalar_Q(k_i[0], k_i[1], k_f[0][:-1], k_f[1][:-1], avg_theta1, 0.0) Q3 = axis_manip.init_scatt_wavevector_to_scalar_Q(k_i[0], k_i[1], k_f[0][1:], k_f[1][1:], avg_theta1, 0.0) Q4 = axis_manip.init_scatt_wavevector_to_scalar_Q(k_i[0], k_i[1], k_f[0][1:], k_f[1][1:], avg_theta2, 0.0) # Calculate the area of the E,Q polygons (A, A_err2) = utils.calc_eq_jacobian_dgs(E_t[:-1], E_t[:-1], E_t[1:], E_t[1:], Q1[X], Q2[X], Q3[X], Q4[X]) # Apply the Jacobian: C/dE_t * dE_t / A(EQ) = C/A(EQ) (jac_ratio, jac_ratio_err2) = array_manip.div_ncerr(E_t_bw, E_t_bw_err2, A, A_err2) (counts, counts_err2) = array_manip.mult_ncerr(yval, yerr2, jac_ratio, jac_ratio_err2) try: (y_2d, y_2d_err2, area_new, bin_count) = axis_manip.rebin_2D_quad_to_rectlin(Q1[X], E_t[:-1], Q2[X], E_t[:-1], Q3[X], E_t[1:], Q4[X], E_t[1:], counts, counts_err2, so_dim.axis[0].val, so_dim.axis[1].val) del bin_count except IndexError, e: # Get the offending index from the error message index = int(str(e).split()[1].split('index')[-1].strip('[]')) print "Id:", map_so.id print "Index:", index print "Verticies: %f, %f, %f, %f, %f, %f, %f, %f" % (Q1[X][index], E_t[:-1][index], Q2[X][index], E_t[:-1][index], Q3[X][index], E_t[1:][index], Q4[X][index], E_t[1:][index]) raise IndexError(str(e)) # Add in together with previous results (so_dim.y, so_dim.var_y) = array_manip.add_ncerr(so_dim.y, so_dim.var_y, y_2d, y_2d_err2) (area_sum, area_sum_err2) = array_manip.add_ncerr(area_sum, area_sum_err2, area_new, area_sum_err2)
def tof_to_scalar_Q(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from time-of-flight to scalarQ. The time-of-flight axis for a C{SOM} must be in units of I{microseconds}. The primary axis of a C{SO} is assumed to be in units of I{microseconds}. A C{tuple} of C{(time-of-flight, time-of-flight_err2)} (assumed to be in units of I{microseconds}) can be converted to C{(scalar_Q, scalar_Q_err2)}. @param obj: Object to be converted @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword polar: The polar angle and its associated error^2 @type polar: C{tuple} or C{list} of C{tuple}s @keyword pathlength: The pathlength and its associated error^2 @type pathlength: C{tuple} or C{list} of C{tuple}s @keyword angle_offset: A constant offset for the polar angle and its associated error^2. The units of the offset should be in radians. @type angle_offset: C{tuple} @keyword lojac: A flag that allows one to turn off the calculation of the linear-order Jacobian. The default action is True for histogram data. @type lojac: C{boolean} @keyword units: The expected units for this function. The default for this function is I{microseconds}. @type units: C{string} @return: Object with a primary axis in time-of-flight converted to scalar Q @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise TypeError: The incoming object is not a type the function recognizes @raise RuntimeError: A C{SOM} is not passed and no polar angle is provided @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds} """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) if o_descr == "list": raise TypeError("Do not know how to handle given type: %s" % \ o_descr) else: pass # Setup keyword arguments try: polar = kwargs["polar"] except KeyError: polar = None try: pathlength = kwargs["pathlength"] except KeyError: pathlength = None try: units = kwargs["units"] except KeyError: units = "microseconds" try: lojac = kwargs["lojac"] except KeyError: lojac = hlr_utils.check_lojac(obj) try: angle_offset = kwargs["angle_offset"] except KeyError: angle_offset = None # Primary axis for transformation. If a SO is passed, the function, will # assume the axis for transformation is at the 0 position if o_descr == "SOM": axis = hlr_utils.one_d_units(obj, units) else: axis = 0 result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, "1/Angstroms", axis) result.setAxisLabel(axis, "scalar wavevector transfer") result.setYUnits("Counts/A-1") result.setYLabel("Intensity") else: pass if pathlength is None or polar is None: if o_descr == "SOM": try: obj.attr_list.instrument.get_primary() inst = obj.attr_list.instrument except RuntimeError: raise RuntimeError("A detector was not provided") else: if pathlength is None and polar is None: raise RuntimeError("If no SOM is provided, then pathlength "\ +"and polar angle information must be "\ +"provided") elif pathlength is None: raise RuntimeError("If no SOM is provided, then pathlength "\ +"information must be provided") elif polar is None: raise RuntimeError("If no SOM is provided, then polar angle "\ +"information must be provided") else: raise RuntimeError("If you get here, see Steve Miller for "\ +"your mug.") else: pass if pathlength is not None: p_descr = hlr_utils.get_descr(pathlength) else: pass if polar is not None: a_descr = hlr_utils.get_descr(polar) else: pass # iterate through the values import axis_manip if lojac: import utils for i in xrange(hlr_utils.get_length(obj)): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) if pathlength is None: (pl, pl_err2) = hlr_utils.get_parameter("total", map_so, inst) else: pl = hlr_utils.get_value(pathlength, i, p_descr) pl_err2 = hlr_utils.get_err2(pathlength, i, p_descr) if polar is None: (angle, angle_err2) = hlr_utils.get_parameter("polar", map_so, inst) else: angle = hlr_utils.get_value(polar, i, a_descr) angle_err2 = hlr_utils.get_err2(polar, i, a_descr) if angle_offset is not None: angle += angle_offset[0] angle_err2 += angle_offset[1] value = axis_manip.tof_to_scalar_Q(val, err2, pl, pl_err2, angle, angle_err2) if lojac: y_val = hlr_utils.get_value(obj, i, o_descr, "y") y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y") counts = utils.linear_order_jacobian(val, value[0], y_val, y_err2) else: pass if o_descr != "number": value1 = axis_manip.reverse_array_cp(value[0]) value2 = axis_manip.reverse_array_cp(value[1]) rev_value = (value1, value2) else: rev_value = value if map_so is not None: if not lojac: map_so.y = axis_manip.reverse_array_cp(map_so.y) map_so.var_y = axis_manip.reverse_array_cp(map_so.var_y) else: map_so.y = axis_manip.reverse_array_cp(counts[0]) map_so.var_y = axis_manip.reverse_array_cp(counts[1]) else: pass hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x", axis) return result
def sum_all_spectra(obj, **kwargs): """ This function takes all the spectra in the given object and sums them together. All of the sprectra are assumed to have the same axis scale. @param obj: Object in which all of the spectra are to be summed together @type obj: C{SOM.SOM} @param kwargs: A list of keyword arguments that the function accepts: @keyword rebin_axis: The axis(es) to rebin the spectra onto. @type rebin_axis: C{nessi_list.NessiList} or C{list} of C{nessi_list.NessiList}s @keyword rebin_axis_dim: Tthe dimension on the spectra being rebinned. The default value is I{1}. @type rebin_axis_dim: C{int} @keyword y_sort: A flag that will sort the spectrum IDs by y. The default behavior is I{False} and this maintains the original x ordering. @type y_sort: C{boolean} @keyword stripe: A flag that will combine spectra in either the x or y direction at a given y or x. The integration direction is based on the setting of y_sort. The default behavior is I{False} and corresponds to summing all spectra into one. @type stripe: C{boolean} @keyword pix_fix: A single or list of pixel IDs with which to override the summed spectrum pixel ID. The setting of y_sort determines is the x component (y_sort=False) or the y component (y_sort=True) of the pixel ID is overridden. @type pix_fix: C{int} or C{list} of C{int}s @return: Object containing a single spectrum @rtype: C{SOM.SOM} @raise TypeError: Anything other than a C{SOM} is given @raise RuntimeError: An unknown rebinning dimension is given """ o_descr = hlr_utils.get_descr(obj) if o_descr != "SOM": raise TypeError("Function argument must be a SOM") # Have a SOM, go on else: pass # If there is only one SO, why run if len(obj) == 1: return obj # OK, we need to sum else: pass try: rebin_axis = kwargs["rebin_axis"] except KeyError: rebin_axis = None try: rebin_axis_dim = kwargs["rebin_axis_dim"] except KeyError: rebin_axis_dim = 1 try: y_sort = kwargs["y_sort"] except KeyError: y_sort = False try: stripe = kwargs["stripe"] except KeyError: stripe = False try: pix_fix = kwargs["pixel_fix"] except KeyError: pix_fix = None import common_lib if rebin_axis is not None: if rebin_axis_dim == 1: obj1 = common_lib.rebin_axis_1D(obj, rebin_axis) elif rebin_axis_dim == 2: obj1 = common_lib.rebin_axis_2D(obj, rebin_axis[0], rebin_axis[1]) else: raise RuntimeError("Do not have rebinning method for %dD." % \ rebin_axis_dim) else: obj1 = obj del obj # Sort SO IDs by y value if y_sort: obj1.sort(lambda x, y: cmp(x.id[1][1], y.id[1][1])) # SO IDs are already sorted by x value else: pass (result, res_descr) = hlr_utils.empty_result(obj1) result = hlr_utils.copy_som_attr(result, res_descr, obj1, o_descr) if not stripe: # iterate through the values so_id_list = [] val1 = hlr_utils.get_value(obj1, 0, o_descr, "all") val2 = hlr_utils.get_value(obj1, 1, o_descr, "all") value = common_lib.add_ncerr(val1, val2) so_id_list.append(val1.id) so_id_list.append(val2.id) for i in xrange(2, hlr_utils.get_length(obj1)): val = hlr_utils.get_value(obj1, i, o_descr, "all") value = common_lib.add_ncerr(val, value) so_id_list.append(val.id) hlr_utils.result_insert(result, res_descr, value, None, "all") result.attr_list["Summed IDs"] = so_id_list if pix_fix is not None: if y_sort: fixed_pixel = (so_id_list[0][0], (pix_fix, so_id_list[0][1][1])) else: fixed_pixel = (so_id_list[0][0], (so_id_list[0][1][0], pix_fix)) else: fixed_pixel = so_id_list[0] result[0].id = fixed_pixel else: # iterate through the values so_id_list = [] i_start = 0 stripe_count = 0 total_size = hlr_utils.get_length(obj1) while i_start < total_size: stripe_list = [] counted = 2 val1 = hlr_utils.get_value(obj1, i_start, o_descr, "all") val2 = hlr_utils.get_value(obj1, i_start+1, o_descr, "all") value = common_lib.add_ncerr(val1, val2) stripe_list.append(val1.id) stripe_list.append(val2.id) if y_sort: comp_id = val2.id[1][1] else: comp_id = val2.id[1][0] for i in xrange(i_start+2, total_size): val = hlr_utils.get_value(obj1, i, o_descr, "all") if y_sort: new_id = val.id[1][1] else: new_id = val.id[1][0] if new_id > comp_id: break value = common_lib.add_ncerr(val, value) stripe_list.append(val.id) counted += 1 i_start += counted so_id_list.append(stripe_list) hlr_utils.result_insert(result, res_descr, value, None, "all") if pix_fix is not None: try: if y_sort: fixed_pixel = (stripe_list[0][0], (pix_fix[stripe_count], stripe_list[0][1][1])) else: fixed_pixel = (stripe_list[0][0], (stripe_list[0][1][0], pix_fix[stripe_count])) except TypeError: if y_sort: fixed_pixel = (stripe_list[0][0], (pix_fix, stripe_list[0][1][1])) else: fixed_pixel = (stripe_list[0][0], (stripe_list[0][1][0], pix_fix)) else: fixed_pixel = stripe_list[0] result[stripe_count].id = fixed_pixel stripe_count += 1 result.attr_list["summed_ids"] = so_id_list return result
def sum_spectra_weighted_ave(obj, **kwargs): """ This function takes a set of data and sums the individual bins by weighted average. That information is then assembled back into a single spectrum. The individual spectra should already have been rebinned. @param obj: Object containing data spectra @type obj: C{SOM.SOM} or C{SOM.SO} @param kwargs: A list of keyword arguments that the function accepts: @return: The summed spectra (one) @rtype: C{SOM.SOM} """ if obj is None: return None # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) # Get the number of axis channels len_axis = len(obj[0]) import nessi_list import SOM import utils # Empty SO for final spctrum so = SOM.SO() len_som = hlr_utils.get_length(obj) # Slice data, calculate weighted average and repackage spectra for i in xrange(len_axis): sliced_data = nessi_list.NessiList() sliced_data_err2 = nessi_list.NessiList() for j in xrange(len_som): obj1 = hlr_utils.get_value(obj, j, o_descr, "all") if i == 0 and j == 0: map_so = hlr_utils.get_map_so(obj, None, j) hlr_utils.result_insert(so, "SO", map_so, None, "all") sliced_data.append(obj1.y[i]) sliced_data_err2.append(obj1.var_y[i]) len_fit = len(sliced_data) value = utils.weighted_average(sliced_data, sliced_data_err2, 0, len_fit-1) so.y[i] = value[0] so.var_y[i] = value[1] hlr_utils.result_insert(result, res_descr, so, None, "all") return result
def tof_to_wavelength_lin_time_zero(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from time-of-flight to wavelength incorporating a linear time zero which is a described as a linear function of the wavelength. The time-of-flight axis for a C{SOM} must be in units of I{microseconds}. The primary axis of a C{SO} is assumed to be in units of I{microseconds}. A C{tuple} of C{(tof, tof_err2)} (assumed to be in units of I{microseconds}) can be converted to C{(wavelength, wavelength_err2)}. @param obj: Object to be converted @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword pathlength: The pathlength and its associated error^2 @type pathlength: C{tuple} or C{list} of C{tuple}s @keyword time_zero_slope: The time zero slope and its associated error^2 @type time_zero_slope: C{tuple} @keyword time_zero_offset: The time zero offset and its associated error^2 @type time_zero_offset: C{tuple} @keyword inst_param: The type of parameter requested from an associated instrument. For this function the acceptable parameters are I{primary}, I{secondary} and I{total}. Default is I{primary}. @type inst_param: C{string} @keyword lojac: A flag that allows one to turn off the calculation of the linear-order Jacobian. The default action is I{True} for histogram data. @type lojac: C{boolean} @keyword units: The expected units for this function. The default for this function is I{microseconds}. @type units: C{string} @keyword cut_val: Specify a wavelength to cut the spectra at. @type cut_val: C{float} @keyword cut_less: A flag that specifies cutting the spectra less than C{cut_val}. The default is C{True}. @type cut_less: C{boolean} @return: Object with a primary axis in time-of-flight converted to wavelength @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise TypeError: The incoming object is not a type the function recognizes @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds} @raise RuntimeError: A C{SOM} does not contain an instrument and no pathlength was provided @raise RuntimeError: No C{SOM} is provided and no pathlength given """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) # Setup keyword arguments try: inst_param = kwargs["inst_param"] except KeyError: inst_param = "primary" try: pathlength = kwargs["pathlength"] except KeyError: pathlength = None try: time_zero_slope = kwargs["time_zero_slope"] except KeyError: time_zero_slope = None # Current constants for Time Zero Slope TIME_ZERO_SLOPE = (float(0.0), float(0.0)) try: time_zero_offset = kwargs["time_zero_offset"] except KeyError: time_zero_offset = None # Current constants for Time Zero Offset TIME_ZERO_OFFSET = (float(0.0), float(0.0)) try: lojac = kwargs["lojac"] except KeyError: lojac = hlr_utils.check_lojac(obj) try: units = kwargs["units"] except KeyError: units = "microseconds" try: cut_val = kwargs["cut_val"] except KeyError: cut_val = None try: cut_less = kwargs["cut_less"] except KeyError: cut_less = True # Primary axis for transformation. If a SO is passed, the function, will # assume the axis for transformation is at the 0 position if o_descr == "SOM": axis = hlr_utils.one_d_units(obj, units) else: axis = 0 result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, "Angstroms", axis) result.setAxisLabel(axis, "wavelength") result.setYUnits("Counts/A") result.setYLabel("Intensity") else: pass if pathlength is not None: p_descr = hlr_utils.get_descr(pathlength) else: if o_descr == "SOM": try: obj.attr_list.instrument.get_primary() inst = obj.attr_list.instrument except RuntimeError: raise RuntimeError("A detector was not provided") else: raise RuntimeError("If no SOM is provided, then pathlength "\ +"information must be provided") if time_zero_slope is not None: t_0_slope_descr = hlr_utils.get_descr(time_zero_slope) else: if o_descr == "SOM": try: t_0_slope = obj.attr_list["Time_zero_slope"][0] t_0_slope_err2 = obj.attr_list["Time_zero_slope"][1] except KeyError: t_0_slope = TIME_ZERO_SLOPE[0] t_0_slope_err2 = TIME_ZERO_SLOPE[1] else: t_0_slope = TIME_ZERO_SLOPE[0] t_0_slope_err2 = TIME_ZERO_SLOPE[1] if time_zero_offset is not None: t_0_offset_descr = hlr_utils.get_descr(time_zero_offset) else: if o_descr == "SOM": try: t_0_offset = obj.attr_list["Time_zero_offset"][0] t_0_offset_err2 = obj.attr_list["Time_zero_offset"][1] except KeyError: t_0_offset = TIME_ZERO_OFFSET[0] t_0_offset_err2 = TIME_ZERO_OFFSET[1] else: t_0_offset = TIME_ZERO_OFFSET[0] t_0_offset_err2 = TIME_ZERO_OFFSET[1] # iterate through the values import axis_manip if lojac or cut_val is not None: import utils for i in xrange(hlr_utils.get_length(obj)): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) if pathlength is None: (pl, pl_err2) = hlr_utils.get_parameter(inst_param, map_so, inst) else: pl = hlr_utils.get_value(pathlength, i, p_descr) pl_err2 = hlr_utils.get_err2(pathlength, i, p_descr) if time_zero_slope is not None: t_0_slope = hlr_utils.get_value(time_zero_slope, i, t_0_slope_descr) t_0_slope_err2 = hlr_utils.get_err2(time_zero_slope, i, t_0_slope_descr) else: pass if time_zero_offset is not None: t_0_offset = hlr_utils.get_value(time_zero_offset, i, t_0_offset_descr) t_0_offset_err2 = hlr_utils.get_err2(time_zero_offset, i, t_0_offset_descr) else: pass value = axis_manip.tof_to_wavelength_lin_time_zero(val, err2, pl, pl_err2, t_0_slope, t_0_slope_err2, t_0_offset, t_0_offset_err2) if cut_val is not None: index = utils.bisect_helper(value[0], cut_val) if cut_less: # Need to cut at this index, so increment by one index += 1 value[0].__delslice__(0, index) value[1].__delslice__(0, index) map_so.y.__delslice__(0, index) map_so.var_y.__delslice__(0, index) if lojac: val.__delslice__(0, index) err2.__delslice__(0, index) else: len_data = len(value[0]) # All axis arrays need starting index adjusted by one since # they always carry one more bin than the data value[0].__delslice__(index + 1, len_data) value[1].__delslice__(index + 1, len_data) map_so.y.__delslice__(index, len_data) map_so.var_y.__delslice__(index, len_data) if lojac: val.__delslice__(index + 1, len_data) err2.__delslice__(index + 1, len_data) if lojac: counts = utils.linear_order_jacobian(val, value[0], map_so.y, map_so.var_y) hlr_utils.result_insert(result, res_descr, counts, map_so, "all", axis, [value[0]]) else: hlr_utils.result_insert(result, res_descr, value, map_so, "x", axis) return result
def rebin_monitor(obj1, obj2, **kwargs): """ This function takes objects (1st is the monitor, 2nd is the detector data) and rebins the data for obj1 onto the axis provided by obj2. The pixel ID can be transferred as the pixel ID of the rebinned monitor histogram. A prefix is placed on the bank ID to dilineate that this is a rebinned monitor spectrum for that pixel. @param obj1: Monitor object that will be rebinned @type obj1: C{SOM.SOM} or C{SOM.SO} @param obj2: Detector data object that will provide the axis for rebinning @type obj2: C{SOM.SOM} or C{SOM.SO} @param kwargs: A list of keyword arguments that the function accepts @keyword use_pix_id: A flag that specifies if the pixel ID is to be used in the rebinned monitor spectrum. The default is I{False}. @type use_pix_id: C{boolean} @keyword prefix: Allows one to specify a prefix for the bank ID. The default is I{m}. @type prefix: C{string} @keyword rtype: A short string that defines the rebinning function to use. The default is I{None} which uses L{common_lib.rebin_axis_1D()}. The other possibilities are I{linint} which uses L{common_lib.rebin_axis_1D_linint()} and I{frac} which uses L{common_lib.rebin_axis_1D_frac()}. @type rtype: C{boolean} @return: Object that has been rebinned @rtype: C{SOM.SOM} or C{SOM.SO} @raise TypeError: The C{SOM}-C{SO} operation is attempted @raise TypeError: The C{SO}-C{SOM} operation is attempted @raise TypeError: obj1 not a C{SOM} or C{SO} @raise TypeError: obj2 not a C{SOM} or C{SO} """ # import the helper functions import hlr_utils # Kickout if monitor object is None if obj1 is None: return obj1 # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj1, obj2) (o1_descr, o2_descr) = hlr_utils.get_descr(obj1, obj2) # error checking for types if o1_descr == "SOM" and o2_descr == "SO": raise TypeError, "SOM-SO operation not supported" elif o1_descr == "SO" and o2_descr == "SOM": raise TypeError("SO-SOM operation not supported") # Have the right object combination, go on else: pass # Check for keywords try: prefix = kwargs["prefix"] except KeyError: prefix = "m" try: use_pix_id = kwargs["use_pix_id"] except KeyError: use_pix_id = False try: rtype = kwargs["rtype"] except KeyError: rtype = None # Set the name of the rebinning function rebin_function_name = "rebin_axis_1D" if rtype is not None: rebin_function_name += "_" + str(rtype) # Get function pointer import common_lib rebin_function = common_lib.__getattribute__(rebin_function_name) result = hlr_utils.copy_som_attr(result, res_descr, obj1, o1_descr) # iterate through the values val1 = hlr_utils.get_value(obj1, 0, o1_descr, "all") # Cache length len_obj2 = hlr_utils.get_length(obj2) for i in xrange(len_obj2): val2 = hlr_utils.get_value(obj2, i, o2_descr, "x") value = rebin_function(val1, val2) if use_pix_id: # Set the pixel ID to the spectrum with modified bank ID try: value.id = (prefix + obj2[i].id[0], (obj2[i].id[1][0], obj2[i].id[1][1])) except TypeError: value.id = prefix + str(obj2[i].id) hlr_utils.result_insert(result, res_descr, value, None, "all") return result
def subtract_axis_dep_bkg(obj, coeffs, **kwargs): """ This function takes spectrum object(s) and a set of coefficients and subtracts an axis dependent background based on a polynomial. The order of the polynomial is based on the number of coefficients provided. @param obj: Object from which to subtract the individual background numbers @type obj: C{SOM.SOM} or C{SOM.SO} @param coeffs: The set of coefficients for the polynomial representation of the background to be subtracted. @type coeffs: C{list} of C{floats} @param kwargs: A list of keyword arguments that the function accepts: @keyword old_scale: The scale factor used to obtain the coefficients used in this function. @type old_scale: C{float} @keyword new_scale: The scale factor for the current data set from which the axis dependent background will be subtracted from. @type new_scale: C{float} @return: Object with the axis dependent background subtracted @rtype: C{SOM.SOM} or C{SOM.SO} @raise TypeError: The first argument is not a C{SOM} or C{SO} """ # Kickout is coeffs is None, or length is zero if coeffs is None: return obj poly_len = len(coeffs) if poly_len == 0: return obj # Check for keywords old_scale = kwargs.get("old_scale", 1.0) new_scale = kwargs.get("new_scale", 1.0) # Reverse coefficients for __eval_poly function coeffs.reverse() # import the helper functions import hlr_utils o_descr = hlr_utils.get_descr(obj) if o_descr != "SOM" and o_descr != "SO": raise TypeError("Incoming object must be a SOM or a SO") # Have a SOM or SO else: pass (result, res_descr) = hlr_utils.empty_result(obj) result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) obj_len = hlr_utils.get_length(obj) import utils # iterate through the values for i in xrange(obj_len): axis = hlr_utils.get_value(obj, i, o_descr, "x", 0) val = hlr_utils.get_value(obj, i, o_descr, "y") err2 = hlr_utils.get_err2 (obj, i, o_descr, "y") map_so = hlr_utils.get_map_so(obj, None, i) len_val = len(val) new_scale_p = new_scale / len_val ratio = old_scale / new_scale_p axis_centers = utils.calc_bin_centers(axis) for j in xrange(len(val)): val[j] -= (ratio * __eval_poly(axis_centers[0][j], coeffs, poly_len)) value = (val, err2) hlr_utils.result_insert(result, res_descr, value, map_so, "y") return result
def initial_wavelength_igs_lin_time_zero_to_tof(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from initial_wavelength_igs_lin_time_zero to time-of-flight. The initial_wavelength_igs_lin_time_zero axis for a C{SOM} must be in units of I{Angstroms}. The primary axis of a C{SO} is assumed to be in units of I{Angstroms}. A C{tuple} of C{(initial_wavelength_igs_lin_time_zero, initial_wavelength_igs_lin_time_zero_err2)} (assumed to be in units of I{Angstroms}) can be converted to C{(tof, tof_err2)}. @param obj: Object to be converted @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword lambda_f:The final wavelength and its associated error^2 @type lambda_f: C{tuple} @keyword time_zero_slope: The time zero slope and its associated error^2 @type time_zero_slope: C{tuple} @keyword time_zero_offset: The time zero offset and its associated error^2 @type time_zero_offset: C{tuple} @keyword dist_source_sample: The source to sample distance information and its associated error^2 @type dist_source_sample: C{tuple} or C{list} of C{tuple}s @keyword dist_sample_detector: The sample to detector distance information and its associated error^2 @type dist_sample_detector: C{tuple} or C{list} of C{tuple}s @keyword lojac: A flag that allows one to turn off the calculation of the linear-order Jacobian. The default action is True for histogram data. @type lojac: C{boolean} @keyword units: The expected units for this function. The default for this function is I{Angstroms} @type units: C{string} @return: Object with a primary axis in initial_wavelength_igs converted to time-of-flight @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise TypeError: The incoming object is not a type the function recognizes @raise RuntimeError: The C{SOM} x-axis units are not I{Angstroms} """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) # Setup keyword arguments try: lambda_f = kwargs["lambda_f"] except KeyError: lambda_f = None try: time_zero_slope = kwargs["time_zero_slope"] except KeyError: time_zero_slope = None # Current constants for Time Zero Slope TIME_ZERO_SLOPE = (float(0.0), float(0.0)) try: time_zero_offset = kwargs["time_zero_offset"] except KeyError: time_zero_offset = None # Current constants for Time Zero Offset TIME_ZERO_OFFSET = (float(0.0), float(0.0)) try: dist_source_sample = kwargs["dist_source_sample"] except KeyError: dist_source_sample = None try: dist_sample_detector = kwargs["dist_sample_detector"] except KeyError: dist_sample_detector = None try: lojac = kwargs["lojac"] except KeyError: lojac = hlr_utils.check_lojac(obj) try: units = kwargs["units"] except KeyError: units = "Angstroms" # Primary axis for transformation. If a SO is passed, the function, will # assume the axis for transformation is at the 0 position if o_descr == "SOM": axis = hlr_utils.one_d_units(obj, units) else: axis = 0 result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, "Microseconds", axis) result.setAxisLabel(axis, "time-of-flight") result.setYUnits("Counts/uS") result.setYLabel("Intensity") else: pass # Where to get instrument information if dist_source_sample is None or dist_sample_detector is None: if o_descr == "SOM": try: obj.attr_list.instrument.get_primary() inst = obj.attr_list.instrument except RuntimeError: raise RuntimeError("A detector was not provided!") else: if dist_source_sample is None and dist_sample_detector is None: raise RuntimeError("If a SOM is not passed, the "\ +"source-sample and sample-detector "\ +"distances must be provided.") elif dist_source_sample is None: raise RuntimeError("If a SOM is not passed, the "\ +"source-sample distance must be provided.") elif dist_sample_detector is None: raise RuntimeError("If a SOM is not passed, the "\ +"sample-detector distance must be "\ +"provided.") else: raise RuntimeError("If you get here, see Steve Miller for "\ +"your mug.") else: pass if lambda_f is not None: l_descr = hlr_utils.get_descr(lambda_f) else: if o_descr == "SOM": try: som_l_f = obj.attr_list["Wavelength_final"] except KeyError: raise RuntimeError("Please provide a final wavelength "\ +"parameter either via the function call "\ +"or the SOM") else: raise RuntimeError("You need to provide a final wavelength") if time_zero_slope is not None: t_0_slope_descr = hlr_utils.get_descr(time_zero_slope) else: if o_descr == "SOM": try: t_0_slope = obj.attr_list["Time_zero_slope"][0] t_0_slope_err2 = obj.attr_list["Time_zero_slope"][1] except KeyError: t_0_slope = TIME_ZERO_SLOPE[0] t_0_slope_err2 = TIME_ZERO_SLOPE[1] else: t_0_slope = TIME_ZERO_SLOPE[0] t_0_slope_err2 = TIME_ZERO_SLOPE[1] if time_zero_offset is not None: t_0_offset_descr = hlr_utils.get_descr(time_zero_offset) else: if o_descr == "SOM": try: t_0_offset = obj.attr_list["Time_zero_offset"][0] t_0_offset_err2 = obj.attr_list["Time_zero_offset"][1] except KeyError: t_0_offset = TIME_ZERO_OFFSET[0] t_0_offset_err2 = TIME_ZERO_OFFSET[1] else: t_0_offset = TIME_ZERO_OFFSET[0] t_0_offset_err2 = TIME_ZERO_OFFSET[1] if dist_source_sample is not None: ls_descr = hlr_utils.get_descr(dist_source_sample) # Do nothing, go on else: pass if dist_sample_detector is not None: ld_descr = hlr_utils.get_descr(dist_sample_detector) # Do nothing, go on else: pass # iterate through the values len_obj = hlr_utils.get_length(obj) MNEUT_OVER_H = 1.0 / 0.003956034 MNEUT_OVER_H2 = MNEUT_OVER_H * MNEUT_OVER_H for i in xrange(len_obj): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) if dist_source_sample is None: (L_s, L_s_err2) = hlr_utils.get_parameter("primary", map_so, inst) else: L_s = hlr_utils.get_value(dist_source_sample, i, ls_descr) L_s_err2 = hlr_utils.get_err2(dist_source_sample, i, ls_descr) if dist_sample_detector is None: (L_d, L_d_err2) = hlr_utils.get_parameter("secondary", map_so, inst) else: L_d = hlr_utils.get_value(dist_sample_detector, i, ld_descr) L_d_err2 = hlr_utils.get_err2(dist_sample_detector, i, ld_descr) if lambda_f is not None: l_f = hlr_utils.get_value(lambda_f, i, l_descr) l_f_err2 = hlr_utils.get_err2(lambda_f, i, l_descr) else: l_f_tuple = hlr_utils.get_special(som_l_f, map_so) l_f = l_f_tuple[0] l_f_err2 = l_f_tuple[1] if time_zero_slope is not None: t_0_slope = hlr_utils.get_value(time_zero_slope, i, t_0_slope_descr) t_0_slope_err2 = hlr_utils.get_err2(time_zero_slope, i, t_0_slope_descr) else: pass if time_zero_offset is not None: t_0_offset = hlr_utils.get_value(time_zero_offset, i, t_0_offset_descr) t_0_offset_err2 = hlr_utils.get_err2(time_zero_offset, i, t_0_offset_descr) else: pass # Going to violate rules since the current usage is with a single # number. When an SCL equivalent function arises, this code can be # fixed. front_const = MNEUT_OVER_H * L_s + t_0_slope term2 = MNEUT_OVER_H * l_f * L_d tof = (front_const * val) + term2 + t_0_offset front_const2 = front_const * front_const eterm1 = l_f * l_f * L_d_err2 eterm2 = L_d * L_d * l_f_err2 eterm3 = MNEUT_OVER_H2 * L_s_err2 tof_err2 = (front_const2 * err2) + (val * val) * \ (eterm3 + t_0_slope_err2) + (MNEUT_OVER_H2 * \ (eterm1 + eterm2)) + \ t_0_offset_err2 hlr_utils.result_insert(result, res_descr, (tof, tof_err2), None, "all") return result
def zero_bins(obj, z_bins): """ This function takes spectra and a set of bins and zeros the values in each spectrum at the bin location. @param obj: The object containing the spectra to be zeroed @type obj: C{SOM.SOM} @param z_bins: The set of bins from a given spectrum that will be zeroed @type z_bins: C{list} of C{int}s @return: Object containing the spectra with zeroed bins @rtype: C{SOM.SOM} @raise TypeError: The first argument is not a C{SOM} or C{SO} """ # Kickout if there are no bins to zero if z_bins is None: return obj # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) if o_descr == "number" or o_descr == "list": raise TypeError("First argument must be a SOM or a SO!") # Have a SOM or SO, go on else: pass result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) # iterate through the values import nessi_list for i in xrange(hlr_utils.get_length(obj)): map_so = hlr_utils.get_map_so(obj, None, i) # Get information from SOM y_val = hlr_utils.get_value(obj, i, o_descr, "y") y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y") y_new = nessi_list.NessiList() var_y_new = nessi_list.NessiList() for j in xrange(len(y_val)): if j in z_bins: y_new.append(0.0) var_y_new.append(0.0) else: y_new.append(y_val[j]) var_y_new.append(y_err2[j]) hlr_utils.result_insert(result, res_descr, (y_new, var_y_new), map_so, "y") return result
def rebin_axis_1D_frac(obj, axis_out): """ This function rebins the primary axis for a C{SOM} or a C{SO} based on the given C{NessiList} axis. @param obj: Object to be rebinned @type obj: C{SOM.SOM} or C{SOM.SO} @param axis_out: The axis to rebin the C{SOM} or C{SO} to @type axis_out: C{NessiList} @return: Two objects that have been rebinned according to the provided axis. The first object contains the rebinned counts and the second contains the fractional area. @rtype: C{tuple} of two C{SOM.SOM}s or C{SOM.SO}s @raise TypeError: The rebinning axis given is not a C{NessiList} @raise TypeError: The object being rebinned is not a C{SOM} or a C{SO} """ # import the helper functions import hlr_utils # set up for working through data try: axis_out.__type__ except AttributeError: raise TypeError("Rebinning axis must be a NessiList!") o_descr = hlr_utils.get_descr(obj) if o_descr == "number" or o_descr == "list": raise TypeError("Do not know how to handle given type: %s" % \ o_descr) else: pass (result1, res1_descr) = hlr_utils.empty_result(obj) result1 = hlr_utils.copy_som_attr(result1, res1_descr, obj, o_descr) (result2, res2_descr) = hlr_utils.empty_result(obj) result2 = hlr_utils.copy_som_attr(result2, res2_descr, obj, o_descr) # iterate through the values import axis_manip len_obj = hlr_utils.get_length(obj) for i in xrange(len_obj): axis_in = hlr_utils.get_value(obj, i, o_descr, "x", 0) val = hlr_utils.get_value(obj, i, o_descr) err2 = hlr_utils.get_err2(obj, i, o_descr) value = axis_manip.rebin_axis_1D_frac(axis_in, val, err2, axis_out) frac_err = nessi_list.NessiList(len(value[2])) xvals = [] xvals.append(axis_out) map_so = hlr_utils.get_map_so(obj, None, i) hlr_utils.result_insert(result1, res1_descr, (value[0], value[1]), map_so, "all", 0, xvals) hlr_utils.result_insert(result2, res2_descr, (value[2], frac_err), map_so, "all", 0, xvals) return (result1, result2)
def init_scatt_wavevector_to_scalar_Q(initk, scattk, **kwargs): """ This function takes an initial wavevector and a scattered wavevector as a C{tuple} and a C{SOM}, a C{tuple} and a C{SO} or two C{tuple}s and calculates the quantity scalar Q units of I{1/Angstroms}. The C{SOM} principle axis must be in units of I{1/Angstroms}. The C{SO}s and C{tuple}(s) is(are) assumed to be in units of I{1/Angstroms}. The polar angle must be provided if one of the initial arguments is not a C{SOM}. If a C{SOM} is passed, by providing the polar angle at the function call time, the polar angle carried in the C{SOM} instrument will be overridden. @param initk: Object holding the initial wavevector @type initk: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param scattk: Object holding the scattered wavevector @type scattk: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword polar: The polar angle and its associated error^2 @type polar: C{tuple} or C{list} of C{tuple}s @keyword units: The expected units for this function. The default for this function is I{1/Angstroms}. @type units: C{string} @return: Object converted to scalar Q @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise TypeError: The C{SOM}-C{SOM} operation is attempted @raise TypeError: The C{SOM}-C{SO} operation is attempted @raise TypeError: The C{SO}-C{SOM} operation is attempted @raise TypeError: The C{SO}-C{SO} operation is attempted @raise RuntimeError: The C{SOM} x-axis units are not I{1/Angstroms} @raise RuntimeError: A C{SOM} is not passed and no polar angle is provided @raise RuntimeError: No C{SOM.Instrument} is provided in a C{SOM} """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(initk, scattk) (i_descr, s_descr) = hlr_utils.get_descr(initk, scattk) # error checking for types if i_descr == "SOM" and s_descr == "SOM": raise TypeError("SOM-SOM operation not supported") elif i_descr == "SOM" and s_descr == "SO": raise TypeError("SOM-SO operation not supported") elif i_descr == "SO" and s_descr == "SOM": raise TypeError("SO-SOM operation not supported") elif i_descr == "SO" and s_descr == "SO": raise TypeError("SO-SO operation not supported") else: pass # Setup keyword arguments try: polar = kwargs["polar"] except KeyError: polar = None try: units = kwargs["units"] except KeyError: units = "1/Angstroms" result = hlr_utils.copy_som_attr(result, res_descr, initk, i_descr, scattk, s_descr) if res_descr == "SOM": index = hlr_utils.one_d_units(result, units) result = hlr_utils.force_units(result, units, index) result.setAxisLabel(index, "scalar wavevector transfer") result.setYUnits("Counts/A-1") result.setYLabel("Intensity") else: pass if polar is None: if i_descr == "SOM": try: initk.attr_list.instrument.get_primary() inst = initk.attr_list.instrument except RuntimeError: raise RuntimeError("A detector was not provided!") elif s_descr == "SOM": try: scattk.attr_list.instrument.get_primary() inst = scattk.attr_list.instrument except RuntimeError: raise RuntimeError("A detector was not provided!") else: raise RuntimeError("If no SOM is provided, then polar "\ +"information must be given.") else: p_descr = hlr_utils.get_descr(polar) # iterate through the values import axis_manip for i in xrange(hlr_utils.get_length(initk, scattk)): val1 = hlr_utils.get_value(initk, i, i_descr, "x") err2_1 = hlr_utils.get_err2(initk, i, i_descr, "x") val2 = hlr_utils.get_value(scattk, i, s_descr, "x") err2_2 = hlr_utils.get_err2(scattk, i, s_descr, "x") map_so = hlr_utils.get_map_so(initk, scattk, i) if polar is None: (angle, angle_err2) = hlr_utils.get_parameter("polar", map_so, inst) else: angle = hlr_utils.get_value(polar, i, p_descr) angle_err2 = hlr_utils.get_err2(polar, i, p_descr) value = axis_manip.init_scatt_wavevector_to_scalar_Q(val1, err2_1, val2, err2_2, angle, angle_err2) hlr_utils.result_insert(result, res_descr, value, map_so, "x") return result
def rebin_efficiency(obj1, obj2, **kwargs): """ This function takes two objects and rebins the data for obj1 onto the axis provided by obj2. The units on the x-axes needs to be I{Angstroms}, since this is what the efficiencies will be present as. @param obj1: Object that will be rebinned @type obj1: C{SOM.SOM} or C{SOM.SO} @param obj2: Object that will provide the axis for rebinning @type obj2: C{SOM.SOM} or C{SOM.SO} @param kwargs: A list of keyword arguments that the function accepts: @keyword units: The expected units for this function. The default for this function is I{Angstroms}. @type units: C{string} @return: Object that has been rebinned @rtype: C{SOM.SOM} or C{SOM.SO} @raise TypeError: The C{SOM}-C{SO} operation is attempted @raise TypeError: The C{SO}-C{SOM} operation is attempted @raise TypeError: obj1 not a C{SOM} or C{SO} @raise TypeError: obj2 not a C{SOM} or C{SO} @raise IndexError: The C{SOM}s do not have the same number of C{SO}s @raise RuntimeError: The C{SOM} x-axis units are not I{Angstroms} @raise RuntimeError: The x-axis units of the C{SOM}s do not match """ # import the helper functions import hlr_utils # Kickout if monitor object is None if obj1 is None: return obj1 # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj1, obj2) (o1_descr, o2_descr) = hlr_utils.get_descr(obj1, obj2) # error checking for types if o1_descr == "SOM" and o2_descr == "SO": raise TypeError, "SOM-SO operation not supported" elif o1_descr == "SO" and o2_descr == "SOM": raise TypeError("SO-SOM operation not supported") # Have the right object combination, go on else: pass # Setup keyword arguments try: units = kwargs["units"] except KeyError: units = "Angstroms" if o1_descr == "SOM" and o2_descr == "SOM": hlr_utils.math_compatible(obj1, o1_descr, obj2, o2_descr) # If both objects are not SOMs, do nothing else: pass result = hlr_utils.copy_som_attr(result, res_descr, obj2, o2_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, units) # Can't force units on anything other than a SOM else: pass # iterate through the values import common_lib for i in xrange(hlr_utils.get_length(obj1, obj2)): val1 = hlr_utils.get_value(obj1, i, o1_descr, "all") val2 = hlr_utils.get_value(obj2, i, o2_descr, "x") value = common_lib.rebin_axis_1D(val1, val2) hlr_utils.result_insert(result, res_descr, value, None, "all") return result
def create_axis_from_data(obj, **kwargs): """ This function inspects the independent axis of the data searching for the minimum and maximum axis values. It also determines the bin width from the first bin in the axis and searches for the smallest value. From these values, an Axis object is created. This function assusmes that the axis is sorted in ascending order. @param obj: The object containing the data with the indpendent axis to be searched. @type obj: C{SOM.SOM} or C{SOM.SO} @param kwargs: A list of keyword arguments that the function accepts: @keyword axis_pos: This is position of the axis in the axis array. If no argument is given, the default value is 0 @type axis_pos: C{int} @keyword width: A override parameter for specifying the axis bin width. @type width: C{float} @return: The axis based on the found values from the data @rtype: L{hlr_utils.Axis} @raise TypeError: The incoming object is not a C{SOM} or a C{SO} """ import hlr_utils # Check for keyword arguments try: axis_pos = kwargs["axis_pos"] except KeyError: axis_pos = 0 try: axis_width = kwargs["width"] width_given = True except KeyError: axis_width = 999999999999999999999999999999999999.0 width_given = False o_descr = hlr_utils.get_descr(obj) if o_descr == "number" or o_descr == "list": raise TypeError("Function argument must be a SOM or a SO") # Have a SOM or a SO, go on else: pass # Set extreme values for axis minimum and maximum axis_min = 999999999999999999999999999999999999 axis_max = -99999999999999999999999999999999999 # iterate through the values for i in xrange(hlr_utils.get_length(obj)): axis = hlr_utils.get_value(obj, i, o_descr, "x", axis_pos) min_index = 0 max_index = -1 index_ok = False while not index_ok: value = axis[min_index] if value == float('-inf'): min_index += 1 else: index_ok = True axis_min = min(axis_min, axis[min_index]) index_ok = False while not index_ok: value = axis[max_index] if value == float('inf'): max_index -= 1 else: index_ok = True axis_max = max(axis_max, axis[max_index]) if not width_given: test_width = axis[min_index + 1] - axis[min_index] axis_width = min(axis_width, test_width) return hlr_utils.Axis(axis_min, axis_max, axis_width)
def dimensionless_mon(obj, min_ext, max_ext, **kwargs): """ This function takes monitor spectra and converts them to dimensionless spectra by dividing each spectrum by the total number of counts within the range [min_ext, max_ext]. Then, each spectrum is multiplied by the quantity max_ext - min_ext. The units of min_ext and max_ext are assumed to be the same as the monitor spectra axis. @param obj: Object containing monitor spectra @type obj: C{SOM.SOM} or C{SOM.SO} @param min_ext: Minimium range and associated error^2 for integrating total counts. @type min_ext: C{tuple} @param max_ext: Maximium range and associated error^2 for integrating total counts. @type max_ext: C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword units: The expected units for this function. The default for this function is I{Angstroms}. @type units: C{string} @return: Dimensionless monitor spectra @rtype: C{SOM.SOM} or C{SOM.SO} """ # import the helper functions import hlr_utils if obj is None: return obj # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) # Setup keyword arguments try: units = kwargs["units"] except KeyError: units = "Angstroms" # Primary axis for transformation. If a SO is passed, the function, will # assume the axis for transformation is at the 0 position if o_descr == "SOM": axis = hlr_utils.one_d_units(obj, units) else: axis = 0 result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) import array_manip import dr_lib import utils for i in xrange(hlr_utils.get_length(obj)): val = hlr_utils.get_value(obj, i, o_descr, "y") err2 = hlr_utils.get_err2(obj, i, o_descr, "y") x_axis = hlr_utils.get_value(obj, i, o_descr, "x", axis) x_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) bin_widths = utils.calc_bin_widths(x_axis, x_err2) # Scale bin contents by bin width value0 = array_manip.mult_ncerr(val, err2, bin_widths[0], bin_widths[1]) # Find bin range for extents min_index = utils.bisect_helper(x_axis, min_ext[0]) max_index = utils.bisect_helper(x_axis, max_ext[0]) # Integrate axis using bin width multiplication (asum, asum_err2) = dr_lib.integrate_axis_py(map_so, start=min_index, end=max_index, width=True) # Get the number of bins in the integration range num_bins = max_index - min_index + 1 asum /= num_bins asum_err2 /= (num_bins * num_bins) # Divide by sum value1 = array_manip.div_ncerr(value0[0], value0[1], asum, asum_err2) hlr_utils.result_insert(result, res_descr, value1, map_so, "y") return result
def rebin_monitor(obj1, obj2, **kwargs): """ This function takes objects (1st is the monitor, 2nd is the detector data) and rebins the data for obj1 onto the axis provided by obj2. The pixel ID can be transferred as the pixel ID of the rebinned monitor histogram. A prefix is placed on the bank ID to dilineate that this is a rebinned monitor spectrum for that pixel. @param obj1: Monitor object that will be rebinned @type obj1: C{SOM.SOM} or C{SOM.SO} @param obj2: Detector data object that will provide the axis for rebinning @type obj2: C{SOM.SOM} or C{SOM.SO} @param kwargs: A list of keyword arguments that the function accepts @keyword use_pix_id: A flag that specifies if the pixel ID is to be used in the rebinned monitor spectrum. The default is I{False}. @type use_pix_id: C{boolean} @keyword prefix: Allows one to specify a prefix for the bank ID. The default is I{m}. @type prefix: C{string} @keyword rtype: A short string that defines the rebinning function to use. The default is I{None} which uses L{common_lib.rebin_axis_1D()}. The other possibilities are I{linint} which uses L{common_lib.rebin_axis_1D_linint()} and I{frac} which uses L{common_lib.rebin_axis_1D_frac()}. @type rtype: C{boolean} @return: Object that has been rebinned @rtype: C{SOM.SOM} or C{SOM.SO} @raise TypeError: The C{SOM}-C{SO} operation is attempted @raise TypeError: The C{SO}-C{SOM} operation is attempted @raise TypeError: obj1 not a C{SOM} or C{SO} @raise TypeError: obj2 not a C{SOM} or C{SO} """ # import the helper functions import hlr_utils # Kickout if monitor object is None if obj1 is None: return obj1 # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj1, obj2) (o1_descr, o2_descr) = hlr_utils.get_descr(obj1, obj2) # error checking for types if o1_descr == "SOM" and o2_descr == "SO": raise TypeError, "SOM-SO operation not supported" elif o1_descr == "SO" and o2_descr == "SOM": raise TypeError("SO-SOM operation not supported") # Have the right object combination, go on else: pass # Check for keywords try: prefix = kwargs["prefix"] except KeyError: prefix = "m" try: use_pix_id = kwargs["use_pix_id"] except KeyError: use_pix_id = False try: rtype = kwargs["rtype"] except KeyError: rtype = None # Set the name of the rebinning function rebin_function_name = "rebin_axis_1D" if rtype is not None: rebin_function_name += "_" + str(rtype) # Get function pointer import common_lib rebin_function = common_lib.__getattribute__(rebin_function_name) result = hlr_utils.copy_som_attr(result, res_descr, obj1, o1_descr) # iterate through the values val1 = hlr_utils.get_value(obj1, 0, o1_descr, "all") # Cache length len_obj2 = hlr_utils.get_length(obj2) for i in xrange(len_obj2): val2 = hlr_utils.get_value(obj2, i, o2_descr, "x") value = rebin_function(val1, val2) if use_pix_id: # Set the pixel ID to the spectrum with modified bank ID try: value.id = (prefix+obj2[i].id[0], (obj2[i].id[1][0], obj2[i].id[1][1])) except TypeError: value.id = prefix+str(obj2[i].id) hlr_utils.result_insert(result, res_descr, value, None, "all") return result
def create_E_vs_Q_igs(som, *args, **kwargs): """ This function starts with the initial IGS wavelength axis and turns this into a 2D spectra with E and Q axes. @param som: The input object with initial IGS wavelength axis @type som: C{SOM.SOM} @param args: A mandatory list of axes for rebinning. There is a particular order to them. They should be present in the following order: Without errors 1. Energy transfer 2. Momentum transfer With errors 1. Energy transfer 2. Energy transfer error^2 3. Momentum transfer 4. Momentum transfer error ^2 @type args: C{nessi_list.NessiList}s @param kwargs: A list of keyword arguments that the function accepts: @keyword withXVar: Flag for whether the function should be expecting the associated axes to have errors. The default value will be I{False}. @type withXVar: C{boolean} @keyword data_type: Name of the data type which can be either I{histogram}, I{density} or I{coordinate}. The default value will be I{histogram} @type data_type: C{string} @keyword Q_filter: Flag to turn on or off Q filtering. The default behavior is I{True}. @type Q_filter: C{boolean} @keyword so_id: The identifier represents a number, string, tuple or other object that describes the resulting C{SO} @type so_id: C{int}, C{string}, C{tuple}, C{pixel ID} @keyword y_label: The y axis label @type y_label: C{string} @keyword y_units: The y axis units @type y_units: C{string} @keyword x_labels: This is a list of names that sets the individual x axis labels @type x_labels: C{list} of C{string}s @keyword x_units: This is a list of names that sets the individual x axis units @type x_units: C{list} of C{string}s @keyword split: This flag causes the counts and the fractional area to be written out into separate files. @type split: C{boolean} @keyword configure: This is the object containing the driver configuration. @type configure: C{Configure} @return: Object containing a 2D C{SO} with E and Q axes @rtype: C{SOM.SOM} @raise RuntimeError: Anything other than a C{SOM} is passed to the function @raise RuntimeError: An instrument is not contained in the C{SOM} """ import nessi_list # Setup some variables dim = 2 N_y = [] N_tot = 1 N_args = len(args) # Get T0 slope in order to calculate dT = dT_i + dT_0 try: t_0_slope = som.attr_list["Time_zero_slope"][0] t_0_slope_err2 = som.attr_list["Time_zero_slope"][1] except KeyError: t_0_slope = float(0.0) t_0_slope_err2 = float(0.0) # Check withXVar keyword argument and also check number of given args. # Set xvar to the appropriate value try: value = kwargs["withXVar"] if value.lower() == "true": if N_args != 4: raise RuntimeError("Since you have requested x errors, 4 x "\ +"axes must be provided.") else: xvar = True elif value.lower() == "false": if N_args != 2: raise RuntimeError("Since you did not requested x errors, 2 "\ +"x axes must be provided.") else: xvar = False else: raise RuntimeError("Do not understand given parameter %s" % \ value) except KeyError: if N_args != 2: raise RuntimeError("Since you did not requested x errors, 2 "\ +"x axes must be provided.") else: xvar = False # Check dataType keyword argument. An offset will be set to 1 for the # histogram type and 0 for either density or coordinate try: data_type = kwargs["data_type"] if data_type.lower() == "histogram": offset = 1 elif data_type.lower() == "density" or \ data_type.lower() == "coordinate": offset = 0 else: raise RuntimeError("Do not understand data type given: %s" % \ data_type) # Default is offset for histogram except KeyError: offset = 1 try: Q_filter = kwargs["Q_filter"] except KeyError: Q_filter = True # Check for split keyword try: split = kwargs["split"] except KeyError: split = False # Check for configure keyword try: configure = kwargs["configure"] except KeyError: configure = None so_dim = SOM.SO(dim) for i in range(dim): # Set the x-axis arguments from the *args list into the new SO if not xvar: # Axis positions are 1 (Q) and 0 (E) position = dim - i - 1 so_dim.axis[i].val = args[position] else: # Axis positions are 2 (Q), 3 (eQ), 0 (E), 1 (eE) position = dim - 2 * i so_dim.axis[i].val = args[position] so_dim.axis[i].var = args[position + 1] # Set individual value axis sizes (not x-axis size) N_y.append(len(args[position]) - offset) # Calculate total 2D array size N_tot = N_tot * N_y[-1] # Create y and var_y lists from total 2D size so_dim.y = nessi_list.NessiList(N_tot) so_dim.var_y = nessi_list.NessiList(N_tot) # Create area sum and errors for the area sum lists from total 2D size area_sum = nessi_list.NessiList(N_tot) area_sum_err2 = nessi_list.NessiList(N_tot) # Create area sum and errors for the area sum lists from total 2D size bin_count = nessi_list.NessiList(N_tot) bin_count_err2 = nessi_list.NessiList(N_tot) inst = som.attr_list.instrument lambda_final = som.attr_list["Wavelength_final"] inst_name = inst.get_name() import bisect import math import dr_lib import utils arr_len = 0 #: Vector of zeros for function calculations zero_vec = None for j in xrange(hlr_utils.get_length(som)): # Get counts counts = hlr_utils.get_value(som, j, "SOM", "y") counts_err2 = hlr_utils.get_err2(som, j, "SOM", "y") arr_len = len(counts) zero_vec = nessi_list.NessiList(arr_len) # Get mapping SO map_so = hlr_utils.get_map_so(som, None, j) # Get lambda_i l_i = hlr_utils.get_value(som, j, "SOM", "x") l_i_err2 = hlr_utils.get_err2(som, j, "SOM", "x") # Get lambda_f from instrument information l_f_tuple = hlr_utils.get_special(lambda_final, map_so) l_f = l_f_tuple[0] l_f_err2 = l_f_tuple[1] # Get source to sample distance (L_s, L_s_err2) = hlr_utils.get_parameter("primary", map_so, inst) # Get sample to detector distance L_d_tuple = hlr_utils.get_parameter("secondary", map_so, inst) L_d = L_d_tuple[0] # Get polar angle from instrument information (angle, angle_err2) = hlr_utils.get_parameter("polar", map_so, inst) # Get the detector pixel height dh_tuple = hlr_utils.get_parameter("dh", map_so, inst) dh = dh_tuple[0] # Need dh in units of Angstrom dh *= 1e10 # Calculate T_i (T_i, T_i_err2) = axis_manip.wavelength_to_tof(l_i, l_i_err2, L_s, L_s_err2) # Scale counts by lambda_f / lambda_i (l_i_bc, l_i_bc_err2) = utils.calc_bin_centers(l_i, l_i_err2) (ratio, ratio_err2) = array_manip.div_ncerr(l_f, l_f_err2, l_i_bc, l_i_bc_err2) (counts, counts_err2) = array_manip.mult_ncerr(counts, counts_err2, ratio, ratio_err2) # Calculate E_i (E_i, E_i_err2) = axis_manip.wavelength_to_energy(l_i, l_i_err2) # Calculate E_f (E_f, E_f_err2) = axis_manip.wavelength_to_energy(l_f, l_f_err2) # Calculate E_t (E_t, E_t_err2) = array_manip.sub_ncerr(E_i, E_i_err2, E_f, E_f_err2) if inst_name == "BSS": # Convert E_t from meV to ueV (E_t, E_t_err2) = array_manip.mult_ncerr(E_t, E_t_err2, 1000.0, 0.0) (counts, counts_err2) = array_manip.mult_ncerr(counts, counts_err2, 1.0/1000.0, 0.0) # Convert lambda_i to k_i (k_i, k_i_err2) = axis_manip.wavelength_to_scalar_k(l_i, l_i_err2) # Convert lambda_f to k_f (k_f, k_f_err2) = axis_manip.wavelength_to_scalar_k(l_f, l_f_err2) # Convert k_i and k_f to Q (Q, Q_err2) = axis_manip.init_scatt_wavevector_to_scalar_Q(k_i, k_i_err2, k_f, k_f_err2, angle, angle_err2) # Calculate dT = dT_0 + dT_i dT_i = utils.calc_bin_widths(T_i, T_i_err2) (l_i_bw, l_i_bw_err2) = utils.calc_bin_widths(l_i, l_i_err2) dT_0 = array_manip.mult_ncerr(l_i_bw, l_i_bw_err2, t_0_slope, t_0_slope_err2) dT_tuple = array_manip.add_ncerr(dT_i[0], dT_i[1], dT_0[0], dT_0[1]) dT = dT_tuple[0] # Calculate Jacobian if inst_name == "BSS": (x_1, x_2, x_3, x_4) = dr_lib.calc_BSS_coeffs(map_so, inst, (E_i, E_i_err2), (Q, Q_err2), (k_i, k_i_err2), (T_i, T_i_err2), dh, angle, E_f, k_f, l_f, L_s, L_d, t_0_slope, zero_vec) else: raise RuntimeError("Do not know how to calculate x_i "\ +"coefficients for instrument %s" % inst_name) (A, A_err2) = dr_lib.calc_EQ_Jacobian(x_1, x_2, x_3, x_4, dT, dh, zero_vec) # Apply Jacobian: C/dlam * dlam / A(EQ) = C/EQ (jac_ratio, jac_ratio_err2) = array_manip.div_ncerr(l_i_bw, l_i_bw_err2, A, A_err2) (counts, counts_err2) = array_manip.mult_ncerr(counts, counts_err2, jac_ratio, jac_ratio_err2) # Reverse counts, E_t, k_i and Q E_t = axis_manip.reverse_array_cp(E_t) E_t_err2 = axis_manip.reverse_array_cp(E_t_err2) Q = axis_manip.reverse_array_cp(Q) Q_err2 = axis_manip.reverse_array_cp(Q_err2) counts = axis_manip.reverse_array_cp(counts) counts_err2 = axis_manip.reverse_array_cp(counts_err2) k_i = axis_manip.reverse_array_cp(k_i) x_1 = axis_manip.reverse_array_cp(x_1) x_2 = axis_manip.reverse_array_cp(x_2) x_3 = axis_manip.reverse_array_cp(x_3) x_4 = axis_manip.reverse_array_cp(x_4) dT = axis_manip.reverse_array_cp(dT) # Filter for duplicate Q values if Q_filter: k_i_cutoff = k_f * math.cos(angle) k_i_cutbin = bisect.bisect(k_i, k_i_cutoff) counts.__delslice__(0, k_i_cutbin) counts_err2.__delslice__(0, k_i_cutbin) Q.__delslice__(0, k_i_cutbin) Q_err2.__delslice__(0, k_i_cutbin) E_t.__delslice__(0, k_i_cutbin) E_t_err2.__delslice__(0, k_i_cutbin) x_1.__delslice__(0, k_i_cutbin) x_2.__delslice__(0, k_i_cutbin) x_3.__delslice__(0, k_i_cutbin) x_4.__delslice__(0, k_i_cutbin) dT.__delslice__(0, k_i_cutbin) zero_vec.__delslice__(0, k_i_cutbin) try: if inst_name == "BSS": ((Q_1, E_t_1), (Q_2, E_t_2), (Q_3, E_t_3), (Q_4, E_t_4)) = dr_lib.calc_BSS_EQ_verticies((E_t, E_t_err2), (Q, Q_err2), x_1, x_2, x_3, x_4, dT, dh, zero_vec) else: raise RuntimeError("Do not know how to calculate (Q_i, "\ +"E_t_i) verticies for instrument %s" \ % inst_name) except IndexError: # All the data got Q filtered, move on continue try: (y_2d, y_2d_err2, area_new, bin_count_new) = axis_manip.rebin_2D_quad_to_rectlin(Q_1, E_t_1, Q_2, E_t_2, Q_3, E_t_3, Q_4, E_t_4, counts, counts_err2, so_dim.axis[0].val, so_dim.axis[1].val) except IndexError, e: # Get the offending index from the error message index = int(str(e).split()[1].split('index')[-1].strip('[]')) print "Id:", map_so.id print "Index:", index print "Verticies: %f, %f, %f, %f, %f, %f, %f, %f" % (Q_1[index], E_t_1[index], Q_2[index], E_t_2[index], Q_3[index], E_t_3[index], Q_4[index], E_t_4[index]) raise IndexError(str(e)) # Add in together with previous results (so_dim.y, so_dim.var_y) = array_manip.add_ncerr(so_dim.y, so_dim.var_y, y_2d, y_2d_err2) (area_sum, area_sum_err2) = array_manip.add_ncerr(area_sum, area_sum_err2, area_new, area_sum_err2) if configure.dump_pix_contrib or configure.scale_sqe: if inst_name == "BSS": dOmega = dr_lib.calc_BSS_solid_angle(map_so, inst) (bin_count_new, bin_count_err2) = array_manip.mult_ncerr(bin_count_new, bin_count_err2, dOmega, 0.0) (bin_count, bin_count_err2) = array_manip.add_ncerr(bin_count, bin_count_err2, bin_count_new, bin_count_err2) else: del bin_count_new
def sum_spectra_weighted_ave(obj, **kwargs): """ This function takes a set of data and sums the individual bins by weighted average. That information is then assembled back into a single spectrum. The individual spectra should already have been rebinned. @param obj: Object containing data spectra @type obj: C{SOM.SOM} or C{SOM.SO} @param kwargs: A list of keyword arguments that the function accepts: @return: The summed spectra (one) @rtype: C{SOM.SOM} """ if obj is None: return None # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) # Get the number of axis channels len_axis = len(obj[0]) import nessi_list import SOM import utils # Empty SO for final spctrum so = SOM.SO() len_som = hlr_utils.get_length(obj) # Slice data, calculate weighted average and repackage spectra for i in xrange(len_axis): sliced_data = nessi_list.NessiList() sliced_data_err2 = nessi_list.NessiList() for j in xrange(len_som): obj1 = hlr_utils.get_value(obj, j, o_descr, "all") if i == 0 and j == 0: map_so = hlr_utils.get_map_so(obj, None, j) hlr_utils.result_insert(so, "SO", map_so, None, "all") sliced_data.append(obj1.y[i]) sliced_data_err2.append(obj1.var_y[i]) len_fit = len(sliced_data) value = utils.weighted_average(sliced_data, sliced_data_err2, 0, len_fit - 1) so.y[i] = value[0] so.var_y[i] = value[1] hlr_utils.result_insert(result, res_descr, so, None, "all") return result
def determine_time_indep_bkg(obj, tof_vals, **kwargs): """ This functions calculates the average counts at four given TOF channels for determining the time-independent background. @param obj: Object used for determining the time-independent background @type obj: C{SOM.SOM} or C{SOM.SO} @param tof_vals: The four TOF channels from which the average counts will be determined @type tof_vals: C{list} @param kwargs: A list of keyword arguments that the function accepts: @keyword is_range: A flag that tells the function that tof_vals is a range from which to determine the time-independent background. The default is I{False}. @type is_range: C{bool} @return: Object containing the time-independent background and the associated error @rtype: C{list} of C{tuple}s @raise TypeError: The incoming object is not a C{SOM} or C{SO}. """ # Kickout if tof_vals is NoneType if tof_vals is None: return None # import the helper functions import hlr_utils # Get keyword arguments is_range = kwargs.get("is_range", False) o_descr = hlr_utils.get_descr(obj) if o_descr != "SOM" and o_descr != "SO": raise TypeError("Incoming object must be a SOM or a SO") # Have a SOM or SO else: pass # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) if not is_range: num_tof_vals = float(len(tof_vals)) import bisect else: num_tof_vals = tof_vals[1] - tof_vals[0] import dr_lib # iterate through the values len_obj = hlr_utils.get_length(obj) for i in xrange(len_obj): obj1 = hlr_utils.get_value(obj, i, o_descr, "all") if not is_range: average = 0.0 ave_err2 = 0.0 for tof in tof_vals: index = bisect.bisect(obj1.axis[0].val, float(tof)) - 1 average += obj1.y[index] ave_err2 += obj1.var_y[index] else: (average, ave_err2) = dr_lib.integrate_axis(obj1, width=True, start=tof_vals[0], end=tof_vals[1]) average /= num_tof_vals ave_err2 /= num_tof_vals hlr_utils.result_insert(result, res_descr, (average, ave_err2), obj1, "yonly") return result
def integrate_spectra(obj, **kwargs): """ This function takes a set of spectra and calculates the integration for the primary axis. If the integration range for a spectrum cannot be found, an error report will be generated with the following information: Range not found: pixel ID, start bin, end bin, length of data array A failing pixel will have the integration tuple set to C{(nan, nan)}. @param obj: Object containing spectra that will have the integration calculated from them. @type obj: C{SOM.SOM} or C{SOM.SO} @param kwargs: A list of keyword arguments that the function accepts: @keyword start: The start range for the integration. @type start: C{int} @keyword end: The end range for the integration. function. @type end: C{int} @keyword axis_pos: This is position of the axis in the axis array. If no argument is given, the default value is I{0}. @type axis_pos: C{int} @keyword norm: This is a flag to turn on the division of the individual spectrum integrations by the solid angle of the corresponding pixel. This also activates the multiplication of the individual spectrum bin values by their corresponding bin width via the I{width} flag in L{integrate_axis}. The default value of the flag is I{False}. @type norm: C{boolean} @keyword total: This is a flag to turn on the summation of all individual spectrum integrations. The default value of the flag is I{False}. @type total: C{boolean} @keyword width: This is a flag to turn on the removal of the individual bin width in the L{integrate_axis} function while doing the integrations. The default value of the flag is I{False}. @type width: C{boolean} @return: Object containing the integration and the uncertainty squared associated with the integration @rtype: C{SOM.SOM} or C{SOM.SO} """ # import the helper functions import hlr_utils if obj is None: return obj # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) # Check for axis_pos keyword argument try: axis_pos = kwargs["axis_pos"] except KeyError: axis_pos = 0 # Check for norm keyword argument try: norm = kwargs["norm"] if norm: if o_descr == "SO": raise RuntimeError("Cannot use norm keyword with SO!") width = True inst = obj.attr_list.instrument else: width = False except KeyError: norm = False width = False # Check for total keyword argument try: total = kwargs["total"] except KeyError: total = False # Check for width keyword argument only if norm isn't present if not norm: try: width = kwargs["width"] except KeyError: width = False # If the integration start bound is not given, set to infinity try: i_start = kwargs["start"] except KeyError: i_start = float("inf") # If the integration end bound is not given, set to infinity try: i_end = kwargs["end"] except KeyError: i_end = float("inf") # iterate through the values import dr_lib len_obj = hlr_utils.get_length(obj) for i in xrange(len_obj): obj1 = hlr_utils.get_value(obj, i, o_descr, "all") # If there's a NaN at the front and back, there are NaN's everywhere if str(obj1.axis[axis_pos].val[0]) == "nan" and \ str(obj1.axis[axis_pos].val[-1]) == "nan": print "Range not found:", obj1.id, i_start, i_end, len(obj1) value = (float('nan'), float('nan')) else: value = dr_lib.integrate_axis(obj1, start=i_start, end=i_end, width=width) if norm: if inst.get_name() == "BSS": map_so = hlr_utils.get_map_so(obj, None, i) dOmega = dr_lib.calc_BSS_solid_angle(map_so, inst) value1 = (value[0] / dOmega, value[1] / (dOmega * dOmega)) else: raise RuntimeError("Do not know how to get solid angle from "\ +"%s" % inst.get_name()) else: value1 = value hlr_utils.result_insert(result, res_descr, value1, obj1, "yonly") if not total: return result else: # Sum all integration counts total_counts = 0 total_err2 = 0 for j in xrange(hlr_utils.get_length(result)): total_counts += hlr_utils.get_value(result, j, res_descr, "y") total_err2 += hlr_utils.get_err2(result, j, res_descr, "y") # Create new result object (result2, res2_descr) = hlr_utils.empty_result(result) result2 = hlr_utils.copy_som_attr(result2, res2_descr, result, res_descr) res1 = hlr_utils.get_value(result, 0, res_descr, "all") hlr_utils.result_insert(result2, res2_descr, (total_counts, total_err2), res1, "yonly") return result2
def sum_all_spectra(obj, **kwargs): """ This function takes all the spectra in the given object and sums them together. All of the sprectra are assumed to have the same axis scale. @param obj: Object in which all of the spectra are to be summed together @type obj: C{SOM.SOM} @param kwargs: A list of keyword arguments that the function accepts: @keyword rebin_axis: The axis(es) to rebin the spectra onto. @type rebin_axis: C{nessi_list.NessiList} or C{list} of C{nessi_list.NessiList}s @keyword rebin_axis_dim: Tthe dimension on the spectra being rebinned. The default value is I{1}. @type rebin_axis_dim: C{int} @keyword y_sort: A flag that will sort the spectrum IDs by y. The default behavior is I{False} and this maintains the original x ordering. @type y_sort: C{boolean} @keyword stripe: A flag that will combine spectra in either the x or y direction at a given y or x. The integration direction is based on the setting of y_sort. The default behavior is I{False} and corresponds to summing all spectra into one. @type stripe: C{boolean} @keyword pix_fix: A single or list of pixel IDs with which to override the summed spectrum pixel ID. The setting of y_sort determines is the x component (y_sort=False) or the y component (y_sort=True) of the pixel ID is overridden. @type pix_fix: C{int} or C{list} of C{int}s @return: Object containing a single spectrum @rtype: C{SOM.SOM} @raise TypeError: Anything other than a C{SOM} is given @raise RuntimeError: An unknown rebinning dimension is given """ o_descr = hlr_utils.get_descr(obj) if o_descr != "SOM": raise TypeError("Function argument must be a SOM") # Have a SOM, go on else: pass # If there is only one SO, why run if len(obj) == 1: return obj # OK, we need to sum else: pass try: rebin_axis = kwargs["rebin_axis"] except KeyError: rebin_axis = None try: rebin_axis_dim = kwargs["rebin_axis_dim"] except KeyError: rebin_axis_dim = 1 try: y_sort = kwargs["y_sort"] except KeyError: y_sort = False try: stripe = kwargs["stripe"] except KeyError: stripe = False try: pix_fix = kwargs["pixel_fix"] except KeyError: pix_fix = None import common_lib if rebin_axis is not None: if rebin_axis_dim == 1: obj1 = common_lib.rebin_axis_1D(obj, rebin_axis) elif rebin_axis_dim == 2: obj1 = common_lib.rebin_axis_2D(obj, rebin_axis[0], rebin_axis[1]) else: raise RuntimeError("Do not have rebinning method for %dD." % \ rebin_axis_dim) else: obj1 = obj del obj # Sort SO IDs by y value if y_sort: obj1.sort(lambda x, y: cmp(x.id[1][1], y.id[1][1])) # SO IDs are already sorted by x value else: pass (result, res_descr) = hlr_utils.empty_result(obj1) result = hlr_utils.copy_som_attr(result, res_descr, obj1, o_descr) if not stripe: # iterate through the values so_id_list = [] val1 = hlr_utils.get_value(obj1, 0, o_descr, "all") val2 = hlr_utils.get_value(obj1, 1, o_descr, "all") value = common_lib.add_ncerr(val1, val2) so_id_list.append(val1.id) so_id_list.append(val2.id) for i in xrange(2, hlr_utils.get_length(obj1)): val = hlr_utils.get_value(obj1, i, o_descr, "all") value = common_lib.add_ncerr(val, value) so_id_list.append(val.id) hlr_utils.result_insert(result, res_descr, value, None, "all") result.attr_list["Summed IDs"] = so_id_list if pix_fix is not None: if y_sort: fixed_pixel = (so_id_list[0][0], (pix_fix, so_id_list[0][1][1])) else: fixed_pixel = (so_id_list[0][0], (so_id_list[0][1][0], pix_fix)) else: fixed_pixel = so_id_list[0] result[0].id = fixed_pixel else: # iterate through the values so_id_list = [] i_start = 0 stripe_count = 0 total_size = hlr_utils.get_length(obj1) while i_start < total_size: stripe_list = [] counted = 2 val1 = hlr_utils.get_value(obj1, i_start, o_descr, "all") val2 = hlr_utils.get_value(obj1, i_start + 1, o_descr, "all") value = common_lib.add_ncerr(val1, val2) stripe_list.append(val1.id) stripe_list.append(val2.id) if y_sort: comp_id = val2.id[1][1] else: comp_id = val2.id[1][0] for i in xrange(i_start + 2, total_size): val = hlr_utils.get_value(obj1, i, o_descr, "all") if y_sort: new_id = val.id[1][1] else: new_id = val.id[1][0] if new_id > comp_id: break value = common_lib.add_ncerr(val, value) stripe_list.append(val.id) counted += 1 i_start += counted so_id_list.append(stripe_list) hlr_utils.result_insert(result, res_descr, value, None, "all") if pix_fix is not None: try: if y_sort: fixed_pixel = (stripe_list[0][0], (pix_fix[stripe_count], stripe_list[0][1][1])) else: fixed_pixel = (stripe_list[0][0], (stripe_list[0][1][0], pix_fix[stripe_count])) except TypeError: if y_sort: fixed_pixel = (stripe_list[0][0], (pix_fix, stripe_list[0][1][1])) else: fixed_pixel = (stripe_list[0][0], (stripe_list[0][1][0], pix_fix)) else: fixed_pixel = stripe_list[0] result[stripe_count].id = fixed_pixel stripe_count += 1 result.attr_list["summed_ids"] = so_id_list return result
def div_ncerr(left, right, **kwargs): """ This function divides two objects (C{SOM}, C{SO} or {tuple(val,val_err2)}) and returns the result of the division in an C{SOM}, C{SO} or C{tuple}. @param left: Object on the left of the division sign @type left: C{SOM.SOM} or C{SOM.SO} or C{tuple} @param right: Object on the right of the division sign @type right: C{SOM.SOM} or C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword axis: This is the axis one wishes to manipulate. If no argument is given the default value is y @type axis: C{string}=<y or x> @keyword axis_pos: This is position of the axis in the axis array. If no argument is given, the default value is 0 @type axis_pos: C{int} @keyword length_one_som: This is a flag that lets the function know it is dealing with a length 1 C{SOM} so that attributes may be passed along. The length 1 C{SOM} will be turned into a C{SO}. The default value is False. @type length_one_som: C{boolean} @keyword length_one_som_pos: This is the argument position of the length 1 C{SOM} since division order is not commutative. The default value is 2. @type length_one_som_pos: C{int}=<1 or 2> @return: Object containing the results of the division @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise IndexError: The two C{SOM}s do not contain the same number of spectra @raise RunTimeError: The x-axis units of the C{SOM}s do not match @raise RunTimeError: The y-axis units of the C{SOM}s do not match @raise RunTimeError: The x-axes of the two C{SO}s are not equal """ # import the helper functions import hlr_utils # Check to see if we are working with a length 1 SOM try: length_one_som = kwargs["length_one_som"] except KeyError: length_one_som = False try: length_one_som_pos = kwargs["length_one_som_pos"] if length_one_som_pos != 1 or length_one_som_pos != 2: raise RuntimeError("length_one_som_pos must be either 1 or 2 and "\ +"%d" % length_one_som_pos) except KeyError: length_one_som_pos = 2 if length_one_som: if length_one_som_pos == 1: som_copy = left left = left[0] else: som_copy = right right = right[0] else: # Not working with a length 1 SOM, do nothing pass # set up for working through data (result, res_descr) = hlr_utils.empty_result(left, right) (l_descr, r_descr) = hlr_utils.get_descr(left, right) is_number = False # error check information if r_descr == "SOM" and l_descr == "SOM": hlr_utils.math_compatible(left, l_descr, right, r_descr) elif l_descr == "number" and r_descr == "number": is_number = True else: pass # Check for axis keyword argument try: axis = kwargs["axis"] except KeyError: axis = "y" # Check for axis_pos keyword argument try: axis_pos = kwargs["axis_pos"] except KeyError: axis_pos = 0 if length_one_som: if length_one_som_pos == 1: result = hlr_utils.copy_som_attr(result, res_descr, som_copy, "SOM", right, r_descr) else: result = hlr_utils.copy_som_attr(result, res_descr, left, l_descr, som_copy, "SOM") else: result = hlr_utils.copy_som_attr(result, res_descr, left, l_descr, right, r_descr) # iterate through the values import array_manip for i in xrange(hlr_utils.get_length(left, right)): val1 = hlr_utils.get_value(left, i, l_descr, axis, axis_pos) err2_1 = hlr_utils.get_err2(left, i, l_descr, axis, axis_pos) val2 = hlr_utils.get_value(right, i, r_descr, axis, axis_pos) err2_2 = hlr_utils.get_err2(right, i, r_descr, axis, axis_pos) (descr_1, descr_2)=hlr_utils.get_descr(val1, val2) hlr_utils.math_compatible(val1, descr_1, val2, descr_2) value = array_manip.div_ncerr(val1, err2_1, val2, err2_2) map_so = hlr_utils.get_map_so(left, right, i) hlr_utils.result_insert(result, res_descr, value, map_so, axis, axis_pos) if is_number: return tuple(result) else: return result
def tof_to_wavelength(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from time-of-flight to wavelength. The wavelength axis for a C{SOM} must be in units of I{microseconds}. The primary axis of a C{SO} is assumed to be in units of I{microseconds}. A C{tuple} of C{(tof, tof_err2)} (assumed to be in units of I{microseconds}) can be converted to C{(wavelength, wavelength_err2)}. @param obj: Object to be converted @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword pathlength: The pathlength and its associated error^2 @type pathlength: C{tuple} or C{list} of C{tuple}s @keyword inst_param: The type of parameter requested from an associated instrument. For this function the acceptable parameters are I{primary}, I{secondary} and I{total}. Default is I{primary}. @type inst_param: C{string} @keyword lojac: A flag that allows one to turn off the calculation of the linear-order Jacobian. The default action is I{True} for histogram data. @type lojac: C{boolean} @keyword units: The expected units for this function. The default for this function is I{microseconds}. @type units: C{string} @return: Object with a primary axis in time-of-flight converted to wavelength @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise TypeError: The incoming object is not a type the function recognizes @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds} @raise RuntimeError: A C{SOM} does not contain an instrument and no pathlength was provided @raise RuntimeError: No C{SOM} is provided and no pathlength given """ # import the helper functions import hlr_utils # set up for working through data (result, res_descr) = hlr_utils.empty_result(obj) o_descr = hlr_utils.get_descr(obj) # Setup keyword arguments try: inst_param = kwargs["inst_param"] except KeyError: inst_param = "primary" try: pathlength = kwargs["pathlength"] except KeyError: pathlength = None try: units = kwargs["units"] except KeyError: units = "microseconds" try: lojac = kwargs["lojac"] except KeyError: lojac = hlr_utils.check_lojac(obj) # Primary axis for transformation. If a SO is passed, the function, will # assume the axis for transformation is at the 0 position if o_descr == "SOM": axis = hlr_utils.one_d_units(obj, units) else: axis = 0 result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) if res_descr == "SOM": result = hlr_utils.force_units(result, "Angstroms", axis) result.setAxisLabel(axis, "wavelength") result.setYUnits("Counts/A") result.setYLabel("Intensity") else: pass if pathlength is not None: p_descr = hlr_utils.get_descr(pathlength) else: if o_descr == "SOM": try: obj.attr_list.instrument.get_primary() inst = obj.attr_list.instrument except RuntimeError: raise RuntimeError("A detector was not provided") else: raise RuntimeError("If no SOM is provided, then pathlength "\ +"information must be provided") # iterate through the values import axis_manip if lojac: import utils for i in xrange(hlr_utils.get_length(obj)): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) if pathlength is None: (pl, pl_err2) = hlr_utils.get_parameter(inst_param, map_so, inst) else: pl = hlr_utils.get_value(pathlength, i, p_descr) pl_err2 = hlr_utils.get_err2(pathlength, i, p_descr) value = axis_manip.tof_to_wavelength(val, err2, pl, pl_err2) if lojac: y_val = hlr_utils.get_value(obj, i, o_descr, "y") y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y") counts = utils.linear_order_jacobian(val, value[0], y_val, y_err2) hlr_utils.result_insert(result, res_descr, counts, map_so, "all", axis, [value[0]]) else: hlr_utils.result_insert(result, res_descr, value, map_so, "x", axis) return result
def add_ncerr(left, right, **kwargs): """ This function adds two objects (C{SOM}, C{SO} or C{tuple(val,val_err2)}) and returns the result of the addition in an C{SOM}, C{SO} or C{tuple}. @param left: Object on the left of the addition sign @type left: C{SOM.SOM} or C{SOM.SO} or C{tuple} @param right: Object on the right of the addition sign @type right: C{SOM.SOM} or C{SOM.SO} or C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword axis: This is the axis one wishes to manipulate. If no argument is given the default value is y @type axis: C{string}=<y or x> @keyword axis_pos: This is position of the axis in the axis array. If no argument is given, the default value is 0 @type axis_pos: C{int} @keyword length_one_som: This is a flag that lets the function know it is dealing with a length 1 C{SOM} so that attributes may be passed along. The length 1 C{SOM} will be turned into a C{SO}. The default value is False. @type length_one_som: C{boolean} @keyword length_one_som_pos: This is the argument position of the length 1 C{SOM} since the check is done before the arguments are swapped. The default value is 2. @type length_one_som_pos: C{int}=<1 or 2> @keyword add_nxpars: This is a flag that will turn on code to add C{SOM.NxParameters} in the two C{SOM}'s attribute lists. @type add_nxpars: C{boolean} @return: Object containing the results of the addition @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple} @raise IndexError: The two C{SOM}s do not contain the same number of spectra @raise RunTimeError: The x-axis units of the C{SOM}s do not match @raise RunTimeError: The y-axis units of the C{SOM}s do not match @raise RunTimeError: The x-axes of the two C{SO}s are not equal """ # import the helper functions import hlr_utils # Check to see if we are working with a length 1 SOM try: length_one_som = kwargs["length_one_som"] except KeyError: length_one_som = False try: length_one_som_pos = kwargs["length_one_som_pos"] if length_one_som_pos != 1 or length_one_som_pos != 2: raise RuntimeError("length_one_som_pos must be either 1 or 2 and "\ +"%d" % length_one_som_pos) except KeyError: length_one_som_pos = 2 if length_one_som: if length_one_som_pos == 1: som_copy = left left = left[0] else: som_copy = right right = right[0] else: # Not working with a length 1 SOM, do nothing pass # set up for working through data (result, res_descr) = hlr_utils.empty_result(left, right) (l_descr, r_descr) = hlr_utils.get_descr(left, right) is_number = False # error check information if (r_descr == "SOM" and l_descr != "SOM") \ or (r_descr == "SO" and l_descr == "number"): left, right = hlr_utils.swap_args(left, right) (l_descr, r_descr) = hlr_utils.swap_args(l_descr, r_descr) elif r_descr == "SOM" and l_descr == "SOM": hlr_utils.math_compatible(left, l_descr, right, r_descr) elif l_descr == "number" and r_descr == "number": is_number = True else: pass # Check for axis keyword argument try: axis = kwargs["axis"] except KeyError: axis = "y" # Check for axis_pos keyword argument try: axis_pos = kwargs["axis_pos"] except KeyError: axis_pos = 0 # Check for add_nxpars keyword argument try: add_nxpars_val = kwargs["add_nxpars"] except KeyError: add_nxpars_val = False if length_one_som: if length_one_som_pos == 1: result = hlr_utils.copy_som_attr(result, res_descr, som_copy, "SOM", right, r_descr) else: result = hlr_utils.copy_som_attr(result, res_descr, left, l_descr, som_copy, "SOM") else: result = hlr_utils.copy_som_attr(result, res_descr, left, l_descr, right, r_descr, add_nxpars=add_nxpars_val) # iterate through the values import array_manip for i in xrange(hlr_utils.get_length(left, right)): val1 = hlr_utils.get_value(left, i, l_descr, axis, axis_pos) err2_1 = hlr_utils.get_err2(left, i, l_descr, axis, axis_pos) val2 = hlr_utils.get_value(right, i, r_descr, axis, axis_pos) err2_2 = hlr_utils.get_err2(right, i, r_descr, axis, axis_pos) (descr_1, descr_2) = hlr_utils.get_descr(val1, val2) hlr_utils.math_compatible(val1, descr_1, val2, descr_2) value = array_manip.add_ncerr(val1, err2_1, val2, err2_2) map_so = hlr_utils.get_map_so(left, None, i) hlr_utils.result_insert(result, res_descr, value, map_so, axis, axis_pos) if is_number: return tuple(result) else: return result
def create_param_vs_Y(som, param, param_func, param_axis, **kwargs): """ This function takes a group of single spectrum with any given axes (wavelength, energy etc.). The function can optionally rebin those axes to a given axis. It then creates a 2D spectrum by using a parameter, parameter functiona and a given axis for the lookup locations and places each original spectrum in the found location. @param som: The input object with arbitrary (but same) axis spectra @type som: C{SOM.SOM} @param param: The parameter that will be used for creating the lookups. @type param: C{string} @param param_func: The function that will convert the parameter into the values for lookups. @type param_func: C{string} @param param_axis: The axis that will be searched for the lookup values. @type param_axis: C{nessi_list.NessiList} @param kwargs: A list of keyword arguments that the function accepts: @keyword rebin_axis: An axis to rebin the given spectra to. @type rebin_axis: C{nessi_list.NessiList} @keyword data_type: The name of the data type which can be either I{histogram}, I{density} or I{coordinate}. The default value will be I{histogram}. @type data_type: C{string} @keyword pixnorm: A flag to track the number of pixels that contribute to a bin and then normalize the bin by that number. @type pixnorm: C{boolean} @keyword prnorm: A parameter to track and determine a range (max - min) for each bin the requested parameter axis. The range will then be divided into the final summed spectrum for the given bin. @type prnorm: C{string} @keyword binnorm: A flag that turns on the scaling of each stripe of the y-axis by the individual bins widths from the y-axis. @type binnorm: C{boolean} @keyword so_id: The identifier represents a number, string, tuple or other object that describes the resulting C{SO}. @type so_id: C{int}, C{string}, C{tuple}, C{pixel ID} @keyword y_label: The dependent axis label @type y_label: C{string} @keyword y_units: The dependent axis units @type y_units: C{string} @keyword x_labels: The two independent axis labels @type x_labels: C{list} of C{string}s @keyword x_units: The two independent axis units @type x_units: C{list} of C{string}s @return: A two dimensional spectrum with the parameter as the x-axis and the given spectra axes as the y-axis. @rtype: C{SOM.SOM} """ import array_manip import dr_lib import hlr_utils import nessi_list import SOM import utils # Check for rebinning axis try: rebin_axis = kwargs["rebin_axis"] except KeyError: rebin_axis = None # Check for pixnorm flag try: pixnorm = kwargs["pixnorm"] except KeyError: pixnorm = False try: binnorm = kwargs["binnorm"] except KeyError: binnorm = False # Check for prnorm flag try: prpar = kwargs["prnorm"] prnorm = True except KeyError: prnorm = False # Check dataType keyword argument. An offset will be set to 1 for the # histogram type and 0 for either density or coordinate try: data_type = kwargs["data_type"] if data_type.lower() == "histogram": offset = 1 elif data_type.lower() == "density" or \ data_type.lower() == "coordinate": offset = 0 else: raise RuntimeError("Do not understand data type given: %s" % \ data_type) # Default is offset for histogram except KeyError: offset = 1 # Setup some variables dim = 2 N_tot = 1 # Create 2D spectrum object so_dim = SOM.SO(dim) # Set the axis locations param_axis_loc = 0 arb_axis_loc = 1 # Rebin original data to rebin_axis if necessary if rebin_axis is not None: (som1, som2) = dr_lib.rebin_axis_1D_frac(som, rebin_axis) len_arb_axis = len(rebin_axis) - offset so_dim.axis[arb_axis_loc].val = rebin_axis else: som1 = som len_arb_axis = len(som[0].axis[0].val) - offset so_dim.axis[arb_axis_loc].val = som[0].axis[0].val del som # Get parameter axis information len_param_axis = len(param_axis) - offset so_dim.axis[param_axis_loc].val = param_axis if pixnorm: pixarr = nessi_list.NessiList(len_param_axis) if prnorm: prarr = [] for i in xrange(len_param_axis): prarr.append(nessi_list.NessiList()) # Get the parameters for all the spectra ppfunc = hlr_utils.__getattribute__("param_array") prarr_lookup = ppfunc(som1, prpar) # Get the parameter lookup array pfunc = hlr_utils.__getattribute__(param_func) lookup_array = pfunc(som1, param) # Create y and var_y lists from total 2D size N_tot = len_param_axis * len_arb_axis so_dim.y = nessi_list.NessiList(N_tot) so_dim.var_y = nessi_list.NessiList(N_tot) if rebin_axis is not None: frac_area = nessi_list.NessiList(N_tot) frac_area_err2 = nessi_list.NessiList(N_tot) # Loop through data and create 2D spectrum len_som = hlr_utils.get_length(som1) for i in xrange(len_som): val = hlr_utils.get_value(som1, i, "SOM", "y") err2 = hlr_utils.get_err2(som1, i, "SOM", "y") bin_index = utils.bisect_helper(param_axis, lookup_array[i]) start = bin_index * len_arb_axis if pixnorm: pixarr[bin_index] += 1 if prnorm: prarr[bin_index].append(prarr_lookup[i]) (so_dim.y, so_dim.var_y) = array_manip.add_ncerr(so_dim.y, so_dim.var_y, val, err2, a_start=start) if rebin_axis is not None: val1 = hlr_utils.get_value(som2, i, "SOM", "y") err1_2 = hlr_utils.get_err2(som2, i, "SOM", "y") (frac_area, frac_area_err2) = array_manip.add_ncerr(frac_area, frac_area_err2, val1, err1_2, a_start=start) if rebin_axis is not None: (so_dim.y, so_dim.var_y) = array_manip.div_ncerr(so_dim.y, so_dim.var_y, frac_area, frac_area_err2) # If parameter range normalization enabled, find the range for the # parameter if prnorm: import math prrange = nessi_list.NessiList(len_param_axis) for i in xrange(len(prrange)): try: max_val = max(prarr[i]) except ValueError: max_val = 0.0 try: min_val = min(prarr[i]) except ValueError: min_val = 0.0 prrange[i] = math.fabs(max_val - min_val) # If pixel normalization tracking enabled, divided slices by pixel counts if pixnorm or prnorm: tmp_y = nessi_list.NessiList(N_tot) tmp_var_y = nessi_list.NessiList(N_tot) for i in range(len_param_axis): start = i * len_arb_axis end = (i + 1) * len_arb_axis slice_y = so_dim.y[start:end] slice_var_y = so_dim.var_y[start:end] divconst = 1.0 if pixnorm: divconst *= pixarr[i] # Scale division constant if parameter range normalization enabled if prnorm: divconst *= prrange[i] (dslice_y, dslice_var_y) = array_manip.div_ncerr(slice_y, slice_var_y, divconst, 0.0) (tmp_y, tmp_var_y) = array_manip.add_ncerr(tmp_y, tmp_var_y, dslice_y, dslice_var_y, a_start=start) so_dim.y = tmp_y so_dim.var_y = tmp_var_y if binnorm: tmp_y = nessi_list.NessiList(N_tot) tmp_var_y = nessi_list.NessiList(N_tot) if rebin_axis is not None: bin_const = utils.calc_bin_widths(rebin_axis) else: bin_const = utils.calc_bin_widths(som1[0].axis[1].val) for i in range(len_param_axis): start = i * len_arb_axis end = (i + 1) * len_arb_axis slice_y = so_dim.y[start:end] slice_var_y = so_dim.var_y[start:end] (dslice_y, dslice_var_y) = array_manip.mult_ncerr(slice_y, slice_var_y, bin_const[0], bin_const[1]) (tmp_y, tmp_var_y) = array_manip.add_ncerr(tmp_y, tmp_var_y, dslice_y, dslice_var_y, a_start=start) so_dim.y = tmp_y so_dim.var_y = tmp_var_y # Create final 2D spectrum object container comb_som = SOM.SOM() comb_som.copyAttributes(som1) del som1 # Check for so_id keyword argument try: so_dim.id = kwargs["so_id"] except KeyError: so_dim.id = 0 # Check for y_label keyword argument try: comb_som.setYLabel(kwargs["y_label"]) except KeyError: comb_som.setYLabel("Counts") # Check for y_units keyword argument try: comb_som.setYUnits(kwargs["y_units"]) except KeyError: comb_som.setYUnits("Counts / Arb") # Check for x_label keyword argument try: comb_som.setAllAxisLabels(kwargs["x_labels"]) except KeyError: comb_som.setAllAxisLabels(["Parameter", "Arbitrary"]) # Check for x_units keyword argument try: comb_som.setAllAxisUnits(kwargs["x_units"]) except KeyError: comb_som.setAllAxisUnits(["Arb", "Arb"]) comb_som.append(so_dim) del so_dim return comb_som