def tof_to_initial_wavelength_igs(obj, **kwargs):
    """
    This function converts a primary axis of a C{SOM} or C{SO} from
    time-of-flight to initial_wavelength_igs. The time-of-flight axis for a
    C{SOM} must be in units of I{microseconds}. The primary axis of a C{SO} is
    assumed to be in units of I{microseconds}. A C{tuple} of C{(tof, tof_err2)}
    (assumed to be in units of I{microseconds}) can be converted to
    C{(initial_wavelength_igs, initial_wavelength_igs_err2)}.

    @param obj: Object to be converted
    @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:
    
    @keyword lambda_f:The final wavelength and its associated error^2
    @type lambda_f: C{tuple}
    
    @keyword time_zero: The time zero offset and its associated error^2
    @type time_zero: C{tuple}
    
    @keyword dist_source_sample: The source to sample distance information and
                                 its associated error^2
    @type dist_source_sample: C{tuple} or C{list} of C{tuple}s 

    @keyword dist_sample_detector: The sample to detector distance information
                                   and its associated error^2
    @type dist_sample_detector: C{tuple} or C{list} of C{tuple}s
    
    @keyword run_filter: This determines if the filter on the negative
                         wavelengths is run. The default setting is True.
    @type run_filter: C{boolean}
    
    @keyword units: The expected units for this function. The default for this
                    function is I{microseconds}
    @type units: C{string}


    @return: Object with a primary axis in time-of-flight converted to
             initial_wavelength_igs
    @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple}


    @raise TypeError: The incoming object is not a type the function recognizes
    
    @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds}
    """

    # 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)

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

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

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

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

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

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

    # 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

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

    # Where to get instrument information
    if dist_source_sample is None or dist_sample_detector is None:
        if o_descr == "SOM":
            try:
                obj.attr_list.instrument.get_primary()
                inst = obj.attr_list.instrument
            except RuntimeError:
                raise RuntimeError("A detector was not provided!")
        else:
            if dist_source_sample is None and dist_sample_detector is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"source-sample and sample-detector "\
                                   +"distances must be provided.")
            elif dist_source_sample is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"source-sample distance must be provided.")
            elif dist_sample_detector is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"sample-detector distance must be "\
                                   +"provided.")
            else:
                raise RuntimeError("If you get here, see Steve Miller for "\
                                   +"your mug.")
    else:
        pass

    if lambda_f is not None:
        l_descr = hlr_utils.get_descr(lambda_f)
    else:
        if o_descr == "SOM":
            try:
                som_l_f = obj.attr_list["Wavelength_final"]
            except KeyError:
                raise RuntimeError("Please provide a final wavelength "\
                                   +"parameter either via the function call "\
                                   +"or the SOM")
        else:
            raise RuntimeError("You need to provide a final wavelength")

    if time_zero is not None:
        t_descr = hlr_utils.get_descr(time_zero)
    else:
        if o_descr == "SOM":
            try:
                t_0 = obj.attr_list["Time_zero"][0]
                t_0_err2 = obj.attr_list["Time_zero"][1]
            except KeyError:
                raise RuntimeError("Please provide a time-zero "\
                                   +"parameter either via the function call "\
                                   +"or the SOM")
        else:
            t_0 = 0.0
            t_0_err2 = 0.0

    if dist_source_sample is not None:
        ls_descr = hlr_utils.get_descr(dist_source_sample)
    # Do nothing, go on
    else:
        pass

    if dist_sample_detector is not None:
        ld_descr = hlr_utils.get_descr(dist_sample_detector)
    # Do nothing, go on
    else:
        pass

    # iterate through the values
    import axis_manip

    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)

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

        if dist_source_sample is None:
            (L_s, L_s_err2) = hlr_utils.get_parameter("primary", map_so, inst)
        else:
            L_s = hlr_utils.get_value(dist_source_sample, i, ls_descr)
            L_s_err2 = hlr_utils.get_err2(dist_source_sample, i, ls_descr)

        if dist_sample_detector is None:
            (L_d, L_d_err2) = hlr_utils.get_parameter("secondary", map_so,
                                                      inst)
        else:
            L_d = hlr_utils.get_value(dist_sample_detector, i, ld_descr)
            L_d_err2 = hlr_utils.get_err2(dist_sample_detector, i, ld_descr)

        if lambda_f is not None:
            l_f = hlr_utils.get_value(lambda_f, i, l_descr)
            l_f_err2 = hlr_utils.get_err2(lambda_f, i, l_descr)
        else:
            l_f_tuple = hlr_utils.get_special(som_l_f, map_so)
            l_f = l_f_tuple[0]
            l_f_err2 = l_f_tuple[1]

        if time_zero is not None:
            t_0 = hlr_utils.get_value(time_zero, i, t_descr)
            t_0_err2 = hlr_utils.get_err2(time_zero, i, t_descr)
        else:
            pass

        value = axis_manip.tof_to_initial_wavelength_igs(
            val, err2, l_f, l_f_err2, t_0, t_0_err2, L_s, L_s_err2, L_d,
            L_d_err2)

        # Remove all wavelengths < 0
        if run_filter:
            index = 0
            for val in value[0]:
                if val >= 0:
                    break
                index += 1

            value[0].__delslice__(0, index)
            value[1].__delslice__(0, index)
            map_so.y.__delslice__(0, index)
            map_so.var_y.__delslice__(0, index)
        else:
            pass

        hlr_utils.result_insert(result, res_descr, value, map_so, "x", axis)

    return result
Example #2
0
def wavelength_to_energy(obj, **kwargs):
    """
    This function converts a primary axis of a C{SOM} or C{SO} from wavelength
    to energy. The wavelength axis for a C{SOM} must be in units of
    I{Angstroms}. The primary axis of a C{SO} is assumed to be in units of
    I{Angstroms}. A C{tuple} of C{(wavelength, wavelength_err2)} (assumed to
    be in units of I{Angstroms}) can be converted to C{(energy, energy_err)}.

    @param obj: Object to be converted
    @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword offset: Energy offset information
    @type offset: C{tuple} or C{list} of C{tuple}s
    
    @keyword lojac: A flag that allows one to turn off the calculation of the
                    linear-order Jacobian. The default action is True for
                    histogram data.
    @type lojac: C{boolean}
    
    @keyword units: The expected units for this function. The default for this
                    function is I{Angstroms}
    @type units: C{string}


    @return: Object with a primary axis in wavelength converted to energy
    @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple}


    @raise TypeError: The incoming object is not a type the function recognizes
    
    @raise RuntimeError: The C{SOM} x-axis units are not I{Angstroms}
    """
    # 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 == "list":
        raise TypeError("Do not know how to handle given type: %s" % \
                        o_descr)
    else:
        pass

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

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

    try:
        lojac = kwargs["lojac"]
    except KeyError:
        lojac = hlr_utils.check_lojac(obj)

    # 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

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

    # iterate through the values
    import array_manip
    import axis_manip
    if lojac:
        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)

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

        value = axis_manip.wavelength_to_energy(val, err2)

        if lojac:
            y_val = hlr_utils.get_value(obj, i, o_descr, "y")
            y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y")
            counts = utils.linear_order_jacobian(val, value[0], y_val, y_err2)
        else:
            pass

        if o_descr != "number":
            value1 = axis_manip.reverse_array_cp(value[0])
            value2 = axis_manip.reverse_array_cp(value[1])
            rev_value = (value1, value2)
        else:
            rev_value = value

        if map_so is not None:
            if not lojac:
                map_so.y = axis_manip.reverse_array_cp(map_so.y)
                map_so.var_y = axis_manip.reverse_array_cp(map_so.var_y)
            else:
                map_so.y = axis_manip.reverse_array_cp(counts[0])
                map_so.var_y = axis_manip.reverse_array_cp(counts[1])
        else:
            pass

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

        hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x",
                                axis)

    return result
def tof_to_ref_scalar_Q(obj, **kwargs):
    """
    This function converts a primary axis of a C{SOM} or C{SO} from
    time-of-flight to reflectometer scalar Q. This means that a single angle
    and a single flightpath is used. The time-of-flight axis for a C{SOM} must
    be in units of I{microseconds}. The primary axis of a C{SO} is assumed to
    be in units of I{microseconds}. A C{tuple} of C{(time-of-flight,
    time-of-flight_err2)} (assumed to be in units of I{microseconds}) can be
    converted to C{(scalar_Q, scalar_Q_err2)}.

    @param obj: Object to be converted
    @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:
    
    @keyword polar: The polar angle and its associated error^2
    @type polar: C{tuple}
    
    @keyword pathlength: The pathlength and its associated error^2
    @type pathlength: C{tuple}

    @keyword angle_offset: A constant offset for the polar angle and its
                           associated error^2. The units of the offset should
                           be in radians.
    @type angle_offset: C{tuple}

    @keyword lojac: A flag that allows one to turn off the calculation of the
                    linear-order Jacobian. The default action is True for
                    histogram data.
    @type lojac: C{boolean}    
    
    @keyword units: The expected units for this function. The default for this
                    function is I{microseconds}.
    @type units: C{string}

    @keyword configure: This is the object containing the driver configuration.
                        This will signal the function to write out the counts
                        and fractional area to files.
    @type configure: C{Configure}


    @return: Object with a primary axis in time-of-flight converted to
             reflectometer scalar Q
    @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple}


    @raise TypeError: The incoming object is not a type the function recognizes
    
    @raise RuntimeError: A C{SOM} is not passed and no polar angle is provided
    
    @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds}
    """
    
    # 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 == "list":
        raise TypeError("Do not know how to handle given type: %s" % \
                        o_descr)
    else:
        pass

    # Setup keyword arguments
    polar = kwargs.get("polar")
    pathlength = kwargs.get("pathlength")
    units = kwargs.get("units", "microseconds")
    lojac = kwargs.get("lojac", hlr_utils.check_lojac(obj))
    angle_offset = kwargs.get("angle_offset")
    config = kwargs.get("configure")

    if config is None:
        beamdiv_corr = False
    else:
        beamdiv_corr = config.beamdiv_corr
    
    # 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

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)
    if res_descr == "SOM":
        result = hlr_utils.force_units(result, "1/Angstroms", axis)
        result.setAxisLabel(axis, "scalar wavevector transfer")
        result.setYUnits("Counts/A-1")
        result.setYLabel("Intensity")
    else:
        pass

    if pathlength is None or polar is None:
        if o_descr == "SOM":
            try:
                obj.attr_list.instrument.get_primary()
                inst = obj.attr_list.instrument
            except RuntimeError:
                raise RuntimeError("A detector was not provided")
        else:
            if pathlength is None and polar is None:
                raise RuntimeError("If no SOM is provided, then pathlength "\
                                   +"and polar angle information must be "\
                                   +"provided")
            elif pathlength is None:
                raise RuntimeError("If no SOM is provided, then pathlength "\
                                   +"information must be provided")
            elif polar is None:
                raise RuntimeError("If no SOM is provided, then polar angle "\
                                   +"information must be provided")
            else:
                raise RuntimeError("If you get here, see Steve Miller for "\
                                   +"your mug.")
    else:
        pass

    if pathlength is None:
        (pl, pl_err2) = obj.attr_list.instrument.get_total_path(obj[0].id,
                                                             det_secondary=True)
    else:
        (pl, pl_err2) = pathlength

    if polar is None:
        angle = hlr_utils.get_special(obj.attr_list["data-theta"], obj[0])[0]
        angle_err2 = 0.0
    else:
        (angle, angle_err2) = polar

    if angle_offset is not None:
        angle += angle_offset[0]
        angle_err2 += angle_offset[1]

    # Need to multiply angle by 2.0 in order to make it be Theta to
    # underlying conversion function
    angle *= 2.0
    angle_err2 *= 4.0

    # iterate through the values
    import axis_manip
    if lojac:
        import utils

    if beamdiv_corr:
        import dr_lib

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

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

        if beamdiv_corr:
            dangle = dr_lib.ref_beamdiv_correct(obj.attr_list, map_so.id,
                                                config.det_spat_res,
                                                config.center_pix)
            # We subtract due to the inversion of the z coordinates from the
            # mirror reflection of the beam at the sample.
            if dangle is not None:
                pangle = angle - (2.0 * dangle)
            else:
                pangle = angle
                skip_pixel = True
        else:
            pangle = angle

        value = axis_manip.tof_to_scalar_Q(val, err2, pl, pl_err2, pangle,
                                           angle_err2)

        if lojac:
            y_val = hlr_utils.get_value(obj, i, o_descr, "y")
            y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y")
            counts = utils.linear_order_jacobian(val, value[0],
                                                 y_val, y_err2)
        else:
            pass

        if o_descr != "number":
            value1 = axis_manip.reverse_array_cp(value[0])
            value2 = axis_manip.reverse_array_cp(value[1])
            rev_value = (value1, value2)
        else:
            rev_value = value

        if map_so is not None:
            if not lojac:
                map_so.y = axis_manip.reverse_array_cp(map_so.y)
                map_so.var_y = axis_manip.reverse_array_cp(map_so.var_y)
            else:
                map_so.y = axis_manip.reverse_array_cp(counts[0])
                map_so.var_y = axis_manip.reverse_array_cp(counts[1])
        else:
            pass

        if not skip_pixel:
            hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x",
                                    axis)

    return result
Example #4
0
def initial_wavelength_igs_lin_time_zero_to_tof(obj, **kwargs):
    """
    This function converts a primary axis of a C{SOM} or C{SO} from
    initial_wavelength_igs_lin_time_zero to time-of-flight. The
    initial_wavelength_igs_lin_time_zero axis for a C{SOM} must be in units of
    I{Angstroms}. The primary axis of a C{SO} is assumed to be in units of
    I{Angstroms}. A C{tuple} of C{(initial_wavelength_igs_lin_time_zero,
    initial_wavelength_igs_lin_time_zero_err2)} (assumed to be in units of
    I{Angstroms}) can be converted to C{(tof, tof_err2)}.

    @param obj: Object to be converted
    @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple}

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

    @keyword lambda_f:The final wavelength and its associated error^2
    @type lambda_f: C{tuple}

    @keyword time_zero_slope: The time zero slope and its associated error^2
    @type time_zero_slope: C{tuple}

    @keyword time_zero_offset: The time zero offset and its associated error^2
    @type time_zero_offset: C{tuple}

    @keyword dist_source_sample: The source to sample distance information and
                                 its associated error^2
    @type dist_source_sample: C{tuple} or C{list} of C{tuple}s

    @keyword dist_sample_detector: The sample to detector distance information
                                   and its associated error^2
    @type dist_sample_detector: C{tuple} or C{list} of C{tuple}s

    @keyword lojac: A flag that allows one to turn off the calculation of the
                    linear-order Jacobian. The default action is True for
                    histogram data.
    @type lojac: C{boolean}

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


    @return: Object with a primary axis in initial_wavelength_igs converted to
             time-of-flight
    @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple}


    @raise TypeError: The incoming object is not a type the function recognizes

    @raise RuntimeError: The C{SOM} x-axis units are not I{Angstroms}
    """
    # 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)

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

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

    # Current constants for Time Zero Slope
    TIME_ZERO_SLOPE = (float(0.0), float(0.0))

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

    # Current constants for Time Zero Offset
    TIME_ZERO_OFFSET = (float(0.0), float(0.0))

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

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

    try:
        lojac = kwargs["lojac"]
    except KeyError:
        lojac = hlr_utils.check_lojac(obj)

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

    # 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

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)
    if res_descr == "SOM":
        result = hlr_utils.force_units(result, "Microseconds", axis)
        result.setAxisLabel(axis, "time-of-flight")
        result.setYUnits("Counts/uS")
        result.setYLabel("Intensity")
    else:
        pass

    # Where to get instrument information
    if dist_source_sample is None or dist_sample_detector is None:
        if o_descr == "SOM":
            try:
                obj.attr_list.instrument.get_primary()
                inst = obj.attr_list.instrument
            except RuntimeError:
                raise RuntimeError("A detector was not provided!")
        else:
            if dist_source_sample is None and dist_sample_detector is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"source-sample and sample-detector "\
                                   +"distances must be provided.")
            elif dist_source_sample is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"source-sample distance must be provided.")
            elif dist_sample_detector is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"sample-detector distance must be "\
                                   +"provided.")
            else:
                raise RuntimeError("If you get here, see Steve Miller for "\
                                   +"your mug.")
    else:
        pass

    if lambda_f is not None:
        l_descr = hlr_utils.get_descr(lambda_f)
    else:
        if o_descr == "SOM":
            try:
                som_l_f = obj.attr_list["Wavelength_final"]
            except KeyError:
                raise RuntimeError("Please provide a final wavelength "\
                                   +"parameter either via the function call "\
                                   +"or the SOM")
        else:
            raise RuntimeError("You need to provide a final wavelength")

    if time_zero_slope is not None:
        t_0_slope_descr = hlr_utils.get_descr(time_zero_slope)
    else:
        if o_descr == "SOM":
            try:
                t_0_slope = obj.attr_list["Time_zero_slope"][0]
                t_0_slope_err2 = obj.attr_list["Time_zero_slope"][1]
            except KeyError:
                t_0_slope = TIME_ZERO_SLOPE[0]
                t_0_slope_err2 = TIME_ZERO_SLOPE[1]
        else:
            t_0_slope = TIME_ZERO_SLOPE[0]
            t_0_slope_err2 = TIME_ZERO_SLOPE[1]

    if time_zero_offset is not None:
        t_0_offset_descr = hlr_utils.get_descr(time_zero_offset)
    else:
        if o_descr == "SOM":
            try:
                t_0_offset = obj.attr_list["Time_zero_offset"][0]
                t_0_offset_err2 = obj.attr_list["Time_zero_offset"][1]
            except KeyError:
                t_0_offset = TIME_ZERO_OFFSET[0]
                t_0_offset_err2 = TIME_ZERO_OFFSET[1]
        else:
            t_0_offset = TIME_ZERO_OFFSET[0]
            t_0_offset_err2 = TIME_ZERO_OFFSET[1]

    if dist_source_sample is not None:
        ls_descr = hlr_utils.get_descr(dist_source_sample)
    # Do nothing, go on
    else:
        pass

    if dist_sample_detector is not None:
        ld_descr = hlr_utils.get_descr(dist_sample_detector)
    # Do nothing, go on
    else:
        pass

    # iterate through the values
    len_obj = hlr_utils.get_length(obj)

    MNEUT_OVER_H = 1.0 / 0.003956034
    MNEUT_OVER_H2 = MNEUT_OVER_H * MNEUT_OVER_H

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

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

        if dist_source_sample is None:
            (L_s, L_s_err2) = hlr_utils.get_parameter("primary", map_so, inst)
        else:
            L_s = hlr_utils.get_value(dist_source_sample, i, ls_descr)
            L_s_err2 = hlr_utils.get_err2(dist_source_sample, i, ls_descr)

        if dist_sample_detector is None:
            (L_d, L_d_err2) = hlr_utils.get_parameter("secondary", map_so,
                                                      inst)
        else:
            L_d = hlr_utils.get_value(dist_sample_detector, i, ld_descr)
            L_d_err2 = hlr_utils.get_err2(dist_sample_detector, i, ld_descr)

        if lambda_f is not None:
            l_f = hlr_utils.get_value(lambda_f, i, l_descr)
            l_f_err2 = hlr_utils.get_err2(lambda_f, i, l_descr)
        else:
            l_f_tuple = hlr_utils.get_special(som_l_f, map_so)
            l_f = l_f_tuple[0]
            l_f_err2 = l_f_tuple[1]

        if time_zero_slope is not None:
            t_0_slope = hlr_utils.get_value(time_zero_slope, i,
                                            t_0_slope_descr)
            t_0_slope_err2 = hlr_utils.get_err2(time_zero_slope, i,
                                                t_0_slope_descr)
        else:
            pass

        if time_zero_offset is not None:
            t_0_offset = hlr_utils.get_value(time_zero_offset, i,
                                             t_0_offset_descr)
            t_0_offset_err2 = hlr_utils.get_err2(time_zero_offset, i,
                                                 t_0_offset_descr)
        else:
            pass

        # Going to violate rules since the current usage is with a single
        # number. When an SCL equivalent function arises, this code can be
        # fixed.
        front_const = MNEUT_OVER_H * L_s + t_0_slope
        term2 = MNEUT_OVER_H * l_f * L_d

        tof = (front_const * val) + term2 + t_0_offset

        front_const2 = front_const * front_const

        eterm1 = l_f * l_f * L_d_err2
        eterm2 = L_d * L_d * l_f_err2
        eterm3 = MNEUT_OVER_H2 * L_s_err2

        tof_err2 = (front_const2 * err2) + (val * val) * \
                   (eterm3 + t_0_slope_err2) + (MNEUT_OVER_H2 * \
                                                (eterm1 + eterm2)) + \
                                                t_0_offset_err2

        hlr_utils.result_insert(result, res_descr, (tof, tof_err2), None,
                                "all")

    return result
Example #5
0
def tof_to_initial_wavelength_igs_lin_time_zero(obj, **kwargs):
    """
    This function converts a primary axis of a C{SOM} or C{SO} from
    time-of-flight to initial_wavelength_igs_lin_time_zero. The time-of-flight
    axis for a C{SOM} must be in units of I{microseconds}. The primary axis of
    a C{SO} is assumed to be in units of I{microseconds}. A C{tuple} of
    C{(tof, tof_err2)} (assumed to be in units of I{microseconds}) can be
    converted to C{(initial_wavelength_igs, initial_wavelength_igs_err2)}.

    @param obj: Object to be converted
    @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:
    
    @keyword lambda_f:The final wavelength and its associated error^2
    @type lambda_f: C{tuple}
    
    @keyword time_zero_slope: The time zero slope and its associated error^2
    @type time_zero_slope: C{tuple}

    @keyword time_zero_offset: The time zero offset and its associated error^2
    @type time_zero_offset: C{tuple}
    
    @keyword dist_source_sample: The source to sample distance information and
                                 its associated error^2
    @type dist_source_sample: C{tuple} or C{list} of C{tuple}s 

    @keyword dist_sample_detector: The sample to detector distance information
                                   and its associated error^2
    @type dist_sample_detector: C{tuple} or C{list} of C{tuple}s
    
    @keyword run_filter: This determines if the filter on the negative
                         wavelengths is run. The default setting is True.
    @type run_filter: C{boolean}

    @keyword lojac: A flag that allows one to turn off the calculation of the
                    linear-order Jacobian. The default action is True for
                    histogram data.
    @type lojac: C{boolean}
    
    @keyword units: The expected units for this function. The default for this
                    function is I{microseconds}
    @type units: C{string}


    @return: Object with a primary axis in time-of-flight converted to
             initial_wavelength_igs
    @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple}


    @raise TypeError: The incoming object is not a type the function recognizes
    
    @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds}
    """

    # 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)

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

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

    # Current constants for Time Zero Slope
    TIME_ZERO_SLOPE = (float(0.0), float(0.0))

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

    # Current constants for Time Zero Offset
    TIME_ZERO_OFFSET = (float(0.0), float(0.0))

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

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

    try:
        lojac = kwargs["lojac"]
    except KeyError:
        lojac = hlr_utils.check_lojac(obj)

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

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

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

    # 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

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

    # Where to get instrument information
    if dist_source_sample is None or dist_sample_detector is None:
        if o_descr == "SOM":
            try:
                obj.attr_list.instrument.get_primary()
                inst = obj.attr_list.instrument
                mobj = obj
            except RuntimeError:
                raise RuntimeError("A detector was not provided!")
        else:
            if iobj is None:
                if dist_source_sample is None and dist_sample_detector is None:
                    raise RuntimeError("If a SOM is not passed, the "\
                                       +"source-sample and sample-detector "\
                                       +"distances must be provided.")
                elif dist_source_sample is None:
                    raise RuntimeError("If a SOM is not passed, the "\
                                       +"source-sample distance must be "\
                                       +"provided.")
                elif dist_sample_detector is None:
                    raise RuntimeError("If a SOM is not passed, the "\
                                       +"sample-detector distance must be "\
                                       +"provided.")
                else:
                    raise RuntimeError("If you get here, see Steve Miller "\
                                       +"for your mug.")
            else:
                inst = iobj.attr_list.instrument
                mobj = iobj
    else:
        mobj = obj

    if lambda_f is not None:
        l_descr = hlr_utils.get_descr(lambda_f)
    else:
        if o_descr == "SOM":
            try:
                som_l_f = obj.attr_list["Wavelength_final"]
            except KeyError:
                raise RuntimeError("Please provide a final wavelength "\
                                   +"parameter either via the function call "\
                                   +"or the SOM")
        else:
            if iobj is None:
                raise RuntimeError("You need to provide a final wavelength")
            else:
                som_l_f = iobj.attr_list["Wavelength_final"]

    if time_zero_slope is not None:
        t_0_slope_descr = hlr_utils.get_descr(time_zero_slope)
    else:
        if o_descr == "SOM":
            try:
                t_0_slope = obj.attr_list["Time_zero_slope"][0]
                t_0_slope_err2 = obj.attr_list["Time_zero_slope"][1]
            except KeyError:
                t_0_slope = TIME_ZERO_SLOPE[0]
                t_0_slope_err2 = TIME_ZERO_SLOPE[1]
        else:
            t_0_slope = TIME_ZERO_SLOPE[0]
            t_0_slope_err2 = TIME_ZERO_SLOPE[1]

    if time_zero_offset is not None:
        t_0_offset_descr = hlr_utils.get_descr(time_zero_offset)
    else:
        if o_descr == "SOM":
            try:
                t_0_offset = obj.attr_list["Time_zero_offset"][0]
                t_0_offset_err2 = obj.attr_list["Time_zero_offset"][1]
            except KeyError:
                t_0_offset = TIME_ZERO_OFFSET[0]
                t_0_offset_err2 = TIME_ZERO_OFFSET[1]
        else:
            t_0_offset = TIME_ZERO_OFFSET[0]
            t_0_offset_err2 = TIME_ZERO_OFFSET[1]

    if dist_source_sample is not None:
        ls_descr = hlr_utils.get_descr(dist_source_sample)
    # Do nothing, go on
    else:
        pass

    if dist_sample_detector is not None:
        ld_descr = hlr_utils.get_descr(dist_sample_detector)
    # Do nothing, go on
    else:
        pass

    # iterate through the values
    import axis_manip
    if lojac:
        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)

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

        if dist_source_sample is None:
            (L_s, L_s_err2) = hlr_utils.get_parameter("primary", map_so, inst)
        else:
            L_s = hlr_utils.get_value(dist_source_sample, i, ls_descr)
            L_s_err2 = hlr_utils.get_err2(dist_source_sample, i, ls_descr)

        if dist_sample_detector is None:
            (L_d, L_d_err2) = hlr_utils.get_parameter("secondary", map_so,
                                                      inst)
        else:
            L_d = hlr_utils.get_value(dist_sample_detector, i, ld_descr)
            L_d_err2 = hlr_utils.get_err2(dist_sample_detector, i, ld_descr)

        if lambda_f is not None:
            l_f = hlr_utils.get_value(lambda_f, i, l_descr)
            l_f_err2 = hlr_utils.get_err2(lambda_f, i, l_descr)
        else:
            l_f_tuple = hlr_utils.get_special(som_l_f, map_so)
            l_f = l_f_tuple[0]
            l_f_err2 = l_f_tuple[1]

        if time_zero_slope is not None:
            t_0_slope = hlr_utils.get_value(time_zero_slope, i,
                                            t_0_slope_descr)
            t_0_slope_err2 = hlr_utils.get_err2(time_zero_slope, i,
                                                t_0_slope_descr)
        else:
            pass

        if time_zero_offset is not None:
            t_0_offset = hlr_utils.get_value(time_zero_offset, i,
                                             t_0_offset_descr)
            t_0_offset_err2 = hlr_utils.get_err2(time_zero_offset, i,
                                                 t_0_offset_descr)
        else:
            pass

        value = axis_manip.tof_to_initial_wavelength_igs_lin_time_zero(
            val, err2, l_f, l_f_err2, t_0_slope, t_0_slope_err2, t_0_offset,
            t_0_offset_err2, L_s, L_s_err2, L_d, L_d_err2)

        # Remove all wavelengths < 0
        if run_filter:
            index = 0
            for valx in value[0]:
                if valx >= 0:
                    break
                index += 1

            value[0].__delslice__(0, index)
            value[1].__delslice__(0, index)
            map_so.y.__delslice__(0, index)
            map_so.var_y.__delslice__(0, index)
            if lojac:
                val.__delslice__(0, index)
                err2.__delslice__(0, index)
        else:
            pass

        if lojac:
            try:
                counts = utils.linear_order_jacobian(val, value[0], map_so.y,
                                                     map_so.var_y)
            except Exception, e:
                # Lets us know offending pixel ID
                raise Exception(str(map_so.id) + " " + str(e))

            hlr_utils.result_insert(result, res_descr, counts, map_so, "all",
                                    axis, [value[0]])

        else:
            hlr_utils.result_insert(result, res_descr, value, map_so, "x",
                                    axis)
def convert_single_to_list(funcname, number, som, **kwargs):
    """
    This function retrieves a function object from the L{common_lib} set of
    functions that provide axis transformations and converts the provided
    number based on that function. Instrument geometry information needs to be
    provided via the C{SOM}. The following is the list of functions supported
    by this one.

      - d_spacing_to_tof_focused_det
      - energy_to_wavelength
      - frequency_to_energy
      - initial_wavelength_igs_lin_time_zero_to_tof
      - init_scatt_wavevector_to_scalar_Q
      - tof_to_initial_wavelength_igs_lin_time_zero
      - tof_to_initial_wavelength_igs
      - tof_to_scalar_Q
      - tof_to_wavelength_lin_time_zero
      - tof_to_wavelength
      - wavelength_to_d_spacing
      - wavelength_to_energy
      - wavelength_to_scalar_k
      - wavelength_to_scalar_Q

    @param funcname: The name of the axis conversion function to use
    @type funcname: C{string}

    @param number: The value and error^2 to convert
    @type number: C{tuple}

    @param som: The object containing geometry and other special information
    @type som: C{SOM.SOM}

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

    @keyword inst_param: The type of parameter requested from an associated
                         instrument. For this function the acceptable
                         parameters are I{primary}, I{secondary} and I{total}.
                         Default is I{primary}.
    @type inst_param: C{string}

    @keyword pixel_id: The pixel ID from which the geometry information will
                       be retrieved from the instrument
    @type pixel_id: C{tuple}=(\"bankN\", (x, y))


    @return: A converted number for every unique spectrum
    @rtype: C{list} of C{tuple}s


    @raise AttributeError: The requested function is not in the approved
                           list
    """
    # Setup supported function list and check to see if funcname is available
    function_list = []
    function_list.append("d_spacing_to_tof_focused_det")
    function_list.append("energy_to_wavelength")
    function_list.append("frequency_to_energy")
    function_list.append("initial_wavelength_igs_lin_time_zero_to_tof")
    function_list.append("init_scatt_wavevector_to_scalar_Q")
    function_list.append("tof_to_initial_wavelength_igs_lin_time_zero")
    function_list.append("tof_to_initial_wavelength_igs")
    function_list.append("tof_to_scalar_Q")
    function_list.append("tof_to_wavelength_lin_time_zero")
    function_list.append("tof_to_wavelength")
    function_list.append("wavelength_to_d_spacing")
    function_list.append("wavelength_to_energy")
    function_list.append("wavelength_to_scalar_k")
    function_list.append("wavelength_to_scalar_Q")

    if funcname not in function_list:
        raise AttributeError("Function %s is not supported by "\
                             +"convert_single_to_list" % funcname)

    import common_lib

    # Get the common_lib function object
    func = common_lib.__getattribute__(funcname)

    # Setup inclusive dictionary containing the requested keywords for all
    # common_lib axis conversion functions

    fkwds = {}
    fkwds["pathlength"] = ()
    fkwds["polar"] = ()
    fkwds["lambda_f"] = ()
    try:
        lambda_final = som.attr_list["Wavelength_final"]
    except KeyError:
        lambda_final = None
    try:
        fkwds["time_zero_slope"] = som.attr_list["Time_zero_slope"]
    except KeyError:
        pass
    try:
        fkwds["time_zero_offset"] = som.attr_list["Time_zero_offset"]
    except KeyError:
        pass
    try:
        fkwds["time_zero"] = som.attr_list["Time_zero"]
    except KeyError:
        pass    
    fkwds["dist_source_sample"] = ()
    fkwds["dist_sample_detector"] = ()
    try:
        fkwds["inst_param"] = kwargs["inst_param"]
    except KeyError:
        fkwds["inst_param"]  = "primary"
    try:
        fkwds["pixel_id"] = kwargs["pixel_id"]
    except KeyError:
        fkwds["pixel_id"]  = None
    fkwds["run_filter"] = False

    # Set up for working through data
    # This time highest object in the hierarchy is NOT what we need
    result = []
    res_descr = "list"

    inst = som.attr_list.instrument
    
    import hlr_utils

    # iterate through the values
    for i in xrange(hlr_utils.get_length(som)):
        map_so = hlr_utils.get_map_so(som, None, i)
        
        fkwds["pathlength"] = hlr_utils.get_parameter(fkwds["inst_param"],
                                                      map_so, inst)
        
        fkwds["dist_source_sample"] = hlr_utils.get_parameter("primary",
                                                              map_so, inst)

        fkwds["dist_sample_detector"] = hlr_utils.get_parameter("secondary",
                                                                map_so, inst)

        fkwds["polar"] = hlr_utils.get_parameter("polar", map_so, inst)

        fkwds["lambda_f"] = hlr_utils.get_special(lambda_final, map_so)

        value = tuple(func(number, **fkwds))

        hlr_utils.result_insert(result, res_descr, value, None, "all")

    return result
def wavelength_to_energy(obj, **kwargs):
    """
    This function converts a primary axis of a C{SOM} or C{SO} from wavelength
    to energy. The wavelength axis for a C{SOM} must be in units of
    I{Angstroms}. The primary axis of a C{SO} is assumed to be in units of
    I{Angstroms}. A C{tuple} of C{(wavelength, wavelength_err2)} (assumed to
    be in units of I{Angstroms}) can be converted to C{(energy, energy_err)}.

    @param obj: Object to be converted
    @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:

    @keyword offset: Energy offset information
    @type offset: C{tuple} or C{list} of C{tuple}s
    
    @keyword lojac: A flag that allows one to turn off the calculation of the
                    linear-order Jacobian. The default action is True for
                    histogram data.
    @type lojac: C{boolean}
    
    @keyword units: The expected units for this function. The default for this
                    function is I{Angstroms}
    @type units: C{string}


    @return: Object with a primary axis in wavelength converted to energy
    @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple}


    @raise TypeError: The incoming object is not a type the function recognizes
    
    @raise RuntimeError: The C{SOM} x-axis units are not I{Angstroms}
    """
    # 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 == "list":
        raise TypeError("Do not know how to handle given type: %s" % \
                        o_descr)
    else:
        pass

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

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

    try:
        lojac = kwargs["lojac"]
    except KeyError:
        lojac = hlr_utils.check_lojac(obj)

    # 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

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

    # iterate through the values
    import array_manip
    import axis_manip
    if lojac:
        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)

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

        value = axis_manip.wavelength_to_energy(val, err2)

        if lojac:
            y_val = hlr_utils.get_value(obj, i, o_descr, "y")
            y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y")
            counts = utils.linear_order_jacobian(val, value[0],
                                                 y_val, y_err2)
        else:
            pass

        if o_descr != "number":
            value1 = axis_manip.reverse_array_cp(value[0])
            value2 = axis_manip.reverse_array_cp(value[1])
            rev_value = (value1, value2)
        else:
            rev_value = value
        
        if map_so is not None:
            if not lojac:
                map_so.y = axis_manip.reverse_array_cp(map_so.y)
                map_so.var_y = axis_manip.reverse_array_cp(map_so.var_y)
            else:
                map_so.y = axis_manip.reverse_array_cp(counts[0])
                map_so.var_y = axis_manip.reverse_array_cp(counts[1])
        else:
            pass

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

        hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x",
                                axis)

    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
Example #9
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_delta_theta_over_theta(som, dataset_type="data"):
    """
    This function takes a C{SOM} that contains reflectometer slit and angle
    information and calculates the parameter delta theta / theta. The function
    will also store the calculated prameter as well as other slit and angle
    information into the C{SOM}s attribute list. The function will not return
    the C{SOM} as the core data values were not changed.

    @param som: The object that contains the slit and angle information
    @type som: C{SOM.SOM}

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


    @raise TypeError: Anything other than a C{SOM} is given
    """
    import hlr_utils
    import SOM

    o_descr = hlr_utils.get_descr(som)

    if o_descr != "SOM":
        raise TypeError("Function argument must be a SOM")
    # Have a SOM, go on
    else:
        pass

    import math

    # Create a dummy SO
    so = SOM.SO()

    # Create a dummy information tuple
    no_info = (None, None, None)

    # Set instrument specific strings
    inst_name = som.attr_list["instrument_name"]
    if inst_name == "REF_L":
        first_slit_ext1 = "Slit1_top"
        first_slit_ext2 = "Slit1_bottom"
        last_slit_ext1 = "Slit2_top"
        last_slit_ext2 = "Slit2_bottom"
        last_slit_dis = "Slit2_distance"
        last_slit = "slit2"
        last_slit_distot = "slit12"
        slit_ext1 = "top"
        slit_ext2 = "bottom"
    elif inst_name == "REF_M":
        first_slit_ext1 = "Slit1_left"
        first_slit_ext2 = "Slit1_right"
        last_slit_ext1 = "Slit3_left"
        last_slit_ext2 = "Slit3_right"
        last_slit_dis = "Slit3_distance"
        last_slit = "slit3"
        last_slit_distot = "slit13"
        slit_ext1 = "left"
        slit_ext2 = "right"
    else:
        raise RuntimeError("Do not know how to handle instrument %s" \
                           % inst_name)

    # Get slit information
    try:
        slit1_ext1 = hlr_utils.get_special(som.attr_list[first_slit_ext1], so)
    except KeyError:
        slit1_ext1 = no_info

    try:
        slit1_ext2 = hlr_utils.get_special(som.attr_list[first_slit_ext2], so)
    except KeyError:
        slit1_ext2 = no_info

    try:
        slit1_dist = hlr_utils.get_special(som.attr_list["Slit1_distance"], so)
    except KeyError:
        slit1_dist = no_info

    if slit1_ext1[0] is None or slit1_ext2[0] is None:
        slit1_size_ok = False
    else:
        slit1_size_ok = True

    try:
        slit2_ext1 = hlr_utils.get_special(som.attr_list[last_slit_ext1], so)
    except KeyError:
        slit2_ext1 = no_info

    try:
        slit2_ext2 = hlr_utils.get_special(som.attr_list[last_slit_ext2], so)
    except KeyError:
        slit2_ext2 = no_info

    try:
        slit2_dist = hlr_utils.get_special(som.attr_list[last_slit_dis], so)
    except KeyError:
        slit2_dist = no_info

    if slit2_ext1[0] is None or slit2_ext2[0] is None:
        slit2_size_ok = False
    else:
        slit2_size_ok = True

    if slit1_dist[0] is None or slit2_dist[0] is None:
        slit12_dist_ok = False
    else:
        slit12_dist_ok = True

    # Unit checks
    if slit1_size_ok and slit2_size_ok:
        if slit1_ext1[2] != slit2_ext1[2]:
            raise ValueError("Slit %s opening distances are not in the same "\
                             +"units. slit1 (%s), %s (%s)" % (slit_ext1,
                                                              slit1_ext1[2],
                                                              last_slit,
                                                              slit2_ext1[2]))

        if slit1_ext2[2] != slit2_ext2[2]:
            raise ValueError("Slit %s opening distances are not in the "\
                             +"same units. slit1 (%s), %s (%s)" \
                             % (slit_ext2,
                                slit1_ext2[2],
                                last_slit,
                                slit2_ext2[2]))

    if slit1_dist[2] != slit2_dist[2] and slit12_dist_ok:
        raise ValueError("Slit distances are not in the same units. "\
                         +"slit1 (%s), %s (%s)" % (slit1_dist[2],
                                                   last_slit,
                                                   slit2_dist[2]))

    # Calculate intermediate slit parameters
    if slit1_size_ok:
        slit1_size = math.fabs(slit1_ext1[0] - slit1_ext2[0])
        if slit1_ext1[2] == "millimetre":
            slit1_size /= 1000.0
            slit1_size_units = "metre"
        else:
            slit1_size_units = slit1_ext1[2]
    else:
        slit1_size = float('nan')
        slit1_size_units = None

    if slit2_size_ok:
        slit2_size = math.fabs(slit2_ext1[0] - slit2_ext2[0])
        if slit2_ext1[2] == "millimetre":
            slit2_size /= 1000.0
            slit2_size_units = "metre"
        else:
            slit2_size_units = slit2_ext1[2]
    else:
        slit2_size = float('nan')
        slit2_size_units = None

    if slit12_dist_ok:
        slit12_distance = math.fabs(slit1_dist[0] - slit2_dist[0])
        slit2_distance = math.fabs(slit2_dist[0])
    else:
        slit12_distance = float('nan')
        slit2_distance = float('nan')

    # Calculate delta theta
    if slit1_size_ok and not slit2_size_ok:
        dtheta = slit1_size / slit12_distance
    elif slit2_size_ok and not slit1_size_ok:
        dtheta = slit2_size / slit12_distance
    else:
        dtheta = max(slit1_size, slit2_size) / slit12_distance

    # Calculate delta theta over theta
    try:
        theta = hlr_utils.get_special(som.attr_list["Theta"], so)
    except KeyError:
        theta = no_info

    if theta[0] is not None:
        if theta[2] == "degrees" or theta[2] == "degree":
            theta_rads = theta[0] * (math.pi / 180.0)
        else:
            theta_rads = theta[0]
    else:
        theta_rads = float('nan')

    dtheta_over_theta = dtheta / theta_rads

    # Add parameters to attribute list
    som.attr_list[dataset_type + "-slit1_size"] = (slit1_size,
                                                   slit1_size_units)
    last_slit_tag = "-%s_size" % last_slit
    som.attr_list[dataset_type + last_slit_tag] = (slit2_size,
                                                   slit2_size_units)
    last_slit_dist_tag = "-%s_distance" % last_slit_distot
    som.attr_list[dataset_type + last_slit_dist_tag] = (slit12_distance,
                                                        slit1_dist[2])
    som.attr_list[dataset_type + "-" +
                  last_slit_dis.lower()] = (slit2_distance, slit1_dist[2])
    som.attr_list[dataset_type + "-delta_theta"] = (dtheta, "radians")
    som.attr_list[dataset_type + "-theta"] = (theta_rads, "radians")
    som.attr_list[dataset_type + "-dtheta_over_theta"] = dtheta_over_theta
def convert_single_to_list(funcname, number, som, **kwargs):
    """
    This function retrieves a function object from the L{common_lib} set of
    functions that provide axis transformations and converts the provided
    number based on that function. Instrument geometry information needs to be
    provided via the C{SOM}. The following is the list of functions supported
    by this one.

      - d_spacing_to_tof_focused_det
      - energy_to_wavelength
      - frequency_to_energy
      - initial_wavelength_igs_lin_time_zero_to_tof
      - init_scatt_wavevector_to_scalar_Q
      - tof_to_initial_wavelength_igs_lin_time_zero
      - tof_to_initial_wavelength_igs
      - tof_to_scalar_Q
      - tof_to_wavelength_lin_time_zero
      - tof_to_wavelength
      - wavelength_to_d_spacing
      - wavelength_to_energy
      - wavelength_to_scalar_k
      - wavelength_to_scalar_Q

    @param funcname: The name of the axis conversion function to use
    @type funcname: C{string}

    @param number: The value and error^2 to convert
    @type number: C{tuple}

    @param som: The object containing geometry and other special information
    @type som: C{SOM.SOM}

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

    @keyword inst_param: The type of parameter requested from an associated
                         instrument. For this function the acceptable
                         parameters are I{primary}, I{secondary} and I{total}.
                         Default is I{primary}.
    @type inst_param: C{string}

    @keyword pixel_id: The pixel ID from which the geometry information will
                       be retrieved from the instrument
    @type pixel_id: C{tuple}=(\"bankN\", (x, y))


    @return: A converted number for every unique spectrum
    @rtype: C{list} of C{tuple}s


    @raise AttributeError: The requested function is not in the approved
                           list
    """
    # Setup supported function list and check to see if funcname is available
    function_list = []
    function_list.append("d_spacing_to_tof_focused_det")
    function_list.append("energy_to_wavelength")
    function_list.append("frequency_to_energy")
    function_list.append("initial_wavelength_igs_lin_time_zero_to_tof")
    function_list.append("init_scatt_wavevector_to_scalar_Q")
    function_list.append("tof_to_initial_wavelength_igs_lin_time_zero")
    function_list.append("tof_to_initial_wavelength_igs")
    function_list.append("tof_to_scalar_Q")
    function_list.append("tof_to_wavelength_lin_time_zero")
    function_list.append("tof_to_wavelength")
    function_list.append("wavelength_to_d_spacing")
    function_list.append("wavelength_to_energy")
    function_list.append("wavelength_to_scalar_k")
    function_list.append("wavelength_to_scalar_Q")

    if funcname not in function_list:
        raise AttributeError("Function %s is not supported by "\
                             +"convert_single_to_list" % funcname)

    import common_lib

    # Get the common_lib function object
    func = common_lib.__getattribute__(funcname)

    # Setup inclusive dictionary containing the requested keywords for all
    # common_lib axis conversion functions

    fkwds = {}
    fkwds["pathlength"] = ()
    fkwds["polar"] = ()
    fkwds["lambda_f"] = ()
    try:
        lambda_final = som.attr_list["Wavelength_final"]
    except KeyError:
        lambda_final = None
    try:
        fkwds["time_zero_slope"] = som.attr_list["Time_zero_slope"]
    except KeyError:
        pass
    try:
        fkwds["time_zero_offset"] = som.attr_list["Time_zero_offset"]
    except KeyError:
        pass
    try:
        fkwds["time_zero"] = som.attr_list["Time_zero"]
    except KeyError:
        pass
    fkwds["dist_source_sample"] = ()
    fkwds["dist_sample_detector"] = ()
    try:
        fkwds["inst_param"] = kwargs["inst_param"]
    except KeyError:
        fkwds["inst_param"] = "primary"
    try:
        fkwds["pixel_id"] = kwargs["pixel_id"]
    except KeyError:
        fkwds["pixel_id"] = None
    fkwds["run_filter"] = False

    # Set up for working through data
    # This time highest object in the hierarchy is NOT what we need
    result = []
    res_descr = "list"

    inst = som.attr_list.instrument

    import hlr_utils

    # iterate through the values
    for i in xrange(hlr_utils.get_length(som)):
        map_so = hlr_utils.get_map_so(som, None, i)

        fkwds["pathlength"] = hlr_utils.get_parameter(fkwds["inst_param"],
                                                      map_so, inst)

        fkwds["dist_source_sample"] = hlr_utils.get_parameter(
            "primary", map_so, inst)

        fkwds["dist_sample_detector"] = hlr_utils.get_parameter(
            "secondary", map_so, inst)

        fkwds["polar"] = hlr_utils.get_parameter("polar", map_so, inst)

        fkwds["lambda_f"] = hlr_utils.get_special(lambda_final, map_so)

        value = tuple(func(number, **fkwds))

        hlr_utils.result_insert(result, res_descr, value, None, "all")

    return result
def tof_to_initial_wavelength_igs(obj, **kwargs):
    """
    This function converts a primary axis of a C{SOM} or C{SO} from
    time-of-flight to initial_wavelength_igs. The time-of-flight axis for a
    C{SOM} must be in units of I{microseconds}. The primary axis of a C{SO} is
    assumed to be in units of I{microseconds}. A C{tuple} of C{(tof, tof_err2)}
    (assumed to be in units of I{microseconds}) can be converted to
    C{(initial_wavelength_igs, initial_wavelength_igs_err2)}.

    @param obj: Object to be converted
    @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:
    
    @keyword lambda_f:The final wavelength and its associated error^2
    @type lambda_f: C{tuple}
    
    @keyword time_zero: The time zero offset and its associated error^2
    @type time_zero: C{tuple}
    
    @keyword dist_source_sample: The source to sample distance information and
                                 its associated error^2
    @type dist_source_sample: C{tuple} or C{list} of C{tuple}s 

    @keyword dist_sample_detector: The sample to detector distance information
                                   and its associated error^2
    @type dist_sample_detector: C{tuple} or C{list} of C{tuple}s
    
    @keyword run_filter: This determines if the filter on the negative
                         wavelengths is run. The default setting is True.
    @type run_filter: C{boolean}
    
    @keyword units: The expected units for this function. The default for this
                    function is I{microseconds}
    @type units: C{string}


    @return: Object with a primary axis in time-of-flight converted to
             initial_wavelength_igs
    @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple}


    @raise TypeError: The incoming object is not a type the function recognizes
    
    @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds}
    """

    # 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)

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

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

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

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

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

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

    # 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

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

    # Where to get instrument information
    if dist_source_sample is None or dist_sample_detector is None:
        if o_descr == "SOM":
            try:
                obj.attr_list.instrument.get_primary()
                inst = obj.attr_list.instrument
            except RuntimeError:
                raise RuntimeError("A detector was not provided!")
        else:
            if dist_source_sample is None and dist_sample_detector is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"source-sample and sample-detector "\
                                   +"distances must be provided.")
            elif dist_source_sample is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"source-sample distance must be provided.")
            elif dist_sample_detector is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"sample-detector distance must be "\
                                   +"provided.")
            else:
                raise RuntimeError("If you get here, see Steve Miller for "\
                                   +"your mug.")
    else:
        pass
        
    if lambda_f is not None:
        l_descr = hlr_utils.get_descr(lambda_f)
    else:
        if o_descr == "SOM":
            try:
                som_l_f = obj.attr_list["Wavelength_final"]
            except KeyError:
                raise RuntimeError("Please provide a final wavelength "\
                                   +"parameter either via the function call "\
                                   +"or the SOM")
        else:
            raise RuntimeError("You need to provide a final wavelength")
            

    if time_zero is not None:
        t_descr = hlr_utils.get_descr(time_zero)
    else:
        if o_descr == "SOM":
            try:
                t_0 = obj.attr_list["Time_zero"][0]
                t_0_err2 = obj.attr_list["Time_zero"][1]
            except KeyError:
                raise RuntimeError("Please provide a time-zero "\
                                   +"parameter either via the function call "\
                                   +"or the SOM")
        else:
            t_0 = 0.0
            t_0_err2 = 0.0


    if dist_source_sample is not None:
        ls_descr = hlr_utils.get_descr(dist_source_sample)
    # Do nothing, go on
    else:
        pass

    if dist_sample_detector is not None:
        ld_descr = hlr_utils.get_descr(dist_sample_detector)
    # Do nothing, go on
    else:
        pass

    # iterate through the values
    import axis_manip
    
    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)

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

        if dist_source_sample is None:
            (L_s, L_s_err2) = hlr_utils.get_parameter("primary", map_so, inst)
        else:
            L_s = hlr_utils.get_value(dist_source_sample, i, ls_descr)
            L_s_err2 = hlr_utils.get_err2(dist_source_sample, i, ls_descr)

        if dist_sample_detector is None:
            (L_d, L_d_err2) = hlr_utils.get_parameter("secondary", map_so,
                                                      inst)
        else:
            L_d = hlr_utils.get_value(dist_sample_detector, i, ld_descr)
            L_d_err2 = hlr_utils.get_err2(dist_sample_detector, i, ld_descr)

        if lambda_f is not None:
            l_f = hlr_utils.get_value(lambda_f, i, l_descr)
            l_f_err2 = hlr_utils.get_err2(lambda_f, i, l_descr)
        else:
            l_f_tuple = hlr_utils.get_special(som_l_f, map_so)
            l_f = l_f_tuple[0]
            l_f_err2 = l_f_tuple[1]
            
        if time_zero is not None:
            t_0 = hlr_utils.get_value(time_zero, i, t_descr)
            t_0_err2 = hlr_utils.get_err2(time_zero, i, t_descr)
        else:
            pass

        value = axis_manip.tof_to_initial_wavelength_igs(val, err2,
                                                         l_f, l_f_err2,
                                                         t_0, t_0_err2,
                                                         L_s, L_s_err2,
                                                         L_d, L_d_err2)

        # Remove all wavelengths < 0
        if run_filter:
            index = 0
            for val in value[0]:
                if val >= 0:
                    break
                index += 1

            value[0].__delslice__(0, index)
            value[1].__delslice__(0, index)
            map_so.y.__delslice__(0, index)
            map_so.var_y.__delslice__(0, index)
        else:
            pass

        hlr_utils.result_insert(result, res_descr, value, map_so, "x", axis)

    return result
def tof_to_initial_wavelength_igs_lin_time_zero(obj, **kwargs):
    """
    This function converts a primary axis of a C{SOM} or C{SO} from
    time-of-flight to initial_wavelength_igs_lin_time_zero. The time-of-flight
    axis for a C{SOM} must be in units of I{microseconds}. The primary axis of
    a C{SO} is assumed to be in units of I{microseconds}. A C{tuple} of
    C{(tof, tof_err2)} (assumed to be in units of I{microseconds}) can be
    converted to C{(initial_wavelength_igs, initial_wavelength_igs_err2)}.

    @param obj: Object to be converted
    @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:
    
    @keyword lambda_f:The final wavelength and its associated error^2
    @type lambda_f: C{tuple}
    
    @keyword time_zero_slope: The time zero slope and its associated error^2
    @type time_zero_slope: C{tuple}

    @keyword time_zero_offset: The time zero offset and its associated error^2
    @type time_zero_offset: C{tuple}
    
    @keyword dist_source_sample: The source to sample distance information and
                                 its associated error^2
    @type dist_source_sample: C{tuple} or C{list} of C{tuple}s 

    @keyword dist_sample_detector: The sample to detector distance information
                                   and its associated error^2
    @type dist_sample_detector: C{tuple} or C{list} of C{tuple}s
    
    @keyword run_filter: This determines if the filter on the negative
                         wavelengths is run. The default setting is True.
    @type run_filter: C{boolean}

    @keyword lojac: A flag that allows one to turn off the calculation of the
                    linear-order Jacobian. The default action is True for
                    histogram data.
    @type lojac: C{boolean}
    
    @keyword units: The expected units for this function. The default for this
                    function is I{microseconds}
    @type units: C{string}


    @return: Object with a primary axis in time-of-flight converted to
             initial_wavelength_igs
    @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple}


    @raise TypeError: The incoming object is not a type the function recognizes
    
    @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds}
    """

    # 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)

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

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

    # Current constants for Time Zero Slope
    TIME_ZERO_SLOPE = (float(0.0), float(0.0))

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

    # Current constants for Time Zero Offset
    TIME_ZERO_OFFSET = (float(0.0), float(0.0))

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

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

    try:
        lojac = kwargs["lojac"]
    except KeyError:
        lojac = hlr_utils.check_lojac(obj)

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

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

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

    # 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

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

    # Where to get instrument information
    if dist_source_sample is None or dist_sample_detector is None:
        if o_descr == "SOM":
            try:
                obj.attr_list.instrument.get_primary()
                inst = obj.attr_list.instrument
                mobj = obj
            except RuntimeError:
                raise RuntimeError("A detector was not provided!")
        else:
            if iobj is None:
                if dist_source_sample is None and dist_sample_detector is None:
                    raise RuntimeError("If a SOM is not passed, the "\
                                       +"source-sample and sample-detector "\
                                       +"distances must be provided.")
                elif dist_source_sample is None:
                    raise RuntimeError("If a SOM is not passed, the "\
                                       +"source-sample distance must be "\
                                       +"provided.")
                elif dist_sample_detector is None:
                    raise RuntimeError("If a SOM is not passed, the "\
                                       +"sample-detector distance must be "\
                                       +"provided.")
                else:
                    raise RuntimeError("If you get here, see Steve Miller "\
                                       +"for your mug.")
            else:
                inst = iobj.attr_list.instrument
                mobj = iobj                
    else:
        mobj = obj
        
    if lambda_f is not None:
        l_descr = hlr_utils.get_descr(lambda_f)
    else:
        if o_descr == "SOM":
            try:
                som_l_f = obj.attr_list["Wavelength_final"]
            except KeyError:
                raise RuntimeError("Please provide a final wavelength "\
                                   +"parameter either via the function call "\
                                   +"or the SOM")
        else:
            if iobj is None:
                raise RuntimeError("You need to provide a final wavelength")
            else:
                som_l_f = iobj.attr_list["Wavelength_final"]

    if time_zero_slope is not None:
        t_0_slope_descr = hlr_utils.get_descr(time_zero_slope)
    else:
        if o_descr == "SOM":
            try:
                t_0_slope = obj.attr_list["Time_zero_slope"][0]
                t_0_slope_err2 = obj.attr_list["Time_zero_slope"][1]
            except KeyError:
                t_0_slope = TIME_ZERO_SLOPE[0]
                t_0_slope_err2 = TIME_ZERO_SLOPE[1]
        else:
            t_0_slope = TIME_ZERO_SLOPE[0]
            t_0_slope_err2 = TIME_ZERO_SLOPE[1]

    if time_zero_offset is not None:
        t_0_offset_descr = hlr_utils.get_descr(time_zero_offset)
    else:
        if o_descr == "SOM":
            try:
                t_0_offset = obj.attr_list["Time_zero_offset"][0]
                t_0_offset_err2 = obj.attr_list["Time_zero_offset"][1]
            except KeyError:
                t_0_offset = TIME_ZERO_OFFSET[0]
                t_0_offset_err2 = TIME_ZERO_OFFSET[1]
        else:
            t_0_offset = TIME_ZERO_OFFSET[0]
            t_0_offset_err2 = TIME_ZERO_OFFSET[1]
            
    if dist_source_sample is not None:
        ls_descr = hlr_utils.get_descr(dist_source_sample)
    # Do nothing, go on
    else:
        pass

    if dist_sample_detector is not None:
        ld_descr = hlr_utils.get_descr(dist_sample_detector)
    # Do nothing, go on
    else:
        pass

    # iterate through the values
    import axis_manip
    if lojac:
        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)

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

        if dist_source_sample is None:
            (L_s, L_s_err2) = hlr_utils.get_parameter("primary", map_so, inst)
        else:
            L_s = hlr_utils.get_value(dist_source_sample, i, ls_descr)
            L_s_err2 = hlr_utils.get_err2(dist_source_sample, i, ls_descr)

        if dist_sample_detector is None:
            (L_d, L_d_err2) = hlr_utils.get_parameter("secondary", map_so,
                                                      inst)
        else:
            L_d = hlr_utils.get_value(dist_sample_detector, i, ld_descr)
            L_d_err2 = hlr_utils.get_err2(dist_sample_detector, i, ld_descr)

        if lambda_f is not None:
            l_f = hlr_utils.get_value(lambda_f, i, l_descr)
            l_f_err2 = hlr_utils.get_err2(lambda_f, i, l_descr)
        else:
            l_f_tuple = hlr_utils.get_special(som_l_f, map_so)
            l_f = l_f_tuple[0]
            l_f_err2 = l_f_tuple[1]
            
        if time_zero_slope is not None:
            t_0_slope = hlr_utils.get_value(time_zero_slope, i,
                                            t_0_slope_descr)
            t_0_slope_err2 = hlr_utils.get_err2(time_zero_slope, i,
                                                t_0_slope_descr)
        else:
            pass

        if time_zero_offset is not None:
            t_0_offset = hlr_utils.get_value(time_zero_offset, i,
                                             t_0_offset_descr)
            t_0_offset_err2 = hlr_utils.get_err2(time_zero_offset, i,
                                                 t_0_offset_descr)
        else:
            pass

        value = axis_manip.tof_to_initial_wavelength_igs_lin_time_zero(
            val, err2,
            l_f, l_f_err2,
            t_0_slope, t_0_slope_err2,
            t_0_offset, t_0_offset_err2,
            L_s, L_s_err2,
            L_d, L_d_err2)

        # Remove all wavelengths < 0
        if run_filter:
            index = 0
            for valx in value[0]:
                if valx >= 0:
                    break
                index += 1

            value[0].__delslice__(0, index)
            value[1].__delslice__(0, index)
            map_so.y.__delslice__(0, index)
            map_so.var_y.__delslice__(0, index)
            if lojac:
                val.__delslice__(0, index)
                err2.__delslice__(0, index)
        else:
            pass

        if lojac:
            try:
                counts = utils.linear_order_jacobian(val, value[0],
                                                     map_so.y, map_so.var_y)
            except Exception, e:
                # Lets us know offending pixel ID
                raise Exception(str(map_so.id) + " " + str(e))
            
            hlr_utils.result_insert(result, res_descr, counts, map_so,
                                    "all", axis, [value[0]])

        else:
            hlr_utils.result_insert(result, res_descr, value, map_so,
                                    "x", axis)
def calc_delta_theta_over_theta(som, dataset_type="data"):
    """
    This function takes a C{SOM} that contains reflectometer slit and angle
    information and calculates the parameter delta theta / theta. The function
    will also store the calculated prameter as well as other slit and angle
    information into the C{SOM}s attribute list. The function will not return
    the C{SOM} as the core data values were not changed.

    @param som: The object that contains the slit and angle information
    @type som: C{SOM.SOM}

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


    @raise TypeError: Anything other than a C{SOM} is given
    """
    import hlr_utils
    import SOM

    o_descr = hlr_utils.get_descr(som)

    if o_descr != "SOM":
        raise TypeError("Function argument must be a SOM")
    # Have a SOM, go on
    else:
        pass

    import math

    # Create a dummy SO
    so = SOM.SO()

    # Create a dummy information tuple
    no_info = (None, None, None)

    # Set instrument specific strings
    inst_name = som.attr_list["instrument_name"]
    if inst_name == "REF_L":
        first_slit_ext1 = "Slit1_top"
        first_slit_ext2 = "Slit1_bottom"
        last_slit_ext1 = "Slit2_top"
        last_slit_ext2 = "Slit2_bottom"
        last_slit_dis = "Slit2_distance"
        last_slit = "slit2"
        last_slit_distot = "slit12"
        slit_ext1 = "top"
        slit_ext2 = "bottom"
    elif inst_name == "REF_M":
        first_slit_ext1 = "Slit1_left"
        first_slit_ext2 = "Slit1_right"
        last_slit_ext1 = "Slit3_left"
        last_slit_ext2 = "Slit3_right"
        last_slit_dis = "Slit3_distance"
        last_slit = "slit3"
        last_slit_distot = "slit13"
        slit_ext1 = "left"
        slit_ext2 = "right"
    else:
        raise RuntimeError("Do not know how to handle instrument %s" % inst_name)

    # Get slit information
    try:
        slit1_ext1 = hlr_utils.get_special(som.attr_list[first_slit_ext1], so)
    except KeyError:
        slit1_ext1 = no_info

    try:
        slit1_ext2 = hlr_utils.get_special(som.attr_list[first_slit_ext2], so)
    except KeyError:
        slit1_ext2 = no_info

    try:
        slit1_dist = hlr_utils.get_special(som.attr_list["Slit1_distance"], so)
    except KeyError:
        slit1_dist = no_info

    if slit1_ext1[0] is None or slit1_ext2[0] is None:
        slit1_size_ok = False
    else:
        slit1_size_ok = True

    try:
        slit2_ext1 = hlr_utils.get_special(som.attr_list[last_slit_ext1], so)
    except KeyError:
        slit2_ext1 = no_info

    try:
        slit2_ext2 = hlr_utils.get_special(som.attr_list[last_slit_ext2], so)
    except KeyError:
        slit2_ext2 = no_info

    try:
        slit2_dist = hlr_utils.get_special(som.attr_list[last_slit_dis], so)
    except KeyError:
        slit2_dist = no_info

    if slit2_ext1[0] is None or slit2_ext2[0] is None:
        slit2_size_ok = False
    else:
        slit2_size_ok = True

    if slit1_dist[0] is None or slit2_dist[0] is None:
        slit12_dist_ok = False
    else:
        slit12_dist_ok = True

    # Unit checks
    if slit1_size_ok and slit2_size_ok:
        if slit1_ext1[2] != slit2_ext1[2]:
            raise ValueError(
                "Slit %s opening distances are not in the same "
                + "units. slit1 (%s), %s (%s)" % (slit_ext1, slit1_ext1[2], last_slit, slit2_ext1[2])
            )

        if slit1_ext2[2] != slit2_ext2[2]:
            raise ValueError(
                "Slit %s opening distances are not in the "
                + "same units. slit1 (%s), %s (%s)" % (slit_ext2, slit1_ext2[2], last_slit, slit2_ext2[2])
            )

    if slit1_dist[2] != slit2_dist[2] and slit12_dist_ok:
        raise ValueError(
            "Slit distances are not in the same units. "
            + "slit1 (%s), %s (%s)" % (slit1_dist[2], last_slit, slit2_dist[2])
        )

    # Calculate intermediate slit parameters
    if slit1_size_ok:
        slit1_size = math.fabs(slit1_ext1[0] - slit1_ext2[0])
        if slit1_ext1[2] == "millimetre":
            slit1_size /= 1000.0
            slit1_size_units = "metre"
        else:
            slit1_size_units = slit1_ext1[2]
    else:
        slit1_size = float("nan")
        slit1_size_units = None

    if slit2_size_ok:
        slit2_size = math.fabs(slit2_ext1[0] - slit2_ext2[0])
        if slit2_ext1[2] == "millimetre":
            slit2_size /= 1000.0
            slit2_size_units = "metre"
        else:
            slit2_size_units = slit2_ext1[2]
    else:
        slit2_size = float("nan")
        slit2_size_units = None

    if slit12_dist_ok:
        slit12_distance = math.fabs(slit1_dist[0] - slit2_dist[0])
        slit2_distance = math.fabs(slit2_dist[0])
    else:
        slit12_distance = float("nan")
        slit2_distance = float("nan")

    # Calculate delta theta
    if slit1_size_ok and not slit2_size_ok:
        dtheta = slit1_size / slit12_distance
    elif slit2_size_ok and not slit1_size_ok:
        dtheta = slit2_size / slit12_distance
    else:
        dtheta = max(slit1_size, slit2_size) / slit12_distance

    # Calculate delta theta over theta
    try:
        theta = hlr_utils.get_special(som.attr_list["Theta"], so)
    except KeyError:
        theta = no_info

    if theta[0] is not None:
        if theta[2] == "degrees" or theta[2] == "degree":
            theta_rads = theta[0] * (math.pi / 180.0)
        else:
            theta_rads = theta[0]
    else:
        theta_rads = float("nan")

    dtheta_over_theta = dtheta / theta_rads

    # Add parameters to attribute list
    som.attr_list[dataset_type + "-slit1_size"] = (slit1_size, slit1_size_units)
    last_slit_tag = "-%s_size" % last_slit
    som.attr_list[dataset_type + last_slit_tag] = (slit2_size, slit2_size_units)
    last_slit_dist_tag = "-%s_distance" % last_slit_distot
    som.attr_list[dataset_type + last_slit_dist_tag] = (slit12_distance, slit1_dist[2])
    som.attr_list[dataset_type + "-" + last_slit_dis.lower()] = (slit2_distance, slit1_dist[2])
    som.attr_list[dataset_type + "-delta_theta"] = (dtheta, "radians")
    som.attr_list[dataset_type + "-theta"] = (theta_rads, "radians")
    som.attr_list[dataset_type + "-dtheta_over_theta"] = dtheta_over_theta
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 #17
0
def tof_to_ref_scalar_Q(obj, **kwargs):
    """
    This function converts a primary axis of a C{SOM} or C{SO} from
    time-of-flight to reflectometer scalar Q. This means that a single angle
    and a single flightpath is used. The time-of-flight axis for a C{SOM} must
    be in units of I{microseconds}. The primary axis of a C{SO} is assumed to
    be in units of I{microseconds}. A C{tuple} of C{(time-of-flight,
    time-of-flight_err2)} (assumed to be in units of I{microseconds}) can be
    converted to C{(scalar_Q, scalar_Q_err2)}.

    @param obj: Object to be converted
    @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple}
    
    @param kwargs: A list of keyword arguments that the function accepts:
    
    @keyword polar: The polar angle and its associated error^2
    @type polar: C{tuple}
    
    @keyword pathlength: The pathlength and its associated error^2
    @type pathlength: C{tuple}

    @keyword angle_offset: A constant offset for the polar angle and its
                           associated error^2. The units of the offset should
                           be in radians.
    @type angle_offset: C{tuple}

    @keyword lojac: A flag that allows one to turn off the calculation of the
                    linear-order Jacobian. The default action is True for
                    histogram data.
    @type lojac: C{boolean}    
    
    @keyword units: The expected units for this function. The default for this
                    function is I{microseconds}.
    @type units: C{string}

    @keyword configure: This is the object containing the driver configuration.
                        This will signal the function to write out the counts
                        and fractional area to files.
    @type configure: C{Configure}


    @return: Object with a primary axis in time-of-flight converted to
             reflectometer scalar Q
    @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple}


    @raise TypeError: The incoming object is not a type the function recognizes
    
    @raise RuntimeError: A C{SOM} is not passed and no polar angle is provided
    
    @raise RuntimeError: The C{SOM} x-axis units are not I{microseconds}
    """

    # 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 == "list":
        raise TypeError("Do not know how to handle given type: %s" % \
                        o_descr)
    else:
        pass

    # Setup keyword arguments
    polar = kwargs.get("polar")
    pathlength = kwargs.get("pathlength")
    units = kwargs.get("units", "microseconds")
    lojac = kwargs.get("lojac", hlr_utils.check_lojac(obj))
    angle_offset = kwargs.get("angle_offset")
    config = kwargs.get("configure")

    if config is None:
        beamdiv_corr = False
    else:
        beamdiv_corr = config.beamdiv_corr

    # 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

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)
    if res_descr == "SOM":
        result = hlr_utils.force_units(result, "1/Angstroms", axis)
        result.setAxisLabel(axis, "scalar wavevector transfer")
        result.setYUnits("Counts/A-1")
        result.setYLabel("Intensity")
    else:
        pass

    if pathlength is None or polar is None:
        if o_descr == "SOM":
            try:
                obj.attr_list.instrument.get_primary()
                inst = obj.attr_list.instrument
            except RuntimeError:
                raise RuntimeError("A detector was not provided")
        else:
            if pathlength is None and polar is None:
                raise RuntimeError("If no SOM is provided, then pathlength "\
                                   +"and polar angle information must be "\
                                   +"provided")
            elif pathlength is None:
                raise RuntimeError("If no SOM is provided, then pathlength "\
                                   +"information must be provided")
            elif polar is None:
                raise RuntimeError("If no SOM is provided, then polar angle "\
                                   +"information must be provided")
            else:
                raise RuntimeError("If you get here, see Steve Miller for "\
                                   +"your mug.")
    else:
        pass

    if pathlength is None:
        (pl,
         pl_err2) = obj.attr_list.instrument.get_total_path(obj[0].id,
                                                            det_secondary=True)
    else:
        (pl, pl_err2) = pathlength

    if polar is None:
        angle = hlr_utils.get_special(obj.attr_list["data-theta"], obj[0])[0]
        angle_err2 = 0.0
    else:
        (angle, angle_err2) = polar

    if angle_offset is not None:
        angle += angle_offset[0]
        angle_err2 += angle_offset[1]

    # Need to multiply angle by 2.0 in order to make it be Theta to
    # underlying conversion function
    angle *= 2.0
    angle_err2 *= 4.0

    # iterate through the values
    import axis_manip
    if lojac:
        import utils

    if beamdiv_corr:
        import dr_lib

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

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

        if beamdiv_corr:
            dangle = dr_lib.ref_beamdiv_correct(obj.attr_list, map_so.id,
                                                config.det_spat_res,
                                                config.center_pix)
            # We subtract due to the inversion of the z coordinates from the
            # mirror reflection of the beam at the sample.
            if dangle is not None:
                pangle = angle - (2.0 * dangle)
            else:
                pangle = angle
                skip_pixel = True
        else:
            pangle = angle

        value = axis_manip.tof_to_scalar_Q(val, err2, pl, pl_err2, pangle,
                                           angle_err2)

        if lojac:
            y_val = hlr_utils.get_value(obj, i, o_descr, "y")
            y_err2 = hlr_utils.get_err2(obj, i, o_descr, "y")
            counts = utils.linear_order_jacobian(val, value[0], y_val, y_err2)
        else:
            pass

        if o_descr != "number":
            value1 = axis_manip.reverse_array_cp(value[0])
            value2 = axis_manip.reverse_array_cp(value[1])
            rev_value = (value1, value2)
        else:
            rev_value = value

        if map_so is not None:
            if not lojac:
                map_so.y = axis_manip.reverse_array_cp(map_so.y)
                map_so.var_y = axis_manip.reverse_array_cp(map_so.var_y)
            else:
                map_so.y = axis_manip.reverse_array_cp(counts[0])
                map_so.var_y = axis_manip.reverse_array_cp(counts[1])
        else:
            pass

        if not skip_pixel:
            hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x",
                                    axis)

    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 initial_wavelength_igs_lin_time_zero_to_tof(obj, **kwargs):
    """
    This function converts a primary axis of a C{SOM} or C{SO} from
    initial_wavelength_igs_lin_time_zero to time-of-flight. The
    initial_wavelength_igs_lin_time_zero axis for a C{SOM} must be in units of
    I{Angstroms}. The primary axis of a C{SO} is assumed to be in units of
    I{Angstroms}. A C{tuple} of C{(initial_wavelength_igs_lin_time_zero,
    initial_wavelength_igs_lin_time_zero_err2)} (assumed to be in units of
    I{Angstroms}) can be converted to C{(tof, tof_err2)}.

    @param obj: Object to be converted
    @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple}

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

    @keyword lambda_f:The final wavelength and its associated error^2
    @type lambda_f: C{tuple}

    @keyword time_zero_slope: The time zero slope and its associated error^2
    @type time_zero_slope: C{tuple}

    @keyword time_zero_offset: The time zero offset and its associated error^2
    @type time_zero_offset: C{tuple}

    @keyword dist_source_sample: The source to sample distance information and
                                 its associated error^2
    @type dist_source_sample: C{tuple} or C{list} of C{tuple}s

    @keyword dist_sample_detector: The sample to detector distance information
                                   and its associated error^2
    @type dist_sample_detector: C{tuple} or C{list} of C{tuple}s

    @keyword lojac: A flag that allows one to turn off the calculation of the
                    linear-order Jacobian. The default action is True for
                    histogram data.
    @type lojac: C{boolean}

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


    @return: Object with a primary axis in initial_wavelength_igs converted to
             time-of-flight
    @rtype: C{SOM.SOM}, C{SOM.SO} or C{tuple}


    @raise TypeError: The incoming object is not a type the function recognizes

    @raise RuntimeError: The C{SOM} x-axis units are not I{Angstroms}
    """
    # 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)

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

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

    # Current constants for Time Zero Slope
    TIME_ZERO_SLOPE = (float(0.0), float(0.0))

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

    # Current constants for Time Zero Offset
    TIME_ZERO_OFFSET = (float(0.0), float(0.0))

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

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

    try:
        lojac = kwargs["lojac"]
    except KeyError:
        lojac = hlr_utils.check_lojac(obj)

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

    # 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

    result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr)
    if res_descr == "SOM":
        result = hlr_utils.force_units(result, "Microseconds", axis)
        result.setAxisLabel(axis, "time-of-flight")
        result.setYUnits("Counts/uS")
        result.setYLabel("Intensity")
    else:
        pass

    # Where to get instrument information
    if dist_source_sample is None or dist_sample_detector is None:
        if o_descr == "SOM":
            try:
                obj.attr_list.instrument.get_primary()
                inst = obj.attr_list.instrument
            except RuntimeError:
                raise RuntimeError("A detector was not provided!")
        else:
            if dist_source_sample is None and dist_sample_detector is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"source-sample and sample-detector "\
                                   +"distances must be provided.")
            elif dist_source_sample is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"source-sample distance must be provided.")
            elif dist_sample_detector is None:
                raise RuntimeError("If a SOM is not passed, the "\
                                   +"sample-detector distance must be "\
                                   +"provided.")
            else:
                raise RuntimeError("If you get here, see Steve Miller for "\
                                   +"your mug.")
    else:
        pass
        
    if lambda_f is not None:
        l_descr = hlr_utils.get_descr(lambda_f)
    else:
        if o_descr == "SOM":
            try:
                som_l_f = obj.attr_list["Wavelength_final"]
            except KeyError:
                raise RuntimeError("Please provide a final wavelength "\
                                   +"parameter either via the function call "\
                                   +"or the SOM")
        else:
            raise RuntimeError("You need to provide a final wavelength")
            

    if time_zero_slope is not None:
        t_0_slope_descr = hlr_utils.get_descr(time_zero_slope)
    else:
        if o_descr == "SOM":
            try:
                t_0_slope = obj.attr_list["Time_zero_slope"][0]
                t_0_slope_err2 = obj.attr_list["Time_zero_slope"][1]
            except KeyError:
                t_0_slope = TIME_ZERO_SLOPE[0]
                t_0_slope_err2 = TIME_ZERO_SLOPE[1]
        else:
            t_0_slope = TIME_ZERO_SLOPE[0]
            t_0_slope_err2 = TIME_ZERO_SLOPE[1]


    if time_zero_offset is not None:
        t_0_offset_descr = hlr_utils.get_descr(time_zero_offset)
    else:
        if o_descr == "SOM":
            try:
                t_0_offset = obj.attr_list["Time_zero_offset"][0]
                t_0_offset_err2 = obj.attr_list["Time_zero_offset"][1]
            except KeyError:
                t_0_offset = TIME_ZERO_OFFSET[0]
                t_0_offset_err2 = TIME_ZERO_OFFSET[1]
        else:
            t_0_offset = TIME_ZERO_OFFSET[0]
            t_0_offset_err2 = TIME_ZERO_OFFSET[1]
            
    if dist_source_sample is not None:
        ls_descr = hlr_utils.get_descr(dist_source_sample)
    # Do nothing, go on
    else:
        pass

    if dist_sample_detector is not None:
        ld_descr = hlr_utils.get_descr(dist_sample_detector)
    # Do nothing, go on
    else:
        pass

    # iterate through the values
    len_obj = hlr_utils.get_length(obj)

    MNEUT_OVER_H = 1.0 / 0.003956034
    MNEUT_OVER_H2 = MNEUT_OVER_H * MNEUT_OVER_H

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

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

        if dist_source_sample is None:
            (L_s, L_s_err2) = hlr_utils.get_parameter("primary", map_so, inst)
        else:
            L_s = hlr_utils.get_value(dist_source_sample, i, ls_descr)
            L_s_err2 = hlr_utils.get_err2(dist_source_sample, i, ls_descr)

        if dist_sample_detector is None:
            (L_d, L_d_err2) = hlr_utils.get_parameter("secondary", map_so,
                                                      inst)
        else:
            L_d = hlr_utils.get_value(dist_sample_detector, i, ld_descr)
            L_d_err2 = hlr_utils.get_err2(dist_sample_detector, i, ld_descr)

        if lambda_f is not None:
            l_f = hlr_utils.get_value(lambda_f, i, l_descr)
            l_f_err2 = hlr_utils.get_err2(lambda_f, i, l_descr)
        else:
            l_f_tuple = hlr_utils.get_special(som_l_f, map_so)
            l_f = l_f_tuple[0]
            l_f_err2 = l_f_tuple[1]

        if time_zero_slope is not None:
            t_0_slope = hlr_utils.get_value(time_zero_slope, i,
                                            t_0_slope_descr)
            t_0_slope_err2 = hlr_utils.get_err2(time_zero_slope, i,
                                                t_0_slope_descr)
        else:
            pass

        if time_zero_offset is not None:
            t_0_offset = hlr_utils.get_value(time_zero_offset, i,
                                             t_0_offset_descr)
            t_0_offset_err2 = hlr_utils.get_err2(time_zero_offset, i,
                                                 t_0_offset_descr)
        else:
            pass

        # Going to violate rules since the current usage is with a single
        # number. When an SCL equivalent function arises, this code can be
        # fixed. 
        front_const = MNEUT_OVER_H * L_s + t_0_slope
        term2 = MNEUT_OVER_H * l_f * L_d

        tof = (front_const * val) + term2 + t_0_offset
        
        front_const2 = front_const * front_const

        eterm1 = l_f * l_f * L_d_err2
        eterm2 = L_d * L_d * l_f_err2
        eterm3 = MNEUT_OVER_H2 * L_s_err2

        tof_err2 = (front_const2 * err2) + (val * val) * \
                   (eterm3 + t_0_slope_err2) + (MNEUT_OVER_H2 * \
                                                (eterm1 + eterm2)) + \
                                                t_0_offset_err2

        hlr_utils.result_insert(result, res_descr, (tof, tof_err2), None,
                                "all")

    return result
Example #20
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