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 integrate_spectra_py(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: Index of the starting bin @type start: C{int} @keyword end: Index of the ending bin. This index is made inclusive by the 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 bin_index: This is a flag to say that the values in the start and end keyword arguments are either bin indicies (I{True}) or bounds (I{False}). The default value is I{False}. @type bin_index: C{boolean} @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) # Create temporary object to access axis if o_descr == "SOM": aobj = obj[0] elif o_descr == "SO": aobj = obj # Check for axis_pos keyword argument try: axis_pos = kwargs["axis_pos"] except KeyError: axis_pos = 0 # Check for bin_index keyword argument try: bin_index = kwargs["bin_index"] except KeyError: bin_index = False # 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, assume the 1st bin try: i_start = kwargs["start"] except KeyError: if bin_index: i_start = 0 else: i_start = aobj.axis[axis_pos].val[0] # If the integration end bound is not given, assume the last bin try: i_end = kwargs["end"] except KeyError: if bin_index: i_end = -1 else: i_end = aobj.axis[axis_pos].val[-1] # iterate through the values import bisect import dr_lib for i in xrange(hlr_utils.get_length(obj)): obj1 = hlr_utils.get_value(obj, i, o_descr, "all") # Find the bin in the y values corresponding to the start bound if not bin_index: b_start = bisect.bisect(obj1.axis[axis_pos].val, i_start) - 1 else: b_start = i_start # Find the bin in the y values corresponding to the end bound if not bin_index: b_end = bisect.bisect(obj1.axis[axis_pos].val, i_end) - 1 else: b_end = i_end try: value = dr_lib.integrate_axis_py(obj1, start=b_start, end=b_end, width=width) except IndexError: print "Range not found:", obj1.id, b_start, b_end, len(obj1) value = (float('nan'), float('nan')) 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 process_ref_data(datalist, conf, signal_roi_file, bkg_roi_file=None, no_bkg=False, **kwargs): """ This function combines Steps 1 through 6 in section 2.4.5 of the data reduction process for Reflectometers (without Monitors) as specified by the document at U{http://neutrons.ornl.gov/asg/projects/SCL/reqspec/DR_Lib_RS.doc}. The function takes a list of file names, a L{hlr_utils.Configure} object, signal and background region-of-interest (ROI) files and an optional flag about background subtraction and processes the data accordingly. @param datalist: The filenames of the data to be processed @type datalist: C{list} of C{string}s @param conf: Object that contains the current setup of the driver @type conf: L{hlr_utils.Configure} @param signal_roi_file: The file containing the list of pixel IDs for the signal region of interest. @type signal_roi_file: C{string} @param bkg_roi_file: The file containing the list of pixel IDs for the (possible) background region of interest. @type bkg_roi_file: C{string} @param no_bkg: (OPTIONAL) Flag which determines if the background will be calculated and subtracted. @type no_bkg: C{boolean} @param kwargs: A list of keyword arguments that the function accepts: @keyword inst_geom_dst: Object that contains the instrument geometry information. @type inst_geom_dst: C{DST.getInstance()} @keyword dataset_type: The practical name of the dataset being processed. The default value is I{data}. @type dataset_type: C{string} @keyword tof_cuts: Time-of-flight bins to remove (zero) from the data @type tof_cuts: C{list} of C{string}s @keyword no_tof_cuts: Flag to stop application of the TOF cuts @type no_tof_cuts: C{boolean} @keyword timer: Timing object so the function can perform timing estimates. @type timer: C{sns_timer.DiffTime} @return: Object that has undergone all requested processing steps @rtype: C{SOM.SOM} """ import common_lib import dr_lib import hlr_utils # Check keywords try: dataset_type = kwargs["dataset_type"] except KeyError: dataset_type = "data" if dataset_type != "data" and dataset_type != "norm": raise RuntimeError("Please use data or norm to specify the dataset "\ +"type. Do not understand how to handle %s." \ % dataset_type) try: t = kwargs["timer"] except KeyError: t = None try: i_geom_dst = kwargs["inst_geom_dst"] except KeyError: i_geom_dst = None try: tof_cuts = kwargs["tof_cuts"] except KeyError: tof_cuts = None no_tof_cuts = kwargs.get("no_tof_cuts", False) so_axis = "time_of_flight" # Step 0: Open data files and select signal (and possible background) ROIs if conf.verbose: print "Reading %s file" % dataset_type if len(conf.norm_data_paths) and dataset_type == "norm": data_path = conf.norm_data_paths.toPath() else: data_path = conf.data_paths.toPath() (d_som1, b_som1) = dr_lib.add_files_bg(datalist, Data_Paths=data_path, SO_Axis=so_axis, dataset_type=dataset_type, Signal_ROI=signal_roi_file, Bkg_ROI=bkg_roi_file, Verbose=conf.verbose, Timer=t) if t is not None: t.getTime(msg="After reading %s " % dataset_type) if i_geom_dst is not None: i_geom_dst.setGeometry(conf.data_paths.toPath(), d_som1) # Calculate delta t over t if conf.verbose: print "Calculating delta t over t" dtot = dr_lib.calc_deltat_over_t(d_som1[0].axis[0].val) # Calculate delta theta over theta if conf.verbose: print "Calculating delta theta over theta" dr_lib.calc_delta_theta_over_theta(d_som1, dataset_type) # Step 1: Sum all spectra along the low resolution direction # Set sorting (y_sort, cent_pixel) = hlr_utils.get_ref_integration_direction( conf.int_dir, conf.inst, d_som1.attr_list.instrument) if dataset_type == "data": d_som1.attr_list["ref_sort"] = y_sort d_som1A = dr_lib.sum_all_spectra(d_som1, y_sort=y_sort, stripe=True, pixel_fix=cent_pixel) del d_som1 if b_som1 is not None: b_som1A = dr_lib.sum_all_spectra(b_som1, y_sort=y_sort, stripe=True, pixel_fix=cent_pixel) del b_som1 else: b_som1A = b_som1 # Set the TOF cuts if no_tof_cuts: tof_cut_min = None tof_cut_max = None else: tof_cut_min = conf.tof_cut_min tof_cut_max = conf.tof_cut_max # Cut the spectra if necessary d_som2 = dr_lib.cut_spectra(d_som1A, tof_cut_min, tof_cut_max) del d_som1A if b_som1A is not None: b_som2 = dr_lib.cut_spectra(b_som1A, tof_cut_min, tof_cut_max) del b_som1A else: b_som2 = b_som1A # Fix TOF cuts to make them list of integers try: tof_cuts = [int(x) for x in tof_cuts] # This will trigger if tof_cuts is None except TypeError: pass d_som3 = dr_lib.zero_bins(d_som2, tof_cuts) del d_som2 if b_som2 is not None: b_som3 = dr_lib.zero_bins(b_som2, tof_cuts) del b_som2 else: b_som3 = b_som2 if conf.dump_specular: if no_tof_cuts: d_som3_1 = dr_lib.cut_spectra(d_som3, conf.tof_cut_min, conf.tof_cut_max) else: d_som3_1 = d_som3 hlr_utils.write_file(conf.output, "text/Spec", d_som3_1, output_ext="sdc", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="specular TOF information") del d_som3_1 # Steps 2-4: Determine background spectrum if conf.verbose and not no_bkg: print "Determining %s background" % dataset_type if dataset_type == "data": peak_excl = conf.data_peak_excl elif dataset_type == "norm": peak_excl = conf.norm_peak_excl if b_som3 is not None: B = dr_lib.calculate_ref_background(b_som3, no_bkg, conf.inst, None, aobj=d_som3) else: B = dr_lib.calculate_ref_background(d_som3, no_bkg, conf.inst, peak_excl) if t is not None: t.getTime(msg="After background determination") if not no_bkg and conf.dump_bkg: if no_tof_cuts: B_1 = dr_lib.cut_spectra(B, conf.tof_cut_min, conf.tof_cut_max) else: B_1 = B hlr_utils.write_file(conf.output, "text/Spec", B_1, output_ext="bkg", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="background TOF information") del B_1 # Step 5: Subtract background spectrum from data spectra if not no_bkg: d_som4 = dr_lib.subtract_bkg_from_data(d_som3, B, verbose=conf.verbose, timer=t, dataset1="data", dataset2="background") else: d_som4 = d_som3 del d_som3 if not no_bkg and conf.dump_sub: if no_tof_cuts: d_som4_1 = dr_lib.cut_spectra(d_som4, conf.tof_cut_min, conf.tof_cut_max) else: d_som4_1 = d_som4 hlr_utils.write_file(conf.output, "text/Spec", d_som4_1, output_ext="sub", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="subtracted TOF information") del d_som4_1 dtot_int = dr_lib.integrate_axis_py(dtot, avg=True) param_key = dataset_type + "-dt_over_t" d_som4.attr_list[param_key] = dtot_int[0] if conf.store_dtot: d_som4.attr_list["extra_som"] = dtot # Step 6: Scale by proton charge pc = d_som4.attr_list[dataset_type + "-proton_charge"] pc_new = hlr_utils.scale_proton_charge(pc, "C") d_som5 = common_lib.div_ncerr(d_som4, (pc_new.getValue(), 0.0)) del d_som4 return d_som5