Beispiel #1
0
def add_files_bg(filelist, **kwargs):
    """
    This function takes a list of U{NeXus<www.nexusformat.org>} files and
    various keyword arguments and returns a data C{SOM} and a background C{SOM}
    (if requested) that is the sum of all the data from the specified files.
    B{It is assumed that the files contain similar data as only crude
    cross-checks will be made. You have been warned.}

    @param filelist: A list containing the names of the files to sum
    @type filelist: C{list}
    
    @param kwargs: A list of keyword arguments that the function accepts:
    
    @keyword SO_Axis: This is the name of the main axis to read from the NeXus
                      file
    @type SO_Axis: C{string}
    
    @keyword Data_Paths: This contains the data paths and signals for the
                         requested detector banks
    @type Data_Paths: C{tuple} of C{tuple}s
    
    @keyword Signal_ROI: This is the name of a file that contains a list of
                         pixel IDs that will be read from the data file and
                         stored as a signal C{SOM}
    @type Signal_ROI: C{string}
    
    @keyword Bkg_ROI: This is the name of a file that contains a list of pixel
                      IDs that will be read from the data file and stored as a
                      background C{SOM}
    @type Bkg_ROI: C{string}
    
    @keyword dataset_type: The practical name of the dataset being processed.
                           The default value is I{data}.
    @type dataset_type: C{string}

    @keyword dst_type: The type of C{DST} to be created during file read-in.
                       The default value is I{application/x-NeXus}.
    @type dst_type: C{string}
    
    @keyword Verbose: This is a flag to turn on print statments. The default is
                      I{False}.
    @type Verbose: C{boolean}
    
    @keyword Timer: This is an SNS Timer object used for showing the
                    performance timing in the function.
    @type Timer: C{sns_timing.Timer}


    @return: Signal C{SOM.SOM} and background C{SOM.SOM}
    @rtype: C{tuple}

    
    @raise SystemExit: If any file cannot be read
    """
    import sys

    import common_lib
    import DST
    import hlr_utils

    # Parse keywords
    try:
        so_axis = kwargs["SO_Axis"]
    except KeyError:
        so_axis = "time_of_flight"

    try:
        data_paths = kwargs["Data_Paths"]
    except KeyError:
        data_paths = None

    try:
        signal_roi = kwargs["Signal_ROI"]
    except KeyError:
        signal_roi = None
    try:
        bkg_roi = kwargs["Bkg_ROI"]
    except KeyError:
        bkg_roi = None

    try:
        dataset_type = kwargs["dataset_type"]
    except KeyError:
        dataset_type = "data"

    try:
        dst_type = kwargs["dst_type"]
    except KeyError:
        try:
            dst_type = hlr_utils.file_peeker(filelist[0])
        except RuntimeError:
            # Assume it is a NeXus file, since it is not a DR produced file
            dst_type = "application/x-NeXus"

    try:
        verbose = kwargs["Verbose"]
    except KeyError:
        verbose = False

    try:
        timer = kwargs["Timer"]
    except KeyError:
        timer = None

    counter = 0

    for filename in filelist:
        if verbose:
            print "File:", filename

        try:
            if dst_type == "application/x-NeXus":
                data_dst = DST.getInstance(dst_type, filename)
            else:
                resource = open(filename, "r")
                data_dst = DST.getInstance(dst_type, resource)
        except SystemError:
            print "ERROR: Failed to data read file %s" % filename
            sys.exit(-1)

        if verbose:
            print "Reading data file %d" % counter

        if counter == 0:
            if dst_type == "application/x-NeXus":
                d_som1 = data_dst.getSOM(data_paths,
                                         so_axis,
                                         roi_file=signal_roi)
                d_som1.rekeyNxPars(dataset_type)
            else:
                if dst_type != "text/Dave2d":
                    d_som1 = data_dst.getSOM(data_paths, roi_file=signal_roi)
                else:
                    d_som1 = data_dst.getSOM(data_paths)

            if verbose:
                print "# Signal SO:", len(d_som1)
                if dst_type == "application/x-NeXus":
                    print "# TOF:", len(d_som1[0])
                    print "# TOF Axis:", len(d_som1[0].axis[0].val)
                elif dst_type != "text/num-info":
                    print "# Data Size:", len(d_som1[0])
                    print "# X-Axis:", len(d_som1[0].axis[0].val)
                    try:
                        axis_len = len(d_som1[0].axis[1].val)
                        print "# Y-Axis:", axis_len
                    except IndexError:
                        pass

            if bkg_roi is not None:
                if dst_type == "application/x-NeXus":
                    b_som1 = data_dst.getSOM(data_paths,
                                             so_axis,
                                             roi_file=bkg_roi)
                    b_som1.rekeyNxPars(dataset_type)
                else:
                    if dst_type != "text/Dave2d":
                        b_som1 = data_dst.getSOM(data_paths, roi_file=bkg_roi)
                    else:
                        b_som1 = data_dst.getSOM(data_paths)
                if verbose:
                    print "# Background SO:", len(b_som1)

            else:
                b_som1 = None

            if timer is not None:
                timer.getTime(msg="After reading data")

        else:
            if dst_type == "application/x-NeXus":
                d_som_t = data_dst.getSOM(data_paths,
                                          so_axis,
                                          roi_file=signal_roi)
                d_som_t.rekeyNxPars(dataset_type)
                add_nxpars_sig = True
            else:
                if dst_type != "text/Dave2d":
                    d_som_t = data_dst.getSOM(data_paths, roi_file=signal_roi)
                else:
                    d_som_t = data_dst.getSOM(data_paths)
                add_nxpars_sig = False

            if bkg_roi is not None:
                if dst_type == "application/x-NeXus":
                    b_som_t = data_dst.getSOM(data_paths,
                                              so_axis,
                                              roi_file=bkg_roi)
                    b_som_t.rekeyNxPars(dataset_type)
                    add_nxpars_bkg = True
                else:
                    if dst_type != "text/Dave2d":
                        b_som_t = data_dst.getSOM(data_paths, roi_file=bkg_roi)
                    else:
                        b_som_t = data_dst.getSOM(data_paths)
                    add_nxpars_bkg = False
            else:
                b_som_t = None
            if timer is not None:
                timer.getTime(msg="After reading data")

            d_som1 = common_lib.add_ncerr(d_som_t,
                                          d_som1,
                                          add_nxpars=add_nxpars_sig)
            if bkg_roi is not None:
                b_som1 = common_lib.add_ncerr(b_som_t,
                                              b_som1,
                                              add_nxpars=add_nxpars_bkg)

            if timer is not None:
                timer.getTime(msg="After adding spectra")

            del d_som_t
            if bkg_roi is not None:
                del b_som_t

            if timer is not None:
                timer.getTime(msg="After SOM deletion")

        data_dst.release_resource()
        del data_dst
        counter += 1

        if timer is not None:
            timer.getTime(msg="After resource release and DST deletion")

        if dst_type == "application/x-NeXus":
            som_key_parts = [dataset_type, "filename"]
            som_key = "-".join(som_key_parts)

            d_som1.attr_list[som_key] = filelist
            if b_som1 is not None:
                b_som1.attr_list[som_key] = filelist
        else:
            # Previously written files already have this structure imposed
            pass

    return (d_som1, b_som1)
Beispiel #2
0
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
Beispiel #3
0
def add_files(filelist, **kwargs):
    """
    This function takes a list of U{NeXus<www.nexusformat.org>} files and
    various keyword arguments and returns a data C{SOM} and a background C{SOM}
    (if requested) that is the sum of all the data from the specified files.
    B{It is assumed that the files contain similar data as only crude
    cross-checks will be made. You have been warned.}

    @param filelist: A list containing the names of the files to sum
    @type filelist: C{list}
    
    @param kwargs: A list of keyword arguments that the function accepts:
    
    @keyword SO_Axis: This is the name of the main axis to read from the NeXus
                      file
    @type SO_Axis: C{string}
    
    @keyword Data_Paths: This contains the data paths and signals for the
                         requested detector banks
    @type Data_Paths: C{tuple} of C{tuple}s
    
    @keyword Signal_ROI: This is the name of a file that contains a list of
                         pixel IDs that will be read from the data file and
                         stored as a signal C{SOM}
    @type Signal_ROI: C{string}

    @keyword Signal_MASK: This is the name of a file that contains a list of
                         pixel IDs that will be read from the data file and
                         stored as a signal C{SOM}
    @type Signal_MASK: C{string}    
    
    @keyword dataset_type: The practical name of the dataset being processed.
                           The default value is I{data}.
    @type dataset_type: C{string}

    @keyword dst_type: The type of C{DST} to be created during file read-in.
                       The default value is I{application/x-NeXus}.
    @type dst_type: C{string}
    
    @keyword Verbose: This is a flag to turn on print statments. The default is
                      I{False}.
    @type Verbose: C{boolean}
    
    @keyword Timer: This is an SNS Timer object used for showing the
                    performance timing in the function.
    @type Timer: C{sns_timing.Timer}


    @return: Signal C{SOM.SOM} and background C{SOM.SOM}
    @rtype: C{tuple}

    
    @raise SystemExit: If any file cannot be read
    @raise RuntimeError: If both a ROI and MASK file are specified
    """
    import sys

    import common_lib
    import DST
    import hlr_utils

    # Parse keywords
    try:
        so_axis = kwargs["SO_Axis"]
    except KeyError:
        so_axis = "time_of_flight"

    try:
        data_paths = kwargs["Data_Paths"]
    except KeyError:
        data_paths = None

    try:
        signal_roi = kwargs["Signal_ROI"]
    except KeyError:
        signal_roi = None

    try:
        signal_mask = kwargs["Signal_MASK"]
    except KeyError:
        signal_mask = None

    try:
        dataset_type = kwargs["dataset_type"]
    except KeyError:
        dataset_type = "data"

    try:
        dst_type = kwargs["dst_type"]
    except KeyError:
        try:
            dst_type = hlr_utils.file_peeker(filelist[0])
        except RuntimeError:
            # Assume it is a NeXus file, since it is not a DR produced file
            dst_type = "application/x-NeXus"

    try:
        verbose = kwargs["Verbose"]
    except KeyError:
        verbose = False

    try:
        timer = kwargs["Timer"]
    except KeyError:
        timer = None

    if signal_roi is not None and signal_mask is not None:
        raise RuntimeError("Cannot specify both ROI and MASK file! Please " + "choose!")

    counter = 0

    for filename in filelist:
        if verbose:
            print "File:", filename

        try:
            if dst_type == "application/x-NeXus":
                data_dst = DST.getInstance(dst_type, filename)
            else:
                resource = open(filename, "r")
                data_dst = DST.getInstance(dst_type, resource)
        except SystemError:
            print "ERROR: Failed to data read file %s" % filename
            sys.exit(-1)

        if verbose:
            print "Reading data file %d" % counter

        if counter == 0:
            if dst_type == "application/x-NeXus":
                d_som1 = data_dst.getSOM(data_paths, so_axis, roi_file=signal_roi, mask_file=signal_mask)
                d_som1.rekeyNxPars(dataset_type)
            else:
                if dst_type != "text/Dave2d":
                    d_som1 = data_dst.getSOM(data_paths, roi_file=signal_roi, mask_file=signal_mask)
                else:
                    d_som1 = data_dst.getSOM(data_paths)

            if verbose:
                len_data = len(d_som1)
                print "# Signal SO:", len_data
                if len_data == 0:
                    print "All data has been filtered. Program exiting."
                    sys.exit(0)

                if dst_type == "application/x-NeXus":
                    print "# TOF:", len(d_som1[0])
                    print "# TOF Axis:", len(d_som1[0].axis[0].val)
                elif dst_type != "text/num-info":
                    print "# Data Size:", len(d_som1[0])
                    print "# X-Axis:", len(d_som1[0].axis[0].val)
                    try:
                        axis_len = len(d_som1[0].axis[1].val)
                        print "# Y-Axis:", axis_len
                    except IndexError:
                        pass

            if timer is not None:
                timer.getTime(msg="After reading data")

        else:
            if dst_type == "application/x-NeXus":
                d_som_t = data_dst.getSOM(data_paths, so_axis, roi_file=signal_roi, mask_file=signal_mask)
                d_som_t.rekeyNxPars(dataset_type)
                add_nxpars_sig = True
            else:
                if dst_type != "text/Dave2d":
                    d_som_t = data_dst.getSOM(data_paths, roi_file=signal_roi, mask_file=signal_mask)
                else:
                    d_som_t = data_dst.getSOM(data_paths)
                add_nxpars_sig = False

            if timer is not None:
                timer.getTime(msg="After reading data")

            d_som1 = common_lib.add_ncerr(d_som_t, d_som1, add_nxpars=add_nxpars_sig)

            if timer is not None:
                timer.getTime(msg="After adding spectra")

            del d_som_t

            if timer is not None:
                timer.getTime(msg="After SOM deletion")

        data_dst.release_resource()
        del data_dst
        counter += 1

        if timer is not None:
            timer.getTime(msg="After resource release and DST deletion")

        if dst_type == "application/x-NeXus":
            som_key_parts = [dataset_type, "filename"]
            som_key = "-".join(som_key_parts)

            d_som1.attr_list[som_key] = filelist
        else:
            # Previously written files already have this structure imposed
            pass

    return d_som1
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