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 process_reflp_data(datalist, conf, roi_file, bkg_roi_file=None, no_bkg=False, **kwargs): """ This function combines Steps 1 through 3 in section 2.4.6.1 of the data reduction process for Reduction from TOF to lambda_T 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, region-of-interest (ROI) file for the normalization dataset, a background region-of-interest (ROI) file and an optional flag about background subtractionand 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 roi_file: The file containing the list of pixel IDs for the region of interest. This only applies to normalization data. @type 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: File object that contains instrument geometry information. @type inst_geom_dst: C{DST.GeomDST} @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 import common_lib import dr_lib # Check keywords try: i_geom_dst = kwargs["inst_geom_dst"] except KeyError: i_geom_dst = None try: t = kwargs["timer"] except KeyError: t = None if roi_file is not None: # Normalization dataset_type = "norm" else: # Sample data dataset_type = "data" so_axis = "time_of_flight" # Step 0: Open data files and select ROI (if necessary) 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=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) # Override geometry if necessary if i_geom_dst is not None: i_geom_dst.setGeometry(conf.data_paths.toPath(), d_som1) if dataset_type == "data": # Get TOF bin width conf.delta_TOF = d_som1[0].axis[0].val[1] - d_som1[0].axis[0].val[0] if conf.mon_norm: 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_som1 = 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 ") else: dm_som1 = None # Step 1: Sum all spectra along the low resolution direction # Set sorting for REF_L if conf.verbose: print "Summing over 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 t is not None: t.getTime(False) d_som2 = dr_lib.sum_all_spectra(d_som1, y_sort=y_sort, stripe=True, pixel_fix=cent_pixel) if b_som1 is not None: b_som2 = dr_lib.sum_all_spectra(b_som1, y_sort=y_sort, stripe=True, pixel_fix=cent_pixel) del b_som1 else: b_som2 = b_som1 if t is not None: t.getTime(msg="After summing low resolution direction ") del d_som1 # Determine background spectrum if conf.verbose and not no_bkg: print "Determining %s background" % dataset_type if b_som2 is not None: B = dr_lib.calculate_ref_background(b_som2, no_bkg, conf.inst, None, aobj=d_som2) if t is not None: t.getTime(msg="After background determination") # Subtract background spectrum from data spectra if not no_bkg: d_som3 = dr_lib.subtract_bkg_from_data(d_som2, B, verbose=conf.verbose, timer=t, dataset1="data", dataset2="background") else: d_som3 = d_som2 del d_som2 # Zero the spectra if necessary if roi_file is None and (conf.tof_cut_min is not None or \ conf.tof_cut_max is not None): import utils # Find the indicies for the non zero range if conf.tof_cut_min is None: conf.TOF_min = d_som3[0].axis[0].val[0] start_index = 0 else: start_index = utils.bisect_helper(d_som3[0].axis[0].val, conf.tof_cut_min) if conf.tof_cut_max is None: conf.TOF_max = d_som3[0].axis[0].val[-1] end_index = len(d_som3[0].axis[0].val) - 1 else: end_index = utils.bisect_helper(d_som3[0].axis[0].val, conf.tof_cut_max) nz_list = [] for i in xrange(hlr_utils.get_length(d_som3)): nz_list.append((start_index, end_index)) d_som4 = dr_lib.zero_spectra(d_som3, nz_list, use_bin_index=True) else: conf.TOF_min = d_som3[0].axis[0].val[0] conf.TOF_max = d_som3[0].axis[0].val[-1] d_som4 = d_som3 del d_som3 # Step N: Convert TOF to wavelength if conf.verbose: print "Converting TOF to wavelength" if t is not None: t.getTime(False) d_som5 = common_lib.tof_to_wavelength(d_som4, inst_param="total", units="microsecond") if dm_som1 is not None: dm_som2 = common_lib.tof_to_wavelength(dm_som1, units="microsecond") else: dm_som2 = None del dm_som1 if t is not None: t.getTime(msg="After converting TOF to wavelength ") del d_som4 if conf.mon_norm: dm_som3 = dr_lib.rebin_monitor(dm_som2, d_som5, rtype="frac") else: dm_som3 = None del dm_som2 if not conf.mon_norm: # Step 2: Multiply the spectra by the proton charge if conf.verbose: print "Multiply spectra by proton charge" pc_tag = dataset_type + "-proton_charge" proton_charge = d_som5.attr_list[pc_tag] if t is not None: t.getTime(False) d_som6 = common_lib.div_ncerr(d_som5, (proton_charge.getValue(), 0.0)) if t is not None: t.getTime(msg="After scaling by proton charge ") else: if conf.verbose: print "Normalize by monitor spectrum" if t is not None: t.getTime(False) d_som6 = common_lib.div_ncerr(d_som5, dm_som3) if t is not None: t.getTime(msg="After monitor normalization ") del d_som5, dm_som3 if roi_file is None: return d_som6 else: # Step 3: Make one spectrum for normalization dataset # Need to create a final rebinning axis pathlength = d_som6.attr_list.instrument.get_total_path( det_secondary=True) delta_lambda = common_lib.tof_to_wavelength((conf.delta_TOF, 0.0), pathlength=pathlength) lambda_bins = dr_lib.create_axis_from_data(d_som6, width=delta_lambda[0]) return dr_lib.sum_by_rebin_frac(d_som6, lambda_bins.toNessiList())
def run(config, tim): """ 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: Object that will allow the method to perform timing evaluations. @type tim: C{sns_time.DiffTime} """ import array_manip import common_lib import dr_lib import DST import SOM import math 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 sample data geometry if one is provided if config.data_inst_geom is not None: if config.verbose: print "Reading in sample data instrument geometry file" data_inst_geom_dst = DST.getInstance("application/x-NxsGeom", config.data_inst_geom) else: data_inst_geom_dst = None # Read in normalization data geometry if one is provided if config.norm_inst_geom is not None: if config.verbose: print "Reading in normalization instrument geometry file" norm_inst_geom_dst = DST.getInstance("application/x-NxsGeom", config.norm_inst_geom) else: norm_inst_geom_dst = None # Perform Steps 1-2 on sample data d_som1 = dr_lib.process_reflp_data(config.data, config, None, config.dbkg_roi_file, config.no_bkg, inst_geom_dst=data_inst_geom_dst, timer=tim) # Get the detector angle if config.omega is None: # Make a fake SO so = SOM.SO() try: theta = hlr_utils.get_special(d_som1.attr_list["Theta"], so) except KeyError: theta = (float('nan'), float('nan')) else: theta = config.omega.toFullTuple() if theta[0] is not None: if theta[2] == "degrees" or theta[2] == "degree": theta_rads = (theta[0] * (math.pi / 180.0), 0.0) else: theta_rads = (theta[0], 0.0) else: theta_rads = (float('nan'), float('nan')) d_som1.attr_list["data-theta"] = (theta_rads[0], theta_rads[1], "radians") # Perform Steps 1-3 on normalization data if config.norm is not None: n_som1 = dr_lib.process_reflp_data(config.norm, config, config.norm_roi_file, config.nbkg_roi_file, config.no_norm_bkg, inst_geom_dst=norm_inst_geom_dst, timer=tim) else: n_som1 = None # Closing sample data instrument geometry file if data_inst_geom_dst is not None: data_inst_geom_dst.release_resource() # Closing normalization data instrument geometry file if norm_inst_geom_dst is not None: norm_inst_geom_dst.release_resource() # Step 4: Divide data by normalization if config.verbose and config.norm is not None: print "Scale data by normalization" if tim is not None: tim.getTime(False) if config.norm is not None: # Need to rebin the normalization spectra to the data pixel spectra n_som2 = dr_lib.rebin_monitor(n_som1, d_som1, rtype="frac") # Now divide the spectra d_som2 = common_lib.div_ncerr(d_som1, n_som2) del n_som2 else: d_som2 = d_som1 if tim is not None and config.norm is not None: tim.getTime(msg="After normalizing signal spectra") del d_som1, n_som1 sin_theta_rads = (math.sin(theta_rads[0]), math.sin(theta_rads[1])) if sin_theta_rads[0] < 0.0: sin_theta_rads = (math.fabs(sin_theta_rads[0]), math.fabs(sin_theta_rads[1])) # Step 6: Scale wavelength axis by sin(theta) to make lambda_T if config.verbose: print "Scaling wavelength axis by sin(theta)" if tim is not None: tim.getTime(False) d_som3 = common_lib.div_ncerr(d_som2, sin_theta_rads, axis="x") if tim is not None: tim.getTime(msg="After scaling wavelength axis ") del d_som2 d_som3.setAxisLabel(0, "lambda_T") # Step 7: Rebin to lambda_T axis if config.verbose: print "Rebinning spectra" if config.lambdap_bins is None: # Create a binning scheme pathlength = d_som3.attr_list.instrument.get_total_path( det_secondary=True) delta_lambda = common_lib.tof_to_wavelength((config.delta_TOF, 0.0), pathlength=pathlength) delta_lambdap = array_manip.div_ncerr(delta_lambda[0], delta_lambda[1], sin_theta_rads[0], 0.0) config.lambdap_bins = dr_lib.create_axis_from_data( d_som3, width=delta_lambdap[0]) else: # Do nothing, got the binning scheme pass if tim is not None: tim.getTime(False) d_som4 = common_lib.rebin_axis_1D_frac(d_som3, config.lambdap_bins.toNessiList()) if tim is not None: tim.getTime(msg="After rebinning spectra ") del d_som3 if config.inst == "REF_M": # Clean up spectrum if config.tof_cut_min is not None: tof_cut_min = float(config.tof_cut_min) else: tof_cut_min = config.TOF_min if config.tof_cut_max is not None: tof_cut_max = float(config.tof_cut_max) else: tof_cut_max = config.TOF_max pathlength = d_som4.attr_list.instrument.get_total_path( det_secondary=True) lambda_min = common_lib.tof_to_wavelength((tof_cut_min, 0.0), pathlength=pathlength) lambda_T_min = common_lib.div_ncerr(lambda_min, sin_theta_rads) lambda_max = common_lib.tof_to_wavelength((tof_cut_max, 0.0), pathlength=pathlength) lambda_T_max = common_lib.div_ncerr(lambda_max, sin_theta_rads) nz_list = [] for i in xrange(hlr_utils.get_length(d_som4)): nz_list.append((lambda_T_min[0], lambda_T_max[0])) d_som4A = dr_lib.zero_spectra(d_som4, nz_list) else: d_som4A = d_som4 del d_som4 # Step 8: Write out all spectra to a file hlr_utils.write_file(config.output, "text/Spec", d_som4A, replace_ext=False, replace_path=False, verbose=config.verbose, message="Reflectivity information") if config.dump_twod: d_som5 = dr_lib.create_X_vs_pixpos(d_som4A, config.lambdap_bins.toNessiList(), rebin=False, y_label="R", y_units="", x_label="$\lambda_T$", x_units="$\AA$") hlr_utils.write_file(config.output, "text/Dave2d", d_som5, output_ext="plp", verbose=config.verbose, data_ext=config.ext_replacement, path_replacement=config.path_replacement, message="2D Reflectivity information") d_som4A.attr_list["config"] = config hlr_utils.write_file(config.output, "text/rmd", d_som4A, output_ext="rmd", verbose=config.verbose, data_ext=config.ext_replacement, path_replacement=config.path_replacement, message="metadata") if tim is not None: tim.setOldTime(old_time) tim.getTime(msg="Total Running Time")
def run(config, tim): """ 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: Object that will allow the method to perform timing evaluations. @type tim: C{sns_time.DiffTime} """ import array_manip import common_lib import dr_lib import DST import SOM import math 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 sample data geometry if one is provided if config.data_inst_geom is not None: if config.verbose: print "Reading in sample data instrument geometry file" data_inst_geom_dst = DST.getInstance("application/x-NxsGeom", config.data_inst_geom) else: data_inst_geom_dst = None # Read in normalization data geometry if one is provided if config.norm_inst_geom is not None: if config.verbose: print "Reading in normalization instrument geometry file" norm_inst_geom_dst = DST.getInstance("application/x-NxsGeom", config.norm_inst_geom) else: norm_inst_geom_dst = None # Perform Steps 1-2 on sample data d_som1 = dr_lib.process_reflp_data(config.data, config, None, config.dbkg_roi_file, config.no_bkg, inst_geom_dst=data_inst_geom_dst, timer=tim) # Get the detector angle if config.omega is None: # Make a fake SO so = SOM.SO() try: theta = hlr_utils.get_special(d_som1.attr_list["Theta"], so) except KeyError: theta = (float('nan'), float('nan')) else: theta = config.omega.toFullTuple() if theta[0] is not None: if theta[2] == "degrees" or theta[2] == "degree": theta_rads = (theta[0] * (math.pi / 180.0), 0.0) else: theta_rads = (theta[0], 0.0) else: theta_rads = (float('nan'), float('nan')) d_som1.attr_list["data-theta"] = (theta_rads[0], theta_rads[1], "radians") # Perform Steps 1-3 on normalization data if config.norm is not None: n_som1 = dr_lib.process_reflp_data(config.norm, config, config.norm_roi_file, config.nbkg_roi_file, config.no_norm_bkg, inst_geom_dst=norm_inst_geom_dst, timer=tim) else: n_som1 = None # Closing sample data instrument geometry file if data_inst_geom_dst is not None: data_inst_geom_dst.release_resource() # Closing normalization data instrument geometry file if norm_inst_geom_dst is not None: norm_inst_geom_dst.release_resource() # Step 4: Divide data by normalization if config.verbose and config.norm is not None: print "Scale data by normalization" if tim is not None: tim.getTime(False) if config.norm is not None: # Need to rebin the normalization spectra to the data pixel spectra n_som2 = dr_lib.rebin_monitor(n_som1, d_som1, rtype="frac") # Now divide the spectra d_som2 = common_lib.div_ncerr(d_som1, n_som2) del n_som2 else: d_som2 = d_som1 if tim is not None and config.norm is not None: tim.getTime(msg="After normalizing signal spectra") del d_som1, n_som1 sin_theta_rads = (math.sin(theta_rads[0]), math.sin(theta_rads[1])) if sin_theta_rads[0] < 0.0: sin_theta_rads = (math.fabs(sin_theta_rads[0]), math.fabs(sin_theta_rads[1])) # Step 6: Scale wavelength axis by sin(theta) to make lambda_T if config.verbose: print "Scaling wavelength axis by sin(theta)" if tim is not None: tim.getTime(False) d_som3 = common_lib.div_ncerr(d_som2, sin_theta_rads, axis="x") if tim is not None: tim.getTime(msg="After scaling wavelength axis ") del d_som2 d_som3.setAxisLabel(0, "lambda_T") # Step 7: Rebin to lambda_T axis if config.verbose: print "Rebinning spectra" if config.lambdap_bins is None: # Create a binning scheme pathlength = d_som3.attr_list.instrument.get_total_path( det_secondary=True) delta_lambda = common_lib.tof_to_wavelength((config.delta_TOF, 0.0), pathlength=pathlength) delta_lambdap = array_manip.div_ncerr(delta_lambda[0], delta_lambda[1], sin_theta_rads[0], 0.0) config.lambdap_bins = dr_lib.create_axis_from_data(d_som3, width=delta_lambdap[0]) else: # Do nothing, got the binning scheme pass if tim is not None: tim.getTime(False) d_som4 = common_lib.rebin_axis_1D_frac(d_som3, config.lambdap_bins.toNessiList()) if tim is not None: tim.getTime(msg="After rebinning spectra ") del d_som3 if config.inst == "REF_M": # Clean up spectrum if config.tof_cut_min is not None: tof_cut_min = float(config.tof_cut_min) else: tof_cut_min = config.TOF_min if config.tof_cut_max is not None: tof_cut_max = float(config.tof_cut_max) else: tof_cut_max = config.TOF_max pathlength = d_som4.attr_list.instrument.get_total_path( det_secondary=True) lambda_min = common_lib.tof_to_wavelength((tof_cut_min, 0.0), pathlength=pathlength) lambda_T_min = common_lib.div_ncerr(lambda_min, sin_theta_rads) lambda_max = common_lib.tof_to_wavelength((tof_cut_max, 0.0), pathlength=pathlength) lambda_T_max = common_lib.div_ncerr(lambda_max, sin_theta_rads) nz_list = [] for i in xrange(hlr_utils.get_length(d_som4)): nz_list.append((lambda_T_min[0], lambda_T_max[0])) d_som4A = dr_lib.zero_spectra(d_som4, nz_list) else: d_som4A = d_som4 del d_som4 # Step 8: Write out all spectra to a file hlr_utils.write_file(config.output, "text/Spec", d_som4A, replace_ext=False, replace_path=False, verbose=config.verbose, message="Reflectivity information") if config.dump_twod: d_som5 = dr_lib.create_X_vs_pixpos(d_som4A, config.lambdap_bins.toNessiList(), rebin=False, y_label="R", y_units="", x_label="$\lambda_T$", x_units="$\AA$") hlr_utils.write_file(config.output, "text/Dave2d", d_som5, output_ext="plp", verbose=config.verbose, data_ext=config.ext_replacement, path_replacement=config.path_replacement, message="2D Reflectivity information") d_som4A.attr_list["config"] = config hlr_utils.write_file(config.output, "text/rmd", d_som4A, output_ext="rmd", verbose=config.verbose, data_ext=config.ext_replacement, path_replacement=config.path_replacement, message="metadata") if tim is not None: tim.setOldTime(old_time) tim.getTime(msg="Total Running Time")
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_reflp_data(datalist, conf, roi_file, bkg_roi_file=None, no_bkg=False, **kwargs): """ This function combines Steps 1 through 3 in section 2.4.6.1 of the data reduction process for Reduction from TOF to lambda_T 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, region-of-interest (ROI) file for the normalization dataset, a background region-of-interest (ROI) file and an optional flag about background subtractionand 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 roi_file: The file containing the list of pixel IDs for the region of interest. This only applies to normalization data. @type 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: File object that contains instrument geometry information. @type inst_geom_dst: C{DST.GeomDST} @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 import common_lib import dr_lib # Check keywords try: i_geom_dst = kwargs["inst_geom_dst"] except KeyError: i_geom_dst = None try: t = kwargs["timer"] except KeyError: t = None if roi_file is not None: # Normalization dataset_type = "norm" else: # Sample data dataset_type = "data" so_axis = "time_of_flight" # Step 0: Open data files and select ROI (if necessary) 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=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) # Override geometry if necessary if i_geom_dst is not None: i_geom_dst.setGeometry(conf.data_paths.toPath(), d_som1) if dataset_type == "data": # Get TOF bin width conf.delta_TOF = d_som1[0].axis[0].val[1] - d_som1[0].axis[0].val[0] if conf.mon_norm: 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_som1 = 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 ") else: dm_som1 = None # Step 1: Sum all spectra along the low resolution direction # Set sorting for REF_L if conf.verbose: print "Summing over 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 t is not None: t.getTime(False) d_som2 = dr_lib.sum_all_spectra(d_som1, y_sort=y_sort, stripe=True, pixel_fix=cent_pixel) if b_som1 is not None: b_som2 = dr_lib.sum_all_spectra(b_som1, y_sort=y_sort, stripe=True, pixel_fix=cent_pixel) del b_som1 else: b_som2 = b_som1 if t is not None: t.getTime(msg="After summing low resolution direction ") del d_som1 # Determine background spectrum if conf.verbose and not no_bkg: print "Determining %s background" % dataset_type if b_som2 is not None: B = dr_lib.calculate_ref_background(b_som2, no_bkg, conf.inst, None, aobj=d_som2) if t is not None: t.getTime(msg="After background determination") # Subtract background spectrum from data spectra if not no_bkg: d_som3 = dr_lib.subtract_bkg_from_data(d_som2, B, verbose=conf.verbose, timer=t, dataset1="data", dataset2="background") else: d_som3 = d_som2 del d_som2 # Zero the spectra if necessary if roi_file is None and (conf.tof_cut_min is not None or \ conf.tof_cut_max is not None): import utils # Find the indicies for the non zero range if conf.tof_cut_min is None: conf.TOF_min = d_som3[0].axis[0].val[0] start_index = 0 else: start_index = utils.bisect_helper(d_som3[0].axis[0].val, conf.tof_cut_min) if conf.tof_cut_max is None: conf.TOF_max = d_som3[0].axis[0].val[-1] end_index = len(d_som3[0].axis[0].val) - 1 else: end_index = utils.bisect_helper(d_som3[0].axis[0].val, conf.tof_cut_max) nz_list = [] for i in xrange(hlr_utils.get_length(d_som3)): nz_list.append((start_index, end_index)) d_som4 = dr_lib.zero_spectra(d_som3, nz_list, use_bin_index=True) else: conf.TOF_min = d_som3[0].axis[0].val[0] conf.TOF_max = d_som3[0].axis[0].val[-1] d_som4 = d_som3 del d_som3 # Step N: Convert TOF to wavelength if conf.verbose: print "Converting TOF to wavelength" if t is not None: t.getTime(False) d_som5 = common_lib.tof_to_wavelength(d_som4, inst_param="total", units="microsecond") if dm_som1 is not None: dm_som2 = common_lib.tof_to_wavelength(dm_som1, units="microsecond") else: dm_som2 = None del dm_som1 if t is not None: t.getTime(msg="After converting TOF to wavelength ") del d_som4 if conf.mon_norm: dm_som3 = dr_lib.rebin_monitor(dm_som2, d_som5, rtype="frac") else: dm_som3 = None del dm_som2 if not conf.mon_norm: # Step 2: Multiply the spectra by the proton charge if conf.verbose: print "Multiply spectra by proton charge" pc_tag = dataset_type + "-proton_charge" proton_charge = d_som5.attr_list[pc_tag] if t is not None: t.getTime(False) d_som6 = common_lib.div_ncerr(d_som5, (proton_charge.getValue(), 0.0)) if t is not None: t.getTime(msg="After scaling by proton charge ") else: if conf.verbose: print "Normalize by monitor spectrum" if t is not None: t.getTime(False) d_som6 = common_lib.div_ncerr(d_som5, dm_som3) if t is not None: t.getTime(msg="After monitor normalization ") del d_som5, dm_som3 if roi_file is None: return d_som6 else: # Step 3: Make one spectrum for normalization dataset # Need to create a final rebinning axis pathlength = d_som6.attr_list.instrument.get_total_path( det_secondary=True) delta_lambda = common_lib.tof_to_wavelength((conf.delta_TOF, 0.0), pathlength=pathlength) lambda_bins = dr_lib.create_axis_from_data(d_som6, width=delta_lambda[0]) return dr_lib.sum_by_rebin_frac(d_som6, lambda_bins.toNessiList())
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