示例#1
0
def subexp_eff(attenc, axis, scalec=None):
    """
    This function calculates an efficiency from a subtracted exponential of the
    form: c(1 - exp(-|k| * x)).

    @param attenc: The attentuation constant k in the exponential.
    @type attenc: L{hlr_utils.DrParameter}

    @param axis: The axis from which to calculate the efficiency
    @type axis: C{nessi_list.NessiList}

    @param scalec: The scaling constant c applied to the subtracted
                   exponential.
    @type scalec: L{hlr_utils.DrParameter}
    

    @return: The calculated efficiency
    @rtype: C{nessi_list.NessiList}
    """
    import array_manip
    import phys_corr
    import utils

    if scalec is None:
        import hlr_utils
        scalec = hlr_utils.DrParameter(1.0, 0.0)
    
    axis_bc = utils.calc_bin_centers(axis)
    temp = phys_corr.exp_detector_eff(axis_bc[0], scalec.getValue(),
                                      scalec.getError(), attenc.getValue())
    return array_manip.sub_ncerr(scalec.getValue(), scalec.getError(),
                                 temp[0], temp[1])
def calc_deltat_over_t(axis, axis_err2=None):
    """
    This function takes a TOF axis and calculates the quantity Delta t / t
    for every element. 

    @param axis: The TOF axis from which Delta t / t will be calculated
    @type axis: C{nessi_list.NessiList}
    
    @param axis_err2: (OPTIONAL) The error^2 on the incoming TOF axis
    @type axis_err2: C{nessi_list.NessiList}


    @return: The calculated Delta t / t
    @rtype: C{SOM.SOM}
    """
    import nessi_list

    # Check to see if incoming is really a NessiList
    try:
        axis.__type__
    except AttributeError:
        raise RuntimeError("The object passed to this function needs to be a "\
                           +"NessiList. Do not understand how to deal with "\
                           +"%s" % type(axis))

    len_axis = len(axis)
    if axis_err2 is None:
        axis_err2 = nessi_list.NessiList(len_axis)

    deltat = nessi_list.NessiList()
    deltat_err2 = nessi_list.NessiList()
    
    # Calculate bin deltas, assume axis in ascending order
    for i in xrange(len_axis - 1):
        deltat.append(axis[i+1] - axis[i])
        deltat_err2.append(axis_err2[i+1] - axis_err2[i])        

    # Calculate bin centers
    import utils
    (binc, binc_err2) = utils.calc_bin_centers(axis, axis_err2)

    # Calculate delta t / t
    import array_manip
    dtot = array_manip.div_ncerr(deltat, deltat_err2, binc, binc_err2)

    import SOM
    som = SOM.SOM()
    so = SOM.SO()
    so.y = dtot[0]
    so.var_y = dtot[1]
    som.append(so)

    som.setDataSetType("density")
    som.setYLabel("deltat_over_t")

    return som
示例#3
0
def calc_deltat_over_t(axis, axis_err2=None):
    """
    This function takes a TOF axis and calculates the quantity Delta t / t
    for every element. 

    @param axis: The TOF axis from which Delta t / t will be calculated
    @type axis: C{nessi_list.NessiList}
    
    @param axis_err2: (OPTIONAL) The error^2 on the incoming TOF axis
    @type axis_err2: C{nessi_list.NessiList}


    @return: The calculated Delta t / t
    @rtype: C{SOM.SOM}
    """
    import nessi_list

    # Check to see if incoming is really a NessiList
    try:
        axis.__type__
    except AttributeError:
        raise RuntimeError("The object passed to this function needs to be a "\
                           +"NessiList. Do not understand how to deal with "\
                           +"%s" % type(axis))

    len_axis = len(axis)
    if axis_err2 is None:
        axis_err2 = nessi_list.NessiList(len_axis)

    deltat = nessi_list.NessiList()
    deltat_err2 = nessi_list.NessiList()

    # Calculate bin deltas, assume axis in ascending order
    for i in xrange(len_axis - 1):
        deltat.append(axis[i + 1] - axis[i])
        deltat_err2.append(axis_err2[i + 1] - axis_err2[i])

    # Calculate bin centers
    import utils
    (binc, binc_err2) = utils.calc_bin_centers(axis, axis_err2)

    # Calculate delta t / t
    import array_manip
    dtot = array_manip.div_ncerr(deltat, deltat_err2, binc, binc_err2)

    import SOM
    som = SOM.SOM()
    so = SOM.SO()
    so.y = dtot[0]
    so.var_y = dtot[1]
    som.append(so)

    som.setDataSetType("density")
    som.setYLabel("deltat_over_t")

    return som
示例#4
0
def shift_spectrum(obj, shift_point, min_ext, max_ext, scale_const=None):
    """
    This function takes a given spectrum and a central value and creates
    a spectrum that is shifted about that point. Values greater than the point
    are moved to the beginning of the new spectrum and values less than the
    point are move towards the end of the new spectrum.
    
    @param obj: Monitor object that will be shifted
    @type obj: C{SOM.SOM} or C{SOM.SO}

    @param shift_point: The point in the spectrum about which to shift the
    data.
    @type shift_point: C{list} of C{floats}

    @param min_ext: The minimum extent of the axis to shift.
    @type min_ext: C{list} of C{floats}

    @param max_ext: The maximum extent of the axis to shift.
    @type max_ext: C{list} of C{floats}
    
    @param scale_const: A scaling constant to apply (multiply) to the newly
                        shifted spectrum. The default is I{None}.
    @type scale_const: C{float}


    @return: Monitor spectrum that have been shifted
    @rtype: C{SOM.SOM} or C{SOM.SO}
    """
    # import the helper functions
    import hlr_utils

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)
    s_descr = hlr_utils.get_descr(shift_point)
    ie_descr = hlr_utils.get_descr(min_ext)
    ae_descr = hlr_utils.get_descr(max_ext)

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)

    import array_manip
    import utils

    len_obj = hlr_utils.get_length(obj)
    for i in xrange(len_obj):
        val = hlr_utils.get_value(obj, i, o_descr, "y")
        err2 = hlr_utils.get_err2(obj, i, o_descr, "y")
        x_axis = hlr_utils.get_value(obj, i, o_descr, "x", 0)
        x_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", 0)
        map_so = hlr_utils.get_map_so(obj, None, i)

        bin_center = utils.calc_bin_centers(x_axis, x_err2)

        # Get shift point and extents
        sp = hlr_utils.get_value(shift_point, i, s_descr, "y")
        ie = hlr_utils.get_value(min_ext, i, ie_descr, "y")
        ae = hlr_utils.get_value(max_ext, i, ae_descr, "y")

        # Make shifted spectrum
        value0 = utils.shift_spectrum(val, err2, x_axis, bin_center[0],
                                      sp, ie, ae)

        # Scale spectrum if necessary
        if scale_const is not None:
            value1 = array_manip.mult_ncerr(value0[0], value0[1],
                                            scale_const, 0.0)
        else:
            value1 = value0

        hlr_utils.result_insert(result, res_descr, value1, map_so, "y")

    return result
def calc_BSS_EQ_verticies(*args):
    """
    This function calculates the S(Q,E) bin verticies for BSS. It uses the
    x_i coefficients, dT, dh and the E and Q bin centers for the calculation.

    @param args: A list of parameters (C{tuple}s with value and err^2) used to
    calculate the x_i coefficients

    The following is a list of the arguments needed in there expected order
      1. Energy Transfer
      2. Momentum Transfer
      3. x_1 coefficient
      4. x_2 coefficient
      5. x_3 coefficient
      6. x_4 coefficient
      7. dT (Time-of-flight bin widths)
      8. dh (Height of detector pixel)
      9. Vector of Zeros
    @type args: C{list}


    @return: The calculated Q and E verticies ((Q_1, E_1), (Q_2, E_2),
             (Q_3, E_3), (Q_4, E_4))
    @rtype: C{tuple} of 4 C{tuple}s of 2 C{nessi_list.NessiList}s
    """
    # Settle out the arguments to sensible names
    E_t = args[0][0]
    E_t_err2 = args[0][1]
    Q = args[1][0]
    Q_err2 = args[1][1]
    x_1 = args[2]
    x_2 = args[3]
    x_3 = args[4]
    x_4 = args[5]
    dT = args[6]
    dh = args[7]
    zero_vec = args[8]

    # Calculate bin centric values
    (E_t_bc, E_t_bc_err2) = utils.calc_bin_centers(E_t, E_t_err2)
    (Q_bc, Q_bc_err2) = utils.calc_bin_centers(Q, Q_err2)

    (x1dh, x1dh_err2) = array_manip.mult_ncerr(x_1, zero_vec, dh, 0.0)
    (x3dh, x3dh_err2) = array_manip.mult_ncerr(x_3, zero_vec, dh, 0.0)
    (x2dT, x2dT_err2) = array_manip.mult_ncerr(x_2, zero_vec, dT, zero_vec)
    (x4dT, x4dT_err2) = array_manip.mult_ncerr(x_4, zero_vec, dT, zero_vec)

    (x1dh_p_x2dT,
     x1dh_p_x2dT_err2) = array_manip.add_ncerr(x1dh, x1dh_err2, x2dT,
                                               x2dT_err2)
    (x3dh_p_x4dT,
     x3dh_p_x4dT_err2) = array_manip.add_ncerr(x3dh, x3dh_err2, x4dT,
                                               x4dT_err2)
    (x1dh_m_x2dT,
     x1dh_m_x2dT_err2) = array_manip.sub_ncerr(x1dh, x1dh_err2, x2dT,
                                               x2dT_err2)
    (x3dh_m_x4dT,
     x3dh_m_x4dT_err2) = array_manip.sub_ncerr(x3dh, x3dh_err2, x4dT,
                                               x4dT_err2)

    (dQ_1, dQ_1_err2) = array_manip.mult_ncerr(x1dh_p_x2dT, x1dh_p_x2dT_err2,
                                               -0.5, 0.0)
    (dE_1, dE_1_err2) = array_manip.mult_ncerr(x3dh_p_x4dT, x3dh_p_x4dT_err2,
                                               -0.5, 0.0)
    (dQ_2, dQ_2_err2) = array_manip.mult_ncerr(x1dh_m_x2dT, x1dh_m_x2dT_err2,
                                               -0.5, 0.0)
    (dE_2, dE_2_err2) = array_manip.mult_ncerr(x3dh_m_x4dT, x3dh_m_x4dT_err2,
                                               -0.5, 0.0)

    (dQ_3, dQ_3_err2) = array_manip.mult_ncerr(dQ_1, dQ_1_err2, -1.0, 0.0)
    (dE_3, dE_3_err2) = array_manip.mult_ncerr(dE_1, dE_1_err2, -1.0, 0.0)
    (dQ_4, dQ_4_err2) = array_manip.mult_ncerr(dQ_2, dQ_2_err2, -1.0, 0.0)
    (dE_4, dE_4_err2) = array_manip.mult_ncerr(dE_2, dE_2_err2, -1.0, 0.0)

    Q_1 = array_manip.add_ncerr(Q_bc, Q_bc_err2, dQ_1, dQ_1_err2)
    E_t_1 = array_manip.add_ncerr(E_t_bc, E_t_bc_err2, dE_1, dE_1_err2)

    Q_2 = array_manip.add_ncerr(Q_bc, Q_bc_err2, dQ_2, dQ_2_err2)
    E_t_2 = array_manip.add_ncerr(E_t_bc, E_t_bc_err2, dE_2, dE_2_err2)

    Q_3 = array_manip.add_ncerr(Q_bc, Q_bc_err2, dQ_3, dQ_3_err2)
    E_t_3 = array_manip.add_ncerr(E_t_bc, E_t_bc_err2, dE_3, dE_3_err2)

    Q_4 = array_manip.add_ncerr(Q_bc, Q_bc_err2, dQ_4, dQ_4_err2)
    E_t_4 = array_manip.add_ncerr(E_t_bc, E_t_bc_err2, dE_4, dE_4_err2)

    return ((Q_1[0], E_t_1[0]), (Q_2[0], E_t_2[0]), (Q_3[0], E_t_3[0]),
            (Q_4[0], E_t_4[0]))
示例#6
0
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 DST
    import math

    if config.inst == "REF_M":
        import axis_manip
        import utils

    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-6 on sample data
    d_som1 = dr_lib.process_ref_data(
        config.data,
        config,
        config.data_roi_file,
        config.dbkg_roi_file,
        config.no_bkg,
        tof_cuts=config.tof_cuts,
        inst_geom_dst=data_inst_geom_dst,
        timer=tim,
    )

    # Perform Steps 1-6 on normalization data
    if config.norm is not None:
        n_som1 = dr_lib.process_ref_data(
            config.norm,
            config,
            config.norm_roi_file,
            config.nbkg_roi_file,
            config.no_norm_bkg,
            dataset_type="norm",
            tof_cuts=config.tof_cuts,
            inst_geom_dst=norm_inst_geom_dst,
            timer=tim,
        )
    else:
        n_som1 = None

    if config.Q_bins is None and config.scatt_angle is not None:
        import copy

        tof_axis = copy.deepcopy(d_som1[0].axis[0].val)

    # 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 7: Sum all normalization spectra together
    if config.norm is not None:
        n_som2 = dr_lib.sum_all_spectra(n_som1)
    else:
        n_som2 = None

    del n_som1

    # Step 8: Divide data by normalization
    if config.verbose and config.norm is not None:
        print "Scale data by normalization"

    if config.norm is not None:
        d_som2 = common_lib.div_ncerr(d_som1, n_som2, length_one_som=True)
    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_som2

    if config.dump_rtof_comb:
        d_som2_1 = dr_lib.sum_all_spectra(d_som2)
        d_som2_2 = dr_lib.data_filter(d_som2_1)
        del d_som2_1

        if config.inst == "REF_M":
            tof_bc = utils.calc_bin_centers(d_som2_2[0].axis[0].val)
            d_som2_2[0].axis[0].val = tof_bc[0]
            d_som2_2.setDataSetType("density")

        hlr_utils.write_file(
            config.output,
            "text/Spec",
            d_som2_2,
            output_ext="crtof",
            verbose=config.verbose,
            data_ext=config.ext_replacement,
            path_replacement=config.path_replacement,
            message="combined R(TOF) information",
        )

        del d_som2_2

    if config.dump_rtof:
        if config.inst == "REF_M":
            d_som2_1 = d_som2
        else:
            d_som2_1 = dr_lib.filter_ref_data(d_som2)

        hlr_utils.write_file(
            config.output,
            "text/Spec",
            d_som2_1,
            output_ext="rtof",
            verbose=config.verbose,
            data_ext=config.ext_replacement,
            path_replacement=config.path_replacement,
            message="R(TOF) information",
        )
        del d_som2_1

    if config.inst == "REF_L":
        # Step 9: Convert TOF to scalar Q
        if config.verbose:
            print "Converting TOF to scalar Q"

        # Check to see if polar angle offset is necessary
        if config.angle_offset is not None:
            # Check on units, offset must be in radians
            p_temp = config.angle_offset.toFullTuple(True)
            if p_temp[2] == "degrees" or p_temp[2] == "degree":
                deg_to_rad = math.pi / 180.0
                p_off_rads = p_temp[0] * deg_to_rad
                p_off_err2_rads = p_temp[1] * deg_to_rad * deg_to_rad
            else:
                p_off_rads = p_temp[0]
                p_off_err2_rads = p_temp[1]

            p_offset = (p_off_rads, p_off_err2_rads)

            d_som2.attr_list["angle_offset"] = config.angle_offset
        else:
            p_offset = None

        if tim is not None:
            tim.getTime(False)

        d_som3 = common_lib.tof_to_scalar_Q(d_som2, units="microsecond", angle_offset=p_offset, lojac=False)

        del d_som2

        if tim is not None:
            tim.getTime(msg="After converting wavelength to scalar Q ")

        if config.dump_rq:
            d_som3_1 = dr_lib.data_filter(d_som3, clean_axis=True)
            hlr_utils.write_file(
                config.output,
                "text/Spec",
                d_som3_1,
                output_ext="rq",
                verbose=config.verbose,
                data_ext=config.ext_replacement,
                path_replacement=config.path_replacement,
                message="pixel R(Q) information",
            )
            del d_som3_1

        if not config.no_filter:
            if config.verbose:
                print "Filtering final data"

            if tim is not None:
                tim.getTime(False)

            d_som4 = dr_lib.data_filter(d_som3)

            if tim is not None:
                tim.getTime(msg="After filtering data")
        else:
            d_som4 = d_som3

        del d_som3
    else:
        d_som4 = d_som2

    # Step 10: Rebin all spectra to final Q axis
    if config.Q_bins is None:
        if config.scatt_angle is None:
            config.Q_bins = dr_lib.create_axis_from_data(d_som4)
            rebin_axis = config.Q_bins.toNessiList()
        else:
            # Get scattering angle and make Q conversion from TOF axis
            # Check on units, scattering angle must be in radians
            sa_temp = config.scatt_angle.toFullTuple(True)
            if sa_temp[2] == "degrees" or sa_temp[2] == "degree":
                deg_to_rad = math.pi / 180.0
                sa_rads = sa_temp[0] * deg_to_rad
                sa_err2_rads = sa_temp[1] * deg_to_rad * deg_to_rad
            else:
                sa_rads = sa_temp[0]
                sa_err2_rads = sa_temp[1]

            sa = (sa_rads, sa_err2_rads)

            pl = d_som4.attr_list.instrument.get_total_path(d_som4[0].id, det_secondary=True)

            import nessi_list

            tof_axis_err2 = nessi_list.NessiList(len(tof_axis))

            rebin_axis = axis_manip.tof_to_scalar_Q(tof_axis, tof_axis_err2, pl[0], pl[1], sa[0], sa[1])[0]

            axis_manip.reverse_array_nc(rebin_axis)
    else:
        rebin_axis = config.Q_bins.toNessiList()

    if config.inst == "REF_L":
        if config.verbose:
            print "Rebinning spectra"

        if tim is not None:
            tim.getTime(False)

        d_som5 = common_lib.rebin_axis_1D_linint(d_som4, rebin_axis)

        if tim is not None:
            tim.getTime(msg="After rebinning spectra")

        del d_som4

        if config.dump_rqr:
            hlr_utils.write_file(
                config.output,
                "text/Spec",
                d_som5,
                output_ext="rqr",
                verbose=config.verbose,
                data_ext=config.ext_replacement,
                path_replacement=config.path_replacement,
                message="pixel R(Q) (after rebinning) " + "information",
            )

        # Step 11: Sum all rebinned spectra
        if config.verbose:
            print "Summing spectra"

        if tim is not None:
            tim.getTime(False)

        d_som6 = dr_lib.sum_all_spectra(d_som5)

        if tim is not None:
            tim.getTime(msg="After summing spectra")

        del d_som5
    else:
        d_som5 = d_som4

    if config.inst == "REF_M":
        d_som5A = dr_lib.sum_all_spectra(d_som5)
        del d_som5
        d_som6 = dr_lib.data_filter(d_som5A)
        del d_som5A
        axis_manip.reverse_array_nc(d_som6[0].y)
        axis_manip.reverse_array_nc(d_som6[0].var_y)

        d_som6.setYLabel("Intensity")
        d_som6.setYUnits("Counts/A-1")
        d_som6.setAllAxisLabels(["scalar wavevector transfer"])
        d_som6.setAllAxisUnits(["1/Angstroms"])

        Q_bc = utils.calc_bin_centers(rebin_axis)
        d_som6[0].axis[0].val = Q_bc[0]
        d_som6.setDataSetType("density")

    hlr_utils.write_file(
        config.output,
        "text/Spec",
        d_som6,
        replace_ext=False,
        replace_path=False,
        verbose=config.verbose,
        message="combined Reflectivity information",
    )

    d_som6.attr_list["config"] = config

    hlr_utils.write_file(
        config.output,
        "text/rmd",
        d_som6,
        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")
                                                          area_new,
                                                          area_sum_err2)

    # Check for so_id keyword argument
    so_dim.id = kwargs.get("so_id", som[0].id)

    comb_som = SOM.SOM()
    comb_som.copyAttributes(som)

    comb_som = __set_som_attributes(comb_som, **kwargs)

    if configure.pdos_Q:
        # Multiply each slice of Q by 1/Q^2 * exp(u^2 * Q^2) where u is
        # the Debye-Waller constant
        import math
        Q_bc = utils.calc_bin_centers(so_dim.axis[0].val)[0]
        len_E = len(so_dim.axis[1].val) - 1

        try:
            dw_const = configure.debye_waller.getValue()
        except AttributeError:
            # No Debye-Waller constant given, so assume zero
            dw_const = 0.0
        
        dw_const2 = dw_const * dw_const
        
        for i, Q in enumerate(Q_bc):
            Q2 = Q * Q
            pdos_scale = math.exp(dw_const2 * Q2) / Q2
            
            i_low = i * len_E
示例#8
0
def shift_spectrum(obj, shift_point, min_ext, max_ext, scale_const=None):
    """
    This function takes a given spectrum and a central value and creates
    a spectrum that is shifted about that point. Values greater than the point
    are moved to the beginning of the new spectrum and values less than the
    point are move towards the end of the new spectrum.
    
    @param obj: Monitor object that will be shifted
    @type obj: C{SOM.SOM} or C{SOM.SO}

    @param shift_point: The point in the spectrum about which to shift the
    data.
    @type shift_point: C{list} of C{floats}

    @param min_ext: The minimum extent of the axis to shift.
    @type min_ext: C{list} of C{floats}

    @param max_ext: The maximum extent of the axis to shift.
    @type max_ext: C{list} of C{floats}
    
    @param scale_const: A scaling constant to apply (multiply) to the newly
                        shifted spectrum. The default is I{None}.
    @type scale_const: C{float}


    @return: Monitor spectrum that have been shifted
    @rtype: C{SOM.SOM} or C{SOM.SO}
    """
    # import the helper functions
    import hlr_utils

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)
    s_descr = hlr_utils.get_descr(shift_point)
    ie_descr = hlr_utils.get_descr(min_ext)
    ae_descr = hlr_utils.get_descr(max_ext)

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)

    import array_manip
    import utils

    len_obj = hlr_utils.get_length(obj)
    for i in xrange(len_obj):
        val = hlr_utils.get_value(obj, i, o_descr, "y")
        err2 = hlr_utils.get_err2(obj, i, o_descr, "y")
        x_axis = hlr_utils.get_value(obj, i, o_descr, "x", 0)
        x_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", 0)
        map_so = hlr_utils.get_map_so(obj, None, i)

        bin_center = utils.calc_bin_centers(x_axis, x_err2)

        # Get shift point and extents
        sp = hlr_utils.get_value(shift_point, i, s_descr, "y")
        ie = hlr_utils.get_value(min_ext, i, ie_descr, "y")
        ae = hlr_utils.get_value(max_ext, i, ae_descr, "y")

        # Make shifted spectrum
        value0 = utils.shift_spectrum(val, err2, x_axis, bin_center[0], sp, ie,
                                      ae)

        # Scale spectrum if necessary
        if scale_const is not None:
            value1 = array_manip.mult_ncerr(value0[0], value0[1], scale_const,
                                            0.0)
        else:
            value1 = value0

        hlr_utils.result_insert(result, res_descr, value1, map_so, "y")

    return result
def calc_substrate_trans(obj, subtrans_coeff, substrate_diam, **kwargs):
    """
    This function calculates substrate transmission via the following formula:
    T = exp[-(A + B * wavelength) * d] where A is a constant with units of
    cm^-1, B is a constant with units of cm^-2 and d is the substrate
    diameter in units of cm.

    @param obj: The data object that contains the TOF axes to calculate the
                transmission from.
    @type obj: C{SOM.SOM} or C{SOM.SO}

    @param subtrans_coeff: The two coefficients for substrate transmission
           calculation.
    @type subtrans_coeff: C{tuple} of two C{float}s

    @param substrate_diam: The diameter of the substrate.
    @type substrate_diam: C{float}

    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword pathlength: The pathlength and its associated error^2
    @type pathlength: C{tuple} or C{list} of C{tuple}s

    @keyword units: The expected units for this function. The default for this
                    function is I{microsecond}.
    @type units: C{string}


    @return: The calculate transmission for the given substrate parameters
    @rtype: C{SOM.SOM} or C{SOM.SO}

    
    @raise TypeError: The object used for calculation is not a C{SOM} or a
                      C{SO}

    @raise RuntimeError: The C{SOM} x-axis units are not I{microsecond}
    
    @raise RuntimeError: A C{SOM} does not contain an instrument and no
                         pathlength was provided
                         
    @raise RuntimeError: No C{SOM} is provided and no pathlength given
    """
    # import the helper functions
    import hlr_utils

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)

    if o_descr == "number" or o_descr == "list":
        raise TypeError("Do not know how to handle given type: %s" % o_descr)
    else:
        pass

    # Setup keyword arguments
    try:
        pathlength = kwargs["pathlength"]
    except KeyError:
        pathlength = None

    try:
        units = kwargs["units"]
    except KeyError:
        units = "microsecond"

    # Primary axis for transformation. If a SO is passed, the function, will
    # assume the axis for transformation is at the 0 position
    if o_descr == "SOM":
        axis = hlr_utils.one_d_units(obj, units)
    else:
        axis = 0

    if pathlength is not None:
        p_descr = hlr_utils.get_descr(pathlength)
    else:
        if o_descr == "SOM":
            try:
                obj.attr_list.instrument.get_primary()
                inst = obj.attr_list.instrument
            except RuntimeError:
                raise RuntimeError("A detector was not provided")
        else:
            raise RuntimeError("If no SOM is provided, then pathlength "\
                               +"information must be provided")            

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)
    if res_descr == "SOM":
        result.setYLabel("Transmission")

    # iterate through the values
    import array_manip
    import axis_manip
    import nessi_list
    import utils

    import math
    
    len_obj = hlr_utils.get_length(obj)
    for i in xrange(len_obj):
        val = hlr_utils.get_value(obj, i, o_descr, "x", axis)
        err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis)
        
        map_so = hlr_utils.get_map_so(obj, None, i)

        if pathlength is None:
            (pl, pl_err2) = hlr_utils.get_parameter("total", map_so, inst)
        else:
            pl = hlr_utils.get_value(pathlength, i, p_descr)
            pl_err2 = hlr_utils.get_err2(pathlength, i, p_descr)        

        value = axis_manip.tof_to_wavelength(val, err2, pl, pl_err2)

        value1 = utils.calc_bin_centers(value[0])
        del value

        # Convert Angstroms to centimeters
        value2 = array_manip.mult_ncerr(value1[0], value1[1],
                                        subtrans_coeff[1]*1.0e-8, 0.0)
        del value1

        # Calculate the exponential
        value3 = array_manip.add_ncerr(value2[0], value2[1],
                                       subtrans_coeff[0], 0.0)
        del value2

        value4 = array_manip.mult_ncerr(value3[0], value3[1],
                                        -1.0*substrate_diam, 0.0)
        del value3

        # Calculate transmission
        trans = nessi_list.NessiList()
        len_trans = len(value4[0])
        for j in xrange(len_trans):
            trans.append(math.exp(value4[0][j]))

        trans_err2 = nessi_list.NessiList(len(trans))

        hlr_utils.result_insert(result, res_descr, (trans, trans_err2), map_so)

    return result
示例#10
0
def rebin_axis_1D_linint(obj, axis_out):
    """
    This function rebins the primary axis for a C{SOM} or a C{SO} based on the
    given C{NessiList} axis using a linear interpolation scheme.

    @param obj: Object to be rebinned
    @type obj: C{SOM.SOM} or C{SOM.SO}

    @param axis_out: The axis to rebin the C{SOM} or C{SO} to
    @type axis_out: C{NessiList}


    @return: Object that has been rebinned according to the provided axis
    @rtype: C{SOM.SOM} or C{SOM.SO}


    @raise TypeError: The rebinning axis given is not a C{NessiList}

    @raise TypeError: The object being rebinned is not a C{SOM} or a C{SO}
    """

    # import the helper functions
    import hlr_utils

    # set up for working through data
    try:
        axis_out.__type__
    except AttributeError:
        raise TypeError("Rebinning axis must be a NessiList!")

    o_descr = hlr_utils.get_descr(obj)

    if o_descr == "number" or o_descr == "list":
        raise TypeError("Do not know how to handle given type: %s" % \
                        o_descr)
    else:
        pass

    (result, res_descr) = hlr_utils.empty_result(obj)

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)

    # Axis out never changes
    xvals = []
    xvals.append(axis_out)

    # Need a vector of zeros for the next function call
    len_axis_out = len(axis_out)
    zero_vec = nessi_list.NessiList(len_axis_out)

    import utils
    bin_centers = utils.calc_bin_centers(axis_out, zero_vec)

    # iterate through the values

    for i in xrange(hlr_utils.get_length(obj)):
        axis_in = hlr_utils.get_value(obj, i, o_descr, "x", 0)
        axis_in_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", 0)

        axis_in_bc = utils.calc_bin_centers(axis_in, axis_in_err2)

        val = hlr_utils.get_value(obj, i, o_descr)
        err2 = hlr_utils.get_err2(obj, i, o_descr)

        map_so = hlr_utils.get_map_so(obj, None, i)

        # Set zero errors to 1 for linear fit
        for j in xrange(len(err2)):
            if utils.compare(err2[j], 0.0) == 0 and \
                   utils.compare(val[j], 0.0) == 0:
                err2[j] = 1.0

        # Create new NessiLists for rebinned values
        rebin_val = nessi_list.NessiList()
        rebin_err2 = nessi_list.NessiList()

        for k in xrange(len_axis_out - 1):
            index_pair = hlr_utils.bisect_helper(axis_in, axis_out[k],
                                                 axis_out[k + 1])

            # Requested range is outside axis boundaries
            if index_pair[0] == -1 and index_pair[1] == -1:
                rebin_val.append(0.0)
                rebin_err2.append(0.0)
                continue

            # If there is only one value, just use it directly
            if index_pair[0] == index_pair[1]:
                rebin_val.append(val[index_pair[0]])
                rebin_err2.append(err2[index_pair[0]])
            else:
                # Do linear interpolation
                fit_params = utils.fit_linear_background(
                    axis_in_bc[0], val, err2, index_pair[0], index_pair[1])

                # Evaluate the interpolation at the rebin axis bin center
                eval_out = utils.eval_linear_fit(bin_centers[0][k:k + 1],
                                                 bin_centers[1][k:k + 1],
                                                 fit_params["slope"][0],
                                                 fit_params["slope"][1],
                                                 fit_params["intercept"][0],
                                                 fit_params["intercept"][1])

                rebin_val.append(eval_out[0][0])

                # Use a geometric average for the error bars
                new_err2 = 0.0
                count = 0
                for m in xrange(index_pair[0], index_pair[1] + 1):
                    if utils.compare(val[m], 0.0) == 0:
                        continue
                    else:
                        new_err2 += err2[m]
                        count += 1

                if count:
                    new_err2 /= float(count)
                rebin_err2.append(new_err2)

        # Do one last clean up
        for n in xrange(len(rebin_val)):
            if utils.compare(rebin_val[n], 0.0) == 0:
                rebin_err2[n] = 0.0

        hlr_utils.result_insert(result, res_descr, (rebin_val, rebin_err2),
                                map_so, "all", 0, xvals)

    return result
示例#11
0
def fix_bin_contents(obj, **kwargs):
    """
    This function takes a SOM or SO and goes through the individual spectra
    adjusting the bin contents by either multiplying or dividing by the
    bin widths or the bin centers taken from the individual spectra.

    @param obj: The data object to be scaled
    @type obj: C{SOM.SOM} or C{SOM.SO}

    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword scale: A flag that signals multiplication by the required bin
                    quantity. The default is I{False} (divide).
    @type scale: C{bool}

    @keyword width: A flag that signals that the adjusting quantity is the
                    bin width. The default is I{True}. If I{False}, the bin
                    center is used.
    @type width: C{bool}

    @keyword units: The expected units for this function. The default for this
                    function is I{microsecond}.
    @type units: C{string}


    @return: The object with the individual spectrum scaled
    @rtype: C{SOM.SOM} or C{SOM.SO}
    """
    import hlr_utils

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)

    # Setup keyword arguments
    try:
        scale = kwargs["scale"]
    except KeyError:
        scale = False

    try:
        width = kwargs["width"]
    except KeyError:
        width = True
    
    try:
        units = kwargs["units"]
    except KeyError:
        units = "microsecond"

    # Primary axis for transformation. If a SO is passed, the function, will
    # assume the axis for transformation is at the 0 position
    if o_descr == "SOM":
        axis_pos = hlr_utils.one_d_units(obj, units)
    else:
        axis_pos = 0

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)
        
    # iterate through the values
    import array_manip
    import utils

    for i in xrange(hlr_utils.get_length(obj)):
        val = hlr_utils.get_value(obj, i, o_descr, "y")
        err2 = hlr_utils.get_err2(obj, i, o_descr, "y")
        axis = hlr_utils.get_value(obj, i, o_descr, "x", axis_pos)
        axis_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis_pos)
        
        map_so = hlr_utils.get_map_so(obj, None, i)

        if width:
            (bin_const, bin_const_err2) = utils.calc_bin_widths(axis,
                                                                axis_err2)
        else:
            (bin_const, bin_const_err2) = utils.calc_bin_centers(axis,
                                                                 axis_err2)

        if scale:
            value = array_manip.mult_ncerr(val, err2, bin_const,
                                           bin_const_err2)
        else:
            value = array_manip.div_ncerr(val, err2, bin_const, bin_const_err2)

        hlr_utils.result_insert(result, res_descr, value, map_so, "y")

    return result
示例#12
0
def calc_substrate_trans(obj, subtrans_coeff, substrate_diam, **kwargs):
    """
    This function calculates substrate transmission via the following formula:
    T = exp[-(A + B * wavelength) * d] where A is a constant with units of
    cm^-1, B is a constant with units of cm^-2 and d is the substrate
    diameter in units of cm.

    @param obj: The data object that contains the TOF axes to calculate the
                transmission from.
    @type obj: C{SOM.SOM} or C{SOM.SO}

    @param subtrans_coeff: The two coefficients for substrate transmission
           calculation.
    @type subtrans_coeff: C{tuple} of two C{float}s

    @param substrate_diam: The diameter of the substrate.
    @type substrate_diam: C{float}

    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword pathlength: The pathlength and its associated error^2
    @type pathlength: C{tuple} or C{list} of C{tuple}s

    @keyword units: The expected units for this function. The default for this
                    function is I{microsecond}.
    @type units: C{string}


    @return: The calculate transmission for the given substrate parameters
    @rtype: C{SOM.SOM} or C{SOM.SO}

    
    @raise TypeError: The object used for calculation is not a C{SOM} or a
                      C{SO}

    @raise RuntimeError: The C{SOM} x-axis units are not I{microsecond}
    
    @raise RuntimeError: A C{SOM} does not contain an instrument and no
                         pathlength was provided
                         
    @raise RuntimeError: No C{SOM} is provided and no pathlength given
    """
    # import the helper functions
    import hlr_utils

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)

    if o_descr == "number" or o_descr == "list":
        raise TypeError("Do not know how to handle given type: %s" % o_descr)
    else:
        pass

    # Setup keyword arguments
    try:
        pathlength = kwargs["pathlength"]
    except KeyError:
        pathlength = None

    try:
        units = kwargs["units"]
    except KeyError:
        units = "microsecond"

    # Primary axis for transformation. If a SO is passed, the function, will
    # assume the axis for transformation is at the 0 position
    if o_descr == "SOM":
        axis = hlr_utils.one_d_units(obj, units)
    else:
        axis = 0

    if pathlength is not None:
        p_descr = hlr_utils.get_descr(pathlength)
    else:
        if o_descr == "SOM":
            try:
                obj.attr_list.instrument.get_primary()
                inst = obj.attr_list.instrument
            except RuntimeError:
                raise RuntimeError("A detector was not provided")
        else:
            raise RuntimeError("If no SOM is provided, then pathlength "\
                               +"information must be provided")

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)
    if res_descr == "SOM":
        result.setYLabel("Transmission")

    # iterate through the values
    import array_manip
    import axis_manip
    import nessi_list
    import utils

    import math

    len_obj = hlr_utils.get_length(obj)
    for i in xrange(len_obj):
        val = hlr_utils.get_value(obj, i, o_descr, "x", axis)
        err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis)

        map_so = hlr_utils.get_map_so(obj, None, i)

        if pathlength is None:
            (pl, pl_err2) = hlr_utils.get_parameter("total", map_so, inst)
        else:
            pl = hlr_utils.get_value(pathlength, i, p_descr)
            pl_err2 = hlr_utils.get_err2(pathlength, i, p_descr)

        value = axis_manip.tof_to_wavelength(val, err2, pl, pl_err2)

        value1 = utils.calc_bin_centers(value[0])
        del value

        # Convert Angstroms to centimeters
        value2 = array_manip.mult_ncerr(value1[0], value1[1],
                                        subtrans_coeff[1] * 1.0e-8, 0.0)
        del value1

        # Calculate the exponential
        value3 = array_manip.add_ncerr(value2[0], value2[1], subtrans_coeff[0],
                                       0.0)
        del value2

        value4 = array_manip.mult_ncerr(value3[0], value3[1],
                                        -1.0 * substrate_diam, 0.0)
        del value3

        # Calculate transmission
        trans = nessi_list.NessiList()
        len_trans = len(value4[0])
        for j in xrange(len_trans):
            trans.append(math.exp(value4[0][j]))

        trans_err2 = nessi_list.NessiList(len(trans))

        hlr_utils.result_insert(result, res_descr, (trans, trans_err2), map_so)

    return result
示例#13
0
def create_det_eff(obj, **kwargs):
    """
    This function creates detector efficiency spectra based on the wavelength
    spectra from the given object. The efficiency spectra are created based on
    the following formalism: Ci*exp(-di*lambda) where i represents the
    constants for a given detector pixel.

    @param obj: Object containing spectra that will create the detector
                efficiency spectra.
    @type obj: C{SOM.SOM} or C{SOM.SO}
    
    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword inst_name: The short name of an instrument.
    @type inst_name: C{string}
    
    @keyword eff_scale_const: Use this provided efficiency scaling constant.
    @type eff_scale_const: L{hlr_utils.DrParameter}

    @keyword eff_atten_const: Use this provided efficiency attenuation
                              constant.
    @type eff_atten_const: L{hlr_utils.DrParameter}    


    @return: Object containing the detector efficiency spectra
    @rtype: C{SOM.SOM} or C{SOM.SO}


    @raise TypeError: Incoming object is not a C{SOM} or a C{SO}
    @raise RuntimeError: The C{SOM} x-axis units are not I{Angstroms}
    """
    # Check keywords
    inst_name = kwargs.get("inst_name")
    eff_scale_const = kwargs.get("eff_scale_const")
    eff_atten_const = kwargs.get("eff_atten_const")

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)

    if o_descr != "SOM" and o_descr != "SO":
        raise TypeError("Only SOM or SO objects permitted to create "\
                        +"efficiency spectra!")

    # Check units on SOM, SO is assumed to be correct
    if o_descr == "SOM":
        if not obj.hasAxisUnits("Angstroms"):
            raise RuntimeError("Incoming object must has a wavelength axis "\
                               +"with units of Angstroms!")

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)

    # iterate through the values
    import dr_lib
    import phys_corr
    import utils

    # Get object length
    len_obj = hlr_utils.get_length(obj)
    for i in xrange(len_obj):
        map_so = hlr_utils.get_map_so(obj, None, i)
        axis = hlr_utils.get_value(obj, i, o_descr, "x", 0)

        if inst_name is None:
            axis_bc = utils.calc_bin_centers(axis)
            (eff, eff_err2) = phys_corr.exp_detector_eff(axis_bc[0], 1.0,
                                                         0.0, 1.0)
        else:
            if inst_name == "SANS":
                (eff, eff_err2) = dr_lib.subexp_eff(eff_atten_const, axis,
                                                    eff_scale_const)
            else:
                raise RuntimeError("Do not know how to handle %s instrument" \
                                   % inst_name)
        
        hlr_utils.result_insert(result, res_descr, (eff, eff_err2), map_so)
    
    return result
示例#14
0
def subtract_axis_dep_bkg(obj, coeffs, **kwargs):
    """
    This function takes spectrum object(s) and a set of coefficients and
    subtracts an axis dependent background based on a polynomial. The order
    of the polynomial is based on the number of coefficients provided.

    @param obj: Object from which to subtract the individual background numbers
    @type obj: C{SOM.SOM} or C{SOM.SO}

    @param coeffs: The set of coefficients for the polynomial representation
                   of the background to be subtracted.
    @type coeffs: C{list} of C{floats}

    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword old_scale: The scale factor used to obtain the coefficients used
                        in this function.
    @type old_scale: C{float}

    @keyword new_scale: The scale factor for the current data set from which
                        the axis dependent background will be subtracted from.
    @type new_scale: C{float}


    @return: Object with the axis dependent background subtracted
    @rtype: C{SOM.SOM} or C{SOM.SO}


    @raise TypeError: The first argument is not a C{SOM} or C{SO}    
    """
    # Kickout is coeffs is None, or length is zero
    if coeffs is None:
        return obj

    poly_len = len(coeffs)
    if poly_len == 0:
        return obj

    # Check for keywords
    old_scale = kwargs.get("old_scale", 1.0)
    new_scale = kwargs.get("new_scale", 1.0)

    # Reverse coefficients for __eval_poly function
    coeffs.reverse()

    # import the helper functions
    import hlr_utils

    o_descr = hlr_utils.get_descr(obj)

    if o_descr != "SOM" and o_descr != "SO":
        raise TypeError("Incoming object must be a SOM or a SO")
    # Have a SOM or SO
    else:
        pass

    (result, res_descr) = hlr_utils.empty_result(obj)

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)

    obj_len = hlr_utils.get_length(obj)

    import utils

    # iterate through the values
    for i in xrange(obj_len):
        axis = hlr_utils.get_value(obj, i, o_descr, "x", 0)
        val = hlr_utils.get_value(obj, i, o_descr, "y")
        err2 = hlr_utils.get_err2(obj, i, o_descr, "y")
        map_so = hlr_utils.get_map_so(obj, None, i)

        len_val = len(val)
        new_scale_p = new_scale / len_val
        ratio = old_scale / new_scale_p

        axis_centers = utils.calc_bin_centers(axis)

        for j in xrange(len(val)):
            val[j] -= (ratio *
                       __eval_poly(axis_centers[0][j], coeffs, poly_len))

        value = (val, err2)

        hlr_utils.result_insert(result, res_descr, value, map_so, "y")

    return result
示例#15
0
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 DST
    import math
    if config.inst == "REF_M":
        import axis_manip
        import utils

    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-6 on sample data
    d_som1 = dr_lib.process_ref_data(config.data,
                                     config,
                                     config.data_roi_file,
                                     config.dbkg_roi_file,
                                     config.no_bkg,
                                     tof_cuts=config.tof_cuts,
                                     inst_geom_dst=data_inst_geom_dst,
                                     no_tof_cuts=True,
                                     timer=tim)

    # Perform Steps 1-6 on normalization data
    if config.norm is not None:
        n_som1 = dr_lib.process_ref_data(config.norm,
                                         config,
                                         config.norm_roi_file,
                                         config.nbkg_roi_file,
                                         config.no_norm_bkg,
                                         dataset_type="norm",
                                         tof_cuts=config.tof_cuts,
                                         inst_geom_dst=norm_inst_geom_dst,
                                         no_tof_cuts=True,
                                         timer=tim)
    else:
        n_som1 = None

    if config.Q_bins is None and config.scatt_angle is not None:
        import copy
        tof_axis = copy.deepcopy(d_som1[0].axis[0].val)

    # 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 7: Sum all normalization spectra together
    if config.norm is not None:
        n_som2 = dr_lib.sum_all_spectra(n_som1)
    else:
        n_som2 = None

    del n_som1

    # Step 8: Divide data by normalization
    if config.verbose and config.norm is not None:
        print "Scale data by normalization"

    if config.norm is not None:
        d_som2 = common_lib.div_ncerr(d_som1, n_som2, length_one_som=True)
    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_som2

    if config.dump_rtof_comb:
        d_som2_1 = dr_lib.sum_all_spectra(d_som2)
        d_som2_2 = dr_lib.data_filter(d_som2_1)
        del d_som2_1

        if config.inst == "REF_M":
            tof_bc = utils.calc_bin_centers(d_som2_2[0].axis[0].val)
            d_som2_2[0].axis[0].val = tof_bc[0]
            d_som2_2.setDataSetType("density")

        d_som2_3 = dr_lib.cut_spectra(d_som2_2, config.tof_cut_min,
                                      config.tof_cut_max)
        del d_som2_2

        hlr_utils.write_file(config.output,
                             "text/Spec",
                             d_som2_3,
                             output_ext="crtof",
                             verbose=config.verbose,
                             data_ext=config.ext_replacement,
                             path_replacement=config.path_replacement,
                             message="combined R(TOF) information")
        del d_som2_3

    if config.dump_rtof:
        if config.inst == "REF_M":
            d_som2_1 = d_som2
        else:
            d_som2_1 = dr_lib.filter_ref_data(d_som2)

        d_som2_2 = dr_lib.cut_spectra(d_som2_1, config.tof_cut_min,
                                      config.tof_cut_max)
        del d_som2_1
        hlr_utils.write_file(config.output,
                             "text/Spec",
                             d_som2_2,
                             output_ext="rtof",
                             verbose=config.verbose,
                             data_ext=config.ext_replacement,
                             path_replacement=config.path_replacement,
                             message="R(TOF) information")
        del d_som2_2

    # Step 9: Convert TOF to scalar Q
    if config.verbose:
        print "Converting TOF to scalar Q"
        if config.beamdiv_corr:
            print "Applying beam divergence correction"

    # Check to see if polar angle offset is necessary
    if config.angle_offset is not None:
        # Check on units, offset must be in radians
        p_offset = hlr_utils.angle_to_radians(config.angle_offset)
        d_som2.attr_list["angle_offset"] = config.angle_offset
    else:
        p_offset = None

    # Check to see if scattering angle is requested
    if config.scatt_angle is not None:
        # Mainly used by REF_M
        scatt_angle = hlr_utils.angle_to_radians(config.scatt_angle)
        scatt_angle = (scatt_angle[0] / 2.0, scatt_angle[1])
    else:
        scatt_angle = None

    if tim is not None:
        tim.getTime(False)

    d_som3 = dr_lib.tof_to_ref_scalar_Q(d_som2,
                                        units="microsecond",
                                        angle_offset=p_offset,
                                        lojac=False,
                                        polar=scatt_angle,
                                        configure=config)

    del d_som2

    if tim is not None:
        tim.getTime(msg="After converting wavelength to scalar Q ")

    # Calculate the Q cut range from the TOF cuts range
    if scatt_angle is not None:
        polar_angle = (scatt_angle[0] / 2.0, scatt_angle[1])
    else:
        polar_angle = (d_som3.attr_list["data-theta"][0], 0)

    if p_offset is not None:
        polar_angle = (polar_angle[0] + p_offset[0],
                       polar_angle[1] + p_offset[1])

    pl = d_som3.attr_list.instrument.get_total_path(det_secondary=True)
    # Since Q ~ 1/T, need to reverse cut designation
    if config.tof_cut_min is not None:
        Q_cut_max = dr_lib.tof_to_ref_scalar_Q(
            (float(config.tof_cut_min), 0.0), pathlength=pl,
            polar=polar_angle)[0]
    else:
        Q_cut_max = None

    if config.tof_cut_max is not None:
        Q_cut_min = dr_lib.tof_to_ref_scalar_Q(
            (float(config.tof_cut_max), 0.0), pathlength=pl,
            polar=polar_angle)[0]
    else:
        Q_cut_min = None

    if config.dump_rq:
        d_som3_1 = dr_lib.data_filter(d_som3, clean_axis=True)
        d_som3_2 = dr_lib.cut_spectra(d_som3_1, Q_cut_min, Q_cut_max)
        del d_som3_1
        hlr_utils.write_file(config.output,
                             "text/Spec",
                             d_som3_2,
                             output_ext="rq",
                             verbose=config.verbose,
                             data_ext=config.ext_replacement,
                             path_replacement=config.path_replacement,
                             message="pixel R(Q) information")
        del d_som3_2

    if config.Q_bins is not None or config.beamdiv_corr:
        if config.verbose:
            print "Rebinning data"
        d_som4 = common_lib.rebin_axis_1D_frac(d_som3,
                                               config.Q_bins.toNessiList())

        if config.dump_rqr:
            d_som4_1 = dr_lib.data_filter(d_som4, clean_axis=True)
            d_som4_2 = dr_lib.cut_spectra(d_som4_1, Q_cut_min, Q_cut_max)
            del d_som4_1
            hlr_utils.write_file(config.output,
                                 "text/Spec",
                                 d_som4_2,
                                 output_ext="rqr",
                                 verbose=config.verbose,
                                 data_ext=config.ext_replacement,
                                 path_replacement=config.path_replacement,
                                 message="rebinned pixel R(Q) information")
            del d_som4_2
    else:
        d_som4 = d_som3

    del d_som3

    if not config.no_filter:
        if config.verbose:
            print "Filtering final data"

        if tim is not None:
            tim.getTime(False)

        d_som5 = dr_lib.data_filter(d_som4)

        if tim is not None:
            tim.getTime(msg="After filtering data")
    else:
        d_som5 = d_som4

    del d_som4

    # Sum all spectra since everything is on same axis
    d_som6 = dr_lib.sum_all_spectra(d_som5)

    del d_som5

    d_som7 = dr_lib.cut_spectra(d_som6,
                                Q_cut_min,
                                Q_cut_max,
                                num_bins_clean=config.num_bins_clean)

    del d_som6

    hlr_utils.write_file(config.output,
                         "text/Spec",
                         d_som7,
                         replace_ext=False,
                         replace_path=False,
                         verbose=config.verbose,
                         message="combined Reflectivity information")

    d_som7.attr_list["config"] = config

    hlr_utils.write_file(config.output,
                         "text/rmd",
                         d_som7,
                         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 igs_energy_transfer(obj, **kwargs):
    """
    @depricated: This function will eventually disappear when the full S(Q,E)
                 transformation for IGS detectors is completed and verified.
                 
    This function takes a SOM or a SO and calculates the energy transfer for
    the IGS class of instruments. It is different from
    common_lib.energy_transfer in that the final wavelength is provided in a
    SOM.Information, SOM.CompositeInformation or a tuple, then converted to
    energy in place before being given to the common_lib.energy_transfer
    function.

    Parameters:
    ----------
    -> obj
    -> kwargs is a list of key word arguments that the function accepts:
          units= a string containing the expected units for this function.
                 The default for this function is meV
          lambda_f= a SOM.Information, SOM.CompositeInformation or a tuple
                    containing the final wavelength information
          offset= a SOM.Information or SOM.CompositeInformation containing
                  the final energy offsets
          scale=<boolean> is a flag that determines if the energy transfer
                          results are scaled by the ratio of lambda_f/lambda_i.
                          The default is False

    Returns:
    -------
    <- A SOM or SO with the energy transfer calculated in units of THz

    Exceptions:
    ----------
    <- RuntimeError is raised if the x-axis units are not meV
    <- RuntimeError is raised if a SOM or SO is not given to the function
    <- RuntimeError is raised if the final wavelength is not provided to the
       function
    """

    # import the helper functions
    import hlr_utils

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)

    if o_descr == "number" or o_descr == "list":
        raise RuntimeError, "Must provide a SOM of a SO to the function."
    # Go on
    else:
        pass

    # Setup keyword arguments
    try:
        units = kwargs["units"]
    except KeyError:
        units = "meV"

    try:
        lambda_f = kwargs["lambda_f"]
    except KeyError:
        lambda_f = None

    try:
        offset = kwargs["offset"]
    except KeyError:
        offset = None

    try:
        scale = kwargs["scale"]
    except KeyError:
        scale = False

        
    # Primary axis for transformation. If a SO is passed, the function, will
    # assume the axis for transformation is at the 0 position
    if o_descr == "SOM":
        axis = hlr_utils.one_d_units(obj, units)
    else:
        axis = 0

    if lambda_f is None:
        if o_descr == "SOM":
            try:
                lambda_f = obj.attr_list["Wavelength_final"]
            except KeyError:
                raise RuntimeError("Must provide a final wavelength via the "\
                                   +"incoming SOM or the lambda_f keyword")
        else:
            raise RuntimeError("Must provide a final wavelength via the "\
                                   +"lambda_f keyword")
    else:
        pass
    

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)
    if res_descr == "SOM":
        result = hlr_utils.force_units(result, "ueV", axis)
        result.setAxisLabel(axis, "energy_transfer")
        result.setYUnits("Counts/ueV")
        result.setYLabel("Intensity")
    else:
        pass

    # iterate through the values
    import array_manip
    import axis_manip
    import utils

    for i in xrange(hlr_utils.get_length(obj)):
        val = hlr_utils.get_value(obj, i, o_descr, "x", axis)
        err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis)

        y_val = hlr_utils.get_value(obj, i, o_descr, "y", axis)
        y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y", axis)
        
        map_so = hlr_utils.get_map_so(obj, None, i)
        
        l_f = hlr_utils.get_special(lambda_f, map_so)

        (E_f, E_f_err2) = axis_manip.wavelength_to_energy(l_f[0], l_f[1])

        if offset is not None:
            info = hlr_utils.get_special(offset, map_so)
            try:
                E_f_new = array_manip.add_ncerr(E_f, E_f_err2,
                                                info[0], info[1])
            except TypeError:
                # Have to do this since add_ncerr does not support
                # scalar-scalar operations
                value1 = E_f + info[0]
                value2 = E_f_err2 + info[1]
                E_f_new = (value1, value2)
        else:
            E_f_new = (E_f, E_f_err2)

        # Scale counts by lambda_f / lambda_i
        if scale:
            l_i = axis_manip.energy_to_wavelength(val, err2)

            l_i_bc = utils.calc_bin_centers(l_i[0], l_i[1])

            ratio = array_manip.div_ncerr(l_f[0], l_f[1],
                                          l_i_bc[0], l_i_bc[1])

            scale_y = array_manip.mult_ncerr(y_val, y_err2, ratio[0], ratio[1])
        else:
            scale_y = (y_val, y_err2)

        value = array_manip.sub_ncerr(val, err2, E_f_new[0], E_f_new[1])
            
        # Convert from meV to ueV
        value2 = array_manip.mult_ncerr(value[0], value[1], 1000.0, 0.0)
        value3 = array_manip.mult_ncerr(scale_y[0], scale_y[1],
                                        1.0/1000.0, 0.0)

        hlr_utils.result_insert(result, res_descr, value3, map_so, "all",
                                0, [value2[0]])

    return result
def rebin_axis_1D_linint(obj, axis_out):
    """
    This function rebins the primary axis for a C{SOM} or a C{SO} based on the
    given C{NessiList} axis using a linear interpolation scheme.

    @param obj: Object to be rebinned
    @type obj: C{SOM.SOM} or C{SOM.SO}

    @param axis_out: The axis to rebin the C{SOM} or C{SO} to
    @type axis_out: C{NessiList}


    @return: Object that has been rebinned according to the provided axis
    @rtype: C{SOM.SOM} or C{SOM.SO}


    @raise TypeError: The rebinning axis given is not a C{NessiList}

    @raise TypeError: The object being rebinned is not a C{SOM} or a C{SO}
    """

    # import the helper functions
    import hlr_utils

    # set up for working through data
    try:
        axis_out.__type__
    except AttributeError:
        raise TypeError("Rebinning axis must be a NessiList!")

    o_descr = hlr_utils.get_descr(obj)

    if o_descr == "number" or o_descr == "list":
        raise TypeError("Do not know how to handle given type: %s" % \
                        o_descr)
    else:
        pass

    (result, res_descr) = hlr_utils.empty_result(obj)

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)

    # Axis out never changes
    xvals = []
    xvals.append(axis_out)

    # Need a vector of zeros for the next function call
    len_axis_out = len(axis_out)
    zero_vec = nessi_list.NessiList(len_axis_out)

    import utils
    bin_centers = utils.calc_bin_centers(axis_out, zero_vec)

    # iterate through the values
    
    for i in xrange(hlr_utils.get_length(obj)):
        axis_in = hlr_utils.get_value(obj, i, o_descr, "x", 0)
        axis_in_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", 0)

        axis_in_bc = utils.calc_bin_centers(axis_in, axis_in_err2)

        val = hlr_utils.get_value(obj, i, o_descr)
        err2 = hlr_utils.get_err2(obj, i, o_descr)

        map_so = hlr_utils.get_map_so(obj, None, i)

        # Set zero errors to 1 for linear fit
        for j in xrange(len(err2)):
            if utils.compare(err2[j], 0.0) == 0 and \
                   utils.compare(val[j], 0.0) == 0:
                err2[j] = 1.0

        # Create new NessiLists for rebinned values
        rebin_val = nessi_list.NessiList()
        rebin_err2 = nessi_list.NessiList()

        for k in xrange(len_axis_out-1):
            index_pair = hlr_utils.bisect_helper(axis_in, axis_out[k],
                                                 axis_out[k+1])

            # Requested range is outside axis boundaries
            if index_pair[0] == -1 and index_pair[1] == -1:
                rebin_val.append(0.0)
                rebin_err2.append(0.0)
                continue

            # If there is only one value, just use it directly
            if index_pair[0] == index_pair[1]:
                rebin_val.append(val[index_pair[0]])
                rebin_err2.append(err2[index_pair[0]])
            else:
                # Do linear interpolation
                fit_params = utils.fit_linear_background(axis_in_bc[0],
                                                         val, err2,
                                                         index_pair[0],
                                                         index_pair[1])

                # Evaluate the interpolation at the rebin axis bin center
                eval_out = utils.eval_linear_fit(bin_centers[0][k:k+1],
                                                 bin_centers[1][k:k+1],
                                                 fit_params["slope"][0],
                                                 fit_params["slope"][1],
                                                 fit_params["intercept"][0],
                                                 fit_params["intercept"][1])

                rebin_val.append(eval_out[0][0])

                # Use a geometric average for the error bars
                new_err2 = 0.0
                count = 0
                for m in xrange(index_pair[0], index_pair[1]+1):
                    if utils.compare(val[m], 0.0) == 0:
                        continue
                    else:
                        new_err2 += err2[m]
                        count += 1

                if count:
                    new_err2 /= float(count)
                rebin_err2.append(new_err2)

        # Do one last clean up
        for n in xrange(len(rebin_val)):
            if utils.compare(rebin_val[n], 0.0) == 0:
                rebin_err2[n] = 0.0
        
        hlr_utils.result_insert(result, res_descr, (rebin_val, rebin_err2),
                                map_so, "all", 0, xvals)

    return result
示例#18
0
def fix_bin_contents(obj, **kwargs):
    """
    This function takes a SOM or SO and goes through the individual spectra
    adjusting the bin contents by either multiplying or dividing by the
    bin widths or the bin centers taken from the individual spectra.

    @param obj: The data object to be scaled
    @type obj: C{SOM.SOM} or C{SOM.SO}

    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword scale: A flag that signals multiplication by the required bin
                    quantity. The default is I{False} (divide).
    @type scale: C{bool}

    @keyword width: A flag that signals that the adjusting quantity is the
                    bin width. The default is I{True}. If I{False}, the bin
                    center is used.
    @type width: C{bool}

    @keyword units: The expected units for this function. The default for this
                    function is I{microsecond}.
    @type units: C{string}


    @return: The object with the individual spectrum scaled
    @rtype: C{SOM.SOM} or C{SOM.SO}
    """
    import hlr_utils

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)

    # Setup keyword arguments
    try:
        scale = kwargs["scale"]
    except KeyError:
        scale = False

    try:
        width = kwargs["width"]
    except KeyError:
        width = True

    try:
        units = kwargs["units"]
    except KeyError:
        units = "microsecond"

    # Primary axis for transformation. If a SO is passed, the function, will
    # assume the axis for transformation is at the 0 position
    if o_descr == "SOM":
        axis_pos = hlr_utils.one_d_units(obj, units)
    else:
        axis_pos = 0

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)

    # iterate through the values
    import array_manip
    import utils

    for i in xrange(hlr_utils.get_length(obj)):
        val = hlr_utils.get_value(obj, i, o_descr, "y")
        err2 = hlr_utils.get_err2(obj, i, o_descr, "y")
        axis = hlr_utils.get_value(obj, i, o_descr, "x", axis_pos)
        axis_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis_pos)

        map_so = hlr_utils.get_map_so(obj, None, i)

        if width:
            (bin_const,
             bin_const_err2) = utils.calc_bin_widths(axis, axis_err2)
        else:
            (bin_const,
             bin_const_err2) = utils.calc_bin_centers(axis, axis_err2)

        if scale:
            value = array_manip.mult_ncerr(val, err2, bin_const,
                                           bin_const_err2)
        else:
            value = array_manip.div_ncerr(val, err2, bin_const, bin_const_err2)

        hlr_utils.result_insert(result, res_descr, value, map_so, "y")

    return result
示例#19
0
         area_sum_err2) = array_manip.add_ncerr(area_sum, area_sum_err2,
                                                area_new, area_sum_err2)

    # Check for so_id keyword argument
    so_dim.id = kwargs.get("so_id", som[0].id)

    comb_som = SOM.SOM()
    comb_som.copyAttributes(som)

    comb_som = __set_som_attributes(comb_som, **kwargs)

    if configure.pdos_Q:
        # Multiply each slice of Q by 1/Q^2 * exp(u^2 * Q^2) where u is
        # the Debye-Waller constant
        import math
        Q_bc = utils.calc_bin_centers(so_dim.axis[0].val)[0]
        len_E = len(so_dim.axis[1].val) - 1

        try:
            dw_const = configure.debye_waller.getValue()
        except AttributeError:
            # No Debye-Waller constant given, so assume zero
            dw_const = 0.0

        dw_const2 = dw_const * dw_const

        for i, Q in enumerate(Q_bc):
            Q2 = Q * Q
            pdos_scale = math.exp(dw_const2 * Q2) / Q2

            i_low = i * len_E
示例#20
0
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 DST
    import math
    if config.inst == "REF_M":
        import axis_manip
        import utils

    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-6 on sample data
    d_som1 = dr_lib.process_ref_data(config.data, config,
                                     config.data_roi_file,
                                     config.dbkg_roi_file,
                                     config.no_bkg,
                                     tof_cuts=config.tof_cuts,
                                     inst_geom_dst=data_inst_geom_dst,
                                     no_tof_cuts=True,
                                     timer=tim)

    # Perform Steps 1-6 on normalization data
    if config.norm is not None:
        n_som1 = dr_lib.process_ref_data(config.norm, config,
                                         config.norm_roi_file,
                                         config.nbkg_roi_file,
                                         config.no_norm_bkg,
                                         dataset_type="norm",
                                         tof_cuts=config.tof_cuts,
                                         inst_geom_dst=norm_inst_geom_dst,
                                         no_tof_cuts=True,
                                         timer=tim)
    else:
        n_som1 = None

    if config.Q_bins is None and config.scatt_angle is not None:
        import copy
        tof_axis = copy.deepcopy(d_som1[0].axis[0].val)

    # 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 7: Sum all normalization spectra together
    if config.norm is not None:
        n_som2 = dr_lib.sum_all_spectra(n_som1)
    else:
        n_som2 = None

    del n_som1

    # Step 8: Divide data by normalization
    if config.verbose and config.norm is not None:
        print "Scale data by normalization"

    if config.norm is not None:
        d_som2 = common_lib.div_ncerr(d_som1, n_som2, length_one_som=True)
    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_som2

    if config.dump_rtof_comb:
        d_som2_1 = dr_lib.sum_all_spectra(d_som2)
        d_som2_2 = dr_lib.data_filter(d_som2_1)
        del d_som2_1

        if config.inst == "REF_M":
            tof_bc = utils.calc_bin_centers(d_som2_2[0].axis[0].val)
            d_som2_2[0].axis[0].val = tof_bc[0]
            d_som2_2.setDataSetType("density")

        d_som2_3 = dr_lib.cut_spectra(d_som2_2, config.tof_cut_min,
                                      config.tof_cut_max)
        del d_som2_2
        
        hlr_utils.write_file(config.output, "text/Spec", d_som2_3,
                             output_ext="crtof",
                             verbose=config.verbose,
                             data_ext=config.ext_replacement,
                             path_replacement=config.path_replacement,
                             message="combined R(TOF) information")
        del d_som2_3

    if config.dump_rtof:
        if config.inst == "REF_M":
            d_som2_1 = d_som2
        else:
            d_som2_1 = dr_lib.filter_ref_data(d_som2)

        d_som2_2 = dr_lib.cut_spectra(d_som2_1, config.tof_cut_min,
                                      config.tof_cut_max)
        del d_som2_1
        hlr_utils.write_file(config.output, "text/Spec", d_som2_2,
                             output_ext="rtof",
                             verbose=config.verbose,
                             data_ext=config.ext_replacement,
                             path_replacement=config.path_replacement,
                             message="R(TOF) information")
        del d_som2_2

    # Step 9: Convert TOF to scalar Q
    if config.verbose:
        print "Converting TOF to scalar Q"
        if config.beamdiv_corr:
            print "Applying beam divergence correction"
    
    # Check to see if polar angle offset is necessary
    if config.angle_offset is not None:
        # Check on units, offset must be in radians
        p_offset = hlr_utils.angle_to_radians(config.angle_offset)
        d_som2.attr_list["angle_offset"] = config.angle_offset
    else:
        p_offset = None

    # Check to see if scattering angle is requested
    if config.scatt_angle is not None:
        # Mainly used by REF_M
        scatt_angle = hlr_utils.angle_to_radians(config.scatt_angle)
        scatt_angle = (scatt_angle[0]/2.0, scatt_angle[1])
    else:
        scatt_angle = None
    
    if tim is not None:
        tim.getTime(False)

    d_som3 = dr_lib.tof_to_ref_scalar_Q(d_som2, units="microsecond",
                                        angle_offset=p_offset,
                                        lojac=False,
                                        polar=scatt_angle,
                                        configure=config)
    
    del d_som2
            
    if tim is not None:
        tim.getTime(msg="After converting wavelength to scalar Q ")

    # Calculate the Q cut range from the TOF cuts range
    if scatt_angle is not None:
        polar_angle = (scatt_angle[0]/2.0, scatt_angle[1])
    else:
        polar_angle = (d_som3.attr_list["data-theta"][0], 0)

    if p_offset is not None:
        polar_angle = (polar_angle[0] + p_offset[0],
                       polar_angle[1] + p_offset[1])

    pl = d_som3.attr_list.instrument.get_total_path(det_secondary=True)
    # Since Q ~ 1/T, need to reverse cut designation
    if config.tof_cut_min is not None:
        Q_cut_max = dr_lib.tof_to_ref_scalar_Q((float(config.tof_cut_min), 0.0),
                                               pathlength=pl,
                                               polar=polar_angle)[0]
    else:
        Q_cut_max = None
        
    if config.tof_cut_max is not None:
        Q_cut_min = dr_lib.tof_to_ref_scalar_Q((float(config.tof_cut_max), 0.0),
                                               pathlength=pl,
                                               polar=polar_angle)[0]
    else:
        Q_cut_min = None
    
    if config.dump_rq:
        d_som3_1 = dr_lib.data_filter(d_som3, clean_axis=True)
        d_som3_2 = dr_lib.cut_spectra(d_som3_1, Q_cut_min, Q_cut_max)
        del d_som3_1
        hlr_utils.write_file(config.output, "text/Spec", d_som3_2,
                             output_ext="rq",
                             verbose=config.verbose,
                             data_ext=config.ext_replacement,
                             path_replacement=config.path_replacement,
                             message="pixel R(Q) information")
        del d_som3_2
                    
    if config.Q_bins is not None or config.beamdiv_corr:
        if config.verbose:
            print "Rebinning data"
        d_som4 = common_lib.rebin_axis_1D_frac(d_som3,
                                               config.Q_bins.toNessiList())
        
        if config.dump_rqr:
            d_som4_1 = dr_lib.data_filter(d_som4, clean_axis=True)
            d_som4_2 = dr_lib.cut_spectra(d_som4_1, Q_cut_min, Q_cut_max)
            del d_som4_1
            hlr_utils.write_file(config.output, "text/Spec", d_som4_2,
                                 output_ext="rqr",
                                 verbose=config.verbose,
                                 data_ext=config.ext_replacement,
                                 path_replacement=config.path_replacement,
                                 message="rebinned pixel R(Q) information")
            del d_som4_2
    else:
        d_som4 = d_som3

    del d_som3

    if not config.no_filter:
        if config.verbose:
            print "Filtering final data"
            
        if tim is not None:
            tim.getTime(False)
            
        d_som5 = dr_lib.data_filter(d_som4)
    
        if tim is not None:
            tim.getTime(msg="After filtering data")
    else:
        d_som5 = d_som4
    
    del d_som4

    # Sum all spectra since everything is on same axis
    d_som6 = dr_lib.sum_all_spectra(d_som5)
    
    del d_som5

    d_som7 = dr_lib.cut_spectra(d_som6, Q_cut_min, Q_cut_max,
                                num_bins_clean=config.num_bins_clean)

    del d_som6

    hlr_utils.write_file(config.output, "text/Spec", d_som7,
                         replace_ext=False,
                         replace_path=False,
                         verbose=config.verbose,
                         message="combined Reflectivity information")

    d_som7.attr_list["config"] = config

    hlr_utils.write_file(config.output, "text/rmd", d_som7,
                         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 igs_energy_transfer(obj, **kwargs):
    """
    @depricated: This function will eventually disappear when the full S(Q,E)
                 transformation for IGS detectors is completed and verified.
                 
    This function takes a SOM or a SO and calculates the energy transfer for
    the IGS class of instruments. It is different from
    common_lib.energy_transfer in that the final wavelength is provided in a
    SOM.Information, SOM.CompositeInformation or a tuple, then converted to
    energy in place before being given to the common_lib.energy_transfer
    function.

    Parameters:
    ----------
    -> obj
    -> kwargs is a list of key word arguments that the function accepts:
          units= a string containing the expected units for this function.
                 The default for this function is meV
          lambda_f= a SOM.Information, SOM.CompositeInformation or a tuple
                    containing the final wavelength information
          offset= a SOM.Information or SOM.CompositeInformation containing
                  the final energy offsets
          scale=<boolean> is a flag that determines if the energy transfer
                          results are scaled by the ratio of lambda_f/lambda_i.
                          The default is False

    Returns:
    -------
    <- A SOM or SO with the energy transfer calculated in units of THz

    Exceptions:
    ----------
    <- RuntimeError is raised if the x-axis units are not meV
    <- RuntimeError is raised if a SOM or SO is not given to the function
    <- RuntimeError is raised if the final wavelength is not provided to the
       function
    """

    # import the helper functions
    import hlr_utils

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)

    if o_descr == "number" or o_descr == "list":
        raise RuntimeError, "Must provide a SOM of a SO to the function."
    # Go on
    else:
        pass

    # Setup keyword arguments
    try:
        units = kwargs["units"]
    except KeyError:
        units = "meV"

    try:
        lambda_f = kwargs["lambda_f"]
    except KeyError:
        lambda_f = None

    try:
        offset = kwargs["offset"]
    except KeyError:
        offset = None

    try:
        scale = kwargs["scale"]
    except KeyError:
        scale = False

    # Primary axis for transformation. If a SO is passed, the function, will
    # assume the axis for transformation is at the 0 position
    if o_descr == "SOM":
        axis = hlr_utils.one_d_units(obj, units)
    else:
        axis = 0

    if lambda_f is None:
        if o_descr == "SOM":
            try:
                lambda_f = obj.attr_list["Wavelength_final"]
            except KeyError:
                raise RuntimeError("Must provide a final wavelength via the "\
                                   +"incoming SOM or the lambda_f keyword")
        else:
            raise RuntimeError("Must provide a final wavelength via the "\
                                   +"lambda_f keyword")
    else:
        pass

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)
    if res_descr == "SOM":
        result = hlr_utils.force_units(result, "ueV", axis)
        result.setAxisLabel(axis, "energy_transfer")
        result.setYUnits("Counts/ueV")
        result.setYLabel("Intensity")
    else:
        pass

    # iterate through the values
    import array_manip
    import axis_manip
    import utils

    for i in xrange(hlr_utils.get_length(obj)):
        val = hlr_utils.get_value(obj, i, o_descr, "x", axis)
        err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis)

        y_val = hlr_utils.get_value(obj, i, o_descr, "y", axis)
        y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y", axis)

        map_so = hlr_utils.get_map_so(obj, None, i)

        l_f = hlr_utils.get_special(lambda_f, map_so)

        (E_f, E_f_err2) = axis_manip.wavelength_to_energy(l_f[0], l_f[1])

        if offset is not None:
            info = hlr_utils.get_special(offset, map_so)
            try:
                E_f_new = array_manip.add_ncerr(E_f, E_f_err2, info[0],
                                                info[1])
            except TypeError:
                # Have to do this since add_ncerr does not support
                # scalar-scalar operations
                value1 = E_f + info[0]
                value2 = E_f_err2 + info[1]
                E_f_new = (value1, value2)
        else:
            E_f_new = (E_f, E_f_err2)

        # Scale counts by lambda_f / lambda_i
        if scale:
            l_i = axis_manip.energy_to_wavelength(val, err2)

            l_i_bc = utils.calc_bin_centers(l_i[0], l_i[1])

            ratio = array_manip.div_ncerr(l_f[0], l_f[1], l_i_bc[0], l_i_bc[1])

            scale_y = array_manip.mult_ncerr(y_val, y_err2, ratio[0], ratio[1])
        else:
            scale_y = (y_val, y_err2)

        value = array_manip.sub_ncerr(val, err2, E_f_new[0], E_f_new[1])

        # Convert from meV to ueV
        value2 = array_manip.mult_ncerr(value[0], value[1], 1000.0, 0.0)
        value3 = array_manip.mult_ncerr(scale_y[0], scale_y[1], 1.0 / 1000.0,
                                        0.0)

        hlr_utils.result_insert(result, res_descr, value3, map_so, "all", 0,
                                [value2[0]])

    return result
def subtract_axis_dep_bkg(obj, coeffs, **kwargs):
    """
    This function takes spectrum object(s) and a set of coefficients and
    subtracts an axis dependent background based on a polynomial. The order
    of the polynomial is based on the number of coefficients provided.

    @param obj: Object from which to subtract the individual background numbers
    @type obj: C{SOM.SOM} or C{SOM.SO}

    @param coeffs: The set of coefficients for the polynomial representation
                   of the background to be subtracted.
    @type coeffs: C{list} of C{floats}

    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword old_scale: The scale factor used to obtain the coefficients used
                        in this function.
    @type old_scale: C{float}

    @keyword new_scale: The scale factor for the current data set from which
                        the axis dependent background will be subtracted from.
    @type new_scale: C{float}


    @return: Object with the axis dependent background subtracted
    @rtype: C{SOM.SOM} or C{SOM.SO}


    @raise TypeError: The first argument is not a C{SOM} or C{SO}    
    """
    # Kickout is coeffs is None, or length is zero
    if coeffs is None:
        return obj

    poly_len = len(coeffs)    
    if poly_len == 0:
        return obj

    # Check for keywords
    old_scale = kwargs.get("old_scale", 1.0)
    new_scale = kwargs.get("new_scale", 1.0)

    # Reverse coefficients for __eval_poly function
    coeffs.reverse()

    # import the helper functions
    import hlr_utils

    o_descr = hlr_utils.get_descr(obj)

    if o_descr != "SOM" and o_descr != "SO":
        raise TypeError("Incoming object must be a SOM or a SO")
    # Have a SOM or SO
    else:
        pass

    (result, res_descr) = hlr_utils.empty_result(obj)

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)

    obj_len = hlr_utils.get_length(obj)

    import utils

    # iterate through the values
    for i in xrange(obj_len):
        axis   = hlr_utils.get_value(obj, i, o_descr, "x", 0)
        val    = hlr_utils.get_value(obj, i, o_descr, "y")
        err2   = hlr_utils.get_err2 (obj, i, o_descr, "y")
        map_so = hlr_utils.get_map_so(obj, None, i)

        len_val = len(val)
        new_scale_p = new_scale / len_val
        ratio = old_scale / new_scale_p

        axis_centers = utils.calc_bin_centers(axis)

        for j in xrange(len(val)):
            val[j] -= (ratio * __eval_poly(axis_centers[0][j], coeffs,
                                           poly_len))

        value = (val, err2)

        hlr_utils.result_insert(result, res_descr, value, map_so, "y")

    return result
示例#23
0
def energy_transfer(obj, itype, axis_const, **kwargs):
    """
    This function takes a SOM with a wavelength axis (initial for IGS and
    final for DGS) and calculates the energy transfer.  

    @param obj: The object containing the wavelength axis
    @type obj: C{SOM.SOM}

    @param itype: The instrument class type. The choices are either I{IGS} or
                  I{DGS}.
    @type itype: C{string}

    @param axis_const: The attribute name for the axis constant which is the 
                         final wavelength for I{IGS} and the initial energy for
                         I{DGS}.
    @type axis_const: C{string}

    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword units: The units for the incoming axis. The default is
                    I{Angstroms}.
    @type units: C{string}

    @keyword change_units: A flag that signals the function to convert from
                           I{meV} to I{ueV}. The default is I{False}.
    @type change_units: C{boolean}

    @keyword scale: A flag to scale the y-axis by lambda_f/lambda_i for I{IGS}
                    and lambda_i/lambda_f for I{DGS}. The default is I{False}.
    @type scale: C{boolean}

    @keyword lojac: A flag that turns on the calculation and application of
                    the linear-order Jacobian. The default is I{False}.
    @type lojac: C{boolean}

    @keyword sa_norm: A flag to turn on solid angle normlaization.
    @type sa_norm: C{boolean}

    @return: Object with the energy transfer calculated in units of I{meV} or
             I{ueV}. The default is I{meV}.
    @rtype: C{SOM.SOM}


    @raise RuntimeError: The instrument class type is not recognized
    @raise RuntimeError: The x-axis units are not Angstroms
    @raise RuntimeError: A SOM is not given to the function
    """
    # Check the instrument class type to make sure its allowed
    allowed_types = ["DGS", "IGS"]

    if itype not in allowed_types:
        raise RuntimeError("The instrument class type %s is not known. "\
                           +"Please use DGS or IGS" % itype)

    # import the helper functions
    import hlr_utils

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)

    if o_descr != "SOM":
        raise RuntimeError("Must provide a SOM to the function.")
    # Go on
    else:
        pass

    # Setup keyword arguments
    try:
        units = kwargs["units"]
    except KeyError:
        units = "Angstroms"

    try:
        change_units = kwargs["change_units"]
    except KeyError:
        change_units = False       

    try:
        scale = kwargs["scale"]
    except KeyError:
        scale = False

    try:
        sa_norm = kwargs["sa_norm"]
    except KeyError:
        sa_norm = False

    if sa_norm:
        inst = obj.attr_list.instrument

    try:
        lojac = kwargs["lojac"]
    except KeyError:
        lojac = False
    
    # Primary axis for transformation. 
    axis = hlr_utils.one_d_units(obj, units)

    # Get the subtraction constant
    try:
        axis_c = obj.attr_list[axis_const]
    except KeyError:
        raise RuntimeError("Must provide a final wavelength (IGS) or initial "\
                           +"energy (DGS) via the incoming SOM")
    
    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)
    if change_units:
        unit_str = "ueV"
    else:
        unit_str = "meV"
    result = hlr_utils.force_units(result, unit_str, axis)
    result.setAxisLabel(axis, "energy_transfer")
    result.setYUnits("Counts/" + unit_str)
    result.setYLabel("Intensity")

    # iterate through the values
    import array_manip
    import axis_manip
    import dr_lib
    import utils

    for i in xrange(hlr_utils.get_length(obj)):
        if itype == "IGS":
            l_i = hlr_utils.get_value(obj, i, o_descr, "x", axis)
            l_i_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis)
        else:
            l_f = hlr_utils.get_value(obj, i, o_descr, "x", axis)
            l_f_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis)
            
        y_val = hlr_utils.get_value(obj, i, o_descr, "y", axis)
        y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y", axis)
        
        map_so = hlr_utils.get_map_so(obj, None, i)

        if itype == "IGS":
            (E_i, E_i_err2) = axis_manip.wavelength_to_energy(l_i, l_i_err2)
            l_f = hlr_utils.get_special(axis_c, map_so)[:2]
            (E_f, E_f_err2) = axis_manip.wavelength_to_energy(l_f[0], l_f[1])
            if lojac:
                (y_val, y_err2) = utils.linear_order_jacobian(l_i, E_i, 
                                                              y_val, y_err2)  
        else:
            (E_i, E_i_err2) = axis_c.toValErrTuple()
            (E_f, E_f_err2) = axis_manip.wavelength_to_energy(l_f, l_f_err2)
            if lojac:
                (y_val, y_err2) = utils.linear_order_jacobian(l_f, E_f, 
                                                              y_val, y_err2)

        if scale:
            # Scale counts by lambda_f / lambda_i
            if itype == "IGS":
                (l_n, l_n_err2) = l_f
                (l_d, l_d_err2) = utils.calc_bin_centers(l_i, l_i_err2)
            else:
                (l_n, l_n_err2) = utils.calc_bin_centers(l_f, l_f_err2)
                (l_d, l_d_err2) = axis_manip.energy_to_wavelength(E_i,
                                                                  E_i_err2)
                
            ratio = array_manip.div_ncerr(l_n, l_n_err2, l_d, l_d_err2)
            scale_y = array_manip.mult_ncerr(y_val, y_err2, ratio[0], ratio[1])
        else:
            scale_y = (y_val, y_err2)

        value = array_manip.sub_ncerr(E_i, E_i_err2, E_f, E_f_err2)

        if change_units:
            # Convert from meV to ueV
            value2 = array_manip.mult_ncerr(value[0], value[1], 1000.0, 0.0)
            scale_y = array_manip.mult_ncerr(scale_y[0], scale_y[1],
                                             1.0/1000.0, 0.0)
        else:
            value2 = value

        if sa_norm:
            if inst.get_name() == "BSS":
                dOmega = dr_lib.calc_BSS_solid_angle(map_so, inst)
                scale_y = array_manip.div_ncerr(scale_y[0], scale_y[1],
                                                dOmega, 0.0)
            else:
                raise RuntimeError("Do not know how to get solid angle from "\
                                   +"%s" % inst.get_name())
            
        if itype == "IGS":
            # Reverse the values due to the conversion
            value_y = axis_manip.reverse_array_cp(scale_y[0])
            value_var_y = axis_manip.reverse_array_cp(scale_y[1])
            value_x = axis_manip.reverse_array_cp(value2[0])
        else:
            value_y = scale_y[0]
            value_var_y = scale_y[1]
            value_x = value2[0]

        hlr_utils.result_insert(result, res_descr, (value_y, value_var_y),
                                map_so, "all", 0, [value_x])

    return result
示例#24
0
def create_E_vs_Q_igs(som, *args, **kwargs):
    """
    This function starts with the initial IGS wavelength axis and turns this
    into a 2D spectra with E and Q axes.

    @param som: The input object with initial IGS wavelength axis
    @type som: C{SOM.SOM}

    @param args: A mandatory list of axes for rebinning. There is a particular
                 order to them. They should be present in the following order:

                 Without errors
                   1. Energy transfer
                   2. Momentum transfer
                 With errors
                   1. Energy transfer
                   2. Energy transfer error^2
                   3. Momentum transfer
                   4. Momentum transfer error ^2
    @type args: C{nessi_list.NessiList}s
       
    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword withXVar: Flag for whether the function should be expecting the
                       associated axes to have errors. The default value will
                       be I{False}.
    @type withXVar: C{boolean}

    @keyword data_type: Name of the data type which can be either I{histogram},
                        I{density} or I{coordinate}. The default value will be
                        I{histogram}
    @type data_type: C{string}
    
    @keyword Q_filter: Flag to turn on or off Q filtering. The default behavior
                       is I{True}.
    @type Q_filter: C{boolean}
    
    @keyword so_id: The identifier represents a number, string, tuple or other
                    object that describes the resulting C{SO}
    @type so_id: C{int}, C{string}, C{tuple}, C{pixel ID}
    
    @keyword y_label: The y axis label
    @type y_label: C{string}
    
    @keyword y_units: The y axis units
    @type y_units: C{string}
    
    @keyword x_labels: This is a list of names that sets the individual x axis
    labels
    @type x_labels: C{list} of C{string}s
    
    @keyword x_units: This is a list of names that sets the individual x axis
    units
    @type x_units: C{list} of C{string}s

    @keyword split: This flag causes the counts and the fractional area to
                    be written out into separate files.
    @type split: C{boolean}

    @keyword configure: This is the object containing the driver configuration.
    @type configure: C{Configure}


    @return: Object containing a 2D C{SO} with E and Q axes
    @rtype: C{SOM.SOM}


    @raise RuntimeError: Anything other than a C{SOM} is passed to the function
    
    @raise RuntimeError: An instrument is not contained in the C{SOM}
    """
    import nessi_list

    # Setup some variables 
    dim = 2
    N_y = []
    N_tot = 1
    N_args = len(args)

    # Get T0 slope in order to calculate dT = dT_i + dT_0
    try:
        t_0_slope = som.attr_list["Time_zero_slope"][0]
        t_0_slope_err2 = som.attr_list["Time_zero_slope"][1]
    except KeyError:
        t_0_slope = float(0.0)
        t_0_slope_err2 = float(0.0)

    # Check withXVar keyword argument and also check number of given args.
    # Set xvar to the appropriate value
    try:
        value = kwargs["withXVar"]
        if value.lower() == "true":
            if N_args != 4:
                raise RuntimeError("Since you have requested x errors, 4 x "\
                                   +"axes must be provided.")
            else:
                xvar = True
        elif value.lower() == "false":
            if N_args != 2:
                raise RuntimeError("Since you did not requested x errors, 2 "\
                                   +"x axes must be provided.")
            else:
                xvar = False
        else:
            raise RuntimeError("Do not understand given parameter %s" % \
                               value)
    except KeyError:
        if N_args != 2:
            raise RuntimeError("Since you did not requested x errors, 2 "\
                               +"x axes must be provided.")
        else:
            xvar = False

    # Check dataType keyword argument. An offset will be set to 1 for the
    # histogram type and 0 for either density or coordinate
    try:
        data_type = kwargs["data_type"]
        if data_type.lower() == "histogram":
            offset = 1
        elif data_type.lower() == "density" or \
                 data_type.lower() == "coordinate":
            offset = 0
        else:
            raise RuntimeError("Do not understand data type given: %s" % \
                               data_type)
    # Default is offset for histogram
    except KeyError:
        offset = 1

    try:
        Q_filter = kwargs["Q_filter"]
    except KeyError:
        Q_filter = True

    # Check for split keyword
    try:
        split = kwargs["split"]
    except KeyError:
        split = False

    # Check for configure keyword
    try:
        configure = kwargs["configure"]
    except KeyError:
        configure = None

    so_dim = SOM.SO(dim)

    for i in range(dim):
        # Set the x-axis arguments from the *args list into the new SO
        if not xvar:
            # Axis positions are 1 (Q) and 0 (E)
            position = dim - i - 1
            so_dim.axis[i].val = args[position]
        else:
            # Axis positions are 2 (Q), 3 (eQ), 0 (E), 1 (eE)
            position = dim - 2 * i
            so_dim.axis[i].val = args[position]
            so_dim.axis[i].var = args[position + 1]

        # Set individual value axis sizes (not x-axis size)
        N_y.append(len(args[position]) - offset)

        # Calculate total 2D array size
        N_tot = N_tot * N_y[-1]

    # Create y and var_y lists from total 2D size
    so_dim.y = nessi_list.NessiList(N_tot)
    so_dim.var_y = nessi_list.NessiList(N_tot)
    
    # Create area sum and errors for the area sum lists from total 2D size
    area_sum = nessi_list.NessiList(N_tot)
    area_sum_err2 = nessi_list.NessiList(N_tot)

    # Create area sum and errors for the area sum lists from total 2D size
    bin_count = nessi_list.NessiList(N_tot)
    bin_count_err2 = nessi_list.NessiList(N_tot)
    
    inst = som.attr_list.instrument
    lambda_final = som.attr_list["Wavelength_final"]
    inst_name = inst.get_name()

    import bisect
    import math

    import dr_lib
    import utils

    arr_len = 0
    #: Vector of zeros for function calculations
    zero_vec = None
    
    for j in xrange(hlr_utils.get_length(som)):
        # Get counts
        counts = hlr_utils.get_value(som, j, "SOM", "y")
        counts_err2 = hlr_utils.get_err2(som, j, "SOM", "y")

        arr_len = len(counts)
        zero_vec = nessi_list.NessiList(arr_len)

        # Get mapping SO
        map_so = hlr_utils.get_map_so(som, None, j)

        # Get lambda_i
        l_i = hlr_utils.get_value(som, j, "SOM", "x")
        l_i_err2 = hlr_utils.get_err2(som, j, "SOM", "x")
        
        # Get lambda_f from instrument information
        l_f_tuple = hlr_utils.get_special(lambda_final, map_so)
        l_f = l_f_tuple[0]
        l_f_err2 = l_f_tuple[1]
        
        # Get source to sample distance
        (L_s, L_s_err2) = hlr_utils.get_parameter("primary", map_so, inst)

        # Get sample to detector distance
        L_d_tuple = hlr_utils.get_parameter("secondary", map_so, inst)
        L_d = L_d_tuple[0]

        # Get polar angle from instrument information
        (angle, angle_err2) = hlr_utils.get_parameter("polar", map_so, inst)

        # Get the detector pixel height
        dh_tuple = hlr_utils.get_parameter("dh", map_so, inst)
        dh = dh_tuple[0]
        # Need dh in units of Angstrom
        dh *= 1e10

        # Calculate T_i
        (T_i, T_i_err2) = axis_manip.wavelength_to_tof(l_i, l_i_err2, 
                                                       L_s, L_s_err2)

        # Scale counts by lambda_f / lambda_i
        (l_i_bc, l_i_bc_err2) = utils.calc_bin_centers(l_i, l_i_err2)

        (ratio, ratio_err2) = array_manip.div_ncerr(l_f, l_f_err2,
                                                    l_i_bc, l_i_bc_err2)

        (counts, counts_err2) = array_manip.mult_ncerr(counts, counts_err2,
                                                       ratio, ratio_err2)

        # Calculate E_i
        (E_i, E_i_err2) = axis_manip.wavelength_to_energy(l_i, l_i_err2)

        # Calculate E_f
        (E_f, E_f_err2) = axis_manip.wavelength_to_energy(l_f, l_f_err2)

        # Calculate E_t
        (E_t, E_t_err2) = array_manip.sub_ncerr(E_i, E_i_err2, E_f, E_f_err2)

        if inst_name == "BSS":
            # Convert E_t from meV to ueV
            (E_t, E_t_err2) = array_manip.mult_ncerr(E_t, E_t_err2,
                                                     1000.0, 0.0)
            (counts, counts_err2) = array_manip.mult_ncerr(counts, counts_err2,
                                                           1.0/1000.0, 0.0)

        # Convert lambda_i to k_i
        (k_i, k_i_err2) = axis_manip.wavelength_to_scalar_k(l_i, l_i_err2)

        # Convert lambda_f to k_f
        (k_f, k_f_err2) = axis_manip.wavelength_to_scalar_k(l_f, l_f_err2)

        # Convert k_i and k_f to Q
        (Q, Q_err2) = axis_manip.init_scatt_wavevector_to_scalar_Q(k_i,
                                                                   k_i_err2,
                                                                   k_f,
                                                                   k_f_err2,
                                                                   angle,
                                                                   angle_err2)

        # Calculate dT = dT_0 + dT_i
        dT_i = utils.calc_bin_widths(T_i, T_i_err2)

        (l_i_bw, l_i_bw_err2) = utils.calc_bin_widths(l_i, l_i_err2)
        dT_0 = array_manip.mult_ncerr(l_i_bw, l_i_bw_err2,
                                      t_0_slope, t_0_slope_err2)

        dT_tuple = array_manip.add_ncerr(dT_i[0], dT_i[1], dT_0[0], dT_0[1])
        dT = dT_tuple[0]

        # Calculate Jacobian
        if inst_name == "BSS":
            (x_1, x_2,
             x_3, x_4) = dr_lib.calc_BSS_coeffs(map_so, inst, (E_i, E_i_err2),
                                                (Q, Q_err2), (k_i, k_i_err2),
                                                (T_i, T_i_err2), dh, angle,
                                                E_f, k_f, l_f, L_s, L_d,
                                                t_0_slope, zero_vec)
        else:
            raise RuntimeError("Do not know how to calculate x_i "\
                               +"coefficients for instrument %s" % inst_name)

        (A, A_err2) = dr_lib.calc_EQ_Jacobian(x_1, x_2, x_3, x_4, dT, dh,
                                              zero_vec)
        
        # Apply Jacobian: C/dlam * dlam / A(EQ) = C/EQ
        (jac_ratio, jac_ratio_err2) = array_manip.div_ncerr(l_i_bw,
                                                            l_i_bw_err2,
                                                            A, A_err2)
        (counts, counts_err2) = array_manip.mult_ncerr(counts, counts_err2,
                                                       jac_ratio,
                                                       jac_ratio_err2)
        
        # Reverse counts, E_t, k_i and Q
        E_t = axis_manip.reverse_array_cp(E_t)
        E_t_err2 = axis_manip.reverse_array_cp(E_t_err2)
        Q = axis_manip.reverse_array_cp(Q)
        Q_err2 = axis_manip.reverse_array_cp(Q_err2)        
        counts = axis_manip.reverse_array_cp(counts)
        counts_err2 = axis_manip.reverse_array_cp(counts_err2)
        k_i = axis_manip.reverse_array_cp(k_i)
        x_1 = axis_manip.reverse_array_cp(x_1)
        x_2 = axis_manip.reverse_array_cp(x_2)
        x_3 = axis_manip.reverse_array_cp(x_3)
        x_4 = axis_manip.reverse_array_cp(x_4)
        dT = axis_manip.reverse_array_cp(dT)        

        # Filter for duplicate Q values
        if Q_filter:
            k_i_cutoff = k_f * math.cos(angle)
            k_i_cutbin = bisect.bisect(k_i, k_i_cutoff)
            
            counts.__delslice__(0, k_i_cutbin)
            counts_err2.__delslice__(0, k_i_cutbin)
            Q.__delslice__(0, k_i_cutbin)
            Q_err2.__delslice__(0, k_i_cutbin)
            E_t.__delslice__(0, k_i_cutbin)
            E_t_err2.__delslice__(0, k_i_cutbin)
            x_1.__delslice__(0, k_i_cutbin)
            x_2.__delslice__(0, k_i_cutbin)
            x_3.__delslice__(0, k_i_cutbin)
            x_4.__delslice__(0, k_i_cutbin)            
            dT.__delslice__(0, k_i_cutbin)
            zero_vec.__delslice__(0, k_i_cutbin)

        try:
            if inst_name == "BSS":
                ((Q_1, E_t_1),
                 (Q_2, E_t_2),
                 (Q_3, E_t_3),
                 (Q_4, E_t_4)) = dr_lib.calc_BSS_EQ_verticies((E_t, E_t_err2),
                                                              (Q, Q_err2), x_1,
                                                              x_2, x_3, x_4,
                                                              dT, dh, zero_vec)
            else:
                raise RuntimeError("Do not know how to calculate (Q_i, "\
                                   +"E_t_i) verticies for instrument %s" \
                                   % inst_name)

        except IndexError:
            # All the data got Q filtered, move on
            continue

        try:
            (y_2d, y_2d_err2,
             area_new,
             bin_count_new) = axis_manip.rebin_2D_quad_to_rectlin(Q_1, E_t_1,
                                                           Q_2, E_t_2,
                                                           Q_3, E_t_3,
                                                           Q_4, E_t_4,
                                                           counts,
                                                           counts_err2,
                                                           so_dim.axis[0].val,
                                                           so_dim.axis[1].val)
        except IndexError, e:
            # Get the offending index from the error message
            index = int(str(e).split()[1].split('index')[-1].strip('[]'))
            print "Id:", map_so.id
            print "Index:", index
            print "Verticies: %f, %f, %f, %f, %f, %f, %f, %f" % (Q_1[index],
                                                                 E_t_1[index],
                                                                 Q_2[index],
                                                                 E_t_2[index],
                                                                 Q_3[index],
                                                                 E_t_3[index],
                                                                 Q_4[index],
                                                                 E_t_4[index])
            raise IndexError(str(e))

        # Add in together with previous results
        (so_dim.y, so_dim.var_y) = array_manip.add_ncerr(so_dim.y,
                                                         so_dim.var_y,
                                                         y_2d, y_2d_err2)
        
        (area_sum, area_sum_err2) = array_manip.add_ncerr(area_sum,
                                                          area_sum_err2,
                                                          area_new,
                                                          area_sum_err2)

        if configure.dump_pix_contrib or configure.scale_sqe:
            if inst_name == "BSS":
                dOmega = dr_lib.calc_BSS_solid_angle(map_so, inst)
                (bin_count_new,
                 bin_count_err2) = array_manip.mult_ncerr(bin_count_new,
                                                          bin_count_err2,
                                                          dOmega, 0.0)
                
                (bin_count,
                 bin_count_err2) = array_manip.add_ncerr(bin_count,
                                                         bin_count_err2,
                                                         bin_count_new,
                                                         bin_count_err2)
        else:
            del bin_count_new
示例#25
0
def calc_BSS_EQ_verticies(*args):
    """
    This function calculates the S(Q,E) bin verticies for BSS. It uses the
    x_i coefficients, dT, dh and the E and Q bin centers for the calculation.

    @param args: A list of parameters (C{tuple}s with value and err^2) used to
    calculate the x_i coefficients

    The following is a list of the arguments needed in there expected order
      1. Energy Transfer
      2. Momentum Transfer
      3. x_1 coefficient
      4. x_2 coefficient
      5. x_3 coefficient
      6. x_4 coefficient
      7. dT (Time-of-flight bin widths)
      8. dh (Height of detector pixel)
      9. Vector of Zeros
    @type args: C{list}


    @return: The calculated Q and E verticies ((Q_1, E_1), (Q_2, E_2),
             (Q_3, E_3), (Q_4, E_4))
    @rtype: C{tuple} of 4 C{tuple}s of 2 C{nessi_list.NessiList}s
    """
    # Settle out the arguments to sensible names
    E_t = args[0][0]
    E_t_err2 = args[0][1]
    Q = args[1][0]
    Q_err2 = args[1][1]
    x_1 = args[2]
    x_2 = args[3]
    x_3 = args[4]
    x_4 = args[5]
    dT = args[6]
    dh = args[7]
    zero_vec = args[8]

    # Calculate bin centric values
    (E_t_bc, E_t_bc_err2) = utils.calc_bin_centers(E_t, E_t_err2)
    (Q_bc, Q_bc_err2) = utils.calc_bin_centers(Q, Q_err2)

    (x1dh, x1dh_err2) = array_manip.mult_ncerr(x_1, zero_vec, dh, 0.0)
    (x3dh, x3dh_err2) = array_manip.mult_ncerr(x_3, zero_vec, dh, 0.0)
    (x2dT, x2dT_err2) = array_manip.mult_ncerr(x_2, zero_vec, dT, zero_vec)
    (x4dT, x4dT_err2) = array_manip.mult_ncerr(x_4, zero_vec, dT, zero_vec)

    (x1dh_p_x2dT, x1dh_p_x2dT_err2) = array_manip.add_ncerr(x1dh, x1dh_err2, x2dT, x2dT_err2)
    (x3dh_p_x4dT, x3dh_p_x4dT_err2) = array_manip.add_ncerr(x3dh, x3dh_err2, x4dT, x4dT_err2)
    (x1dh_m_x2dT, x1dh_m_x2dT_err2) = array_manip.sub_ncerr(x1dh, x1dh_err2, x2dT, x2dT_err2)
    (x3dh_m_x4dT, x3dh_m_x4dT_err2) = array_manip.sub_ncerr(x3dh, x3dh_err2, x4dT, x4dT_err2)

    (dQ_1, dQ_1_err2) = array_manip.mult_ncerr(x1dh_p_x2dT, x1dh_p_x2dT_err2, -0.5, 0.0)
    (dE_1, dE_1_err2) = array_manip.mult_ncerr(x3dh_p_x4dT, x3dh_p_x4dT_err2, -0.5, 0.0)
    (dQ_2, dQ_2_err2) = array_manip.mult_ncerr(x1dh_m_x2dT, x1dh_m_x2dT_err2, -0.5, 0.0)
    (dE_2, dE_2_err2) = array_manip.mult_ncerr(x3dh_m_x4dT, x3dh_m_x4dT_err2, -0.5, 0.0)

    (dQ_3, dQ_3_err2) = array_manip.mult_ncerr(dQ_1, dQ_1_err2, -1.0, 0.0)
    (dE_3, dE_3_err2) = array_manip.mult_ncerr(dE_1, dE_1_err2, -1.0, 0.0)
    (dQ_4, dQ_4_err2) = array_manip.mult_ncerr(dQ_2, dQ_2_err2, -1.0, 0.0)
    (dE_4, dE_4_err2) = array_manip.mult_ncerr(dE_2, dE_2_err2, -1.0, 0.0)

    Q_1 = array_manip.add_ncerr(Q_bc, Q_bc_err2, dQ_1, dQ_1_err2)
    E_t_1 = array_manip.add_ncerr(E_t_bc, E_t_bc_err2, dE_1, dE_1_err2)

    Q_2 = array_manip.add_ncerr(Q_bc, Q_bc_err2, dQ_2, dQ_2_err2)
    E_t_2 = array_manip.add_ncerr(E_t_bc, E_t_bc_err2, dE_2, dE_2_err2)

    Q_3 = array_manip.add_ncerr(Q_bc, Q_bc_err2, dQ_3, dQ_3_err2)
    E_t_3 = array_manip.add_ncerr(E_t_bc, E_t_bc_err2, dE_3, dE_3_err2)

    Q_4 = array_manip.add_ncerr(Q_bc, Q_bc_err2, dQ_4, dQ_4_err2)
    E_t_4 = array_manip.add_ncerr(E_t_bc, E_t_bc_err2, dE_4, dE_4_err2)

    return ((Q_1[0], E_t_1[0]), (Q_2[0], E_t_2[0]), (Q_3[0], E_t_3[0]), (Q_4[0], E_t_4[0]))
示例#26
0
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 DST
    import math
    if config.inst == "REF_M":
        import axis_manip
        import utils

    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-6 on sample data
    d_som1 = dr_lib.process_ref_data(config.data, config,
                                     config.data_roi_file,
                                     config.dbkg_roi_file,
                                     config.no_bkg,
                                     tof_cuts=config.tof_cuts,
                                     inst_geom_dst=data_inst_geom_dst,
                                     timer=tim)

    # Perform Steps 1-6 on normalization data
    if config.norm is not None:
        n_som1 = dr_lib.process_ref_data(config.norm, config,
                                         config.norm_roi_file,
                                         config.nbkg_roi_file,
                                         config.no_norm_bkg,
                                         dataset_type="norm",
                                         tof_cuts=config.tof_cuts,
                                         inst_geom_dst=norm_inst_geom_dst,
                                         timer=tim)
    else:
        n_som1 = None

    if config.Q_bins is None and config.scatt_angle is not None:
        import copy
        tof_axis = copy.deepcopy(d_som1[0].axis[0].val)

    # 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 7: Sum all normalization spectra together
    if config.norm is not None:
        n_som2 = dr_lib.sum_all_spectra(n_som1)
    else:
        n_som2 = None

    del n_som1

    # Step 8: Divide data by normalization
    if config.verbose and config.norm is not None:
        print "Scale data by normalization"

    if config.norm is not None:
        d_som2 = common_lib.div_ncerr(d_som1, n_som2, length_one_som=True)
    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_som2

    if config.dump_rtof_comb:
        d_som2_1 = dr_lib.sum_all_spectra(d_som2)
        d_som2_2 = dr_lib.data_filter(d_som2_1)
        del d_som2_1

        if config.inst == "REF_M":
            tof_bc = utils.calc_bin_centers(d_som2_2[0].axis[0].val)
            d_som2_2[0].axis[0].val = tof_bc[0]
            d_som2_2.setDataSetType("density")
        
        hlr_utils.write_file(config.output, "text/Spec", d_som2_2,
                             output_ext="crtof",
                             verbose=config.verbose,
                             data_ext=config.ext_replacement,
                             path_replacement=config.path_replacement,
                             message="combined R(TOF) information")

        del d_som2_2

    if config.dump_rtof:
        if config.inst == "REF_M":
            d_som2_1 = d_som2
        else:
            d_som2_1 = dr_lib.filter_ref_data(d_som2)
        
        hlr_utils.write_file(config.output, "text/Spec", d_som2_1,
                             output_ext="rtof",
                             verbose=config.verbose,
                             data_ext=config.ext_replacement,
                             path_replacement=config.path_replacement,
                             message="R(TOF) information")
        del d_som2_1

    if config.inst == "REF_L":
        # Step 9: Convert TOF to scalar Q
        if config.verbose:
            print "Converting TOF to scalar Q"
    
        # Check to see if polar angle offset is necessary
        if config.angle_offset is not None:
            # Check on units, offset must be in radians
            p_temp = config.angle_offset.toFullTuple(True)
            if p_temp[2] == "degrees" or p_temp[2] == "degree":
                deg_to_rad =  (math.pi / 180.0)
                p_off_rads = p_temp[0] * deg_to_rad
                p_off_err2_rads = p_temp[1] * deg_to_rad * deg_to_rad
            else:
                p_off_rads = p_temp[0]
                p_off_err2_rads = p_temp[1]
    
            p_offset = (p_off_rads, p_off_err2_rads)
    
            d_som2.attr_list["angle_offset"] = config.angle_offset
        else:
            p_offset = None
    
        if tim is not None:
            tim.getTime(False)
    
        d_som3 = common_lib.tof_to_scalar_Q(d_som2, units="microsecond",
                                            angle_offset=p_offset,
                                            lojac=False)
    
        del d_som2
            
        if tim is not None:
            tim.getTime(msg="After converting wavelength to scalar Q ")
    
        if config.dump_rq:
            d_som3_1 = dr_lib.data_filter(d_som3, clean_axis=True)
            hlr_utils.write_file(config.output, "text/Spec", d_som3_1,
                                 output_ext="rq",
                                 verbose=config.verbose,
                                 data_ext=config.ext_replacement,
                                 path_replacement=config.path_replacement,
                                 message="pixel R(Q) information")
            del d_som3_1
                    
        if not config.no_filter:
            if config.verbose:
                print "Filtering final data"
            
            if tim is not None:
                tim.getTime(False)
            
            d_som4 = dr_lib.data_filter(d_som3)
    
            if tim is not None:
                tim.getTime(msg="After filtering data")
        else:
            d_som4 = d_som3
    
        del d_som3
    else:
        d_som4 = d_som2

    # Step 10: Rebin all spectra to final Q axis
    if config.Q_bins is None:
        if config.scatt_angle is None:
            config.Q_bins = dr_lib.create_axis_from_data(d_som4)
            rebin_axis = config.Q_bins.toNessiList()
        else:
            # Get scattering angle and make Q conversion from TOF axis
            # Check on units, scattering angle must be in radians
            sa_temp = config.scatt_angle.toFullTuple(True)
            if sa_temp[2] == "degrees" or sa_temp[2] == "degree":
                deg_to_rad =  (math.pi / 180.0)
                sa_rads = sa_temp[0] * deg_to_rad
                sa_err2_rads = sa_temp[1] * deg_to_rad * deg_to_rad
            else:
                sa_rads = sa_temp[0]
                sa_err2_rads = sa_temp[1]

            sa = (sa_rads, sa_err2_rads)

            pl = d_som4.attr_list.instrument.get_total_path(d_som4[0].id,
                                                            det_secondary=True)

            import nessi_list
            tof_axis_err2 = nessi_list.NessiList(len(tof_axis))

            rebin_axis = axis_manip.tof_to_scalar_Q(tof_axis,
                                                    tof_axis_err2,
                                                    pl[0], pl[1],
                                                    sa[0], sa[1])[0]

            axis_manip.reverse_array_nc(rebin_axis)            
    else:
        rebin_axis = config.Q_bins.toNessiList()

    if config.inst == "REF_L":
        if config.verbose:
            print "Rebinning spectra"

        if tim is not None:
            tim.getTime(False)
            
        d_som5 = common_lib.rebin_axis_1D_linint(d_som4, rebin_axis)
    
        if tim is not None:
            tim.getTime(msg="After rebinning spectra")
    
        del d_som4
    
        if config.dump_rqr:
            hlr_utils.write_file(config.output, "text/Spec", d_som5,
                                 output_ext="rqr",
                                 verbose=config.verbose,
                                 data_ext=config.ext_replacement,
                                 path_replacement=config.path_replacement,
                                 message="pixel R(Q) (after rebinning) "\
                                 +"information")
    
        # Step 11: Sum all rebinned spectra
        if config.verbose:
            print "Summing spectra"
    
        if tim is not None:
            tim.getTime(False)
    
        d_som6 = dr_lib.sum_all_spectra(d_som5)
    
        if tim is not None:
            tim.getTime(msg="After summing spectra")
    
        del d_som5
    else:
        d_som5 = d_som4

    if config.inst == "REF_M":
        d_som5A = dr_lib.sum_all_spectra(d_som5)
        del d_som5
        d_som6 = dr_lib.data_filter(d_som5A)
        del d_som5A
        axis_manip.reverse_array_nc(d_som6[0].y)
        axis_manip.reverse_array_nc(d_som6[0].var_y)

        d_som6.setYLabel("Intensity")
        d_som6.setYUnits("Counts/A-1")
        d_som6.setAllAxisLabels(["scalar wavevector transfer"])
        d_som6.setAllAxisUnits(["1/Angstroms"])

        Q_bc = utils.calc_bin_centers(rebin_axis)
        d_som6[0].axis[0].val = Q_bc[0]
        d_som6.setDataSetType("density")

    hlr_utils.write_file(config.output, "text/Spec", d_som6,
                         replace_ext=False,
                         replace_path=False,
                         verbose=config.verbose,
                         message="combined Reflectivity information")

    d_som6.attr_list["config"] = config

    hlr_utils.write_file(config.output, "text/rmd", d_som6,
                         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")
示例#27
0
def calc_BSS_coeffs(map_so, inst, *args):
    """
    This function calculates the x_i coefficients for the BSS instrument

    @param map_so: The spectrum object to calculate the coefficients for
    @type map_so: C{SOM.SO}

    @param inst: The instrument object associated with the data
    @type inst: C{SOM.Instrument} or C{SOM.CompositeInstrument}

    @param args: A list of parameters (C{tuple}s with value and err^2) used to
    calculate the x_i coefficients

    The following is a list of the arguments needed in there expected order
      1. Initial Energy
      2. Momentum Transfer
      3. Initial Wavevector
      4. Initial Time-of-Flight
      5. Detector Pixel Height
      6. Polar Angle
      7. Final Energy
      8. Final Wavevector
      9. Final Wavelength
      10. Source to Sample Distance
      11. Sample to Detector Distance
      12. Time-zero Slope
      13. Vector of Zeros
    @type args: C{list}


    @return: The calculated coefficients (x_1, x_2, x_3, x_4)
    @rtype: C{tuple} of 4 C{nessi_list.NessiList}s 
    """
    import math

    # Settle out the arguments to sensible names
    E_i = args[0][0]
    E_i_err2 = args[0][1]
    Q = args[1][0]
    Q_err2 = args[1][1]
    k_i = args[2][0]
    k_i_err2 = args[2][1]
    T_i = args[3][0]
    T_i_err2 = args[3][1]
    dh = args[4]
    polar_angle = args[5]
    E_f = args[6]
    k_f = args[7]
    l_f = args[8]
    L_s = args[9]
    L_d = args[10]
    T_0_s = args[11]
    zero_vec = args[12]

    # Constant h/m_n (meters / microsecond)
    H_OVER_MNEUT = 0.003956034e-10

    # Get the differential geometry parameters
    dlf_dh_tuple = hlr_utils.get_parameter("dlf_dh", map_so, inst)
    dlf_dh = dlf_dh_tuple[0]
    # dlf_dh should be unitless (Angstrom/Angstrom)
    dlf_dh *= 1e-10

    dpol_dh_tuple = hlr_utils.get_parameter("dpol_dh", map_so, inst)
    dpol_dh = dpol_dh_tuple[0]
    # Convert to radian/Angstrom
    dpol_dh *= 1e-10

    dpol_dtd_tuple = hlr_utils.get_parameter("dpol_dtd", map_so, inst)
    dpol_dtd = dpol_dtd_tuple[0]

    # Get the detector pixel angular width
    dtd_tuple = hlr_utils.get_parameter("dtd", map_so, inst)
    dtd = dtd_tuple[0]

    # Calculate bin centric values
    E_i_bc_tuple = utils.calc_bin_centers(E_i, E_i_err2)
    E_i_bc = E_i_bc_tuple[0]

    k_i_bc_tuple = utils.calc_bin_centers(k_i, k_i_err2)
    k_i_bc = k_i_bc_tuple[0]

    Q_bc_tuple = utils.calc_bin_centers(Q, Q_err2)
    Q_bc = Q_bc_tuple[0]

    T_i_bc_tuple = utils.calc_bin_centers(T_i, T_i_err2)
    T_i_bc = T_i_bc_tuple[0]

    # Get numeric values
    sin_polar = math.sin(polar_angle)
    cos_polar = math.cos(polar_angle)
    length_ratio = L_d / L_s
    lambda_const = ((2.0 * math.pi) / (l_f * l_f)) * dlf_dh
    kf_cos_pol = k_f * cos_polar
    kf_sin_pol = k_f * sin_polar
    t0_slope_corr = 1.0 / (1.0 + H_OVER_MNEUT * (T_0_s / L_s))
    dtd_over_dh = dtd / dh

    # Calculate coefficients
    x_1_tuple = __calc_x1(
        k_i_bc,
        Q_bc,
        length_ratio,
        k_f,
        kf_cos_pol,
        kf_sin_pol,
        lambda_const,
        dpol_dh,
        dpol_dtd,
        dtd_over_dh,
        cos_polar,
        t0_slope_corr,
        zero_vec,
    )
    x_1 = x_1_tuple[0]

    x_2_tuple = __calc_x2(k_i_bc, Q_bc, T_i_bc, kf_cos_pol, t0_slope_corr, zero_vec)
    x_2 = x_2_tuple[0]

    x_3_tuple = __calc_x3(k_i_bc, E_i_bc, length_ratio, E_f, k_f, lambda_const, t0_slope_corr, zero_vec)
    x_3 = x_3_tuple[0]

    x_4_tuple = __calc_x4(E_i_bc, T_i_bc, t0_slope_corr, zero_vec)
    x_4 = x_4_tuple[0]

    return (x_1, x_2, x_3, x_4)
示例#28
0
def calc_BSS_coeffs(map_so, inst, *args):
    """
    This function calculates the x_i coefficients for the BSS instrument

    @param map_so: The spectrum object to calculate the coefficients for
    @type map_so: C{SOM.SO}

    @param inst: The instrument object associated with the data
    @type inst: C{SOM.Instrument} or C{SOM.CompositeInstrument}

    @param args: A list of parameters (C{tuple}s with value and err^2) used to
    calculate the x_i coefficients

    The following is a list of the arguments needed in there expected order
      1. Initial Energy
      2. Momentum Transfer
      3. Initial Wavevector
      4. Initial Time-of-Flight
      5. Detector Pixel Height
      6. Polar Angle
      7. Final Energy
      8. Final Wavevector
      9. Final Wavelength
      10. Source to Sample Distance
      11. Sample to Detector Distance
      12. Time-zero Slope
      13. Vector of Zeros
    @type args: C{list}


    @return: The calculated coefficients (x_1, x_2, x_3, x_4)
    @rtype: C{tuple} of 4 C{nessi_list.NessiList}s 
    """
    import math

    # Settle out the arguments to sensible names
    E_i = args[0][0]
    E_i_err2 = args[0][1]
    Q = args[1][0]
    Q_err2 = args[1][1]
    k_i = args[2][0]
    k_i_err2 = args[2][1]
    T_i = args[3][0]
    T_i_err2 = args[3][1]
    dh = args[4]
    polar_angle = args[5]
    E_f = args[6]
    k_f = args[7]
    l_f = args[8]
    L_s = args[9]
    L_d = args[10]
    T_0_s = args[11]
    zero_vec = args[12]

    # Constant h/m_n (meters / microsecond)
    H_OVER_MNEUT = 0.003956034e-10

    # Get the differential geometry parameters
    dlf_dh_tuple = hlr_utils.get_parameter("dlf_dh", map_so, inst)
    dlf_dh = dlf_dh_tuple[0]
    # dlf_dh should be unitless (Angstrom/Angstrom)
    dlf_dh *= 1e-10

    dpol_dh_tuple = hlr_utils.get_parameter("dpol_dh", map_so, inst)
    dpol_dh = dpol_dh_tuple[0]
    # Convert to radian/Angstrom
    dpol_dh *= 1e-10

    dpol_dtd_tuple = hlr_utils.get_parameter("dpol_dtd", map_so, inst)
    dpol_dtd = dpol_dtd_tuple[0]

    # Get the detector pixel angular width
    dtd_tuple = hlr_utils.get_parameter("dtd", map_so, inst)
    dtd = dtd_tuple[0]

    # Calculate bin centric values
    E_i_bc_tuple = utils.calc_bin_centers(E_i, E_i_err2)
    E_i_bc = E_i_bc_tuple[0]

    k_i_bc_tuple = utils.calc_bin_centers(k_i, k_i_err2)
    k_i_bc = k_i_bc_tuple[0]

    Q_bc_tuple = utils.calc_bin_centers(Q, Q_err2)
    Q_bc = Q_bc_tuple[0]

    T_i_bc_tuple = utils.calc_bin_centers(T_i, T_i_err2)
    T_i_bc = T_i_bc_tuple[0]

    # Get numeric values
    sin_polar = math.sin(polar_angle)
    cos_polar = math.cos(polar_angle)
    length_ratio = L_d / L_s
    lambda_const = ((2.0 * math.pi) / (l_f * l_f)) * dlf_dh
    kf_cos_pol = k_f * cos_polar
    kf_sin_pol = k_f * sin_polar
    t0_slope_corr = (1.0 / (1.0 + H_OVER_MNEUT * (T_0_s / L_s)))
    dtd_over_dh = dtd / dh

    # Calculate coefficients
    x_1_tuple = __calc_x1(k_i_bc, Q_bc, length_ratio, k_f, kf_cos_pol,
                          kf_sin_pol, lambda_const, dpol_dh, dpol_dtd,
                          dtd_over_dh, cos_polar, t0_slope_corr, zero_vec)
    x_1 = x_1_tuple[0]

    x_2_tuple = __calc_x2(k_i_bc, Q_bc, T_i_bc, kf_cos_pol, t0_slope_corr,
                          zero_vec)
    x_2 = x_2_tuple[0]

    x_3_tuple = __calc_x3(k_i_bc, E_i_bc, length_ratio, E_f, k_f, lambda_const,
                          t0_slope_corr, zero_vec)
    x_3 = x_3_tuple[0]

    x_4_tuple = __calc_x4(E_i_bc, T_i_bc, t0_slope_corr, zero_vec)
    x_4 = x_4_tuple[0]

    return (x_1, x_2, x_3, x_4)
示例#29
0
def create_E_vs_Q_igs(som, *args, **kwargs):
    """
    This function starts with the initial IGS wavelength axis and turns this
    into a 2D spectra with E and Q axes.

    @param som: The input object with initial IGS wavelength axis
    @type som: C{SOM.SOM}

    @param args: A mandatory list of axes for rebinning. There is a particular
                 order to them. They should be present in the following order:

                 Without errors
                   1. Energy transfer
                   2. Momentum transfer
                 With errors
                   1. Energy transfer
                   2. Energy transfer error^2
                   3. Momentum transfer
                   4. Momentum transfer error ^2
    @type args: C{nessi_list.NessiList}s
       
    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword withXVar: Flag for whether the function should be expecting the
                       associated axes to have errors. The default value will
                       be I{False}.
    @type withXVar: C{boolean}

    @keyword data_type: Name of the data type which can be either I{histogram},
                        I{density} or I{coordinate}. The default value will be
                        I{histogram}
    @type data_type: C{string}
    
    @keyword Q_filter: Flag to turn on or off Q filtering. The default behavior
                       is I{True}.
    @type Q_filter: C{boolean}
    
    @keyword so_id: The identifier represents a number, string, tuple or other
                    object that describes the resulting C{SO}
    @type so_id: C{int}, C{string}, C{tuple}, C{pixel ID}
    
    @keyword y_label: The y axis label
    @type y_label: C{string}
    
    @keyword y_units: The y axis units
    @type y_units: C{string}
    
    @keyword x_labels: This is a list of names that sets the individual x axis
    labels
    @type x_labels: C{list} of C{string}s
    
    @keyword x_units: This is a list of names that sets the individual x axis
    units
    @type x_units: C{list} of C{string}s

    @keyword split: This flag causes the counts and the fractional area to
                    be written out into separate files.
    @type split: C{boolean}

    @keyword configure: This is the object containing the driver configuration.
    @type configure: C{Configure}


    @return: Object containing a 2D C{SO} with E and Q axes
    @rtype: C{SOM.SOM}


    @raise RuntimeError: Anything other than a C{SOM} is passed to the function
    
    @raise RuntimeError: An instrument is not contained in the C{SOM}
    """
    import nessi_list

    # Setup some variables
    dim = 2
    N_y = []
    N_tot = 1
    N_args = len(args)

    # Get T0 slope in order to calculate dT = dT_i + dT_0
    try:
        t_0_slope = som.attr_list["Time_zero_slope"][0]
        t_0_slope_err2 = som.attr_list["Time_zero_slope"][1]
    except KeyError:
        t_0_slope = float(0.0)
        t_0_slope_err2 = float(0.0)

    # Check withXVar keyword argument and also check number of given args.
    # Set xvar to the appropriate value
    try:
        value = kwargs["withXVar"]
        if value.lower() == "true":
            if N_args != 4:
                raise RuntimeError("Since you have requested x errors, 4 x "\
                                   +"axes must be provided.")
            else:
                xvar = True
        elif value.lower() == "false":
            if N_args != 2:
                raise RuntimeError("Since you did not requested x errors, 2 "\
                                   +"x axes must be provided.")
            else:
                xvar = False
        else:
            raise RuntimeError("Do not understand given parameter %s" % \
                               value)
    except KeyError:
        if N_args != 2:
            raise RuntimeError("Since you did not requested x errors, 2 "\
                               +"x axes must be provided.")
        else:
            xvar = False

    # Check dataType keyword argument. An offset will be set to 1 for the
    # histogram type and 0 for either density or coordinate
    try:
        data_type = kwargs["data_type"]
        if data_type.lower() == "histogram":
            offset = 1
        elif data_type.lower() == "density" or \
                 data_type.lower() == "coordinate":
            offset = 0
        else:
            raise RuntimeError("Do not understand data type given: %s" % \
                               data_type)
    # Default is offset for histogram
    except KeyError:
        offset = 1

    try:
        Q_filter = kwargs["Q_filter"]
    except KeyError:
        Q_filter = True

    # Check for split keyword
    try:
        split = kwargs["split"]
    except KeyError:
        split = False

    # Check for configure keyword
    try:
        configure = kwargs["configure"]
    except KeyError:
        configure = None

    so_dim = SOM.SO(dim)

    for i in range(dim):
        # Set the x-axis arguments from the *args list into the new SO
        if not xvar:
            # Axis positions are 1 (Q) and 0 (E)
            position = dim - i - 1
            so_dim.axis[i].val = args[position]
        else:
            # Axis positions are 2 (Q), 3 (eQ), 0 (E), 1 (eE)
            position = dim - 2 * i
            so_dim.axis[i].val = args[position]
            so_dim.axis[i].var = args[position + 1]

        # Set individual value axis sizes (not x-axis size)
        N_y.append(len(args[position]) - offset)

        # Calculate total 2D array size
        N_tot = N_tot * N_y[-1]

    # Create y and var_y lists from total 2D size
    so_dim.y = nessi_list.NessiList(N_tot)
    so_dim.var_y = nessi_list.NessiList(N_tot)

    # Create area sum and errors for the area sum lists from total 2D size
    area_sum = nessi_list.NessiList(N_tot)
    area_sum_err2 = nessi_list.NessiList(N_tot)

    # Create area sum and errors for the area sum lists from total 2D size
    bin_count = nessi_list.NessiList(N_tot)
    bin_count_err2 = nessi_list.NessiList(N_tot)

    inst = som.attr_list.instrument
    lambda_final = som.attr_list["Wavelength_final"]
    inst_name = inst.get_name()

    import bisect
    import math

    import dr_lib
    import utils

    arr_len = 0
    #: Vector of zeros for function calculations
    zero_vec = None

    for j in xrange(hlr_utils.get_length(som)):
        # Get counts
        counts = hlr_utils.get_value(som, j, "SOM", "y")
        counts_err2 = hlr_utils.get_err2(som, j, "SOM", "y")

        arr_len = len(counts)
        zero_vec = nessi_list.NessiList(arr_len)

        # Get mapping SO
        map_so = hlr_utils.get_map_so(som, None, j)

        # Get lambda_i
        l_i = hlr_utils.get_value(som, j, "SOM", "x")
        l_i_err2 = hlr_utils.get_err2(som, j, "SOM", "x")

        # Get lambda_f from instrument information
        l_f_tuple = hlr_utils.get_special(lambda_final, map_so)
        l_f = l_f_tuple[0]
        l_f_err2 = l_f_tuple[1]

        # Get source to sample distance
        (L_s, L_s_err2) = hlr_utils.get_parameter("primary", map_so, inst)

        # Get sample to detector distance
        L_d_tuple = hlr_utils.get_parameter("secondary", map_so, inst)
        L_d = L_d_tuple[0]

        # Get polar angle from instrument information
        (angle, angle_err2) = hlr_utils.get_parameter("polar", map_so, inst)

        # Get the detector pixel height
        dh_tuple = hlr_utils.get_parameter("dh", map_so, inst)
        dh = dh_tuple[0]
        # Need dh in units of Angstrom
        dh *= 1e10

        # Calculate T_i
        (T_i, T_i_err2) = axis_manip.wavelength_to_tof(l_i, l_i_err2, L_s,
                                                       L_s_err2)

        # Scale counts by lambda_f / lambda_i
        (l_i_bc, l_i_bc_err2) = utils.calc_bin_centers(l_i, l_i_err2)

        (ratio, ratio_err2) = array_manip.div_ncerr(l_f, l_f_err2, l_i_bc,
                                                    l_i_bc_err2)

        (counts, counts_err2) = array_manip.mult_ncerr(counts, counts_err2,
                                                       ratio, ratio_err2)

        # Calculate E_i
        (E_i, E_i_err2) = axis_manip.wavelength_to_energy(l_i, l_i_err2)

        # Calculate E_f
        (E_f, E_f_err2) = axis_manip.wavelength_to_energy(l_f, l_f_err2)

        # Calculate E_t
        (E_t, E_t_err2) = array_manip.sub_ncerr(E_i, E_i_err2, E_f, E_f_err2)

        if inst_name == "BSS":
            # Convert E_t from meV to ueV
            (E_t, E_t_err2) = array_manip.mult_ncerr(E_t, E_t_err2, 1000.0,
                                                     0.0)
            (counts,
             counts_err2) = array_manip.mult_ncerr(counts, counts_err2,
                                                   1.0 / 1000.0, 0.0)

        # Convert lambda_i to k_i
        (k_i, k_i_err2) = axis_manip.wavelength_to_scalar_k(l_i, l_i_err2)

        # Convert lambda_f to k_f
        (k_f, k_f_err2) = axis_manip.wavelength_to_scalar_k(l_f, l_f_err2)

        # Convert k_i and k_f to Q
        (Q, Q_err2) = axis_manip.init_scatt_wavevector_to_scalar_Q(
            k_i, k_i_err2, k_f, k_f_err2, angle, angle_err2)

        # Calculate dT = dT_0 + dT_i
        dT_i = utils.calc_bin_widths(T_i, T_i_err2)

        (l_i_bw, l_i_bw_err2) = utils.calc_bin_widths(l_i, l_i_err2)
        dT_0 = array_manip.mult_ncerr(l_i_bw, l_i_bw_err2, t_0_slope,
                                      t_0_slope_err2)

        dT_tuple = array_manip.add_ncerr(dT_i[0], dT_i[1], dT_0[0], dT_0[1])
        dT = dT_tuple[0]

        # Calculate Jacobian
        if inst_name == "BSS":
            (x_1, x_2, x_3, x_4) = dr_lib.calc_BSS_coeffs(
                map_so, inst, (E_i, E_i_err2), (Q, Q_err2), (k_i, k_i_err2),
                (T_i, T_i_err2), dh, angle, E_f, k_f, l_f, L_s, L_d, t_0_slope,
                zero_vec)
        else:
            raise RuntimeError("Do not know how to calculate x_i "\
                               +"coefficients for instrument %s" % inst_name)

        (A, A_err2) = dr_lib.calc_EQ_Jacobian(x_1, x_2, x_3, x_4, dT, dh,
                                              zero_vec)

        # Apply Jacobian: C/dlam * dlam / A(EQ) = C/EQ
        (jac_ratio,
         jac_ratio_err2) = array_manip.div_ncerr(l_i_bw, l_i_bw_err2, A,
                                                 A_err2)
        (counts, counts_err2) = array_manip.mult_ncerr(counts, counts_err2,
                                                       jac_ratio,
                                                       jac_ratio_err2)

        # Reverse counts, E_t, k_i and Q
        E_t = axis_manip.reverse_array_cp(E_t)
        E_t_err2 = axis_manip.reverse_array_cp(E_t_err2)
        Q = axis_manip.reverse_array_cp(Q)
        Q_err2 = axis_manip.reverse_array_cp(Q_err2)
        counts = axis_manip.reverse_array_cp(counts)
        counts_err2 = axis_manip.reverse_array_cp(counts_err2)
        k_i = axis_manip.reverse_array_cp(k_i)
        x_1 = axis_manip.reverse_array_cp(x_1)
        x_2 = axis_manip.reverse_array_cp(x_2)
        x_3 = axis_manip.reverse_array_cp(x_3)
        x_4 = axis_manip.reverse_array_cp(x_4)
        dT = axis_manip.reverse_array_cp(dT)

        # Filter for duplicate Q values
        if Q_filter:
            k_i_cutoff = k_f * math.cos(angle)
            k_i_cutbin = bisect.bisect(k_i, k_i_cutoff)

            counts.__delslice__(0, k_i_cutbin)
            counts_err2.__delslice__(0, k_i_cutbin)
            Q.__delslice__(0, k_i_cutbin)
            Q_err2.__delslice__(0, k_i_cutbin)
            E_t.__delslice__(0, k_i_cutbin)
            E_t_err2.__delslice__(0, k_i_cutbin)
            x_1.__delslice__(0, k_i_cutbin)
            x_2.__delslice__(0, k_i_cutbin)
            x_3.__delslice__(0, k_i_cutbin)
            x_4.__delslice__(0, k_i_cutbin)
            dT.__delslice__(0, k_i_cutbin)
            zero_vec.__delslice__(0, k_i_cutbin)

        try:
            if inst_name == "BSS":
                ((Q_1, E_t_1), (Q_2, E_t_2), (Q_3, E_t_3),
                 (Q_4, E_t_4)) = dr_lib.calc_BSS_EQ_verticies(
                     (E_t, E_t_err2), (Q, Q_err2), x_1, x_2, x_3, x_4, dT, dh,
                     zero_vec)
            else:
                raise RuntimeError("Do not know how to calculate (Q_i, "\
                                   +"E_t_i) verticies for instrument %s" \
                                   % inst_name)

        except IndexError:
            # All the data got Q filtered, move on
            continue

        try:
            (y_2d, y_2d_err2, area_new,
             bin_count_new) = axis_manip.rebin_2D_quad_to_rectlin(
                 Q_1, E_t_1, Q_2, E_t_2, Q_3, E_t_3, Q_4, E_t_4, counts,
                 counts_err2, so_dim.axis[0].val, so_dim.axis[1].val)
        except IndexError, e:
            # Get the offending index from the error message
            index = int(str(e).split()[1].split('index')[-1].strip('[]'))
            print "Id:", map_so.id
            print "Index:", index
            print "Verticies: %f, %f, %f, %f, %f, %f, %f, %f" % (
                Q_1[index], E_t_1[index], Q_2[index], E_t_2[index], Q_3[index],
                E_t_3[index], Q_4[index], E_t_4[index])
            raise IndexError(str(e))

        # Add in together with previous results
        (so_dim.y,
         so_dim.var_y) = array_manip.add_ncerr(so_dim.y, so_dim.var_y, y_2d,
                                               y_2d_err2)

        (area_sum,
         area_sum_err2) = array_manip.add_ncerr(area_sum, area_sum_err2,
                                                area_new, area_sum_err2)

        if configure.dump_pix_contrib or configure.scale_sqe:
            if inst_name == "BSS":
                dOmega = dr_lib.calc_BSS_solid_angle(map_so, inst)
                (bin_count_new, bin_count_err2) = array_manip.mult_ncerr(
                    bin_count_new, bin_count_err2, dOmega, 0.0)

                (bin_count, bin_count_err2) = array_manip.add_ncerr(
                    bin_count, bin_count_err2, bin_count_new, bin_count_err2)
        else:
            del bin_count_new
示例#30
0
def create_det_eff(obj, **kwargs):
    """
    This function creates detector efficiency spectra based on the wavelength
    spectra from the given object. The efficiency spectra are created based on
    the following formalism: Ci*exp(-di*lambda) where i represents the
    constants for a given detector pixel.

    @param obj: Object containing spectra that will create the detector
                efficiency spectra.
    @type obj: C{SOM.SOM} or C{SOM.SO}
    
    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword inst_name: The short name of an instrument.
    @type inst_name: C{string}
    
    @keyword eff_scale_const: Use this provided efficiency scaling constant.
    @type eff_scale_const: L{hlr_utils.DrParameter}

    @keyword eff_atten_const: Use this provided efficiency attenuation
                              constant.
    @type eff_atten_const: L{hlr_utils.DrParameter}    


    @return: Object containing the detector efficiency spectra
    @rtype: C{SOM.SOM} or C{SOM.SO}


    @raise TypeError: Incoming object is not a C{SOM} or a C{SO}
    @raise RuntimeError: The C{SOM} x-axis units are not I{Angstroms}
    """
    # Check keywords
    inst_name = kwargs.get("inst_name")
    eff_scale_const = kwargs.get("eff_scale_const")
    eff_atten_const = kwargs.get("eff_atten_const")

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)

    if o_descr != "SOM" and o_descr != "SO":
        raise TypeError("Only SOM or SO objects permitted to create "\
                        +"efficiency spectra!")

    # Check units on SOM, SO is assumed to be correct
    if o_descr == "SOM":
        if not obj.hasAxisUnits("Angstroms"):
            raise RuntimeError("Incoming object must has a wavelength axis "\
                               +"with units of Angstroms!")

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)

    # iterate through the values
    import dr_lib
    import phys_corr
    import utils

    # Get object length
    len_obj = hlr_utils.get_length(obj)
    for i in xrange(len_obj):
        map_so = hlr_utils.get_map_so(obj, None, i)
        axis = hlr_utils.get_value(obj, i, o_descr, "x", 0)

        if inst_name is None:
            axis_bc = utils.calc_bin_centers(axis)
            (eff,
             eff_err2) = phys_corr.exp_detector_eff(axis_bc[0], 1.0, 0.0, 1.0)
        else:
            if inst_name == "SANS":
                (eff, eff_err2) = dr_lib.subexp_eff(eff_atten_const, axis,
                                                    eff_scale_const)
            else:
                raise RuntimeError("Do not know how to handle %s instrument" \
                                   % inst_name)

        hlr_utils.result_insert(result, res_descr, (eff, eff_err2), map_so)

    return result
示例#31
0
def energy_transfer(obj, itype, axis_const, **kwargs):
    """
    This function takes a SOM with a wavelength axis (initial for IGS and
    final for DGS) and calculates the energy transfer.  

    @param obj: The object containing the wavelength axis
    @type obj: C{SOM.SOM}

    @param itype: The instrument class type. The choices are either I{IGS} or
                  I{DGS}.
    @type itype: C{string}

    @param axis_const: The attribute name for the axis constant which is the 
                         final wavelength for I{IGS} and the initial energy for
                         I{DGS}.
    @type axis_const: C{string}

    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword units: The units for the incoming axis. The default is
                    I{Angstroms}.
    @type units: C{string}

    @keyword change_units: A flag that signals the function to convert from
                           I{meV} to I{ueV}. The default is I{False}.
    @type change_units: C{boolean}

    @keyword scale: A flag to scale the y-axis by lambda_f/lambda_i for I{IGS}
                    and lambda_i/lambda_f for I{DGS}. The default is I{False}.
    @type scale: C{boolean}

    @keyword lojac: A flag that turns on the calculation and application of
                    the linear-order Jacobian. The default is I{False}.
    @type lojac: C{boolean}

    @keyword sa_norm: A flag to turn on solid angle normlaization.
    @type sa_norm: C{boolean}

    @return: Object with the energy transfer calculated in units of I{meV} or
             I{ueV}. The default is I{meV}.
    @rtype: C{SOM.SOM}


    @raise RuntimeError: The instrument class type is not recognized
    @raise RuntimeError: The x-axis units are not Angstroms
    @raise RuntimeError: A SOM is not given to the function
    """
    # Check the instrument class type to make sure its allowed
    allowed_types = ["DGS", "IGS"]

    if itype not in allowed_types:
        raise RuntimeError("The instrument class type %s is not known. "\
                           +"Please use DGS or IGS" % itype)

    # import the helper functions
    import hlr_utils

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(obj)
    o_descr = hlr_utils.get_descr(obj)

    if o_descr != "SOM":
        raise RuntimeError("Must provide a SOM to the function.")
    # Go on
    else:
        pass

    # Setup keyword arguments
    try:
        units = kwargs["units"]
    except KeyError:
        units = "Angstroms"

    try:
        change_units = kwargs["change_units"]
    except KeyError:
        change_units = False

    try:
        scale = kwargs["scale"]
    except KeyError:
        scale = False

    try:
        sa_norm = kwargs["sa_norm"]
    except KeyError:
        sa_norm = False

    if sa_norm:
        inst = obj.attr_list.instrument

    try:
        lojac = kwargs["lojac"]
    except KeyError:
        lojac = False

    # Primary axis for transformation.
    axis = hlr_utils.one_d_units(obj, units)

    # Get the subtraction constant
    try:
        axis_c = obj.attr_list[axis_const]
    except KeyError:
        raise RuntimeError("Must provide a final wavelength (IGS) or initial "\
                           +"energy (DGS) via the incoming SOM")

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)
    if change_units:
        unit_str = "ueV"
    else:
        unit_str = "meV"
    result = hlr_utils.force_units(result, unit_str, axis)
    result.setAxisLabel(axis, "energy_transfer")
    result.setYUnits("Counts/" + unit_str)
    result.setYLabel("Intensity")

    # iterate through the values
    import array_manip
    import axis_manip
    import dr_lib
    import utils

    for i in xrange(hlr_utils.get_length(obj)):
        if itype == "IGS":
            l_i = hlr_utils.get_value(obj, i, o_descr, "x", axis)
            l_i_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis)
        else:
            l_f = hlr_utils.get_value(obj, i, o_descr, "x", axis)
            l_f_err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis)

        y_val = hlr_utils.get_value(obj, i, o_descr, "y", axis)
        y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y", axis)

        map_so = hlr_utils.get_map_so(obj, None, i)

        if itype == "IGS":
            (E_i, E_i_err2) = axis_manip.wavelength_to_energy(l_i, l_i_err2)
            l_f = hlr_utils.get_special(axis_c, map_so)[:2]
            (E_f, E_f_err2) = axis_manip.wavelength_to_energy(l_f[0], l_f[1])
            if lojac:
                (y_val,
                 y_err2) = utils.linear_order_jacobian(l_i, E_i, y_val, y_err2)
        else:
            (E_i, E_i_err2) = axis_c.toValErrTuple()
            (E_f, E_f_err2) = axis_manip.wavelength_to_energy(l_f, l_f_err2)
            if lojac:
                (y_val,
                 y_err2) = utils.linear_order_jacobian(l_f, E_f, y_val, y_err2)

        if scale:
            # Scale counts by lambda_f / lambda_i
            if itype == "IGS":
                (l_n, l_n_err2) = l_f
                (l_d, l_d_err2) = utils.calc_bin_centers(l_i, l_i_err2)
            else:
                (l_n, l_n_err2) = utils.calc_bin_centers(l_f, l_f_err2)
                (l_d,
                 l_d_err2) = axis_manip.energy_to_wavelength(E_i, E_i_err2)

            ratio = array_manip.div_ncerr(l_n, l_n_err2, l_d, l_d_err2)
            scale_y = array_manip.mult_ncerr(y_val, y_err2, ratio[0], ratio[1])
        else:
            scale_y = (y_val, y_err2)

        value = array_manip.sub_ncerr(E_i, E_i_err2, E_f, E_f_err2)

        if change_units:
            # Convert from meV to ueV
            value2 = array_manip.mult_ncerr(value[0], value[1], 1000.0, 0.0)
            scale_y = array_manip.mult_ncerr(scale_y[0], scale_y[1],
                                             1.0 / 1000.0, 0.0)
        else:
            value2 = value

        if sa_norm:
            if inst.get_name() == "BSS":
                dOmega = dr_lib.calc_BSS_solid_angle(map_so, inst)
                scale_y = array_manip.div_ncerr(scale_y[0], scale_y[1], dOmega,
                                                0.0)
            else:
                raise RuntimeError("Do not know how to get solid angle from "\
                                   +"%s" % inst.get_name())

        if itype == "IGS":
            # Reverse the values due to the conversion
            value_y = axis_manip.reverse_array_cp(scale_y[0])
            value_var_y = axis_manip.reverse_array_cp(scale_y[1])
            value_x = axis_manip.reverse_array_cp(value2[0])
        else:
            value_y = scale_y[0]
            value_var_y = scale_y[1]
            value_x = value2[0]

        hlr_utils.result_insert(result, res_descr, (value_y, value_var_y),
                                map_so, "all", 0, [value_x])

    return result