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])
Example #2
0
def calc_EQ_Jacobian(*args):
    """
    This function calculates the Jacobian for S(Q,E) via the following formula

    A = |x_1 * x4 - x_2 * x_3| * dh * dT
    
    @param args: A list of parameters used to calculate the Jacobian

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


    @return: The calculated Jacobian
    @rtype: (C{nessi_list.NessiList}, C{nessi_list.NessiList})
    """
    import array_manip

    # Settle out the arguments to sensible names
    x_1 = args[0]
    x_2 = args[1]
    x_3 = args[2]
    x_4 = args[3]
    dT = args[4]
    dh = args[5]
    zero_vec = args[6]
    
    # x_2 * x_3
    x_23 = array_manip.mult_ncerr(x_2, zero_vec, x_3, zero_vec)
    # x_1 * x_4
    x_14 = array_manip.mult_ncerr(x_1, zero_vec, x_4, zero_vec)
    # dh * dT
    dhdT = array_manip.mult_ncerr(dT, zero_vec, dh, 0.0)
    # x_1 * x_4 - x_2 * x_3
    x14_m_x23 = array_manip.sub_ncerr(x_14[0], x_14[1], x_23[0], x_23[1])
    # |x_1 * x_4 - x_2 * x_3|
    abs_x14_m_x23 = (array_manip.abs_val(x14_m_x23[0]), x14_m_x23[1])
    # |x_1 * x_4 - x_2 * x_3| * dh * dT 
    return array_manip.mult_ncerr(dhdT[0], dhdT[1],
                                  abs_x14_m_x23[0], abs_x14_m_x23[1])
def __calc_x2(*args):
    """
    This function calculates the x2 coeffiecient to the S(Q,E) Jacobian

    @param args: A list of parameters used to calculate the x2 coefficient

    The following is a list of the arguments needed in there expected order
      1. Initial Wavevector
      2. Momentum Transfer
      3. Initial Time-of-Flight
      4. Wavevector Final x Cos(polar)
      5. Time-zero Slope Correction
      6. Vector of Zeros
    @type args: C{list}

    
    @return: The calculated x2 coefficient
    @rtype: (C{nessi_list.NessiList}, C{nessi_list.NessiList})
    """
    # Settle out the arguments to sensible names
    k_i = args[0]
    Q = args[1]
    T_i = args[2]
    k_f_cos_pol = args[3]
    t_0_s_corr = args[4]
    z_vec = args[5]

    # k_f * cos(pol) - k_i
    temp1 = array_manip.sub_ncerr(k_f_cos_pol, 0.0, k_i, z_vec)
    # (k_f * cos(pol) - k_i) / Q
    temp2 = array_manip.div_ncerr(temp1[0], temp1[1], Q, z_vec)
    # k_i / T_i
    temp3 = array_manip.div_ncerr(k_i, z_vec, T_i, z_vec)
    # (k_i / T_i) * ((k_f * cos(pol) - k_i) / Q)
    temp4 = array_manip.mult_ncerr(temp2[0], temp2[1], temp3[0], temp3[1])
    # (k_i / T_i) * ((k_f * cos(pol) - k_i) / Q) *
    # (1 / 1 + ((h / m) * (t0_s / L_i)))
    return array_manip.mult_ncerr(temp4[0], temp4[1], t_0_s_corr, 0.0)
def __calc_x2(*args):
    """
    This function calculates the x2 coeffiecient to the S(Q,E) Jacobian

    @param args: A list of parameters used to calculate the x2 coefficient

    The following is a list of the arguments needed in there expected order
      1. Initial Wavevector
      2. Momentum Transfer
      3. Initial Time-of-Flight
      4. Wavevector Final x Cos(polar)
      5. Time-zero Slope Correction
      6. Vector of Zeros
    @type args: C{list}

    
    @return: The calculated x2 coefficient
    @rtype: (C{nessi_list.NessiList}, C{nessi_list.NessiList})
    """
    # Settle out the arguments to sensible names
    k_i = args[0]
    Q = args[1]
    T_i = args[2]
    k_f_cos_pol = args[3]
    t_0_s_corr = args[4]
    z_vec = args[5]

    # k_f * cos(pol) - k_i
    temp1 = array_manip.sub_ncerr(k_f_cos_pol, 0.0, k_i, z_vec)
    # (k_f * cos(pol) - k_i) / Q
    temp2 = array_manip.div_ncerr(temp1[0], temp1[1], Q, z_vec)
    # k_i / T_i
    temp3 = array_manip.div_ncerr(k_i, z_vec, T_i, z_vec)
    # (k_i / T_i) * ((k_f * cos(pol) - k_i) / Q)
    temp4 = array_manip.mult_ncerr(temp2[0], temp2[1], temp3[0], temp3[1])
    # (k_i / T_i) * ((k_f * cos(pol) - k_i) / Q) *
    # (1 / 1 + ((h / m) * (t0_s / L_i)))
    return array_manip.mult_ncerr(temp4[0], temp4[1], t_0_s_corr, 0.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
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
Example #7
0
def sub_ncerr(left, right, **kwargs):
    """
    This function subtracts two objects (C{SOM}, C{SO} or
    C{tuple(val,val_err2)}) and returns the result of the subtraction in a
    C{SOM}, C{SO} or C{tuple}.

    @param left: Object on the left of the subtraction sign
    @type left: C{SOM.SOM} or C{SOM.SO} or C{tuple}
    
    @param right: Object on the right of the subtraction sign
    @type right: C{SOM.SOM} or C{SOM.SO} or C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:
    
    @keyword axis: This is the axis one wishes to manipulate. If no argument
                   is given the default value is y
    @type axis: C{string}=<y or x>
    
    @keyword axis_pos: This is position of the axis in the axis array. If no
                       argument is given, the default value is 0
    @type axis_pos: C{int}
    
    @keyword length_one_som: This is a flag that lets the function know it is
                             dealing with a length 1 C{SOM} so that attributes
                             may be passed along. The length 1 C{SOM} will be
                             turned into a C{SO}. The default value is False.
    @type length_one_som: C{boolean}
    
    @keyword length_one_som_pos: This is the argument position of the length 1
                                 C{SOM} since subtraction order is not
                                 commutative. The default value is 2.
    @type length_one_som_pos: C{int}=<1 or 2> 


    @return: Object containing the results of the subtraction
    @rtype: C{SOM.SOM} or C{SOM.SO} 


    @raise IndexError: The two C{SOM}s do not contain the same number of
                       spectra
                       
    @raise RunTimeError: The x-axis units of the C{SOM}s do not match
    
    @raise RunTimeError: The y-axis units of the C{SOM}s do not match
    
    @raise RunTimeError: The x-axes of the two C{SO}s are not equal
    """

    # import the helper functions
    import hlr_utils

    # Check to see if we are working with a length 1 SOM
    try:
        length_one_som = kwargs["length_one_som"]
    except KeyError:
        length_one_som = False

    try:
        length_one_som_pos = kwargs["length_one_som_pos"]
        if length_one_som_pos != 1 or length_one_som_pos != 2:
            raise RuntimeError("length_one_som_pos must be either 1 or 2 and "\
                               +"%d" % length_one_som_pos)
    except KeyError:
        length_one_som_pos = 2

    if length_one_som:
        if length_one_som_pos == 1:
            som_copy = left
            left = left[0]
        else:
            som_copy = right
            right = right[0]
    else:
        # Not working with a length 1 SOM, do nothing
        pass

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(left, right)
    (l_descr, r_descr) = hlr_utils.get_descr(left, right)

    is_number = False

    # error check information
    if r_descr == "SOM" and l_descr == "SOM":
        hlr_utils.math_compatible(left, l_descr, right, r_descr)
    elif l_descr == "number" and r_descr == "number":
        is_number = True
    else:
        pass

    # Check for axis keyword argument
    try:
        axis = kwargs["axis"]
    except KeyError:
        axis = "y"

    # Check for axis_pos keyword argument
    try:
        axis_pos = kwargs["axis_pos"]
    except KeyError:
        axis_pos = 0

    if length_one_som:
        if length_one_som_pos == 1:
            result = hlr_utils.copy_som_attr(result, res_descr, som_copy,
                                             "SOM", right, r_descr)
        else:
            result = hlr_utils.copy_som_attr(result, res_descr, left, l_descr,
                                             som_copy, "SOM")
    else:
        result = hlr_utils.copy_som_attr(result, res_descr, left, l_descr,
                                         right, r_descr)

    # iterate through the values
    import array_manip

    for i in xrange(hlr_utils.get_length(left, right)):
        val1 = hlr_utils.get_value(left, i, l_descr, axis, axis_pos)
        err2_1 = hlr_utils.get_err2(left, i, l_descr, axis, axis_pos)

        val2 = hlr_utils.get_value(right, i, r_descr, axis, axis_pos)
        err2_2 = hlr_utils.get_err2(right, i, r_descr, axis, axis_pos)

        (descr_1, descr_2) = hlr_utils.get_descr(val1, val2)

        hlr_utils.math_compatible(val1, descr_1, val2, descr_2)

        value = array_manip.sub_ncerr(val1, err2_1, val2, err2_2)

        map_so = hlr_utils.get_map_so(left, right, i)
        hlr_utils.result_insert(result, res_descr, value, map_so, axis,
                                axis_pos)

    if is_number:
        return tuple(result)
    else:
        return result
def create_E_vs_Q_dgs(som, E_i, Q_final, **kwargs):
    """
    This function starts with the rebinned energy transfer and turns this
    into a 2D spectra with E and Q axes for DGS instruments.

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

    @param E_i: The initial energy for the given data.
    @type E_i: C{tuple}

    @param Q_final: The momentum transfer axis to rebin the data to
    @type Q_final: C{nessi_list.NessiList}

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

    @keyword corner_angles: The object that contains the corner geometry
                            information.
    @type corner_angles: C{dict}

    @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}    
    """
    import array_manip
    import axis_manip
    import common_lib
    import hlr_utils
    import nessi_list
    import SOM
    import utils

    # Check for keywords
    corner_angles = kwargs["corner_angles"]
    configure = kwargs.get("configure")
    split = kwargs.get("split", False)

    # Setup output object
    so_dim = SOM.SO(2)

    so_dim.axis[0].val = Q_final
    so_dim.axis[1].val = som[0].axis[0].val # E_t

    # Calculate total 2D array size
    N_tot = (len(so_dim.axis[0].val) - 1) * (len(so_dim.axis[1].val) - 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)

    # Convert initial energy to initial wavevector
    l_i = common_lib.energy_to_wavelength(E_i)
    k_i = common_lib.wavelength_to_scalar_k(l_i)

    # Since all the data is rebinned to the same energy transfer axis, we can
    # calculate the final energy axis once
    E_t = som[0].axis[0].val
    if som[0].axis[0].var is not None:
        E_t_err2 = som[0].axis[0].var
    else:
        E_t_err2 = nessi_list.NessiList(len(E_t))        

    # Get the bin width arrays from E_t
    (E_t_bw, E_t_bw_err2) = utils.calc_bin_widths(E_t)

    E_f = array_manip.sub_ncerr(E_i[0], E_i[1], E_t, E_t_err2)
    
    # Now we can get the final wavevector
    l_f = axis_manip.energy_to_wavelength(E_f[0], E_f[1])
    k_f = axis_manip.wavelength_to_scalar_k(l_f[0], l_f[1])

    # Output position for Q
    X = 0

    # Iterate though the data
    len_som = hlr_utils.get_length(som)
    for i in xrange(len_som):
        map_so = hlr_utils.get_map_so(som, None, i)

        yval = hlr_utils.get_value(som, i, "SOM", "y")
        yerr2 = hlr_utils.get_err2(som, i, "SOM", "y")

        cangles = corner_angles[str(map_so.id)]

        avg_theta1 = (cangles.getPolar(0) + cangles.getPolar(1)) / 2.0
        avg_theta2 = (cangles.getPolar(2) + cangles.getPolar(3)) / 2.0
        
        Q1 = axis_manip.init_scatt_wavevector_to_scalar_Q(k_i[0],
                                                          k_i[1],
                                                          k_f[0][:-1],
                                                          k_f[1][:-1],
                                                          avg_theta2,
                                                          0.0)
        
        Q2 = axis_manip.init_scatt_wavevector_to_scalar_Q(k_i[0],
                                                          k_i[1],
                                                          k_f[0][:-1],
                                                          k_f[1][:-1],
                                                          avg_theta1,
                                                          0.0)
        
        Q3 = axis_manip.init_scatt_wavevector_to_scalar_Q(k_i[0],
                                                          k_i[1],
                                                          k_f[0][1:],
                                                          k_f[1][1:],
                                                          avg_theta1,
                                                          0.0)

        Q4 = axis_manip.init_scatt_wavevector_to_scalar_Q(k_i[0],
                                                          k_i[1],
                                                          k_f[0][1:],
                                                          k_f[1][1:],
                                                          avg_theta2,
                                                          0.0)

        # Calculate the area of the E,Q polygons
        (A, A_err2) = utils.calc_eq_jacobian_dgs(E_t[:-1], E_t[:-1], 
                                                 E_t[1:], E_t[1:],
                                                 Q1[X], Q2[X], Q3[X], Q4[X])

        # Apply the Jacobian: C/dE_t * dE_t / A(EQ) = C/A(EQ)
        (jac_ratio, jac_ratio_err2) = array_manip.div_ncerr(E_t_bw,
                                                            E_t_bw_err2,
                                                            A, A_err2)
        (counts, counts_err2) = array_manip.mult_ncerr(yval, yerr2,
                                                       jac_ratio,
                                                       jac_ratio_err2)
        
        try:
            (y_2d, y_2d_err2,
             area_new,
             bin_count) = axis_manip.rebin_2D_quad_to_rectlin(Q1[X], E_t[:-1],
                                                           Q2[X], E_t[:-1],
                                                           Q3[X], E_t[1:],
                                                           Q4[X], E_t[1:],
                                                           counts,
                                                           counts_err2,
                                                           so_dim.axis[0].val,
                                                           so_dim.axis[1].val)
            
            del bin_count
            
        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" % (Q1[X][index],
                                                              E_t[:-1][index],
                                                                 Q2[X][index],
                                                              E_t[:-1][index],
                                                                 Q3[X][index],
                                                              E_t[1:][index],
                                                                 Q4[X][index],
                                                              E_t[1:][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)
Example #9
0
def sub_ncerr(left, right, **kwargs):
    """
    This function subtracts two objects (C{SOM}, C{SO} or
    C{tuple(val,val_err2)}) and returns the result of the subtraction in a
    C{SOM}, C{SO} or C{tuple}.

    @param left: Object on the left of the subtraction sign
    @type left: C{SOM.SOM} or C{SOM.SO} or C{tuple}
    
    @param right: Object on the right of the subtraction sign
    @type right: C{SOM.SOM} or C{SOM.SO} or C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:
    
    @keyword axis: This is the axis one wishes to manipulate. If no argument
                   is given the default value is y
    @type axis: C{string}=<y or x>
    
    @keyword axis_pos: This is position of the axis in the axis array. If no
                       argument is given, the default value is 0
    @type axis_pos: C{int}
    
    @keyword length_one_som: This is a flag that lets the function know it is
                             dealing with a length 1 C{SOM} so that attributes
                             may be passed along. The length 1 C{SOM} will be
                             turned into a C{SO}. The default value is False.
    @type length_one_som: C{boolean}
    
    @keyword length_one_som_pos: This is the argument position of the length 1
                                 C{SOM} since subtraction order is not
                                 commutative. The default value is 2.
    @type length_one_som_pos: C{int}=<1 or 2> 


    @return: Object containing the results of the subtraction
    @rtype: C{SOM.SOM} or C{SOM.SO} 


    @raise IndexError: The two C{SOM}s do not contain the same number of
                       spectra
                       
    @raise RunTimeError: The x-axis units of the C{SOM}s do not match
    
    @raise RunTimeError: The y-axis units of the C{SOM}s do not match
    
    @raise RunTimeError: The x-axes of the two C{SO}s are not equal
    """

    # import the helper functions
    import hlr_utils

    # Check to see if we are working with a length 1 SOM
    try:
        length_one_som = kwargs["length_one_som"]
    except KeyError:
        length_one_som = False

    try:
        length_one_som_pos = kwargs["length_one_som_pos"]
        if length_one_som_pos != 1 or length_one_som_pos != 2:
            raise RuntimeError("length_one_som_pos must be either 1 or 2 and "\
                               +"%d" % length_one_som_pos)
    except KeyError:
        length_one_som_pos = 2

    if length_one_som:
        if length_one_som_pos == 1:
            som_copy = left
            left = left[0]
        else:
            som_copy = right
            right = right[0]
    else:
        # Not working with a length 1 SOM, do nothing
        pass

    # set up for working through data
    (result, res_descr) = hlr_utils.empty_result(left, right)
    (l_descr, r_descr) = hlr_utils.get_descr(left, right)

    is_number = False
    
    # error check information
    if r_descr == "SOM" and l_descr == "SOM":
        hlr_utils.math_compatible(left, l_descr, right, r_descr)
    elif l_descr == "number" and r_descr == "number":
        is_number = True
    else:
        pass

    # Check for axis keyword argument
    try:
        axis = kwargs["axis"]
    except KeyError:
        axis = "y"
        
    # Check for axis_pos keyword argument
    try:
        axis_pos = kwargs["axis_pos"]
    except KeyError:
        axis_pos = 0

    if length_one_som:
        if length_one_som_pos == 1:
            result = hlr_utils.copy_som_attr(result, res_descr,
                                             som_copy, "SOM",
                                             right, r_descr)
        else:
            result = hlr_utils.copy_som_attr(result, res_descr, left, l_descr,
                                             som_copy, "SOM")            
    else:
        result = hlr_utils.copy_som_attr(result, res_descr, left, l_descr,
                                         right, r_descr)

    # iterate through the values
    import array_manip
    
    for i in xrange(hlr_utils.get_length(left, right)):
        val1 = hlr_utils.get_value(left, i, l_descr, axis, axis_pos)
        err2_1 = hlr_utils.get_err2(left, i, l_descr, axis, axis_pos)

        val2 = hlr_utils.get_value(right, i, r_descr, axis, axis_pos)
        err2_2 = hlr_utils.get_err2(right, i, r_descr, axis, axis_pos)

        (descr_1, descr_2) = hlr_utils.get_descr(val1, val2)

        hlr_utils.math_compatible(val1, descr_1, val2, descr_2)

        value = array_manip.sub_ncerr(val1, err2_1, val2, err2_2)

        map_so = hlr_utils.get_map_so(left, right, i)
        hlr_utils.result_insert(result, res_descr, value, map_so, axis,
                                axis_pos)

    if is_number:
        return tuple(result)
    else:
        return result
Example #10
0
def process_dgs_data(obj, conf, bcan, ecan, tcoeff, **kwargs):
    """
    This function combines Steps 7 through 16 in Section 2.1.1 of the data
    reduction process for Direct Geometry Spectrometers as specified by the
    document at 
    U{http://neutrons.ornl.gov/asg/projects/SCL/reqspec/DR_Lib_RS.doc}. The
    function takes a calibrated dataset, a L{hlr_utils.Configure} object and
    processes the data accordingly.

    @param obj: A calibrated dataset object.
    @type obj: C{SOM.SOM}

    @param conf: Object that contains the current setup of the driver.
    @type conf: L{hlr_utils.Configure}

    @param bcan: The object containing the black can data.
    @type bcan: C{SOM.SOM}

    @param ecan: The object containing the empty can data.
    @type ecan: C{SOM.SOM}

    @param tcoeff: The transmission coefficient appropriate to the given data
                   set.
    @type tcoeff: C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword dataset_type: The practical name of the dataset being processed.
                           The default value is I{data}.
    @type dataset_type: C{string}

    @keyword cwp_used: A flag signalling the use of the chopper phase
                       corrections.
    @type cwp_used: C{bool}

    @keyword timer: Timing object so the function can perform timing estimates.
    @type timer: C{sns_timer.DiffTime}


    @return: Object that has undergone all requested processing steps
    @rtype: C{SOM.SOM}
    """
    import array_manip
    import common_lib
    import dr_lib
    import hlr_utils

    # Check keywords
    try:
        dataset_type = kwargs["dataset_type"]
    except KeyError:
        dataset_type = "data"

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

    cwp_used = kwargs.get("cwp_used", False)

    if conf.verbose:
        print "Processing %s information" % dataset_type

    # Step 7: Create black can background contribution
    if bcan is not None:
        if conf.verbose:
            print "Creating black can background contribution for %s" \
                  % dataset_type

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

        bccoeff = array_manip.sub_ncerr(1.0, 0.0, tcoeff[0], tcoeff[1])
        bcan1 = common_lib.mult_ncerr(bcan, bccoeff)

        if t is not None:
            t.getTime(msg="After creating black can background contribution ")

        del bcan
    else:
        bcan1 = None

    # Step 8: Create empty can background contribution
    if ecan is not None:
        if conf.verbose:
            print "Creating empty can background contribution for %s" \
                  % dataset_type

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

        ecan1 = common_lib.mult_ncerr(ecan, tcoeff)

        if t is not None:
            t.getTime(msg="After creating empty can background contribution ")

        del ecan
    else:
        ecan1 = None

    # Step 9: Create background spectra
    if bcan1 is not None or ecan1 is not None and conf.verbose:
        print "Creating background spectra for %s" % dataset_type

    if bcan1 is not None and ecan1 is not None:
        if cwp_used:
            if conf.verbose:
                print "Rebinning empty can to black can axis."

            ecan2 = common_lib.rebin_axis_1D_frac(ecan1, bcan1[0].axis[0].val)
        else:
            ecan2 = ecan1

        del ecan1

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

        b_som = common_lib.add_ncerr(bcan1, ecan2)

        if t is not None:
            t.getTime(msg="After creating background spectra ")
    elif bcan1 is not None and ecan1 is None:
        b_som = bcan1
    elif bcan1 is None and ecan1 is not None:
        b_som = ecan1
    else:
        b_som = None

    del bcan1, ecan1

    if cwp_used:
        if conf.verbose:
            print "Rebinning background spectra to %s" % dataset_type

        b_som1 = common_lib.rebin_axis_1D_frac(b_som, obj[0].axis[0].val)
    else:
        b_som1 = b_som

    del b_som

    if conf.dump_ctof_comb and b_som1 is not None:
        b_som_1 = dr_lib.sum_all_spectra(b_som1)
        hlr_utils.write_file(conf.output,
                             "text/Spec",
                             b_som_1,
                             output_ext="ctof",
                             extra_tag="background",
                             data_ext=conf.ext_replacement,
                             path_replacement=conf.path_replacement,
                             verbose=conf.verbose,
                             message="combined background TOF information")
        del b_som_1

    # Step 10: Subtract background from data
    obj1 = dr_lib.subtract_bkg_from_data(obj,
                                         b_som1,
                                         verbose=conf.verbose,
                                         timer=t,
                                         dataset1=dataset_type,
                                         dataset2="background")

    del obj, b_som1

    # Step 11: Calculate initial velocity
    if conf.verbose:
        print "Calculating initial velocity"

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

    if conf.initial_energy is not None:
        initial_wavelength = common_lib.energy_to_wavelength(\
            conf.initial_energy.toValErrTuple())
        initial_velocity = common_lib.wavelength_to_velocity(\
            initial_wavelength)
    else:
        # This should actually calculate it, but don't have a way right now
        pass

    if t is not None:
        t.getTime(msg="After calculating initial velocity ")

    # Step 12: Calculate the time-zero offset
    if conf.time_zero_offset is not None:
        time_zero_offset = conf.time_zero_offset.toValErrTuple()
    else:
        # This should actually calculate it, but don't have a way right now
        time_zero_offset = (0.0, 0.0)

    # Step 13: Convert time-of-flight to final velocity
    if conf.verbose:
        print "Converting TOF to final velocity DGS"

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

    obj2 = common_lib.tof_to_final_velocity_dgs(obj1,
                                                initial_velocity,
                                                time_zero_offset,
                                                units="microsecond")

    if t is not None:
        t.getTime(msg="After calculating TOF to final velocity DGS ")

    del obj1

    # Step 14: Convert final velocity to final wavelength
    if conf.verbose:
        print "Converting final velocity DGS to final wavelength"

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

    obj3 = common_lib.velocity_to_wavelength(obj2)

    if t is not None:
        t.getTime(msg="After calculating velocity to wavelength ")

    del obj2

    if conf.dump_wave_comb:
        obj3_1 = dr_lib.sum_all_spectra(
            obj3, rebin_axis=conf.lambda_bins.toNessiList())
        hlr_utils.write_file(conf.output,
                             "text/Spec",
                             obj3_1,
                             output_ext="fwv",
                             extra_tag=dataset_type,
                             data_ext=conf.ext_replacement,
                             path_replacement=conf.path_replacement,
                             verbose=conf.verbose,
                             message="combined final wavelength information")

        del obj3_1

    # Step 15: Create the detector efficiency
    if conf.det_eff is not None:
        if conf.verbose:
            print "Creating detector efficiency spectra"

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

        det_eff = dr_lib.create_det_eff(obj3)

        if t is not None:
            t.getTime(msg="After creating detector efficiency spectra ")
    else:
        det_eff = None

    # Step 16: Divide the detector pixel spectra by the detector efficiency
    if det_eff is not None:
        if conf.verbose:
            print "Correcting %s for detector efficiency" % dataset_type

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

        obj4 = common_lib.div_ncerr(obj3, det_eff)

        if t is not None:
            t.getTime(msg="After correcting %s for detector efficiency" \
                      % dataset_type)
    else:
        obj4 = obj3

    del obj3, det_eff

    return obj4
Example #11
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
def __calc_x1(*args):
    """
    This function calculates the x1 coeffiecient to the S(Q,E) Jacobian

    @param args: A list of parameters used to calculate the x1 coefficient

    The following is a list of the arguments needed in there expected order
      1. Initial Wavevector
      2. Momentum Transfer
      3. Length Ratio (L_f / L_i)
      4. Final Wavevector
      5. Wavevector Final x Cos(polar)
      6. Wavevector Final x Sin(polar)
      7. Lambda Constant (2*pi/l_f^2)(dlf/dh)
      8. Derivative dazi_dh
      9. Derivative dpol_dh
      10. Derivative dpol_dtd
      11. Derivative dazi_dtd
      12. Cos(polar)
      13. Time-zero Slope Correction
      14. Vector of Zeros
    @type args: C{list}

    
    @return: The calculated x1 coefficient
    @rtype: (C{nessi_list.NessiList}, C{nessi_list.NessiList})
    """
    # Settle out the arguments to sensible names
    k_i = args[0]
    Q = args[1]
    len_ratio = args[2]
    k_f = args[3]
    k_f_cos_pol = args[4]
    k_f_sin_pol = args[5]
    lam_const = args[6]
    dpol_dh = args[7]
    dpol_dtd = args[8]
    dtd_over_dh = args[9]
    cos_pol = args[10]
    t_0_s_corr = args[11]
    z_vec = args[12]

    # (L_f / L_i) * (1 / k_f)^2 * (1 / 1 + ((h / m) * (t0_s / L_i)))
    const1 = (len_ratio * t_0_s_corr) / (k_f * k_f)
    # (dpol/dh + (dpol/dtd * dtd/dh)) * k_f * sin(pol)
    const2 = (dpol_dh + (dpol_dtd * dtd_over_dh)) * k_f_sin_pol

    # k_i^2
    temp1 = array_manip.mult_ncerr(k_i, z_vec, k_i, z_vec)
    # (L_f / L_i) * (k_i / k_f)^2 * (1 / 1 + ((h / m) * (t0_s / L_i)))
    temp2 = array_manip.mult_ncerr(temp1[0], temp1[1], const1, 0.0)
    # k_i - k_f * cos(pol)
    temp3 = array_manip.sub_ncerr(k_i, z_vec, k_f_cos_pol, 0.0)
    # (k_i - k_f * cos(pol)) * (L_f / L_i) * (k_i / k_f)^2
    temp4 = array_manip.mult_ncerr(temp2[0], temp2[1], temp3[0], temp3[1])

    # k_i * cos(pol)
    temp5 = array_manip.mult_ncerr(k_i, z_vec, cos_pol, 0.0)
    # k_f - k_i * cos(pol)
    temp6 = array_manip.sub_ncerr(k_f, 0.0, temp5[0], temp5[1])

    # (k_i - k_f * cos(pol)) * (L_f / L_i) * (k_i / k_f)^2 -
    # (k_f - k_i * cos(pol))
    temp7 = array_manip.sub_ncerr(temp4[0], temp4[1], temp6[0], temp6[1])
    # ((k_i - k_f * cos(pol)) * (L_f / L_i) * (k_i / k_f)^2 -
    # (k_f - k_i * cos(pol))) * (2 * pi / l_f^2) * dlf/dh
    temp8 = array_manip.mult_ncerr(temp7[0], temp7[1], lam_const, 0.0)

    # k_i * k_f * sin(pol) * (dpol/dh + (dpol/dtd * dtd/dh))
    temp9 = array_manip.mult_ncerr(k_i, z_vec, const2, 0.0)

    # ((k_i - k_f * cos(pol)) * (L_f / L_i) * (k_i / k_f)^2 -
    # (k_f - k_i * cos(pol))) * (2 * pi / l_f^2) * dlf/dh +
    # k_i * k_f * sin(pol) * (dpol/dh + (dpol/dtd * dtd/dh))
    temp10 = array_manip.add_ncerr(temp8[0], temp8[1], temp9[0], temp9[1])

    # (((k_i - k_f * cos(pol)) * (L_f / L_i) * (k_i / k_f)^2 -
    # (k_f - k_i * cos(pol))) * (2 * pi / l_f^2) * dlf/dh +
    # k_i * k_f * sin(pol) * (dpol/dh - (dpol/dtd dazi/dh / dazi/dtd))
    return array_manip.div_ncerr(temp10[0], temp10[1], Q, z_vec)
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]))
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]))
Example #15
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
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 create_E_vs_Q_dgs(som, E_i, Q_final, **kwargs):
    """
    This function starts with the rebinned energy transfer and turns this
    into a 2D spectra with E and Q axes for DGS instruments.

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

    @param E_i: The initial energy for the given data.
    @type E_i: C{tuple}

    @param Q_final: The momentum transfer axis to rebin the data to
    @type Q_final: C{nessi_list.NessiList}

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

    @keyword corner_angles: The object that contains the corner geometry
                            information.
    @type corner_angles: C{dict}

    @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}    
    """
    import array_manip
    import axis_manip
    import common_lib
    import hlr_utils
    import nessi_list
    import SOM
    import utils

    # Check for keywords
    corner_angles = kwargs["corner_angles"]
    configure = kwargs.get("configure")
    split = kwargs.get("split", False)

    # Setup output object
    so_dim = SOM.SO(2)

    so_dim.axis[0].val = Q_final
    so_dim.axis[1].val = som[0].axis[0].val  # E_t

    # Calculate total 2D array size
    N_tot = (len(so_dim.axis[0].val) - 1) * (len(so_dim.axis[1].val) - 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)

    # Convert initial energy to initial wavevector
    l_i = common_lib.energy_to_wavelength(E_i)
    k_i = common_lib.wavelength_to_scalar_k(l_i)

    # Since all the data is rebinned to the same energy transfer axis, we can
    # calculate the final energy axis once
    E_t = som[0].axis[0].val
    if som[0].axis[0].var is not None:
        E_t_err2 = som[0].axis[0].var
    else:
        E_t_err2 = nessi_list.NessiList(len(E_t))

    # Get the bin width arrays from E_t
    (E_t_bw, E_t_bw_err2) = utils.calc_bin_widths(E_t)

    E_f = array_manip.sub_ncerr(E_i[0], E_i[1], E_t, E_t_err2)

    # Now we can get the final wavevector
    l_f = axis_manip.energy_to_wavelength(E_f[0], E_f[1])
    k_f = axis_manip.wavelength_to_scalar_k(l_f[0], l_f[1])

    # Output position for Q
    X = 0

    # Iterate though the data
    len_som = hlr_utils.get_length(som)
    for i in xrange(len_som):
        map_so = hlr_utils.get_map_so(som, None, i)

        yval = hlr_utils.get_value(som, i, "SOM", "y")
        yerr2 = hlr_utils.get_err2(som, i, "SOM", "y")

        cangles = corner_angles[str(map_so.id)]

        avg_theta1 = (cangles.getPolar(0) + cangles.getPolar(1)) / 2.0
        avg_theta2 = (cangles.getPolar(2) + cangles.getPolar(3)) / 2.0

        Q1 = axis_manip.init_scatt_wavevector_to_scalar_Q(
            k_i[0], k_i[1], k_f[0][:-1], k_f[1][:-1], avg_theta2, 0.0)

        Q2 = axis_manip.init_scatt_wavevector_to_scalar_Q(
            k_i[0], k_i[1], k_f[0][:-1], k_f[1][:-1], avg_theta1, 0.0)

        Q3 = axis_manip.init_scatt_wavevector_to_scalar_Q(
            k_i[0], k_i[1], k_f[0][1:], k_f[1][1:], avg_theta1, 0.0)

        Q4 = axis_manip.init_scatt_wavevector_to_scalar_Q(
            k_i[0], k_i[1], k_f[0][1:], k_f[1][1:], avg_theta2, 0.0)

        # Calculate the area of the E,Q polygons
        (A, A_err2) = utils.calc_eq_jacobian_dgs(E_t[:-1], E_t[:-1], E_t[1:],
                                                 E_t[1:], Q1[X], Q2[X], Q3[X],
                                                 Q4[X])

        # Apply the Jacobian: C/dE_t * dE_t / A(EQ) = C/A(EQ)
        (jac_ratio,
         jac_ratio_err2) = array_manip.div_ncerr(E_t_bw, E_t_bw_err2, A,
                                                 A_err2)
        (counts, counts_err2) = array_manip.mult_ncerr(yval, yerr2, jac_ratio,
                                                       jac_ratio_err2)

        try:
            (y_2d, y_2d_err2, area_new,
             bin_count) = axis_manip.rebin_2D_quad_to_rectlin(
                 Q1[X], E_t[:-1], Q2[X], E_t[:-1], Q3[X], E_t[1:], Q4[X],
                 E_t[1:], counts, counts_err2, so_dim.axis[0].val,
                 so_dim.axis[1].val)

            del bin_count

        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" % (
                Q1[X][index], E_t[:-1][index], Q2[X][index], E_t[:-1][index],
                Q3[X][index], E_t[1:][index], Q4[X][index], E_t[1:][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)
def create_Qvec_vs_E_dgs(som, E_i, conf, **kwargs):
    """
    This function starts with the energy transfer axis from DGS reduction and
    turns this into a 4D spectra with Qx, Qy, Qz and Et axes.

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

    @param E_i: The initial energy for the given data.
    @type E_i: C{tuple}

    @param conf: Object that contains the current setup of the driver.
    @type conf: L{hlr_utils.Configure}

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

    @keyword timer: Timing object so the function can perform timing estimates.
    @type timer: C{sns_timer.DiffTime}

    @keyword corner_angles: The object that contains the corner geometry
                            information.
    @type corner_angles: C{dict}

    @keyword make_fixed: A flag that turns on writing the fixed grid mesh
                         information to a file.
    @type make_fixed: C{boolean}

    @keyword output: The output filename and or directory.
    @type output: C{string}
    """
    import array_manip
    import axis_manip
    import common_lib
    import hlr_utils

    import os
    
    # Check keywords
    try:
        t = kwargs["timer"]
    except KeyError:
        t = None

    corner_angles = kwargs["corner_angles"]

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

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

    # Convert initial energy to initial wavevector
    l_i = common_lib.energy_to_wavelength(E_i)
    k_i = common_lib.wavelength_to_scalar_k(l_i)

    # Since all the data is rebinned to the same energy transfer axis, we can
    # calculate the final energy axis once
    E_t = som[0].axis[0].val
    if som[0].axis[0].var is not None:
        E_t_err2 = som[0].axis[0].var
    else:
        import nessi_list
        E_t_err2 = nessi_list.NessiList(len(E_t))        

    E_f = array_manip.sub_ncerr(E_i[0], E_i[1], E_t, E_t_err2)

    # Check for negative final energies which will cause problems with
    # wavelength conversion due to square root
    if E_f[0][-1] < 0:
        E_f[0].reverse()
        E_f[1].reverse()
        index = 0
        for E in E_f[0]:
            if E >= 0:
                break
            index += 1
        E_f[0].__delslice__(0, index)
        E_f[1].__delslice__(0, index)
        E_f[0].reverse()
        E_f[1].reverse()

    len_E = len(E_f[0]) - 1

    # Now we can get the final wavevector
    l_f = axis_manip.energy_to_wavelength(E_f[0], E_f[1])
    k_f = axis_manip.wavelength_to_scalar_k(l_f[0], l_f[1])

    # Grab the instrument from the som
    inst = som.attr_list.instrument

    if make_fixed:
        import SOM
        fixed_grid = {}
        for key in corner_angles:
            so_id = SOM.NeXusId.fromString(key).toTuple()
            try:
                pathlength = inst.get_secondary(so_id)[0]
                points = []
                for j in range(4):
                    points.extend(__calc_xyz(pathlength,
                                          corner_angles[key].getPolar(j),
                                          corner_angles[key].getAzimuthal(j)))
                fixed_grid[key] = points
            except KeyError:
                # Pixel ID is not in instrument geometry
                pass

    CNT = {}
    ERR2 = {}
    V1 = {}
    V2 = {}
    V3 = {}
    V4 = {}
    # Output positions for Qx, Qy, Qz coordinates
    X = 0
    Y = 2
    Z = 4

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

    # Iterate though the data
    len_som = hlr_utils.get_length(som)
    for i in xrange(len_som):
        map_so = hlr_utils.get_map_so(som, None, i)

        yval = hlr_utils.get_value(som, i, "SOM", "y")
        yerr2 = hlr_utils.get_err2(som, i, "SOM", "y")

        CNT[str(map_so.id)] = yval
        ERR2[str(map_so.id)] = yerr2

        cangles = corner_angles[str(map_so.id)]

        Q1 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1],
                                                   k_f[0], k_f[1],
                                                   cangles.getAzimuthal(0),
                                                   0.0,
                                                   cangles.getPolar(0),
                                                   0.0)
        V1[str(map_so.id)] = {}
        V1[str(map_so.id)]["x"] = Q1[X]
        V1[str(map_so.id)]["y"] = Q1[Y]
        V1[str(map_so.id)]["z"] = Q1[Z]
        

        Q2 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1],
                                                   k_f[0], k_f[1],
                                                   cangles.getAzimuthal(1),
                                                   0.0,
                                                   cangles.getPolar(1),
                                                   0.0)

        V2[str(map_so.id)] = {}
        V2[str(map_so.id)]["x"] = Q2[X]
        V2[str(map_so.id)]["y"] = Q2[Y]
        V2[str(map_so.id)]["z"] = Q2[Z]
        
        Q3 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1],
                                                   k_f[0], k_f[1],
                                                   cangles.getAzimuthal(2),
                                                   0.0,
                                                   cangles.getPolar(2),
                                                   0.0)
        V3[str(map_so.id)] = {}
        V3[str(map_so.id)]["x"] = Q3[X]
        V3[str(map_so.id)]["y"] = Q3[Y]
        V3[str(map_so.id)]["z"] = Q3[Z]
        
        Q4 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1],
                                                   k_f[0], k_f[1],
                                                   cangles.getAzimuthal(3),
                                                   0.0,
                                                   cangles.getPolar(3),
                                                   0.0)

        V4[str(map_so.id)] = {}
        V4[str(map_so.id)]["x"] = Q4[X]
        V4[str(map_so.id)]["y"] = Q4[Y]
        V4[str(map_so.id)]["z"] = Q4[Z]

    if t is not None:
        t.getTime(msg="After calculating verticies ")

    # Form the messages
    if t is not None:
        t.getTime(False)

    jobstr = 'MR' + hlr_utils.create_binner_string(conf) + 'JH'
    num_lines = len(CNT) * len_E
    linestr = str(num_lines)

    if output is not None:
        outdir = os.path.dirname(output)
        if outdir != '':
            if outdir.rfind('.') != -1:
                outdir = ""
    else:
        outdir = ""

    value = str(som.attr_list["data-run_number"].getValue()).split('/')

    topdir = os.path.join(outdir, value[0].strip() + "-mesh")
    try:
        os.mkdir(topdir)
    except OSError:
        pass

    outtag = os.path.basename(output)
    if outtag.rfind('.') == -1:
        outtag = ""
    else:
        outtag = outtag.split('.')[0]

    if outtag != "":
        filehead = outtag + "_bmesh"
        if make_fixed:
            filehead1 = outtag + "_fgrid"
        filehead2 = outtag + "_conf"
    else:
        filehead = "bmesh"
        if make_fixed:    
            filehead1 = "fgrid"
        filehead2 = "conf"

    hfile = open(os.path.join(topdir, "%s.in" % filehead2), "w")
    print >> hfile, jobstr
    print >> hfile, linestr
    hfile.close()

    import utils
    use_zero_supp = not conf.no_zero_supp
    
    for k in xrange(len_E):
        ofile = open(os.path.join(topdir, "%s%04d.in" % (filehead, k)), "w")
        if make_fixed:
            ofile1 = open(os.path.join(topdir, "%s%04d.in" % (filehead1, k)),
                          "w")
        for pid in CNT:
            if use_zero_supp:
                write_value = not utils.compare(CNT[pid][k], 0.0) == 0
            else:
                write_value = True

            if write_value:
                result = []
                result.append(str(k))
                result.append(str(E_t[k]))
                result.append(str(E_t[k+1]))
                result.append(str(CNT[pid][k]))
                result.append(str(ERR2[pid][k]))
                __get_coords(V1, pid, k, result)
                __get_coords(V2, pid, k, result)
                __get_coords(V3, pid, k, result)
                __get_coords(V4, pid, k, result)
                __get_coords(V1, pid, k+1, result)
                __get_coords(V2, pid, k+1, result)
                __get_coords(V3, pid, k+1, result)
                __get_coords(V4, pid, k+1, result)

                print >> ofile, " ".join(result)

            if make_fixed:
                result1 = []
                result1.append(str(k))
                result1.append(str(E_t[k]))
                result1.append(str(E_t[k+1]))
                result1.append(str(CNT[pid][k]))
                result1.append(str(ERR2[pid][k]))
                result1.extend([str(x) for x in fixed_grid[pid]])
                print >> ofile1, " ".join(result1)

        ofile.close()
        if make_fixed:
            ofile1.close()

    if t is not None:
        t.getTime(msg="After creating messages ")
def __calc_x1(*args):
    """
    This function calculates the x1 coeffiecient to the S(Q,E) Jacobian

    @param args: A list of parameters used to calculate the x1 coefficient

    The following is a list of the arguments needed in there expected order
      1. Initial Wavevector
      2. Momentum Transfer
      3. Length Ratio (L_f / L_i)
      4. Final Wavevector
      5. Wavevector Final x Cos(polar)
      6. Wavevector Final x Sin(polar)
      7. Lambda Constant (2*pi/l_f^2)(dlf/dh)
      8. Derivative dazi_dh
      9. Derivative dpol_dh
      10. Derivative dpol_dtd
      11. Derivative dazi_dtd
      12. Cos(polar)
      13. Time-zero Slope Correction
      14. Vector of Zeros
    @type args: C{list}

    
    @return: The calculated x1 coefficient
    @rtype: (C{nessi_list.NessiList}, C{nessi_list.NessiList})
    """
    # Settle out the arguments to sensible names
    k_i = args[0]
    Q = args[1]
    len_ratio = args[2]
    k_f = args[3]
    k_f_cos_pol = args[4]
    k_f_sin_pol = args[5]
    lam_const = args[6]
    dpol_dh = args[7]
    dpol_dtd = args[8]
    dtd_over_dh = args[9]
    cos_pol = args[10]
    t_0_s_corr = args[11]
    z_vec = args[12]

    # (L_f / L_i) * (1 / k_f)^2 * (1 / 1 + ((h / m) * (t0_s / L_i)))
    const1 = (len_ratio * t_0_s_corr) / (k_f * k_f)
    # (dpol/dh + (dpol/dtd * dtd/dh)) * k_f * sin(pol)
    const2 = (dpol_dh + (dpol_dtd * dtd_over_dh)) * k_f_sin_pol

    # k_i^2
    temp1 = array_manip.mult_ncerr(k_i, z_vec, k_i, z_vec)
    # (L_f / L_i) * (k_i / k_f)^2 * (1 / 1 + ((h / m) * (t0_s / L_i)))
    temp2 = array_manip.mult_ncerr(temp1[0], temp1[1], const1, 0.0)
    # k_i - k_f * cos(pol)
    temp3 = array_manip.sub_ncerr(k_i, z_vec, k_f_cos_pol, 0.0)
    # (k_i - k_f * cos(pol)) * (L_f / L_i) * (k_i / k_f)^2
    temp4 = array_manip.mult_ncerr(temp2[0], temp2[1], temp3[0], temp3[1])

    # k_i * cos(pol)
    temp5 = array_manip.mult_ncerr(k_i, z_vec, cos_pol, 0.0)
    # k_f - k_i * cos(pol)
    temp6 = array_manip.sub_ncerr(k_f, 0.0, temp5[0], temp5[1])

    # (k_i - k_f * cos(pol)) * (L_f / L_i) * (k_i / k_f)^2 -
    # (k_f - k_i * cos(pol))
    temp7 = array_manip.sub_ncerr(temp4[0], temp4[1], temp6[0], temp6[1])
    # ((k_i - k_f * cos(pol)) * (L_f / L_i) * (k_i / k_f)^2 -
    # (k_f - k_i * cos(pol))) * (2 * pi / l_f^2) * dlf/dh
    temp8 = array_manip.mult_ncerr(temp7[0], temp7[1], lam_const, 0.0)

    # k_i * k_f * sin(pol) * (dpol/dh + (dpol/dtd * dtd/dh))
    temp9 = array_manip.mult_ncerr(k_i, z_vec, const2, 0.0)

    # ((k_i - k_f * cos(pol)) * (L_f / L_i) * (k_i / k_f)^2 -
    # (k_f - k_i * cos(pol))) * (2 * pi / l_f^2) * dlf/dh +
    # k_i * k_f * sin(pol) * (dpol/dh + (dpol/dtd * dtd/dh))
    temp10 = array_manip.add_ncerr(temp8[0], temp8[1], temp9[0], temp9[1])

    # (((k_i - k_f * cos(pol)) * (L_f / L_i) * (k_i / k_f)^2 -
    # (k_f - k_i * cos(pol))) * (2 * pi / l_f^2) * dlf/dh +
    # k_i * k_f * sin(pol) * (dpol/dh - (dpol/dtd dazi/dh / dazi/dtd))
    return array_manip.div_ncerr(temp10[0], temp10[1], Q, z_vec)
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 create_Qvec_vs_E_dgs(som, E_i, conf, **kwargs):
    """
    This function starts with the energy transfer axis from DGS reduction and
    turns this into a 4D spectra with Qx, Qy, Qz and Et axes.

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

    @param E_i: The initial energy for the given data.
    @type E_i: C{tuple}

    @param conf: Object that contains the current setup of the driver.
    @type conf: L{hlr_utils.Configure}

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

    @keyword timer: Timing object so the function can perform timing estimates.
    @type timer: C{sns_timer.DiffTime}

    @keyword corner_angles: The object that contains the corner geometry
                            information.
    @type corner_angles: C{dict}

    @keyword make_fixed: A flag that turns on writing the fixed grid mesh
                         information to a file.
    @type make_fixed: C{boolean}

    @keyword output: The output filename and or directory.
    @type output: C{string}
    """
    import array_manip
    import axis_manip
    import common_lib
    import hlr_utils

    import os

    # Check keywords
    try:
        t = kwargs["timer"]
    except KeyError:
        t = None

    corner_angles = kwargs["corner_angles"]

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

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

    # Convert initial energy to initial wavevector
    l_i = common_lib.energy_to_wavelength(E_i)
    k_i = common_lib.wavelength_to_scalar_k(l_i)

    # Since all the data is rebinned to the same energy transfer axis, we can
    # calculate the final energy axis once
    E_t = som[0].axis[0].val
    if som[0].axis[0].var is not None:
        E_t_err2 = som[0].axis[0].var
    else:
        import nessi_list
        E_t_err2 = nessi_list.NessiList(len(E_t))

    E_f = array_manip.sub_ncerr(E_i[0], E_i[1], E_t, E_t_err2)

    # Check for negative final energies which will cause problems with
    # wavelength conversion due to square root
    if E_f[0][-1] < 0:
        E_f[0].reverse()
        E_f[1].reverse()
        index = 0
        for E in E_f[0]:
            if E >= 0:
                break
            index += 1
        E_f[0].__delslice__(0, index)
        E_f[1].__delslice__(0, index)
        E_f[0].reverse()
        E_f[1].reverse()

    len_E = len(E_f[0]) - 1

    # Now we can get the final wavevector
    l_f = axis_manip.energy_to_wavelength(E_f[0], E_f[1])
    k_f = axis_manip.wavelength_to_scalar_k(l_f[0], l_f[1])

    # Grab the instrument from the som
    inst = som.attr_list.instrument

    if make_fixed:
        import SOM
        fixed_grid = {}
        for key in corner_angles:
            so_id = SOM.NeXusId.fromString(key).toTuple()
            try:
                pathlength = inst.get_secondary(so_id)[0]
                points = []
                for j in range(4):
                    points.extend(
                        __calc_xyz(pathlength, corner_angles[key].getPolar(j),
                                   corner_angles[key].getAzimuthal(j)))
                fixed_grid[key] = points
            except KeyError:
                # Pixel ID is not in instrument geometry
                pass

    CNT = {}
    ERR2 = {}
    V1 = {}
    V2 = {}
    V3 = {}
    V4 = {}
    # Output positions for Qx, Qy, Qz coordinates
    X = 0
    Y = 2
    Z = 4

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

    # Iterate though the data
    len_som = hlr_utils.get_length(som)
    for i in xrange(len_som):
        map_so = hlr_utils.get_map_so(som, None, i)

        yval = hlr_utils.get_value(som, i, "SOM", "y")
        yerr2 = hlr_utils.get_err2(som, i, "SOM", "y")

        CNT[str(map_so.id)] = yval
        ERR2[str(map_so.id)] = yerr2

        cangles = corner_angles[str(map_so.id)]

        Q1 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1], k_f[0],
                                                   k_f[1],
                                                   cangles.getAzimuthal(0),
                                                   0.0, cangles.getPolar(0),
                                                   0.0)
        V1[str(map_so.id)] = {}
        V1[str(map_so.id)]["x"] = Q1[X]
        V1[str(map_so.id)]["y"] = Q1[Y]
        V1[str(map_so.id)]["z"] = Q1[Z]

        Q2 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1], k_f[0],
                                                   k_f[1],
                                                   cangles.getAzimuthal(1),
                                                   0.0, cangles.getPolar(1),
                                                   0.0)

        V2[str(map_so.id)] = {}
        V2[str(map_so.id)]["x"] = Q2[X]
        V2[str(map_so.id)]["y"] = Q2[Y]
        V2[str(map_so.id)]["z"] = Q2[Z]

        Q3 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1], k_f[0],
                                                   k_f[1],
                                                   cangles.getAzimuthal(2),
                                                   0.0, cangles.getPolar(2),
                                                   0.0)
        V3[str(map_so.id)] = {}
        V3[str(map_so.id)]["x"] = Q3[X]
        V3[str(map_so.id)]["y"] = Q3[Y]
        V3[str(map_so.id)]["z"] = Q3[Z]

        Q4 = axis_manip.init_scatt_wavevector_to_Q(k_i[0], k_i[1], k_f[0],
                                                   k_f[1],
                                                   cangles.getAzimuthal(3),
                                                   0.0, cangles.getPolar(3),
                                                   0.0)

        V4[str(map_so.id)] = {}
        V4[str(map_so.id)]["x"] = Q4[X]
        V4[str(map_so.id)]["y"] = Q4[Y]
        V4[str(map_so.id)]["z"] = Q4[Z]

    if t is not None:
        t.getTime(msg="After calculating verticies ")

    # Form the messages
    if t is not None:
        t.getTime(False)

    jobstr = 'MR' + hlr_utils.create_binner_string(conf) + 'JH'
    num_lines = len(CNT) * len_E
    linestr = str(num_lines)

    if output is not None:
        outdir = os.path.dirname(output)
        if outdir != '':
            if outdir.rfind('.') != -1:
                outdir = ""
    else:
        outdir = ""

    value = str(som.attr_list["data-run_number"].getValue()).split('/')

    topdir = os.path.join(outdir, value[0].strip() + "-mesh")
    try:
        os.mkdir(topdir)
    except OSError:
        pass

    outtag = os.path.basename(output)
    if outtag.rfind('.') == -1:
        outtag = ""
    else:
        outtag = outtag.split('.')[0]

    if outtag != "":
        filehead = outtag + "_bmesh"
        if make_fixed:
            filehead1 = outtag + "_fgrid"
        filehead2 = outtag + "_conf"
    else:
        filehead = "bmesh"
        if make_fixed:
            filehead1 = "fgrid"
        filehead2 = "conf"

    hfile = open(os.path.join(topdir, "%s.in" % filehead2), "w")
    print >> hfile, jobstr
    print >> hfile, linestr
    hfile.close()

    import utils
    use_zero_supp = not conf.no_zero_supp

    for k in xrange(len_E):
        ofile = open(os.path.join(topdir, "%s%04d.in" % (filehead, k)), "w")
        if make_fixed:
            ofile1 = open(os.path.join(topdir, "%s%04d.in" % (filehead1, k)),
                          "w")
        for pid in CNT:
            if use_zero_supp:
                write_value = not utils.compare(CNT[pid][k], 0.0) == 0
            else:
                write_value = True

            if write_value:
                result = []
                result.append(str(k))
                result.append(str(E_t[k]))
                result.append(str(E_t[k + 1]))
                result.append(str(CNT[pid][k]))
                result.append(str(ERR2[pid][k]))
                __get_coords(V1, pid, k, result)
                __get_coords(V2, pid, k, result)
                __get_coords(V3, pid, k, result)
                __get_coords(V4, pid, k, result)
                __get_coords(V1, pid, k + 1, result)
                __get_coords(V2, pid, k + 1, result)
                __get_coords(V3, pid, k + 1, result)
                __get_coords(V4, pid, k + 1, result)

                print >> ofile, " ".join(result)

            if make_fixed:
                result1 = []
                result1.append(str(k))
                result1.append(str(E_t[k]))
                result1.append(str(E_t[k + 1]))
                result1.append(str(CNT[pid][k]))
                result1.append(str(ERR2[pid][k]))
                result1.extend([str(x) for x in fixed_grid[pid]])
                print >> ofile1, " ".join(result1)

        ofile.close()
        if make_fixed:
            ofile1.close()

    if t is not None:
        t.getTime(msg="After creating messages ")
Example #22
0
def process_dgs_data(obj, conf, bcan, ecan, tcoeff, **kwargs):
    """
    This function combines Steps 7 through 16 in Section 2.1.1 of the data
    reduction process for Direct Geometry Spectrometers as specified by the
    document at 
    U{http://neutrons.ornl.gov/asg/projects/SCL/reqspec/DR_Lib_RS.doc}. The
    function takes a calibrated dataset, a L{hlr_utils.Configure} object and
    processes the data accordingly.

    @param obj: A calibrated dataset object.
    @type obj: C{SOM.SOM}

    @param conf: Object that contains the current setup of the driver.
    @type conf: L{hlr_utils.Configure}

    @param bcan: The object containing the black can data.
    @type bcan: C{SOM.SOM}

    @param ecan: The object containing the empty can data.
    @type ecan: C{SOM.SOM}

    @param tcoeff: The transmission coefficient appropriate to the given data
                   set.
    @type tcoeff: C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword dataset_type: The practical name of the dataset being processed.
                           The default value is I{data}.
    @type dataset_type: C{string}

    @keyword cwp_used: A flag signalling the use of the chopper phase
                       corrections.
    @type cwp_used: C{bool}

    @keyword timer: Timing object so the function can perform timing estimates.
    @type timer: C{sns_timer.DiffTime}


    @return: Object that has undergone all requested processing steps
    @rtype: C{SOM.SOM}
    """
    import array_manip
    import common_lib
    import dr_lib
    import hlr_utils

    # Check keywords
    try:
        dataset_type = kwargs["dataset_type"]
    except KeyError:
        dataset_type = "data"

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

    cwp_used = kwargs.get("cwp_used", False)
        
    if conf.verbose:
        print "Processing %s information" % dataset_type

    # Step 7: Create black can background contribution
    if bcan is not None:
        if conf.verbose:
            print "Creating black can background contribution for %s" \
                  % dataset_type

        if t is not None:
            t.getTime(False)
            
        bccoeff = array_manip.sub_ncerr(1.0, 0.0, tcoeff[0], tcoeff[1])
        bcan1 = common_lib.mult_ncerr(bcan, bccoeff)

        if t is not None:
            t.getTime(msg="After creating black can background contribution ")
        
        del bcan
    else:
        bcan1 = None

    # Step 8: Create empty can background contribution
    if ecan is not None:
        if conf.verbose:
            print "Creating empty can background contribution for %s" \
                  % dataset_type

        if t is not None:
            t.getTime(False)
        
        ecan1 = common_lib.mult_ncerr(ecan, tcoeff)

        if t is not None:
            t.getTime(msg="After creating empty can background contribution ")
        
        del ecan
    else:
        ecan1 = None

    # Step 9: Create background spectra
    if bcan1 is not None or ecan1 is not None and conf.verbose:
        print "Creating background spectra for %s" % dataset_type
    
    if bcan1 is not None and ecan1 is not None:
        if cwp_used:
            if conf.verbose:
                print "Rebinning empty can to black can axis."
                
            ecan2 = common_lib.rebin_axis_1D_frac(ecan1, bcan1[0].axis[0].val)
        else:
            ecan2 = ecan1

        del ecan1
        
        if t is not None:
            t.getTime(False)

        b_som = common_lib.add_ncerr(bcan1, ecan2)

        if t is not None:
            t.getTime(msg="After creating background spectra ")
    elif bcan1 is not None and ecan1 is None:
        b_som = bcan1
    elif bcan1 is None and ecan1 is not None:
        b_som = ecan1
    else:
        b_som = None

    del bcan1, ecan1

    if cwp_used:
        if conf.verbose:
            print "Rebinning background spectra to %s" % dataset_type

        b_som1 = common_lib.rebin_axis_1D_frac(b_som, obj[0].axis[0].val)
    else:
        b_som1 = b_som

    del b_som

    if conf.dump_ctof_comb and b_som1 is not None:
        b_som_1 = dr_lib.sum_all_spectra(b_som1)
        hlr_utils.write_file(conf.output, "text/Spec", b_som_1,
                             output_ext="ctof",
                             extra_tag="background",
                             data_ext=conf.ext_replacement,    
                             path_replacement=conf.path_replacement,
                             verbose=conf.verbose,
                             message="combined background TOF information")
        del b_som_1
        
    # Step 10: Subtract background from data
    obj1 = dr_lib.subtract_bkg_from_data(obj, b_som1, verbose=conf.verbose,
                                         timer=t,
                                         dataset1=dataset_type,
                                         dataset2="background")

    del obj, b_som1

    # Step 11: Calculate initial velocity
    if conf.verbose:
        print "Calculating initial velocity"

    if t is not None:
        t.getTime(False)
        
    if conf.initial_energy is not None:
        initial_wavelength = common_lib.energy_to_wavelength(\
            conf.initial_energy.toValErrTuple())
        initial_velocity = common_lib.wavelength_to_velocity(\
            initial_wavelength)
    else:
        # This should actually calculate it, but don't have a way right now
        pass

    if t is not None:
        t.getTime(msg="After calculating initial velocity ")

    # Step 12: Calculate the time-zero offset
    if conf.time_zero_offset is not None:
        time_zero_offset = conf.time_zero_offset.toValErrTuple()
    else:
        # This should actually calculate it, but don't have a way right now
        time_zero_offset = (0.0, 0.0)

    # Step 13: Convert time-of-flight to final velocity
    if conf.verbose:
        print "Converting TOF to final velocity DGS"

    if t is not None:
        t.getTime(False)
        
    obj2 = common_lib.tof_to_final_velocity_dgs(obj1, initial_velocity,
                                                time_zero_offset,
                                                units="microsecond")

    if t is not None:
        t.getTime(msg="After calculating TOF to final velocity DGS ")
        
    del obj1
    
    # Step 14: Convert final velocity to final wavelength
    if conf.verbose:
        print "Converting final velocity DGS to final wavelength"

    if t is not None:
        t.getTime(False)
        
    obj3 = common_lib.velocity_to_wavelength(obj2)

    if t is not None:
        t.getTime(msg="After calculating velocity to wavelength ")

    del obj2

    if conf.dump_wave_comb:
        obj3_1 = dr_lib.sum_all_spectra(obj3,
                                     rebin_axis=conf.lambda_bins.toNessiList())
        hlr_utils.write_file(conf.output, "text/Spec", obj3_1,
                             output_ext="fwv",
                             extra_tag=dataset_type,
                             data_ext=conf.ext_replacement,    
                             path_replacement=conf.path_replacement,
                             verbose=conf.verbose,
                             message="combined final wavelength information")

        del obj3_1

    # Step 15: Create the detector efficiency
    if conf.det_eff is not None:
        if conf.verbose:
            print "Creating detector efficiency spectra"

        if t is not None:
            t.getTime(False)
            
        det_eff = dr_lib.create_det_eff(obj3)

        if t is not None:
            t.getTime(msg="After creating detector efficiency spectra ")
    else:
        det_eff = None

    # Step 16: Divide the detector pixel spectra by the detector efficiency
    if det_eff is not None:
        if conf.verbose:
            print "Correcting %s for detector efficiency" % dataset_type

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

        obj4 = common_lib.div_ncerr(obj3, det_eff)

        if t is not None:
            t.getTime(msg="After correcting %s for detector efficiency" \
                      % dataset_type)
    else:
        obj4 = obj3

    del obj3, det_eff

    return obj4