def __write_output(som, conf, t, ot): """ This is private helper function for writing the output to a file @param som: The object to be written to file. @type som: C{SOM.SOM} @param conf: The current driver configuration object. @type conf: L{hlr_utils.Configure} @param t: The current timing object. @type t: C{sns_timing.DiffTime} @param ot: The origianl timing object. @type ot: C{sns_timing.DiffTime} """ # Get file comments if present try: file_comments = conf.comments del conf.comments except AttributeError: file_comments = None # Writing 2D DAVE file if not conf.split: hlr_utils.write_file(conf.output, "text/Dave2d", som, verbose=conf.verbose, message="data", comments=file_comments, replace_path=False, replace_ext=False) som.attr_list["config"] = conf hlr_utils.write_file(conf.output, "text/rmd", som, output_ext="rmd", data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, verbose=conf.verbose, message="metadata") if t is not None: t.setOldTime(ot) t.getTime(msg="Total Running Time")
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 process_sas_data(datalist, conf, **kwargs): """ This function combines Steps 1 through 9 of the data reduction process for Small-Angle Scattering section 2.5.1 as specified by the documents 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 and processes the data accordingly. This function should really only be used in the context of I{sas_reduction}. @param datalist: A list containing 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 kwargs: A list of keyword arguments that the function accepts: @keyword inst_geom_dst: File object that contains instrument geometry information. @type inst_geom_dst: C{DST.GeomDST} @keyword dataset_type: The practical name of the dataset being processed. The default value is I{data}. @type dataset_type: C{string} @keyword trans_data: Alternate data for the transmission spectrum. This is used in the absence of transmission monitors. @type trans_data: C{string} @keyword transmission: A flag that signals the function to stop after doing the conversion from TOF to wavelength. The default is I{False}. @type transmission: C{boolean} @keyword bkg_subtract: A list of coefficients that help determine the wavelength dependent background subtraction. @type bkg_subtract: C{list} @keyword get_background: A flag that signals the function to convert the main data to wavelength and exit before normalizing to the beam monitor. @type get_background: C{boolean} @keyword acc_down_time: The information for the accelerator downtime. @type acc_down_time: C{tuple} @keyword bkg_scale: The scaling used for the axis dependent background parameters. @type bkg_scale: C{float} @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" try: i_geom_dst = kwargs["inst_geom_dst"] except KeyError: i_geom_dst = None try: t = kwargs["timer"] except KeyError: t = None try: transmission = kwargs["transmission"] except KeyError: transmission = False try: bkg_subtract = kwargs["bkg_subtract"] except KeyError: bkg_subtract = None try: trans_data = kwargs["trans_data"] except KeyError: trans_data = None try: get_background = kwargs["get_background"] except KeyError: get_background = False acc_down_time = kwargs.get("acc_down_time") bkg_scale = kwargs.get("bkg_scale") # Add so_axis to Configure object conf.so_axis = "time_of_flight" # Step 0: Open appropriate data files # Data if conf.verbose: print "Reading %s file" % dataset_type # The [0] is to get the data SOM and ignore the None background SOM dp_som = dr_lib.add_files(datalist, Data_Paths=conf.data_paths.toPath(), SO_Axis=conf.so_axis, Signal_ROI=conf.roi_file, dataset_type=dataset_type, Verbose=conf.verbose, Timer=t) if t is not None: t.getTime(msg="After reading %s " % dataset_type) dp_som1 = dr_lib.fix_bin_contents(dp_som) del dp_som if conf.inst_geom is not None: i_geom_dst.setGeometry(conf.data_paths.toPath(), dp_som1) if conf.dump_tof_r: dp_som1_1 = dr_lib.create_param_vs_Y(dp_som1, "radius", "param_array", conf.r_bins.toNessiList(), y_label="counts", y_units="counts / (usec * m)", x_labels=["Radius", "TOF"], x_units=["m", "usec"]) hlr_utils.write_file(conf.output, "text/Dave2d", dp_som1_1, output_ext="tvr", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="TOF vs radius information") del dp_som1_1 if conf.dump_tof_theta: dp_som1_1 = dr_lib.create_param_vs_Y(dp_som1, "polar", "param_array", conf.theta_bins.toNessiList(), y_label="counts", y_units="counts / (usec * rads)", x_labels=["Polar Angle", "TOF"], x_units=["rads", "usec"]) hlr_utils.write_file(conf.output, "text/Dave2d", dp_som1_1, output_ext="tvt", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="TOF vs polar angle information") del dp_som1_1 # Beam monitor if not get_background: if conf.beammon_over is None: if conf.verbose: print "Reading in beam monitor data from %s file" \ % dataset_type # The [0] is to get the data SOM and ignore the None # background SOM dbm_som0 = dr_lib.add_files(datalist, Data_Paths=conf.bmon_path.toPath(), SO_Axis=conf.so_axis, dataset_type=dataset_type, Verbose=conf.verbose, Timer=t) if t is not None: t.getTime(msg="After reading beam monitor data ") if conf.inst_geom is not None: i_geom_dst.setGeometry(conf.bmon_path.toPath(), dbm_som0) else: if conf.verbose: print "Reading in vanadium data" dbm_som0 = dr_lib.add_files(datalist, Data_Paths=conf.data_paths.toPath(), Signal_ROI=conf.roi_file, SO_Axis=conf.so_axis, dataset_type=dataset_type, Verbose=conf.verbose, Timer=t) if t is not None: t.getTime(msg="After reading vanadium data ") if conf.inst_geom is not None: i_geom_dst.setGeometry(conf.data_paths.toPath(), dbm_som0) dbm_som1 = dr_lib.fix_bin_contents(dbm_som0) del dbm_som0 else: dbm_som1 = None # Transmission monitor if trans_data is None: if conf.verbose: print "Reading in transmission monitor data from %s file" \ % dataset_type try: dtm_som0 = dr_lib.add_files(datalist, Data_Paths=conf.tmon_path.toPath(), SO_Axis=conf.so_axis, dataset_type=dataset_type, Verbose=conf.verbose, Timer=t) if t is not None: t.getTime(msg="After reading transmission monitor data ") if conf.inst_geom is not None: i_geom_dst.setGeometry(conf.tmon_path.toPath(), dtm_som0) dtm_som1 = dr_lib.fix_bin_contents(dtm_som0) del dtm_som0 # Transmission monitor cannot be found except KeyError: if conf.verbose: print "Transmission monitor not found" dtm_som1 = None else: dtm_som1 = None # Note: time_zero_offset_det MUST be a tuple if conf.time_zero_offset_det is not None: dp_som1.attr_list["Time_zero_offset_det"] = \ conf.time_zero_offset_det.toValErrTuple() # Note: time_zero_offset_mon MUST be a tuple if conf.time_zero_offset_mon is not None and not get_background and \ conf.beammon_over is None: dbm_som1.attr_list["Time_zero_offset_mon"] = \ conf.time_zero_offset_mon.toValErrTuple() if conf.beammon_over is not None: dbm_som1.attr_list["Time_zero_offset_det"] = \ conf.time_zero_offset_det.toValErrTuple() if trans_data is None and dtm_som1 is not None: dtm_som1.attr_list["Time_zero_offset_mon"] = \ conf.time_zero_offset_mon.toValErrTuple() # Step 1: Convert TOF to wavelength for data and monitor if conf.verbose: print "Converting TOF to wavelength" if t is not None: t.getTime(False) if not get_background: # Convert beam monitor if conf.beammon_over is None: dbm_som2 = common_lib.tof_to_wavelength_lin_time_zero( dbm_som1, units="microsecond", time_zero_offset=conf.time_zero_offset_mon.toValErrTuple()) else: dbm_som2 = common_lib.tof_to_wavelength_lin_time_zero( dbm_som1, units="microsecond", time_zero_offset=conf.time_zero_offset_det.toValErrTuple(), inst_param="total") else: dbm_som2 = None # Convert detector pixels dp_som2 = common_lib.tof_to_wavelength_lin_time_zero( dp_som1, units="microsecond", time_zero_offset=conf.time_zero_offset_det.toValErrTuple(), inst_param="total") if get_background: return dp_som2 if dtm_som1 is not None: # Convert transmission monitor dtm_som2 = common_lib.tof_to_wavelength_lin_time_zero( dtm_som1, units="microsecond", time_zero_offset=conf.time_zero_offset_mon.toValErrTuple()) else: dtm_som2 = dtm_som1 if t is not None: t.getTime(msg="After converting TOF to wavelength ") del dp_som1, dbm_som1, dtm_som1 if conf.verbose and (conf.lambda_low_cut is not None or \ conf.lambda_high_cut is not None): print "Cutting data spectra" if t is not None: t.getTime(False) dp_som3 = dr_lib.cut_spectra(dp_som2, conf.lambda_low_cut, conf.lambda_high_cut) if t is not None: t.getTime(msg="After cutting data spectra ") del dp_som2 if conf.beammon_over is not None: dbm_som2 = dr_lib.cut_spectra(dbm_som2, conf.lambda_low_cut, conf.lambda_high_cut) if conf.dump_wave: hlr_utils.write_file(conf.output, "text/Spec", dp_som3, output_ext="pxl", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="pixel wavelength information") if conf.dump_bmon_wave: if conf.beammon_over is None: hlr_utils.write_file(conf.output, "text/Spec", dbm_som2, output_ext="bmxl", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="beam monitor wavelength information") else: dbm_som2_1 = dr_lib.sum_by_rebin_frac(dbm_som2, conf.lambda_bins.toNessiList()) hlr_utils.write_file(conf.output, "text/Spec", dbm_som2_1, output_ext="bmxl", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="beam monitor override wavelength "\ +"information") del dbm_som2_1 # Step 2: Subtract wavelength dependent background if necessary if conf.verbose and bkg_subtract is not None: print "Subtracting wavelength dependent background" if bkg_subtract is not None: if t is not None: t.getTime(False) duration = dp_som3.attr_list["%s-duration" % dataset_type] scale = duration.getValue() - acc_down_time[0] dp_som4 = dr_lib.subtract_axis_dep_bkg(dp_som3, bkg_subtract, old_scale=bkg_scale, new_scale=scale) if t is not None: t.getTime(msg="After subtracting wavelength dependent background ") else: dp_som4 = dp_som3 del dp_som3 # Step 3: Efficiency correct beam monitor if conf.verbose and conf.mon_effc: print "Efficiency correct beam monitor data" if t is not None: t.getTime(False) if conf.mon_effc: dbm_som3 = dr_lib.feff_correct_mon(dbm_som2, inst_name=conf.inst, eff_const=conf.mon_eff_const) else: dbm_som3 = dbm_som2 if t is not None and conf.mon_effc: t.getTime(msg="After efficiency correcting beam monitor ") if conf.dump_bmon_effc and conf.mon_effc: hlr_utils.write_file(conf.output, "text/Spec", dbm_som3, output_ext="bmel", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="beam monitor wavelength information "\ +"(efficiency)") del dbm_som2 # Step 4: Efficiency correct transmission monitor if dtm_som2 is not None: if conf.verbose and conf.mon_effc: print "Efficiency correct transmission monitor data" if t is not None: t.getTime(False) if conf.mon_effc: dtm_som3 = dr_lib.feff_correct_mon(dtm_som2) else: dtm_som3 = dtm_som2 else: dtm_som3 = dtm_som2 if t is not None and conf.mon_effc and dtm_som2 is not None: t.getTime(msg="After efficiency correcting beam monitor ") # Step 5: Efficiency correct detector pixels if conf.det_effc: if conf.verbose: print "Calculating detector efficiency" if t is not None: t.getTime(False) det_eff = dr_lib.create_det_eff(dp_som4, inst_name=conf.inst, eff_scale_const=conf.det_eff_scale_const, eff_atten_const=conf.det_eff_atten_const) if t is not None: t.getTime(msg="After calculating detector efficiency") if conf.verbose: print "Applying detector efficiency" if t is not None: t.getTime(False) dp_som5 = common_lib.div_ncerr(dp_som4, det_eff) if t is not None: t.getTime(msg="After spplying detector efficiency") else: dp_som5 = dp_som4 del dp_som4 # Step 6: Rebin beam monitor axis onto detector pixel axis if conf.beammon_over is None: if not conf.no_bmon_norm: if conf.verbose: print "Rebin beam monitor axis to detector pixel axis" if t is not None: t.getTime(False) dbm_som4 = dr_lib.rebin_monitor(dbm_som3, dp_som5, rtype="frac") if t is not None: t.getTime(msg="After rebinning beam monitor ") else: dbm_som4 = dbm_som3 else: dbm_som4 = dbm_som3 del dbm_som3 if conf.dump_bmon_rebin: hlr_utils.write_file(conf.output, "text/Spec", dbm_som4, output_ext="bmrl", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="beam monitor wavelength information "\ +"(rebinned)") # Step 7: Normalize data by beam monitor if not conf.no_bmon_norm: if conf.verbose: print "Normalizing data by beam monitor" if t is not None: t.getTime(False) dp_som6 = common_lib.div_ncerr(dp_som5, dbm_som4) if t is not None: t.getTime(msg="After normalizing data by beam monitor ") else: dp_som6 = dp_som5 del dp_som5 if transmission: return dp_som6 if conf.dump_wave_bmnorm: dp_som6_1 = dr_lib.sum_by_rebin_frac(dp_som6, conf.lambda_bins.toNessiList()) write_message = "combined pixel wavelength information" write_message += " (beam monitor normalized)" hlr_utils.write_file(conf.output, "text/Spec", dp_som6_1, output_ext="pbml", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message=write_message) del dp_som6_1 if conf.dump_wave_r: dp_som6_1 = dr_lib.create_param_vs_Y(dp_som6, "radius", "param_array", conf.r_bins.toNessiList(), rebin_axis=conf.lambda_bins.toNessiList(), y_label="counts", y_units="counts / (Angstrom * m)", x_labels=["Radius", "Wavelength"], x_units=["m", "Angstrom"]) hlr_utils.write_file(conf.output, "text/Dave2d", dp_som6_1, output_ext="lvr", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="wavelength vs radius information") del dp_som6_1 if conf.dump_wave_theta: dp_som6_1 = dr_lib.create_param_vs_Y(dp_som6, "polar", "param_array", conf.theta_bins.toNessiList(), rebin_axis=conf.lambda_bins.toNessiList(), y_label="counts", y_units="counts / (Angstrom * rads)", x_labels=["Polar Angle", "Wavelength"], x_units=["rads", "Angstrom"]) hlr_utils.write_file(conf.output, "text/Dave2d", dp_som6_1, output_ext="lvt", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="wavelength vs polar angle information") del dp_som6_1 # Step 8: Rebin transmission monitor axis onto detector pixel axis if trans_data is not None: print "Reading in transmission monitor data from file" dtm_som3 = dr_lib.add_files([trans_data], dataset_type=dataset_type, dst_type="text/Spec", Verbose=conf.verbose, Timer=t) if conf.verbose and dtm_som3 is not None: print "Rebin transmission monitor axis to detector pixel axis" if t is not None: t.getTime(False) dtm_som4 = dr_lib.rebin_monitor(dtm_som3, dp_som6, rtype="frac") if t is not None and dtm_som3 is not None: t.getTime(msg="After rebinning transmission monitor ") del dtm_som3 # Step 9: Normalize data by transmission monitor if conf.verbose and dtm_som4 is not None: print "Normalizing data by transmission monitor" if t is not None: t.getTime(False) if dtm_som4 is not None: # The transmission spectra derived from sas_tranmission does not have # the same y information by convention as sample data or a # tranmission monitor. Therefore, we'll fake it by setting the # y information from the sample data into the transmission if trans_data is not None: dtm_som4.setYLabel(dp_som6.getYLabel()) dtm_som4.setYUnits(dp_som6.getYUnits()) dp_som7 = common_lib.div_ncerr(dp_som6, dtm_som4) else: dp_som7 = dp_som6 if t is not None and dtm_som4 is not None: t.getTime(msg="After normalizing data by transmission monitor ") del dp_som6 # Step 10: Convert wavelength to Q for data if conf.verbose: print "Converting data from wavelength to scalar Q" if t is not None: t.getTime(False) dp_som8 = common_lib.wavelength_to_scalar_Q(dp_som7) if t is not None: t.getTime(msg="After converting wavelength to scalar Q ") del dp_som7 if conf.facility == "LENS": # Step 11: Apply SAS correction factor to data if conf.verbose: print "Applying geometrical correction" if t is not None: t.getTime(False) dp_som9 = dr_lib.apply_sas_correct(dp_som8) if t is not None: t.getTime(msg="After applying geometrical correction ") return dp_som9 else: return dp_som8
def run(config, tim=None): """ This method is where the data reduction process gets done. @param config: Object containing the data reduction configuration information. @type config: L{hlr_utils.Configure} @param tim: (OPTIONAL) Object that will allow the method to perform timing evaluations. @type tim: C{sns_time.DiffTime} """ import common_lib import dr_lib import DST if tim is not None: tim.getTime(False) old_time = tim.getOldTime() if config.data is None: raise RuntimeError("Need to pass a data filename to the driver "\ +"script.") # Read in geometry if one is provided if config.inst_geom is not None: if config.verbose: print "Reading in instrument geometry file" inst_geom_dst = DST.getInstance("application/x-NxsGeom", config.inst_geom) else: inst_geom_dst = None # Perform early background subtraction if the hwfix flag is used if config.hwfix: if not config.mc: so_axis = "time_of_flight" else: so_axis = "Time_of_Flight" bkg_som0 = dr_lib.add_files(config.back, Data_Paths=config.data_paths.toPath(), SO_Axis=so_axis, Signal_ROI=config.roi_file, dataset_type="background", Verbose=config.verbose, Timer=tim) bkg_som = dr_lib.fix_bin_contents(bkg_som0) del bkg_som0 else: bkg_som = None # Perform Steps 1-15 on sample data d_som1 = dr_lib.process_igs_data(config.data, config, timer=tim, inst_geom_dst=inst_geom_dst, tib_const=config.tib_data_const, bkg_som=bkg_som) # Perform Steps 1-15 on empty can data if config.ecan is not None: e_som1 = dr_lib.process_igs_data(config.ecan, config, timer=tim, inst_geom_dst=inst_geom_dst, dataset_type="empty_can", tib_const=config.tib_ecan_const, bkg_som=bkg_som) else: e_som1 = None # Perform Steps 1-15 on normalization data if config.norm is not None: n_som1 = dr_lib.process_igs_data(config.norm, config, timer=tim, inst_geom_dst=inst_geom_dst, dataset_type="normalization", tib_const=config.tib_norm_const, bkg_som=bkg_som) else: n_som1 = None # Perform Steps 1-15 on background data if config.back is not None: b_som1 = dr_lib.process_igs_data(config.back, config, timer=tim, inst_geom_dst=inst_geom_dst, dataset_type="background", tib_const=config.tib_back_const, bkg_som=bkg_som) else: b_som1 = None # Perform Step 1-15 on direct scattering background data if config.dsback is not None: ds_som1 = dr_lib.process_igs_data(config.dsback, config, timer=tim, inst_geom_dst=inst_geom_dst, tib_const=config.tib_dsback_const, dataset_type="dsbackground", bkg_som=bkg_som) # Note: time_zero_slope MUST be a tuple if config.time_zero_slope is not None: ds_som1.attr_list["Time_zero_slope"] = \ config.time_zero_slope.toValErrTuple() # Note: time_zero_offset MUST be a tuple if config.time_zero_offset is not None: ds_som1.attr_list["Time_zero_offset"] = \ config.time_zero_offset.toValErrTuple() # Step 16: Linearly interpolate TOF elastic range in direct scattering # background data # First convert TOF elastic range to appropriate pixel initial # wavelengths if config.verbose: print "Determining initial wavelength range for elastic line" if tim is not None: tim.getTime(False) if config.tof_elastic is None: # Units are in microseconds tof_elastic_range = (140300, 141300) else: tof_elastic_range = config.tof_elastic ctof_elastic_low = dr_lib.convert_single_to_list(\ "tof_to_initial_wavelength_igs_lin_time_zero", (tof_elastic_range[0], 0.0), ds_som1) ctof_elastic_high = dr_lib.convert_single_to_list(\ "tof_to_initial_wavelength_igs_lin_time_zero", (tof_elastic_range[1], 0.0), ds_som1) ctof_elastic_range = [(ctof_elastic_low[i][0], ctof_elastic_high[i][0]) for i in xrange(len(ctof_elastic_low))] if tim is not None: tim.getTime(msg="After calculating initial wavelength range for "\ +"elastic line ") del ctof_elastic_low, ctof_elastic_high if config.split: lambda_filter = [(d_som1[i].axis[0].val[0], d_som1[i].axis[0].val[-1]) for i in xrange(len(d_som1))] else: lambda_filter = None # Now interpolate spectra between TOF elastic range (converted to # initial wavelength) if config.verbose: print "Linearly interpolating direct scattering spectra" if tim is not None: tim.getTime(False) ds_som2 = dr_lib.lin_interpolate_spectra(ds_som1, ctof_elastic_range, filter_axis=lambda_filter) if tim is not None: tim.getTime(msg="After linearly interpolating direct scattering "\ +"spectra ") if config.dump_dslin: ds_som2_1 = dr_lib.sum_all_spectra(ds_som2,\ rebin_axis=config.lambda_bins.toNessiList()) hlr_utils.write_file(config.output, "text/Spec", ds_som2_1, output_ext="lin", data_ext=config.ext_replacement, path_replacement=config.path_replacement, verbose=config.verbose, message="dsbackground linear interpolation") del ds_som2_1 del ds_som1 else: ds_som2 = None if inst_geom_dst is not None: inst_geom_dst.release_resource() # Steps 17-18: Subtract background spectrum from sample spectrum if config.dsback is None: back_som = b_som1 bkg_type = "background" else: back_som = ds_som2 bkg_type = "dsbackground" d_som2 = dr_lib.subtract_bkg_from_data(d_som1, back_som, verbose=config.verbose, timer=tim, dataset1="data", dataset2=bkg_type, scale=config.scale_bs) if config.dsback is not None: del ds_som2 # Step 19: Zero region outside TOF elastic for background for empty can if config.dsback is None: bcs_som = b_som1 cs_som = e_som1 else: if config.verbose and b_som1 is not None: print "Zeroing background spectra" if tim is not None and b_som1 is not None: tim.getTime(False) bcs_som = dr_lib.zero_spectra(b_som1, ctof_elastic_range) if tim is not None and b_som1 is not None: tim.getTime(msg="After zeroing background spectra") if config.verbose and e_som1 is not None: print "Zeroing empty can spectra" if tim is not None and e_som1 is not None: tim.getTime(False) cs_som = dr_lib.zero_spectra(e_som1, ctof_elastic_range) if tim is not None and e_som1 is not None: tim.getTime(msg="After zeroing empty can spectra") del ctof_elastic_range # Steps 20-21: Subtract background spectrum from empty can spectrum e_som2 = dr_lib.subtract_bkg_from_data(cs_som, bcs_som, verbose=config.verbose, timer=tim, dataset1="data-empty_can", dataset2="background", scale=config.scale_bcs) # Steps 22-23: Subtract background spectrum from empty can spectrum for # normalization try: config.pre_norm except AttributeError: config.pre_norm = False if not config.pre_norm: e_som3 = dr_lib.subtract_bkg_from_data(e_som1, b_som1, verbose=config.verbose, timer=tim, dataset1="norm-empty_can", dataset2="background", scale=config.scale_bcn) else: e_som3 = None # Steps 24-25: Subtract background spectrum from normalization spectrum if not config.pre_norm: n_som2 = dr_lib.subtract_bkg_from_data(n_som1, b_som1, verbose=config.verbose, timer=tim, dataset1="normalization", dataset2="background", scale=config.scale_bn) else: n_som2 = n_som1 del b_som1, e_som1, bcs_som, cs_som # Steps 26-27: Subtract empty can spectrum from sample spectrum d_som3 = dr_lib.subtract_bkg_from_data(d_som2, e_som2, verbose=config.verbose, timer=tim, dataset1="data", dataset2="empty_can", scale=config.scale_cs) del d_som2, e_som2 # Steps 28-29: Subtract empty can spectrum from normalization spectrum if not config.pre_norm: n_som3 = dr_lib.subtract_bkg_from_data(n_som2, e_som3, verbose=config.verbose, timer=tim, dataset1="normalization", dataset2="empty_can", scale=config.scale_cn) else: n_som3 = n_som2 del n_som2, e_som3 # Step 30-31: Integrate normalization spectra if config.verbose and n_som3 is not None and not config.pre_norm: print "Integrating normalization spectra" if not config.pre_norm: norm_int = dr_lib.integrate_spectra(n_som3, start=config.norm_start, end=config.norm_end, norm=True) else: norm_int = n_som3 del n_som3 # Step 32: Normalize data by integrated values if config.verbose and norm_int is not None: print "Normalizing data by normalization data" if norm_int is not None: d_som4 = common_lib.div_ncerr(d_som3, norm_int) else: d_som4 = d_som3 if norm_int is not None: if tim is not None: tim.getTime(msg="After normalizing data ") del d_som3, norm_int if config.dump_norm: if tim is not None: tim.getTime(False) hlr_utils.write_file(config.output, "text/Spec", d_som4, output_ext="wvn", data_ext=config.ext_replacement, path_replacement=config.path_replacement, verbose=config.verbose, message="wavelength (vanadium norm) information") if tim is not None: tim.getTime(msg="After writing wavelength (vanadium norm) info ") # Steps 33 to end: Creating S(Q,E) if config.Q_bins is not None: if config.verbose: print "Creating 2D spectrum" if tim is not None: tim.getTime(False) d_som5 = dr_lib.create_E_vs_Q_igs(d_som4, config.E_bins.toNessiList(), config.Q_bins.toNessiList(), so_id="Full Detector", y_label="counts", y_units="counts / (ueV * A^-1)", x_labels=["Q transfer", "energy transfer"], x_units=["1/Angstroms","ueV"], split=config.split, Q_filter=False, configure=config) if tim is not None: tim.getTime(msg="After creation of final spectrum ") del d_som4 # Steps 33 to 36: Create S(-cos(polar), E) elif config.ncospol_bins is not None: if config.verbose: print "Convert wavelength to energy transfer" if tim is not None: tim.getTime(False) d_som4a = dr_lib.energy_transfer(d_som4, "IGS", "Wavelength_final", sa_norm=True, scale=True, change_units=True) if tim is not None: tim.getTime(msg="After wavelength to energy transfer conversion ") del d_som4 if config.verbose: print "Creating 2D spectrum" if tim is not None: tim.getTime(False) d_som5 = dr_lib.create_param_vs_Y(d_som4a, "polar", "negcos_param_array", config.ncospol_bins.toNessiList(), rebin_axis=config.E_bins.toNessiList(), y_label="counts", y_units="counts / ueV", x_labels=["-cos(polar)", "Energy Transfer"], x_units=["", "ueV"]) if tim is not None: tim.getTime(msg="After creation of final spectrum ") # If rescaling factor present, rescale the data if config.rescale_final is not None and not config.split: d_som6 = common_lib.mult_ncerr(d_som5, (config.rescale_final, 0.0)) else: d_som6 = d_som5 if tim is None: old_time = None if not __name__ == "amorphous_reduction_sqe": del d_som5 __write_output(d_som6, config, tim, old_time) else: if config.create_output: del d_som5 __write_output(d_som6, config, tim, old_time) else: return d_som6
comb_som = __set_som_attributes(comb_som, inst_name, **kwargs) if configure.dump_pix_contrib: som1 = SOM.SOM() som1.copyAttributes(comb_som) som1.append(SOM.SO(2, so_dim.id)) som1[0].y = bin_count som1[0].var_y = bin_count_err2 som1[0].axis[0].val = so_dim.axis[0].val som1[0].axis[1].val = so_dim.axis[1].val # Write out pixel contribution into file hlr_utils.write_file(configure.output, "text/Dave2d", som1, output_ext="pcs", verbose=configure.verbose, data_ext=configure.ext_replacement, path_replacement=configure.path_replacement, message="pixel contribution") del som1 if split: comb_som.append(so_dim) # Write out summed counts into file hlr_utils.write_file(configure.output, "text/Dave2d", comb_som, output_ext="cnt", verbose=configure.verbose, data_ext=configure.ext_replacement, path_replacement=configure.path_replacement, message="summed counts")
def calibrate_dgs_data(datalist, conf, dkcur, **kwargs): """ This function combines Steps 3 through 6 in Section 2.1.1 of the data reduction process for Direct Geometry Spectrometers 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 and processes the data accordingly. @param datalist: A list containing 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 dkcur: The object containing the TOF dark current data. @type dkcur: C{SOM.SOM} @param kwargs: A list of keyword arguments that the function accepts: @keyword inst_geom_dst: File object that contains instrument geometry information. @type inst_geom_dst: C{DST.GeomDST} @keyword tib_const: A time-independent background constant to subtract from every pixel. @type tib_const: L{hlr_utils.DrParameter} @keyword dataset_type: The practical name of the dataset being processed. The default value is I{data}. @type dataset_type: C{string} @keyword cwp: A list of chopper phase corrections in units of microseconds. @type cwp: C{list} of C{float}s @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: tib_const = kwargs["tib_const"] except KeyError: tib_const = None try: dataset_type = kwargs["dataset_type"] except KeyError: dataset_type = "data" try: t = kwargs["timer"] except KeyError: t = None try: i_geom_dst = kwargs["inst_geom_dst"] except KeyError: i_geom_dst = None dataset_cwp = kwargs.get("cwp") # Open the appropriate datafiles if conf.verbose: print "Reading %s file" % dataset_type data_paths = conf.data_paths.toPath() if conf.no_mon_norm: mon_paths = None else: mon_paths = conf.usmon_path.toPath() # Check for mask file since normalization drive doesn't understand option try: mask_file = conf.mask_file except AttributeError: mask_file = None if t is not None: oldtime = t.getOldTime() (dp_som0, dm_som0) = dr_lib.add_files_dm(datalist, Data_Paths=data_paths, Mon_Paths=mon_paths, SO_Axis=conf.so_axis, Signal_ROI=conf.roi_file, Signal_MASK=mask_file, dataset_type=dataset_type, dataset_cwp=dataset_cwp, Verbose=conf.verbose, Timer=t) if t is not None: t.setOldTime(oldtime) t.getTime(msg="After reading %s file" % dataset_type) # Cut the spectra if necessary dp_somA = dr_lib.cut_spectra(dp_som0, conf.tof_cut_min, conf.tof_cut_max) del dp_som0 dp_somB = dr_lib.fix_bin_contents(dp_somA) del dp_somA if dp_somB.attr_list.instrument.get_name() != "CNCS": if conf.verbose: print "Cutting spectrum at minimum TOF" if t is not None: t.getTime(False) # Calculate minimum TOF for physical neutrons if conf.initial_energy is not None: initial_wavelength = common_lib.energy_to_wavelength(\ conf.initial_energy.toValErrTuple()) initial_velocity = common_lib.wavelength_to_velocity(\ initial_wavelength) else: # This should actually calculate it, but don't have a way right now pass if conf.time_zero_offset is not None: time_zero_offset = conf.time_zero_offset.toValErrTuple() else: # This should actually calculate it, but don't have a way right now time_zero_offset = (0.0, 0.0) ss_length = dp_somB.attr_list.instrument.get_primary() tof_min = (ss_length[0] / initial_velocity[0]) + time_zero_offset[0] # Cut all spectra a the minimum TOF dp_som1 = dr_lib.cut_spectra(dp_somB, tof_min, None) if t is not None: t.getTime(msg="After cutting spectrum at minimum TOF ") else: dp_som1 = dp_somB del dp_somB if dm_som0 is not None: dm_som1 = dr_lib.fix_bin_contents(dm_som0) else: dm_som1 = dm_som0 del dm_som0 # Override geometry if necessary if conf.inst_geom is not None: i_geom_dst.setGeometry(data_paths, dp_som1) if conf.inst_geom is not None and dm_som1 is not None: i_geom_dst.setGeometry(mon_paths, dm_som1) # Step 3: Integrate the upstream monitor if dm_som1 is not None: if conf.verbose: print "Integrating upstream monitor spectrum" if t is not None: t.getTime(False) if conf.mon_int_range is None: start_val = float("inf") end_val = float("inf") else: start_val = conf.mon_int_range[0] end_val = conf.mon_int_range[1] dm_som2 = dr_lib.integrate_spectra(dm_som1, start=start_val, end=end_val, width=True) if t is not None: t.getTime(msg="After integrating upstream monitor spectrum ") else: dm_som2 = dm_som1 del dm_som1 tib_norm_const = None # Step 4: Divide data set by summed monitor spectrum if dm_som2 is not None: if conf.verbose: print "Normalizing %s by monitor sum" % dataset_type if t is not None: t.getTime(False) dp_som2 = common_lib.div_ncerr(dp_som1, dm_som2, length_one_som=True) tib_norm_const = dm_som2[0].y if t is not None: t.getTime(msg="After normalizing %s by monitor sum" % dataset_type) elif conf.pc_norm: if conf.verbose: print "Normalizing %s by proton charge" % dataset_type pc_tag = dataset_type+"-proton_charge" pc = dp_som1.attr_list[pc_tag] # Scale the proton charge and then set the scale PC back to attributes if conf.scale_pc is not None: if conf.verbose: print "Scaling %s proton charge" % dataset_type pc = hlr_utils.scale_proton_charge(pc, conf.scale_pc) dp_som1.attr_list[pc_tag] = pc tib_norm_const = pc.getValue() if t is not None: t.getTime(False) dp_som2 = common_lib.div_ncerr(dp_som1, (pc.getValue(), 0.0)) if t is not None: t.getTime(msg="After normalizing %s by proton charge" \ % dataset_type) else: dp_som2 = dp_som1 del dp_som1, dm_som2 # Step 5: Scale dark current by data set measurement time if dkcur is not None: if conf.verbose: print "Scaling dark current by %s acquisition time" % dataset_type if t is not None: t.getTime(False) dstime_tag = dataset_type+"-duration" dstime = dp_som2.attr_list[dstime_tag] dkcur1 = common_lib.div_ncerr(dkcur, (dstime.getValue(), 0.0)) if t is not None: t.getTime(msg="After scaling dark current by %s acquisition time" \ % dataset_type) else: dkcur1 = dkcur del dkcur # Step 6: Subtract scaled dark current from data set if dkcur1 is not None: if conf.verbose: print "Subtracting %s by scaled dark current" % dataset_type if t is not None: t.getTime(False) dp_som3 = common_lib.sub_ncerr(dp_som2, dkcur1) if t is not None: t.getTime(msg="After subtracting %s by scaled dark current" \ % dataset_type) elif tib_const is not None and dkcur1 is None: if conf.verbose: print "Subtracting TIB constant from %s" % dataset_type # Normalize the TIB constant by dividing by the current normalization # the duration (if necessary) and the conversion from seconds to # microseconds tib_c = tib_const.toValErrTuple() conv_sec_to_usec = 1.0e-6 if tib_norm_const is None: tib_norm_const = 1 duration = 1 else: duration_tag = dataset_type+"-duration" duration = dp_som2.attr_list[duration_tag].getValue() norm_const = (duration * conv_sec_to_usec) / tib_norm_const tib_val = tib_c[0] * norm_const tib_err2 = tib_c[1] * (norm_const * norm_const) if t is not None: t.getTime(False) dp_som3 = common_lib.sub_ncerr(dp_som2, (tib_val, tib_err2)) if t is not None: t.getTime(msg="After subtracting TIB constant from %s" \ % dataset_type) elif conf.tib_range is not None and dkcur1 is None: if conf.verbose: print "Determining TIB constant from %s" % dataset_type if t is not None: t.getTime(False) TIB = dr_lib.determine_time_indep_bkg(dp_som2, conf.tib_range, is_range=True) if t is not None: t.getTime(msg="After determining TIB constant from %s" \ % dataset_type) if conf.dump_tib: file_comment = "TIB TOF Range: [%d, %d]" % (conf.tib_range[0], conf.tib_range[1]) hlr_utils.write_file(conf.output, "text/num-info", TIB, output_ext="tib", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="time-independent background "\ +"information", tag="Average TIB", units="counts/usec", comments=[file_comment]) if conf.verbose: print "Subtracting TIB constant from %s" % dataset_type if t is not None: t.getTime(False) dp_som3 = common_lib.sub_ncerr(dp_som2, TIB) if t is not None: t.getTime(msg="After subtracting TIB constant from %s" \ % dataset_type) del TIB else: dp_som3 = dp_som2 del dp_som2, dkcur1 if conf.dump_ctof_comb: dp_som3_1 = dr_lib.sum_all_spectra(dp_som3) hlr_utils.write_file(conf.output, "text/Spec", dp_som3_1, output_ext="ctof", extra_tag=dataset_type, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, verbose=conf.verbose, message="combined calibrated TOF information") del dp_som3_1 return dp_som3
def process_dgs_data(obj, conf, bcan, ecan, tcoeff, **kwargs): """ This function combines Steps 7 through 16 in Section 2.1.1 of the data reduction process for Direct Geometry Spectrometers as specified by the document at U{http://neutrons.ornl.gov/asg/projects/SCL/reqspec/DR_Lib_RS.doc}. The function takes a calibrated dataset, a L{hlr_utils.Configure} object and processes the data accordingly. @param obj: A calibrated dataset object. @type obj: C{SOM.SOM} @param conf: Object that contains the current setup of the driver. @type conf: L{hlr_utils.Configure} @param bcan: The object containing the black can data. @type bcan: C{SOM.SOM} @param ecan: The object containing the empty can data. @type ecan: C{SOM.SOM} @param tcoeff: The transmission coefficient appropriate to the given data set. @type tcoeff: C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword dataset_type: The practical name of the dataset being processed. The default value is I{data}. @type dataset_type: C{string} @keyword cwp_used: A flag signalling the use of the chopper phase corrections. @type cwp_used: C{bool} @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 array_manip import common_lib import dr_lib import hlr_utils # Check keywords try: dataset_type = kwargs["dataset_type"] except KeyError: dataset_type = "data" try: t = kwargs["timer"] except KeyError: t = None cwp_used = kwargs.get("cwp_used", False) if conf.verbose: print "Processing %s information" % dataset_type # Step 7: Create black can background contribution if bcan is not None: if conf.verbose: print "Creating black can background contribution for %s" \ % dataset_type if t is not None: t.getTime(False) bccoeff = array_manip.sub_ncerr(1.0, 0.0, tcoeff[0], tcoeff[1]) bcan1 = common_lib.mult_ncerr(bcan, bccoeff) if t is not None: t.getTime(msg="After creating black can background contribution ") del bcan else: bcan1 = None # Step 8: Create empty can background contribution if ecan is not None: if conf.verbose: print "Creating empty can background contribution for %s" \ % dataset_type if t is not None: t.getTime(False) ecan1 = common_lib.mult_ncerr(ecan, tcoeff) if t is not None: t.getTime(msg="After creating empty can background contribution ") del ecan else: ecan1 = None # Step 9: Create background spectra if bcan1 is not None or ecan1 is not None and conf.verbose: print "Creating background spectra for %s" % dataset_type if bcan1 is not None and ecan1 is not None: if cwp_used: if conf.verbose: print "Rebinning empty can to black can axis." ecan2 = common_lib.rebin_axis_1D_frac(ecan1, bcan1[0].axis[0].val) else: ecan2 = ecan1 del ecan1 if t is not None: t.getTime(False) b_som = common_lib.add_ncerr(bcan1, ecan2) if t is not None: t.getTime(msg="After creating background spectra ") elif bcan1 is not None and ecan1 is None: b_som = bcan1 elif bcan1 is None and ecan1 is not None: b_som = ecan1 else: b_som = None del bcan1, ecan1 if cwp_used: if conf.verbose: print "Rebinning background spectra to %s" % dataset_type b_som1 = common_lib.rebin_axis_1D_frac(b_som, obj[0].axis[0].val) else: b_som1 = b_som del b_som if conf.dump_ctof_comb and b_som1 is not None: b_som_1 = dr_lib.sum_all_spectra(b_som1) hlr_utils.write_file(conf.output, "text/Spec", b_som_1, output_ext="ctof", extra_tag="background", data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, verbose=conf.verbose, message="combined background TOF information") del b_som_1 # Step 10: Subtract background from data obj1 = dr_lib.subtract_bkg_from_data(obj, b_som1, verbose=conf.verbose, timer=t, dataset1=dataset_type, dataset2="background") del obj, b_som1 # Step 11: Calculate initial velocity if conf.verbose: print "Calculating initial velocity" if t is not None: t.getTime(False) if conf.initial_energy is not None: initial_wavelength = common_lib.energy_to_wavelength(\ conf.initial_energy.toValErrTuple()) initial_velocity = common_lib.wavelength_to_velocity(\ initial_wavelength) else: # This should actually calculate it, but don't have a way right now pass if t is not None: t.getTime(msg="After calculating initial velocity ") # Step 12: Calculate the time-zero offset if conf.time_zero_offset is not None: time_zero_offset = conf.time_zero_offset.toValErrTuple() else: # This should actually calculate it, but don't have a way right now time_zero_offset = (0.0, 0.0) # Step 13: Convert time-of-flight to final velocity if conf.verbose: print "Converting TOF to final velocity DGS" if t is not None: t.getTime(False) obj2 = common_lib.tof_to_final_velocity_dgs(obj1, initial_velocity, time_zero_offset, units="microsecond") if t is not None: t.getTime(msg="After calculating TOF to final velocity DGS ") del obj1 # Step 14: Convert final velocity to final wavelength if conf.verbose: print "Converting final velocity DGS to final wavelength" if t is not None: t.getTime(False) obj3 = common_lib.velocity_to_wavelength(obj2) if t is not None: t.getTime(msg="After calculating velocity to wavelength ") del obj2 if conf.dump_wave_comb: obj3_1 = dr_lib.sum_all_spectra( obj3, rebin_axis=conf.lambda_bins.toNessiList()) hlr_utils.write_file(conf.output, "text/Spec", obj3_1, output_ext="fwv", extra_tag=dataset_type, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, verbose=conf.verbose, message="combined final wavelength information") del obj3_1 # Step 15: Create the detector efficiency if conf.det_eff is not None: if conf.verbose: print "Creating detector efficiency spectra" if t is not None: t.getTime(False) det_eff = dr_lib.create_det_eff(obj3) if t is not None: t.getTime(msg="After creating detector efficiency spectra ") else: det_eff = None # Step 16: Divide the detector pixel spectra by the detector efficiency if det_eff is not None: if conf.verbose: print "Correcting %s for detector efficiency" % dataset_type if t is not None: t.getTime(False) obj4 = common_lib.div_ncerr(obj3, det_eff) if t is not None: t.getTime(msg="After correcting %s for detector efficiency" \ % dataset_type) else: obj4 = obj3 del obj3, det_eff return obj4
comb_som = __set_som_attributes(comb_som, inst_name, **kwargs) if configure.dump_pix_contrib: som1 = SOM.SOM() som1.copyAttributes(comb_som) som1.append(SOM.SO(2, so_dim.id)) som1[0].y = bin_count som1[0].var_y = bin_count_err2 som1[0].axis[0].val = so_dim.axis[0].val som1[0].axis[1].val = so_dim.axis[1].val # Write out pixel contribution into file hlr_utils.write_file(configure.output, "text/Dave2d", som1, output_ext="pcs", verbose=configure.verbose, data_ext=configure.ext_replacement, path_replacement=configure.path_replacement, message="pixel contribution") del som1 if split: comb_som.append(so_dim) # Write out summed counts into file hlr_utils.write_file(configure.output, "text/Dave2d", comb_som, output_ext="cnt", verbose=configure.verbose,
def calibrate_dgs_data(datalist, conf, dkcur, **kwargs): """ This function combines Steps 3 through 6 in Section 2.1.1 of the data reduction process for Direct Geometry Spectrometers 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 and processes the data accordingly. @param datalist: A list containing 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 dkcur: The object containing the TOF dark current data. @type dkcur: C{SOM.SOM} @param kwargs: A list of keyword arguments that the function accepts: @keyword inst_geom_dst: File object that contains instrument geometry information. @type inst_geom_dst: C{DST.GeomDST} @keyword tib_const: A time-independent background constant to subtract from every pixel. @type tib_const: L{hlr_utils.DrParameter} @keyword dataset_type: The practical name of the dataset being processed. The default value is I{data}. @type dataset_type: C{string} @keyword cwp: A list of chopper phase corrections in units of microseconds. @type cwp: C{list} of C{float}s @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: tib_const = kwargs["tib_const"] except KeyError: tib_const = None try: dataset_type = kwargs["dataset_type"] except KeyError: dataset_type = "data" try: t = kwargs["timer"] except KeyError: t = None try: i_geom_dst = kwargs["inst_geom_dst"] except KeyError: i_geom_dst = None dataset_cwp = kwargs.get("cwp") # Open the appropriate datafiles if conf.verbose: print "Reading %s file" % dataset_type data_paths = conf.data_paths.toPath() if conf.no_mon_norm: mon_paths = None else: mon_paths = conf.usmon_path.toPath() # Check for mask file since normalization drive doesn't understand option try: mask_file = conf.mask_file except AttributeError: mask_file = None if t is not None: oldtime = t.getOldTime() (dp_som0, dm_som0) = dr_lib.add_files_dm(datalist, Data_Paths=data_paths, Mon_Paths=mon_paths, SO_Axis=conf.so_axis, Signal_ROI=conf.roi_file, Signal_MASK=mask_file, dataset_type=dataset_type, dataset_cwp=dataset_cwp, Verbose=conf.verbose, Timer=t) if t is not None: t.setOldTime(oldtime) t.getTime(msg="After reading %s file" % dataset_type) # Cut the spectra if necessary dp_somA = dr_lib.cut_spectra(dp_som0, conf.tof_cut_min, conf.tof_cut_max) del dp_som0 dp_somB = dr_lib.fix_bin_contents(dp_somA) del dp_somA if dp_somB.attr_list.instrument.get_name() != "CNCS": if conf.verbose: print "Cutting spectrum at minimum TOF" if t is not None: t.getTime(False) # Calculate minimum TOF for physical neutrons if conf.initial_energy is not None: initial_wavelength = common_lib.energy_to_wavelength(\ conf.initial_energy.toValErrTuple()) initial_velocity = common_lib.wavelength_to_velocity(\ initial_wavelength) else: # This should actually calculate it, but don't have a way right now pass if conf.time_zero_offset is not None: time_zero_offset = conf.time_zero_offset.toValErrTuple() else: # This should actually calculate it, but don't have a way right now time_zero_offset = (0.0, 0.0) ss_length = dp_somB.attr_list.instrument.get_primary() tof_min = (ss_length[0] / initial_velocity[0]) + time_zero_offset[0] # Cut all spectra a the minimum TOF dp_som1 = dr_lib.cut_spectra(dp_somB, tof_min, None) if t is not None: t.getTime(msg="After cutting spectrum at minimum TOF ") else: dp_som1 = dp_somB del dp_somB if dm_som0 is not None: dm_som1 = dr_lib.fix_bin_contents(dm_som0) else: dm_som1 = dm_som0 del dm_som0 # Override geometry if necessary if conf.inst_geom is not None: i_geom_dst.setGeometry(data_paths, dp_som1) if conf.inst_geom is not None and dm_som1 is not None: i_geom_dst.setGeometry(mon_paths, dm_som1) # Step 3: Integrate the upstream monitor if dm_som1 is not None: if conf.verbose: print "Integrating upstream monitor spectrum" if t is not None: t.getTime(False) if conf.mon_int_range is None: start_val = float("inf") end_val = float("inf") else: start_val = conf.mon_int_range[0] end_val = conf.mon_int_range[1] dm_som2 = dr_lib.integrate_spectra(dm_som1, start=start_val, end=end_val, width=True) if t is not None: t.getTime(msg="After integrating upstream monitor spectrum ") else: dm_som2 = dm_som1 del dm_som1 tib_norm_const = None # Step 4: Divide data set by summed monitor spectrum if dm_som2 is not None: if conf.verbose: print "Normalizing %s by monitor sum" % dataset_type if t is not None: t.getTime(False) dp_som2 = common_lib.div_ncerr(dp_som1, dm_som2, length_one_som=True) tib_norm_const = dm_som2[0].y if t is not None: t.getTime(msg="After normalizing %s by monitor sum" % dataset_type) elif conf.pc_norm: if conf.verbose: print "Normalizing %s by proton charge" % dataset_type pc_tag = dataset_type + "-proton_charge" pc = dp_som1.attr_list[pc_tag] # Scale the proton charge and then set the scale PC back to attributes if conf.scale_pc is not None: if conf.verbose: print "Scaling %s proton charge" % dataset_type pc = hlr_utils.scale_proton_charge(pc, conf.scale_pc) dp_som1.attr_list[pc_tag] = pc tib_norm_const = pc.getValue() if t is not None: t.getTime(False) dp_som2 = common_lib.div_ncerr(dp_som1, (pc.getValue(), 0.0)) if t is not None: t.getTime(msg="After normalizing %s by proton charge" \ % dataset_type) else: dp_som2 = dp_som1 del dp_som1, dm_som2 # Step 5: Scale dark current by data set measurement time if dkcur is not None: if conf.verbose: print "Scaling dark current by %s acquisition time" % dataset_type if t is not None: t.getTime(False) dstime_tag = dataset_type + "-duration" dstime = dp_som2.attr_list[dstime_tag] dkcur1 = common_lib.div_ncerr(dkcur, (dstime.getValue(), 0.0)) if t is not None: t.getTime(msg="After scaling dark current by %s acquisition time" \ % dataset_type) else: dkcur1 = dkcur del dkcur # Step 6: Subtract scaled dark current from data set if dkcur1 is not None: if conf.verbose: print "Subtracting %s by scaled dark current" % dataset_type if t is not None: t.getTime(False) dp_som3 = common_lib.sub_ncerr(dp_som2, dkcur1) if t is not None: t.getTime(msg="After subtracting %s by scaled dark current" \ % dataset_type) elif tib_const is not None and dkcur1 is None: if conf.verbose: print "Subtracting TIB constant from %s" % dataset_type # Normalize the TIB constant by dividing by the current normalization # the duration (if necessary) and the conversion from seconds to # microseconds tib_c = tib_const.toValErrTuple() conv_sec_to_usec = 1.0e-6 if tib_norm_const is None: tib_norm_const = 1 duration = 1 else: duration_tag = dataset_type + "-duration" duration = dp_som2.attr_list[duration_tag].getValue() norm_const = (duration * conv_sec_to_usec) / tib_norm_const tib_val = tib_c[0] * norm_const tib_err2 = tib_c[1] * (norm_const * norm_const) if t is not None: t.getTime(False) dp_som3 = common_lib.sub_ncerr(dp_som2, (tib_val, tib_err2)) if t is not None: t.getTime(msg="After subtracting TIB constant from %s" \ % dataset_type) elif conf.tib_range is not None and dkcur1 is None: if conf.verbose: print "Determining TIB constant from %s" % dataset_type if t is not None: t.getTime(False) TIB = dr_lib.determine_time_indep_bkg(dp_som2, conf.tib_range, is_range=True) if t is not None: t.getTime(msg="After determining TIB constant from %s" \ % dataset_type) if conf.dump_tib: file_comment = "TIB TOF Range: [%d, %d]" % (conf.tib_range[0], conf.tib_range[1]) hlr_utils.write_file(conf.output, "text/num-info", TIB, output_ext="tib", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="time-independent background "\ +"information", tag="Average TIB", units="counts/usec", comments=[file_comment]) if conf.verbose: print "Subtracting TIB constant from %s" % dataset_type if t is not None: t.getTime(False) dp_som3 = common_lib.sub_ncerr(dp_som2, TIB) if t is not None: t.getTime(msg="After subtracting TIB constant from %s" \ % dataset_type) del TIB else: dp_som3 = dp_som2 del dp_som2, dkcur1 if conf.dump_ctof_comb: dp_som3_1 = dr_lib.sum_all_spectra(dp_som3) hlr_utils.write_file(conf.output, "text/Spec", dp_som3_1, output_ext="ctof", extra_tag=dataset_type, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, verbose=conf.verbose, message="combined calibrated TOF information") del dp_som3_1 return dp_som3
def process_igs_data(datalist, conf, **kwargs): """ This function combines Steps 1 through 8 of the data reduction process for Inverse Geometry Spectrometers as specified by the documents 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 and processes the data accordingly. This function should really only be used in the context of I{amorphous_reduction} and I{calc_norm_eff}. @param datalist: A list containing 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 kwargs: A list of keyword arguments that the function accepts: @keyword inst_geom_dst: File object that contains instrument geometry information. @type inst_geom_dst: C{DST.GeomDST} @keyword dataset_type: The practical name of the dataset being processed. The default value is I{data}. @type dataset_type: C{string} @keyword tib_const: Object providing the time-independent background constant to subtract. @type tib_const: L{hlr_utils.DrParameter} @keyword bkg_som: Object that will be used for early background subtraction @type bkg_som: C{SOM.SOM} @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 hlr_utils # Check keywords try: dataset_type = kwargs["dataset_type"] except KeyError: dataset_type = "data" try: t = kwargs["timer"] except KeyError: t = None try: if kwargs["tib_const"] is not None: tib_const = kwargs["tib_const"].toValErrTuple() else: tib_const = None except KeyError: tib_const = None try: i_geom_dst = kwargs["inst_geom_dst"] except KeyError: i_geom_dst = None try: bkg_som = kwargs["bkg_som"] except KeyError: bkg_som = None # Step 1: Open appropriate data files if not conf.mc: so_axis = "time_of_flight" else: so_axis = "Time_of_Flight" # Add so_axis to Configure object conf.so_axis = so_axis if conf.verbose: print "Reading %s file" % dataset_type # Special case handling for normalization data. Dynamically trying to # determine if incoming file is a previously calculated one. if dataset_type == "normalization": try: # Check the first incoming file dst_type = hlr_utils.file_peeker(datalist[0]) # If file_peeker succeeds, the DST is different than the function # returns dst_type = "text/num-info" # Let ROI file handle filtering data_paths = None except RuntimeError: # It's a NeXus file dst_type = "application/x-NeXus" data_paths = conf.data_paths.toPath() else: dst_type = "application/x-NeXus" data_paths = conf.data_paths.toPath() # The [0] is to get the data SOM and ignore the None background SOM dp_som0 = dr_lib.add_files(datalist, Data_Paths=data_paths, SO_Axis=so_axis, Signal_ROI=conf.roi_file, dataset_type=dataset_type, dst_type=dst_type, Verbose=conf.verbose, Timer=t) if t is not None: t.getTime(msg="After reading %s " % dataset_type) if dst_type == "text/num-info": # Since we have a pre-calculated normalization dataset, set the flag # and return the SOM now conf.pre_norm = True # Make the labels and units compatible with a NeXus file based SOM dp_som0.setAxisLabel(0, "wavelength") dp_som0.setAxisUnits(0, "Angstroms") dp_som0.setYUnits("Counts/A") return dp_som0 else: if dataset_type == "normalization": # Since we have a NeXus file, we need to continue conf.pre_norm = False # Cut the spectra if necessary dp_somA = dr_lib.cut_spectra(dp_som0, conf.tof_cut_min, conf.tof_cut_max) del dp_som0 dp_som1 = dr_lib.fix_bin_contents(dp_somA) del dp_somA if conf.inst_geom is not None: i_geom_dst.setGeometry(conf.data_paths.toPath(), dp_som1) if conf.no_mon_norm: dm_som1 = None else: if conf.verbose: print "Reading in monitor data from %s file" % dataset_type # The [0] is to get the data SOM and ignore the None background SOM dm_som0 = dr_lib.add_files(datalist, Data_Paths=conf.mon_path.toPath(), SO_Axis=so_axis, dataset_type=dataset_type, Verbose=conf.verbose, Timer=t) if t is not None: t.getTime(msg="After reading monitor data ") dm_som1 = dr_lib.fix_bin_contents(dm_som0) del dm_som0 if conf.inst_geom is not None: i_geom_dst.setGeometry(conf.mon_path.toPath(), dm_som1) if bkg_som is not None: bkg_pcharge = bkg_som.attr_list["background-proton_charge"].getValue() data_pcharge = dp_som1.attr_list[dataset_type + "-proton_charge"].getValue() ratio = data_pcharge / bkg_pcharge bkg_som1 = common_lib.mult_ncerr(bkg_som, (ratio, 0.0)) del bkg_som dp_som2 = dr_lib.subtract_bkg_from_data(dp_som1, bkg_som1, verbose=conf.verbose, timer=t, dataset1=dataset_type, dataset2="background") else: dp_som2 = dp_som1 del dp_som1 # Step 2: Dead Time Correction # No dead time correction is being applied to the data yet # Step 3: Time-independent background determination if conf.verbose and conf.tib_tofs is not None: print "Determining time-independent background from data" if t is not None and conf.tib_tofs is not None: t.getTime(False) B = dr_lib.determine_time_indep_bkg(dp_som2, conf.tib_tofs) if t is not None and B is not None: t.getTime(msg="After determining time-independent background ") if conf.dump_tib and B is not None: file_comment = "TOFs: %s" % conf.tib_tofs hlr_utils.write_file(conf.output, "text/num-info", B, output_ext="tib", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="time-independent background "\ +"information", tag="Average", units="counts", comments=[file_comment]) # Step 4: Subtract time-independent background if conf.verbose and B is not None: print "Subtracting time-independent background from data" if t is not None: t.getTime(False) if B is not None: dp_som3 = common_lib.sub_ncerr(dp_som2, B) else: dp_som3 = dp_som2 if B is not None and t is not None: t.getTime(msg="After subtracting time-independent background ") del dp_som2, B # Step 5: Subtract time-independent background constant if conf.verbose and tib_const is not None: print "Subtracting time-independent background constant from data" if t is not None and tib_const is not None: t.getTime(False) if tib_const is not None: dp_som4 = common_lib.sub_ncerr(dp_som3, tib_const) else: dp_som4 = dp_som3 if t is not None and tib_const is not None: t.getTime(msg="After subtracting time-independent background "\ +"constant ") del dp_som3 # Provide override capability for final wavelength, time-zero slope and # time-zero offset if conf.wavelength_final is not None: dp_som4.attr_list["Wavelength_final"] = \ conf.wavelength_final.toValErrTuple() # Note: time_zero_slope MUST be a tuple if conf.time_zero_slope is not None: dp_som4.attr_list["Time_zero_slope"] = \ conf.time_zero_slope.toValErrTuple() if dm_som1 is not None: dm_som1.attr_list["Time_zero_slope"] = \ conf.time_zero_slope.toValErrTuple() # Note: time_zero_offset MUST be a tuple if conf.time_zero_offset is not None: dp_som4.attr_list["Time_zero_offset"] = \ conf.time_zero_offset.toValErrTuple() if dm_som1 is not None: dm_som1.attr_list["Time_zero_offset"] = \ conf.time_zero_offset.toValErrTuple() # Step 6: Convert TOF to wavelength for data and monitor if conf.verbose: print "Converting TOF to wavelength" if t is not None: t.getTime(False) # Convert monitor if dm_som1 is not None: dm_som2 = common_lib.tof_to_wavelength_lin_time_zero( dm_som1, units="microsecond") else: dm_som2 = None # Convert detector pixels dp_som5 = common_lib.tof_to_initial_wavelength_igs_lin_time_zero( dp_som4, units="microsecond", run_filter=conf.filter) if t is not None: t.getTime(msg="After converting TOF to wavelength ") if conf.dump_wave: hlr_utils.write_file(conf.output, "text/Spec", dp_som5, output_ext="pxl", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="pixel wavelength information") if conf.dump_mon_wave and dm_som2 is not None: hlr_utils.write_file(conf.output, "text/Spec", dm_som2, output_ext="mxl", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="monitor wavelength information") del dp_som4, dm_som1 # Step 7: Efficiency correct monitor if conf.verbose and dm_som2 is not None and not conf.no_mon_effc: print "Efficiency correct monitor data" if t is not None: t.getTime(False) if not conf.no_mon_effc: dm_som3 = dr_lib.feff_correct_mon(dm_som2) else: dm_som3 = dm_som2 if t is not None and dm_som2 is not None and not conf.no_mon_effc: t.getTime(msg="After efficiency correcting monitor ") if conf.dump_mon_effc and not conf.no_mon_effc and dm_som3 is not None: hlr_utils.write_file(conf.output, "text/Spec", dm_som3, output_ext="mel", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="monitor wavelength information "\ +"(efficiency)") del dm_som2 # Step 8: Rebin monitor axis onto detector pixel axis if conf.verbose and dm_som3 is not None: print "Rebin monitor axis to detector pixel axis" if t is not None: t.getTime(False) dm_som4 = dr_lib.rebin_monitor(dm_som3, dp_som5) if t is not None and dm_som4 is not None: t.getTime(msg="After rebinning monitor ") del dm_som3 if conf.dump_mon_rebin and dm_som4 is not None: hlr_utils.write_file(conf.output, "text/Spec", dm_som4, output_ext="mrl", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="monitor wavelength information "\ +"(rebinned)") # The lambda-dependent background is only done on sample data (aka data) # for the BSS instrument at the SNS if conf.inst == "BSS" and conf.ldb_const is not None and \ dataset_type == "data": # Step 9: Convert chopper center wavelength to TOF center if conf.verbose: print "Converting chopper center wavelength to TOF" if t is not None: t.getTime(False) tof_center = dr_lib.convert_single_to_list(\ "initial_wavelength_igs_lin_time_zero_to_tof", conf.chopper_lambda_cent.toValErrTuple(), dp_som5) # Step 10: Calculate beginning and end of detector TOF spectrum if conf.verbose: print "Calculating beginning and ending TOF ranges" half_inv_chop_freq = 0.5 / conf.chopper_freq.toValErrTuple()[0] # Above is in seconds, need microseconds half_inv_chop_freq *= 1.0e6 tof_begin = common_lib.sub_ncerr(tof_center, (half_inv_chop_freq, 0.0)) tof_end = common_lib.add_ncerr(tof_center, (half_inv_chop_freq, 0.0)) # Step 11: Convert TOF_begin and TOF_end to wavelength if conf.verbose: print "Converting TOF_begin and TOF_end to wavelength" # Check for time-zero slope information try: tz_slope = conf.time_zero_slope.toValErrTuple() except AttributeError: tz_slope = (0.0, 0.0) # Check for time-zero offset information try: tz_offset = conf.time_zero_offset.toValErrTuple() except AttributeError: tz_offset = (0.0, 0.0) l_begin = common_lib.tof_to_initial_wavelength_igs_lin_time_zero(\ tof_begin, time_zero_slope=tz_slope, time_zero_offset=tz_offset, iobj=dp_som5, run_filter=False) l_end = common_lib.tof_to_initial_wavelength_igs_lin_time_zero(\ tof_end, time_zero_slope=tz_slope, time_zero_offset=tz_offset, iobj=dp_som5, run_filter=False) # Step 12: tof-least-bkg to lambda-least-bkg if conf.verbose: print "Converting TOF least background to wavelength" lambda_least_bkg = dr_lib.convert_single_to_list(\ "tof_to_initial_wavelength_igs_lin_time_zero", conf.tof_least_bkg.toValErrTuple(), dp_som5) if t is not None: t.getTime(msg="After converting boundary positions ") # Step 13: Create lambda-dependent background spectrum if conf.verbose: print "Creating lambda-dependent background spectra" if t is not None: t.getTime(False) ldb_som = dr_lib.shift_spectrum(dm_som4, lambda_least_bkg, l_begin, l_end, conf.ldb_const.getValue()) if t is not None: t.getTime(msg="After creating lambda-dependent background "\ +"spectra ") # Step 14: Subtract lambda-dependent background from sample data if conf.verbose: print "Subtracting lambda-dependent background from data" if t is not None: t.getTime(False) dp_som6 = common_lib.sub_ncerr(dp_som5, ldb_som) if t is not None: t.getTime(msg="After subtracting lambda-dependent background "\ +"from data ") else: dp_som6 = dp_som5 del dp_som5 # Step 15: Normalize data by monitor if conf.verbose and dm_som4 is not None: print "Normalizing data by monitor" if t is not None: t.getTime(False) if dm_som4 is not None: dp_som7 = common_lib.div_ncerr(dp_som6, dm_som4) if t is not None: t.getTime(msg="After normalizing data by monitor ") else: dp_som7 = dp_som6 if conf.dump_wave_mnorm: dp_som7_1 = dr_lib.sum_all_spectra(dp_som7,\ rebin_axis=conf.lambda_bins.toNessiList()) write_message = "combined pixel wavelength information" if dm_som4 is not None: write_message += " (monitor normalized)" hlr_utils.write_file(conf.output, "text/Spec", dp_som7_1, output_ext="pml", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message=write_message) del dp_som7_1 del dm_som4, dp_som6 return dp_som7
def run(config, tim=None): """ This method is where the data reduction process gets done. @param config: Object containing the data reduction configuration information. @type config: L{hlr_utils.Configure} @param tim: (OPTIONAL) Object that will allow the method to perform timing evaluations. @type tim: C{sns_time.DiffTime} """ import common_lib import dr_lib import DST if tim is not None: tim.getTime(False) old_time = tim.getOldTime() if config.data is None: raise RuntimeError("Need to pass a data filename to the driver "\ +"script.") # Read in geometry if one is provided if config.inst_geom is not None: if config.verbose: print "Reading in instrument geometry file" inst_geom_dst = DST.getInstance("application/x-NxsGeom", config.inst_geom) else: inst_geom_dst = None # Perform early background subtraction if the hwfix flag is used if config.hwfix: if not config.mc: so_axis = "time_of_flight" else: so_axis = "Time_of_Flight" bkg_som0 = dr_lib.add_files(config.back, Data_Paths=config.data_paths.toPath(), SO_Axis=so_axis, Signal_ROI=config.roi_file, dataset_type="background", Verbose=config.verbose, Timer=tim) bkg_som = dr_lib.fix_bin_contents(bkg_som0) del bkg_som0 else: bkg_som = None # Perform Steps 1-15 on sample data d_som1 = dr_lib.process_igs_data(config.data, config, timer=tim, inst_geom_dst=inst_geom_dst, tib_const=config.tib_data_const, bkg_som=bkg_som) # Perform Steps 1-15 on empty can data if config.ecan is not None: e_som1 = dr_lib.process_igs_data(config.ecan, config, timer=tim, inst_geom_dst=inst_geom_dst, dataset_type="empty_can", tib_const=config.tib_ecan_const, bkg_som=bkg_som) else: e_som1 = None # Perform Steps 1-15 on normalization data if config.norm is not None: n_som1 = dr_lib.process_igs_data(config.norm, config, timer=tim, inst_geom_dst=inst_geom_dst, dataset_type="normalization", tib_const=config.tib_norm_const, bkg_som=bkg_som) else: n_som1 = None # Perform Steps 1-15 on background data if config.back is not None: b_som1 = dr_lib.process_igs_data(config.back, config, timer=tim, inst_geom_dst=inst_geom_dst, dataset_type="background", tib_const=config.tib_back_const, bkg_som=bkg_som) else: b_som1 = None # Perform Step 1-15 on direct scattering background data if config.dsback is not None: ds_som1 = dr_lib.process_igs_data(config.dsback, config, timer=tim, inst_geom_dst=inst_geom_dst, tib_const=config.tib_dsback_const, dataset_type="dsbackground", bkg_som=bkg_som) # Note: time_zero_slope MUST be a tuple if config.time_zero_slope is not None: ds_som1.attr_list["Time_zero_slope"] = \ config.time_zero_slope.toValErrTuple() # Note: time_zero_offset MUST be a tuple if config.time_zero_offset is not None: ds_som1.attr_list["Time_zero_offset"] = \ config.time_zero_offset.toValErrTuple() # Step 16: Linearly interpolate TOF elastic range in direct scattering # background data # First convert TOF elastic range to appropriate pixel initial # wavelengths if config.verbose: print "Determining initial wavelength range for elastic line" if tim is not None: tim.getTime(False) if config.tof_elastic is None: # Units are in microseconds tof_elastic_range = (140300, 141300) else: tof_elastic_range = config.tof_elastic ctof_elastic_low = dr_lib.convert_single_to_list(\ "tof_to_initial_wavelength_igs_lin_time_zero", (tof_elastic_range[0], 0.0), ds_som1) ctof_elastic_high = dr_lib.convert_single_to_list(\ "tof_to_initial_wavelength_igs_lin_time_zero", (tof_elastic_range[1], 0.0), ds_som1) ctof_elastic_range = [(ctof_elastic_low[i][0], ctof_elastic_high[i][0]) for i in xrange(len(ctof_elastic_low))] if tim is not None: tim.getTime(msg="After calculating initial wavelength range for "\ +"elastic line ") del ctof_elastic_low, ctof_elastic_high if config.split: lambda_filter = [(d_som1[i].axis[0].val[0], d_som1[i].axis[0].val[-1]) for i in xrange(len(d_som1))] else: lambda_filter = None # Now interpolate spectra between TOF elastic range (converted to # initial wavelength) if config.verbose: print "Linearly interpolating direct scattering spectra" if tim is not None: tim.getTime(False) ds_som2 = dr_lib.lin_interpolate_spectra(ds_som1, ctof_elastic_range, filter_axis=lambda_filter) if tim is not None: tim.getTime(msg="After linearly interpolating direct scattering "\ +"spectra ") if config.dump_dslin: ds_som2_1 = dr_lib.sum_all_spectra(ds_som2,\ rebin_axis=config.lambda_bins.toNessiList()) hlr_utils.write_file(config.output, "text/Spec", ds_som2_1, output_ext="lin", data_ext=config.ext_replacement, path_replacement=config.path_replacement, verbose=config.verbose, message="dsbackground linear interpolation") del ds_som2_1 del ds_som1 else: ds_som2 = None if inst_geom_dst is not None: inst_geom_dst.release_resource() # Steps 17-18: Subtract background spectrum from sample spectrum if config.dsback is None: back_som = b_som1 bkg_type = "background" else: back_som = ds_som2 bkg_type = "dsbackground" d_som2 = dr_lib.subtract_bkg_from_data(d_som1, back_som, verbose=config.verbose, timer=tim, dataset1="data", dataset2=bkg_type, scale=config.scale_bs) if config.dsback is not None: del ds_som2 # Step 19: Zero region outside TOF elastic for background for empty can if config.dsback is None: bcs_som = b_som1 cs_som = e_som1 else: if config.verbose and b_som1 is not None: print "Zeroing background spectra" if tim is not None and b_som1 is not None: tim.getTime(False) bcs_som = dr_lib.zero_spectra(b_som1, ctof_elastic_range) if tim is not None and b_som1 is not None: tim.getTime(msg="After zeroing background spectra") if config.verbose and e_som1 is not None: print "Zeroing empty can spectra" if tim is not None and e_som1 is not None: tim.getTime(False) cs_som = dr_lib.zero_spectra(e_som1, ctof_elastic_range) if tim is not None and e_som1 is not None: tim.getTime(msg="After zeroing empty can spectra") del ctof_elastic_range # Steps 20-21: Subtract background spectrum from empty can spectrum e_som2 = dr_lib.subtract_bkg_from_data(cs_som, bcs_som, verbose=config.verbose, timer=tim, dataset1="data-empty_can", dataset2="background", scale=config.scale_bcs) # Steps 22-23: Subtract background spectrum from empty can spectrum for # normalization try: config.pre_norm except AttributeError: config.pre_norm = False if not config.pre_norm: e_som3 = dr_lib.subtract_bkg_from_data(e_som1, b_som1, verbose=config.verbose, timer=tim, dataset1="norm-empty_can", dataset2="background", scale=config.scale_bcn) else: e_som3 = None # Steps 24-25: Subtract background spectrum from normalization spectrum if not config.pre_norm: n_som2 = dr_lib.subtract_bkg_from_data(n_som1, b_som1, verbose=config.verbose, timer=tim, dataset1="normalization", dataset2="background", scale=config.scale_bn) else: n_som2 = n_som1 del b_som1, e_som1, bcs_som, cs_som # Steps 26-27: Subtract empty can spectrum from sample spectrum d_som3 = dr_lib.subtract_bkg_from_data(d_som2, e_som2, verbose=config.verbose, timer=tim, dataset1="data", dataset2="empty_can", scale=config.scale_cs) del d_som2, e_som2 # Steps 28-29: Subtract empty can spectrum from normalization spectrum if not config.pre_norm: n_som3 = dr_lib.subtract_bkg_from_data(n_som2, e_som3, verbose=config.verbose, timer=tim, dataset1="normalization", dataset2="empty_can", scale=config.scale_cn) else: n_som3 = n_som2 del n_som2, e_som3 # Step 30-31: Integrate normalization spectra if config.verbose and n_som3 is not None and not config.pre_norm: print "Integrating normalization spectra" if not config.pre_norm: norm_int = dr_lib.integrate_spectra(n_som3, start=config.norm_start, end=config.norm_end, norm=True) else: norm_int = n_som3 del n_som3 # Step 32: Normalize data by integrated values if config.verbose and norm_int is not None: print "Normalizing data by normalization data" if norm_int is not None: d_som4 = common_lib.div_ncerr(d_som3, norm_int) else: d_som4 = d_som3 if norm_int is not None: if tim is not None: tim.getTime(msg="After normalizing data ") del d_som3, norm_int if config.dump_norm: if tim is not None: tim.getTime(False) hlr_utils.write_file(config.output, "text/Spec", d_som4, output_ext="wvn", data_ext=config.ext_replacement, path_replacement=config.path_replacement, verbose=config.verbose, message="wavelength (vanadium norm) information") if tim is not None: tim.getTime(msg="After writing wavelength (vanadium norm) info ") # Steps 33 to end: Creating S(Q,E) if config.Q_bins is not None: if config.verbose: print "Creating 2D spectrum" if tim is not None: tim.getTime(False) d_som5 = dr_lib.create_E_vs_Q_igs( d_som4, config.E_bins.toNessiList(), config.Q_bins.toNessiList(), so_id="Full Detector", y_label="counts", y_units="counts / (ueV * A^-1)", x_labels=["Q transfer", "energy transfer"], x_units=["1/Angstroms", "ueV"], split=config.split, Q_filter=False, configure=config) if tim is not None: tim.getTime(msg="After creation of final spectrum ") del d_som4 # Steps 33 to 36: Create S(-cos(polar), E) elif config.ncospol_bins is not None: if config.verbose: print "Convert wavelength to energy transfer" if tim is not None: tim.getTime(False) d_som4a = dr_lib.energy_transfer(d_som4, "IGS", "Wavelength_final", sa_norm=True, scale=True, change_units=True) if tim is not None: tim.getTime(msg="After wavelength to energy transfer conversion ") del d_som4 if config.verbose: print "Creating 2D spectrum" if tim is not None: tim.getTime(False) d_som5 = dr_lib.create_param_vs_Y( d_som4a, "polar", "negcos_param_array", config.ncospol_bins.toNessiList(), rebin_axis=config.E_bins.toNessiList(), y_label="counts", y_units="counts / ueV", x_labels=["-cos(polar)", "Energy Transfer"], x_units=["", "ueV"]) if tim is not None: tim.getTime(msg="After creation of final spectrum ") # If rescaling factor present, rescale the data if config.rescale_final is not None and not config.split: d_som6 = common_lib.mult_ncerr(d_som5, (config.rescale_final, 0.0)) else: d_som6 = d_som5 if tim is None: old_time = None if not __name__ == "amorphous_reduction_sqe": del d_som5 __write_output(d_som6, config, tim, old_time) else: if config.create_output: del d_som5 __write_output(d_som6, config, tim, old_time) else: return d_som6
def process_igs_data(datalist, conf, **kwargs): """ This function combines Steps 1 through 8 of the data reduction process for Inverse Geometry Spectrometers as specified by the documents 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 and processes the data accordingly. This function should really only be used in the context of I{amorphous_reduction} and I{calc_norm_eff}. @param datalist: A list containing 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 kwargs: A list of keyword arguments that the function accepts: @keyword inst_geom_dst: File object that contains instrument geometry information. @type inst_geom_dst: C{DST.GeomDST} @keyword dataset_type: The practical name of the dataset being processed. The default value is I{data}. @type dataset_type: C{string} @keyword tib_const: Object providing the time-independent background constant to subtract. @type tib_const: L{hlr_utils.DrParameter} @keyword bkg_som: Object that will be used for early background subtraction @type bkg_som: C{SOM.SOM} @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 hlr_utils # Check keywords try: dataset_type = kwargs["dataset_type"] except KeyError: dataset_type = "data" try: t = kwargs["timer"] except KeyError: t = None try: if kwargs["tib_const"] is not None: tib_const = kwargs["tib_const"].toValErrTuple() else: tib_const = None except KeyError: tib_const = None try: i_geom_dst = kwargs["inst_geom_dst"] except KeyError: i_geom_dst = None try: bkg_som = kwargs["bkg_som"] except KeyError: bkg_som = None # Step 1: Open appropriate data files if not conf.mc: so_axis = "time_of_flight" else: so_axis = "Time_of_Flight" # Add so_axis to Configure object conf.so_axis = so_axis if conf.verbose: print "Reading %s file" % dataset_type # Special case handling for normalization data. Dynamically trying to # determine if incoming file is a previously calculated one. if dataset_type == "normalization": try: # Check the first incoming file dst_type = hlr_utils.file_peeker(datalist[0]) # If file_peeker succeeds, the DST is different than the function # returns dst_type = "text/num-info" # Let ROI file handle filtering data_paths = None except RuntimeError: # It's a NeXus file dst_type = "application/x-NeXus" data_paths = conf.data_paths.toPath() else: dst_type = "application/x-NeXus" data_paths = conf.data_paths.toPath() # The [0] is to get the data SOM and ignore the None background SOM dp_som0 = dr_lib.add_files( datalist, Data_Paths=data_paths, SO_Axis=so_axis, Signal_ROI=conf.roi_file, dataset_type=dataset_type, dst_type=dst_type, Verbose=conf.verbose, Timer=t, ) if t is not None: t.getTime(msg="After reading %s " % dataset_type) if dst_type == "text/num-info": # Since we have a pre-calculated normalization dataset, set the flag # and return the SOM now conf.pre_norm = True # Make the labels and units compatible with a NeXus file based SOM dp_som0.setAxisLabel(0, "wavelength") dp_som0.setAxisUnits(0, "Angstroms") dp_som0.setYUnits("Counts/A") return dp_som0 else: if dataset_type == "normalization": # Since we have a NeXus file, we need to continue conf.pre_norm = False # Cut the spectra if necessary dp_somA = dr_lib.cut_spectra(dp_som0, conf.tof_cut_min, conf.tof_cut_max) del dp_som0 dp_som1 = dr_lib.fix_bin_contents(dp_somA) del dp_somA if conf.inst_geom is not None: i_geom_dst.setGeometry(conf.data_paths.toPath(), dp_som1) if conf.no_mon_norm: dm_som1 = None else: if conf.verbose: print "Reading in monitor data from %s file" % dataset_type # The [0] is to get the data SOM and ignore the None background SOM dm_som0 = dr_lib.add_files( datalist, Data_Paths=conf.mon_path.toPath(), SO_Axis=so_axis, dataset_type=dataset_type, Verbose=conf.verbose, Timer=t, ) if t is not None: t.getTime(msg="After reading monitor data ") dm_som1 = dr_lib.fix_bin_contents(dm_som0) del dm_som0 if conf.inst_geom is not None: i_geom_dst.setGeometry(conf.mon_path.toPath(), dm_som1) if bkg_som is not None: bkg_pcharge = bkg_som.attr_list["background-proton_charge"].getValue() data_pcharge = dp_som1.attr_list[dataset_type + "-proton_charge"].getValue() ratio = data_pcharge / bkg_pcharge bkg_som1 = common_lib.mult_ncerr(bkg_som, (ratio, 0.0)) del bkg_som dp_som2 = dr_lib.subtract_bkg_from_data( dp_som1, bkg_som1, verbose=conf.verbose, timer=t, dataset1=dataset_type, dataset2="background" ) else: dp_som2 = dp_som1 del dp_som1 # Step 2: Dead Time Correction # No dead time correction is being applied to the data yet # Step 3: Time-independent background determination if conf.verbose and conf.tib_tofs is not None: print "Determining time-independent background from data" if t is not None and conf.tib_tofs is not None: t.getTime(False) B = dr_lib.determine_time_indep_bkg(dp_som2, conf.tib_tofs) if t is not None and B is not None: t.getTime(msg="After determining time-independent background ") if conf.dump_tib and B is not None: file_comment = "TOFs: %s" % conf.tib_tofs hlr_utils.write_file( conf.output, "text/num-info", B, output_ext="tib", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="time-independent background " + "information", tag="Average", units="counts", comments=[file_comment], ) # Step 4: Subtract time-independent background if conf.verbose and B is not None: print "Subtracting time-independent background from data" if t is not None: t.getTime(False) if B is not None: dp_som3 = common_lib.sub_ncerr(dp_som2, B) else: dp_som3 = dp_som2 if B is not None and t is not None: t.getTime(msg="After subtracting time-independent background ") del dp_som2, B # Step 5: Subtract time-independent background constant if conf.verbose and tib_const is not None: print "Subtracting time-independent background constant from data" if t is not None and tib_const is not None: t.getTime(False) if tib_const is not None: dp_som4 = common_lib.sub_ncerr(dp_som3, tib_const) else: dp_som4 = dp_som3 if t is not None and tib_const is not None: t.getTime(msg="After subtracting time-independent background " + "constant ") del dp_som3 # Provide override capability for final wavelength, time-zero slope and # time-zero offset if conf.wavelength_final is not None: dp_som4.attr_list["Wavelength_final"] = conf.wavelength_final.toValErrTuple() # Note: time_zero_slope MUST be a tuple if conf.time_zero_slope is not None: dp_som4.attr_list["Time_zero_slope"] = conf.time_zero_slope.toValErrTuple() if dm_som1 is not None: dm_som1.attr_list["Time_zero_slope"] = conf.time_zero_slope.toValErrTuple() # Note: time_zero_offset MUST be a tuple if conf.time_zero_offset is not None: dp_som4.attr_list["Time_zero_offset"] = conf.time_zero_offset.toValErrTuple() if dm_som1 is not None: dm_som1.attr_list["Time_zero_offset"] = conf.time_zero_offset.toValErrTuple() # Step 6: Convert TOF to wavelength for data and monitor if conf.verbose: print "Converting TOF to wavelength" if t is not None: t.getTime(False) # Convert monitor if dm_som1 is not None: dm_som2 = common_lib.tof_to_wavelength_lin_time_zero(dm_som1, units="microsecond") else: dm_som2 = None # Convert detector pixels dp_som5 = common_lib.tof_to_initial_wavelength_igs_lin_time_zero( dp_som4, units="microsecond", run_filter=conf.filter ) if t is not None: t.getTime(msg="After converting TOF to wavelength ") if conf.dump_wave: hlr_utils.write_file( conf.output, "text/Spec", dp_som5, output_ext="pxl", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="pixel wavelength information", ) if conf.dump_mon_wave and dm_som2 is not None: hlr_utils.write_file( conf.output, "text/Spec", dm_som2, output_ext="mxl", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="monitor wavelength information", ) del dp_som4, dm_som1 # Step 7: Efficiency correct monitor if conf.verbose and dm_som2 is not None and not conf.no_mon_effc: print "Efficiency correct monitor data" if t is not None: t.getTime(False) if not conf.no_mon_effc: dm_som3 = dr_lib.feff_correct_mon(dm_som2) else: dm_som3 = dm_som2 if t is not None and dm_som2 is not None and not conf.no_mon_effc: t.getTime(msg="After efficiency correcting monitor ") if conf.dump_mon_effc and not conf.no_mon_effc and dm_som3 is not None: hlr_utils.write_file( conf.output, "text/Spec", dm_som3, output_ext="mel", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="monitor wavelength information " + "(efficiency)", ) del dm_som2 # Step 8: Rebin monitor axis onto detector pixel axis if conf.verbose and dm_som3 is not None: print "Rebin monitor axis to detector pixel axis" if t is not None: t.getTime(False) dm_som4 = dr_lib.rebin_monitor(dm_som3, dp_som5) if t is not None and dm_som4 is not None: t.getTime(msg="After rebinning monitor ") del dm_som3 if conf.dump_mon_rebin and dm_som4 is not None: hlr_utils.write_file( conf.output, "text/Spec", dm_som4, output_ext="mrl", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message="monitor wavelength information " + "(rebinned)", ) # The lambda-dependent background is only done on sample data (aka data) # for the BSS instrument at the SNS if conf.inst == "BSS" and conf.ldb_const is not None and dataset_type == "data": # Step 9: Convert chopper center wavelength to TOF center if conf.verbose: print "Converting chopper center wavelength to TOF" if t is not None: t.getTime(False) tof_center = dr_lib.convert_single_to_list( "initial_wavelength_igs_lin_time_zero_to_tof", conf.chopper_lambda_cent.toValErrTuple(), dp_som5 ) # Step 10: Calculate beginning and end of detector TOF spectrum if conf.verbose: print "Calculating beginning and ending TOF ranges" half_inv_chop_freq = 0.5 / conf.chopper_freq.toValErrTuple()[0] # Above is in seconds, need microseconds half_inv_chop_freq *= 1.0e6 tof_begin = common_lib.sub_ncerr(tof_center, (half_inv_chop_freq, 0.0)) tof_end = common_lib.add_ncerr(tof_center, (half_inv_chop_freq, 0.0)) # Step 11: Convert TOF_begin and TOF_end to wavelength if conf.verbose: print "Converting TOF_begin and TOF_end to wavelength" # Check for time-zero slope information try: tz_slope = conf.time_zero_slope.toValErrTuple() except AttributeError: tz_slope = (0.0, 0.0) # Check for time-zero offset information try: tz_offset = conf.time_zero_offset.toValErrTuple() except AttributeError: tz_offset = (0.0, 0.0) l_begin = common_lib.tof_to_initial_wavelength_igs_lin_time_zero( tof_begin, time_zero_slope=tz_slope, time_zero_offset=tz_offset, iobj=dp_som5, run_filter=False ) l_end = common_lib.tof_to_initial_wavelength_igs_lin_time_zero( tof_end, time_zero_slope=tz_slope, time_zero_offset=tz_offset, iobj=dp_som5, run_filter=False ) # Step 12: tof-least-bkg to lambda-least-bkg if conf.verbose: print "Converting TOF least background to wavelength" lambda_least_bkg = dr_lib.convert_single_to_list( "tof_to_initial_wavelength_igs_lin_time_zero", conf.tof_least_bkg.toValErrTuple(), dp_som5 ) if t is not None: t.getTime(msg="After converting boundary positions ") # Step 13: Create lambda-dependent background spectrum if conf.verbose: print "Creating lambda-dependent background spectra" if t is not None: t.getTime(False) ldb_som = dr_lib.shift_spectrum(dm_som4, lambda_least_bkg, l_begin, l_end, conf.ldb_const.getValue()) if t is not None: t.getTime(msg="After creating lambda-dependent background " + "spectra ") # Step 14: Subtract lambda-dependent background from sample data if conf.verbose: print "Subtracting lambda-dependent background from data" if t is not None: t.getTime(False) dp_som6 = common_lib.sub_ncerr(dp_som5, ldb_som) if t is not None: t.getTime(msg="After subtracting lambda-dependent background " + "from data ") else: dp_som6 = dp_som5 del dp_som5 # Step 15: Normalize data by monitor if conf.verbose and dm_som4 is not None: print "Normalizing data by monitor" if t is not None: t.getTime(False) if dm_som4 is not None: dp_som7 = common_lib.div_ncerr(dp_som6, dm_som4) if t is not None: t.getTime(msg="After normalizing data by monitor ") else: dp_som7 = dp_som6 if conf.dump_wave_mnorm: dp_som7_1 = dr_lib.sum_all_spectra(dp_som7, rebin_axis=conf.lambda_bins.toNessiList()) write_message = "combined pixel wavelength information" if dm_som4 is not None: write_message += " (monitor normalized)" hlr_utils.write_file( conf.output, "text/Spec", dp_som7_1, output_ext="pml", extra_tag=dataset_type, verbose=conf.verbose, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, message=write_message, ) del dp_som7_1 del dm_som4, dp_som6 return dp_som7
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
def process_dgs_data(obj, conf, bcan, ecan, tcoeff, **kwargs): """ This function combines Steps 7 through 16 in Section 2.1.1 of the data reduction process for Direct Geometry Spectrometers as specified by the document at U{http://neutrons.ornl.gov/asg/projects/SCL/reqspec/DR_Lib_RS.doc}. The function takes a calibrated dataset, a L{hlr_utils.Configure} object and processes the data accordingly. @param obj: A calibrated dataset object. @type obj: C{SOM.SOM} @param conf: Object that contains the current setup of the driver. @type conf: L{hlr_utils.Configure} @param bcan: The object containing the black can data. @type bcan: C{SOM.SOM} @param ecan: The object containing the empty can data. @type ecan: C{SOM.SOM} @param tcoeff: The transmission coefficient appropriate to the given data set. @type tcoeff: C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @keyword dataset_type: The practical name of the dataset being processed. The default value is I{data}. @type dataset_type: C{string} @keyword cwp_used: A flag signalling the use of the chopper phase corrections. @type cwp_used: C{bool} @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 array_manip import common_lib import dr_lib import hlr_utils # Check keywords try: dataset_type = kwargs["dataset_type"] except KeyError: dataset_type = "data" try: t = kwargs["timer"] except KeyError: t = None cwp_used = kwargs.get("cwp_used", False) if conf.verbose: print "Processing %s information" % dataset_type # Step 7: Create black can background contribution if bcan is not None: if conf.verbose: print "Creating black can background contribution for %s" \ % dataset_type if t is not None: t.getTime(False) bccoeff = array_manip.sub_ncerr(1.0, 0.0, tcoeff[0], tcoeff[1]) bcan1 = common_lib.mult_ncerr(bcan, bccoeff) if t is not None: t.getTime(msg="After creating black can background contribution ") del bcan else: bcan1 = None # Step 8: Create empty can background contribution if ecan is not None: if conf.verbose: print "Creating empty can background contribution for %s" \ % dataset_type if t is not None: t.getTime(False) ecan1 = common_lib.mult_ncerr(ecan, tcoeff) if t is not None: t.getTime(msg="After creating empty can background contribution ") del ecan else: ecan1 = None # Step 9: Create background spectra if bcan1 is not None or ecan1 is not None and conf.verbose: print "Creating background spectra for %s" % dataset_type if bcan1 is not None and ecan1 is not None: if cwp_used: if conf.verbose: print "Rebinning empty can to black can axis." ecan2 = common_lib.rebin_axis_1D_frac(ecan1, bcan1[0].axis[0].val) else: ecan2 = ecan1 del ecan1 if t is not None: t.getTime(False) b_som = common_lib.add_ncerr(bcan1, ecan2) if t is not None: t.getTime(msg="After creating background spectra ") elif bcan1 is not None and ecan1 is None: b_som = bcan1 elif bcan1 is None and ecan1 is not None: b_som = ecan1 else: b_som = None del bcan1, ecan1 if cwp_used: if conf.verbose: print "Rebinning background spectra to %s" % dataset_type b_som1 = common_lib.rebin_axis_1D_frac(b_som, obj[0].axis[0].val) else: b_som1 = b_som del b_som if conf.dump_ctof_comb and b_som1 is not None: b_som_1 = dr_lib.sum_all_spectra(b_som1) hlr_utils.write_file(conf.output, "text/Spec", b_som_1, output_ext="ctof", extra_tag="background", data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, verbose=conf.verbose, message="combined background TOF information") del b_som_1 # Step 10: Subtract background from data obj1 = dr_lib.subtract_bkg_from_data(obj, b_som1, verbose=conf.verbose, timer=t, dataset1=dataset_type, dataset2="background") del obj, b_som1 # Step 11: Calculate initial velocity if conf.verbose: print "Calculating initial velocity" if t is not None: t.getTime(False) if conf.initial_energy is not None: initial_wavelength = common_lib.energy_to_wavelength(\ conf.initial_energy.toValErrTuple()) initial_velocity = common_lib.wavelength_to_velocity(\ initial_wavelength) else: # This should actually calculate it, but don't have a way right now pass if t is not None: t.getTime(msg="After calculating initial velocity ") # Step 12: Calculate the time-zero offset if conf.time_zero_offset is not None: time_zero_offset = conf.time_zero_offset.toValErrTuple() else: # This should actually calculate it, but don't have a way right now time_zero_offset = (0.0, 0.0) # Step 13: Convert time-of-flight to final velocity if conf.verbose: print "Converting TOF to final velocity DGS" if t is not None: t.getTime(False) obj2 = common_lib.tof_to_final_velocity_dgs(obj1, initial_velocity, time_zero_offset, units="microsecond") if t is not None: t.getTime(msg="After calculating TOF to final velocity DGS ") del obj1 # Step 14: Convert final velocity to final wavelength if conf.verbose: print "Converting final velocity DGS to final wavelength" if t is not None: t.getTime(False) obj3 = common_lib.velocity_to_wavelength(obj2) if t is not None: t.getTime(msg="After calculating velocity to wavelength ") del obj2 if conf.dump_wave_comb: obj3_1 = dr_lib.sum_all_spectra(obj3, rebin_axis=conf.lambda_bins.toNessiList()) hlr_utils.write_file(conf.output, "text/Spec", obj3_1, output_ext="fwv", extra_tag=dataset_type, data_ext=conf.ext_replacement, path_replacement=conf.path_replacement, verbose=conf.verbose, message="combined final wavelength information") del obj3_1 # Step 15: Create the detector efficiency if conf.det_eff is not None: if conf.verbose: print "Creating detector efficiency spectra" if t is not None: t.getTime(False) det_eff = dr_lib.create_det_eff(obj3) if t is not None: t.getTime(msg="After creating detector efficiency spectra ") else: det_eff = None # Step 16: Divide the detector pixel spectra by the detector efficiency if det_eff is not None: if conf.verbose: print "Correcting %s for detector efficiency" % dataset_type if t is not None: t.getTime(False) obj4 = common_lib.div_ncerr(obj3, det_eff) if t is not None: t.getTime(msg="After correcting %s for detector efficiency" \ % dataset_type) else: obj4 = obj3 del obj3, det_eff return obj4