def reverse_array_cp(obj): """ This function reverses the y and var_y values of all the C{SO}s in a C{SOM} or an individual C{SO}. This is assuming that there was a previous transformation on the x-axis of the C{SO} or C{SOM}. @param obj: Object that needs to have its y and var_y values reversed @type obj: C{SOM.SOM} or C{SOM.SO} @return: Object containing the results of the reversal process @rtype: C{SOM.SOM} or C{SOM.SO} @raise TypeError: A C{tuple} or C{list} of C{tuple}s is presented 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 TypeError("Do not know how to handle given type: %s" % \ o_descr) else: pass result = hlr_utils.copy_som_attr(result, res_descr, obj, o_descr) # 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) err2 = hlr_utils.get_err2(obj, i, o_descr) value1 = axis_manip.reverse_array_cp(val) value2 = axis_manip.reverse_array_cp(err2) map_so = hlr_utils.get_map_so(obj, None, i) hlr_utils.result_insert(result, res_descr, (value1, value2), map_so) return result
def wavelength_to_velocity(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from wavelength to velocity. 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{(velocity, velocity_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 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 velocity @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: 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, "meters/microseconds", axis) result.setAxisLabel(axis, "velocity") result.setYUnits("Counts/meters/microseconds") result.setYLabel("Intensity") else: pass # iterate through the values import axis_manip if lojac: import utils len_obj = hlr_utils.get_length(obj) for i in xrange(len_obj): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) value = axis_manip.wavelength_to_velocity(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 hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x", axis) return result
def tof_to_scalar_Q(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from time-of-flight to scalarQ. 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} or C{list} of C{tuple}s @keyword pathlength: The pathlength and its associated error^2 @type pathlength: C{tuple} or C{list} of C{tuple}s @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} @return: Object with a primary axis in time-of-flight converted to 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 try: polar = kwargs["polar"] except KeyError: polar = None try: pathlength = kwargs["pathlength"] except KeyError: pathlength = None try: units = kwargs["units"] except KeyError: units = "microseconds" try: lojac = kwargs["lojac"] except KeyError: lojac = hlr_utils.check_lojac(obj) try: angle_offset = kwargs["angle_offset"] except KeyError: angle_offset = 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, "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 not None: p_descr = hlr_utils.get_descr(pathlength) else: pass if polar is not None: a_descr = hlr_utils.get_descr(polar) 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(obj, None, i) if pathlength is None: (pl, pl_err2) = hlr_utils.get_parameter("total", map_so, inst) else: pl = hlr_utils.get_value(pathlength, i, p_descr) pl_err2 = hlr_utils.get_err2(pathlength, i, p_descr) if polar is None: (angle, angle_err2) = hlr_utils.get_parameter("polar", map_so, inst) else: angle = hlr_utils.get_value(polar, i, a_descr) angle_err2 = hlr_utils.get_err2(polar, i, a_descr) if angle_offset is not None: angle += angle_offset[0] angle_err2 += angle_offset[1] value = axis_manip.tof_to_scalar_Q(val, err2, pl, pl_err2, angle, 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 hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x", axis) return result
def wavelength_to_scalar_k(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from wavelength to scalar k. 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{(scalar_k, scalar_k_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 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 scalar k @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" # 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") result.setYUnits("Counts/A-1") result.setYLabel("Intensity") 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) value = axis_manip.wavelength_to_scalar_k(val, err2) 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 map_so = hlr_utils.get_map_so(obj, None, i) if map_so is not None: 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: 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
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
def wavelength_to_scalar_Q(obj, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from wavelength to scalar Q. 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{(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} or C{list} of C{tuple}s @keyword pathlength: The pathlength and its associated error^2 @type pathlength: C{tuple} or C{list} of C{tuple}s @keyword units: The expected units for this function. The default for this function is I{Angstroms}. @type units: C{string} @return: Object with a primary axis in wavelength converted to 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{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: polar = kwargs["polar"] except KeyError: polar = None try: units = kwargs["units"] except KeyError: units = "Angstroms" 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, "1/Angstroms", axis) result.setAxisLabel(axis, "scalar wavevector transfer") result.setYUnits("Counts/A-1") result.setYLabel("Intensity") else: pass if 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: raise RuntimeError("If no SOM is provided, then polar "\ +"information must be given.") else: p_descr = hlr_utils.get_descr(polar) # 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(obj, None, i) if polar is None: (angle, angle_err2) = hlr_utils.get_parameter("polar", map_so, inst) else: angle = hlr_utils.get_value(polar, i, p_descr) angle_err2 = hlr_utils.get_err2(polar, i, p_descr) value = axis_manip.wavelength_to_scalar_Q(val, err2, angle, 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 hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x", axis) return result
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 tof_to_final_velocity_dgs(obj, velocity_i, time_zero_offset, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from time-of-flight to final_velocity_dgs. 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{(final_velocity_dgs, final_velocity_dgs_err2)}. @param obj: Object to be converted @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param velocity_i: The initial velocity and its associated error^2 @type velocity_i: C{tuple} @param time_zero_offset: The time zero offset and its associated error^2 @type time_zero_offset: C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @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 velocities 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 final_velocity_dgs @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 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: 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 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, "meters/microseconds", axis) result.setAxisLabel(axis, "velocity") result.setYUnits("Counts/meters/microseconds") 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 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 len_obj = hlr_utils.get_length(obj) for i in xrange(len_obj): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) if 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) value = axis_manip.tof_to_final_velocity_dgs(val, err2, velocity_i[0], velocity_i[1], time_zero_offset[0], time_zero_offset[1], L_s, L_s_err2, L_d, L_d_err2) # Remove all velocities < 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: (map_so.y, map_so.var_y) = utils.linear_order_jacobian( val, value[0], map_so.y, map_so.var_y) # Need to reverse arrays due to conversion if o_descr != "number": valx = axis_manip.reverse_array_cp(value[0]) valxe = axis_manip.reverse_array_cp(value[1]) rev_value = (valx, valxe) else: rev_value = value if map_so is not None: map_so.y = axis_manip.reverse_array_cp(map_so.y) map_so.var_y = axis_manip.reverse_array_cp(map_so.var_y) hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x", axis) return result
def tof_to_final_velocity_dgs(obj, velocity_i, time_zero_offset, **kwargs): """ This function converts a primary axis of a C{SOM} or C{SO} from time-of-flight to final_velocity_dgs. 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{(final_velocity_dgs, final_velocity_dgs_err2)}. @param obj: Object to be converted @type obj: C{SOM.SOM}, C{SOM.SO} or C{tuple} @param velocity_i: The initial velocity and its associated error^2 @type velocity_i: C{tuple} @param time_zero_offset: The time zero offset and its associated error^2 @type time_zero_offset: C{tuple} @param kwargs: A list of keyword arguments that the function accepts: @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 velocities 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 final_velocity_dgs @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 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: 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 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, "meters/microseconds", axis) result.setAxisLabel(axis, "velocity") result.setYUnits("Counts/meters/microseconds") 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 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 len_obj = hlr_utils.get_length(obj) for i in xrange(len_obj): val = hlr_utils.get_value(obj, i, o_descr, "x", axis) err2 = hlr_utils.get_err2(obj, i, o_descr, "x", axis) map_so = hlr_utils.get_map_so(obj, None, i) if 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) value = axis_manip.tof_to_final_velocity_dgs(val, err2, velocity_i[0], velocity_i[1], time_zero_offset[0], time_zero_offset[1], L_s, L_s_err2, L_d, L_d_err2) # Remove all velocities < 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: (map_so.y, map_so.var_y) = utils.linear_order_jacobian(val, value[0], map_so.y, map_so.var_y) # Need to reverse arrays due to conversion if o_descr != "number": valx = axis_manip.reverse_array_cp(value[0]) valxe = axis_manip.reverse_array_cp(value[1]) rev_value = (valx, valxe) else: rev_value = value if map_so is not None: map_so.y = axis_manip.reverse_array_cp(map_so.y) map_so.var_y = axis_manip.reverse_array_cp(map_so.var_y) hlr_utils.result_insert(result, res_descr, rev_value, map_so, "x", axis) return result
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