예제 #1
0
    def get_pole_figure_vectors(self, det_id, max_cost, min_cost=1.):
        """ return Pole figure in a numpy 2D array
        :param det_id:
        :param max_cost:
        :param min_cost:
        :return: 2-tuple: (1) an integer list (2) numpy array with shape (n, 3).  n is the number of data points
        """
        # check input
        if max_cost is None:
            max_cost = 1.E20
        else:
            checkdatatypes.check_float_variable(
                'Maximum peak fitting cost value', max_cost, (0., None))

        # get raw parameters' fitted value
        log_index_vec, pole_figure_vec = self._pole_figure_dict[det_id]

        # get costs and filter out isnan()
        cost_vec = self.get_peak_fit_parameter_vec('cost', det_id)

        taken_index_list = list()
        for idx in range(len(cost_vec)):
            if min_cost < cost_vec[idx] < max_cost:
                taken_index_list.append(idx)
        # END-IF

        selected_log_index_vec = np.take(log_index_vec,
                                         taken_index_list,
                                         axis=0)
        selected_pole_figure_vec = np.take(pole_figure_vec,
                                           taken_index_list,
                                           axis=0)

        return selected_log_index_vec, selected_pole_figure_vec
예제 #2
0
def save_mantid_mask(mask_vec, h5_name, two_theta, note):
    """
    Save a mask vector to
    :param mask_vec:
    :param h5_name:
    :param two_theta:
    :param note:
    :return:
    """
    checkdatatypes.check_numpy_arrays('Mask vector', [mask_vec],
                                      dimension=1,
                                      check_same_shape=False)
    checkdatatypes.check_file_name(h5_name, False, True, False,
                                   'PyRS masking file to export to')
    if two_theta is not None:
        checkdatatypes.check_float_variable('2-theta', two_theta, (-360., 360))
    if note is not None:
        checkdatatypes.check_string_variable('Mask note', note, None)

    # create file
    mask_file = h5py.File(h5_name, 'w')
    # add data set
    mask_data_set = mask_file.create_dataset('mask', data=mask_vec)
    # add attributes
    if two_theta:
        mask_data_set.attrs['2theta'] = two_theta  # '{}'.format(two_theta)
    if note:
        mask_data_set.attrs['note'] = note
    # close file
    mask_file.close()

    return
예제 #3
0
    def write_wavelength(self, wave_length):
        """ Set the calibrated wave length
        Location:
          .../instrument/monochromator setting/ ... .../
        Note:
        - same wave length to all sub runs
        - only calibrated wave length in project file
        - raw wave length comes from a table with setting
        :param wave_length: wave length in A
        :return: None
        """
        checkdatatypes.check_float_variable('Wave length', wave_length,
                                            (0, 1000))

        # Create 'monochromator setting' node if it does not exist
        if HidraConstants.MONO not in list(
                self._project_h5[HidraConstants.INSTRUMENT].keys()):
            self._project_h5[HidraConstants.INSTRUMENT].create_group(
                HidraConstants.MONO)

        # Get node and write value
        wl_entry = self._project_h5[HidraConstants.INSTRUMENT][
            HidraConstants.MONO]
        # delete the dataset if it does exist to replace
        if HidraConstants.WAVELENGTH in list(wl_entry.keys()):
            del wl_entry[HidraConstants.WAVELENGTH]
        wl_entry.create_dataset(HidraConstants.WAVELENGTH,
                                data=numpy.array([wave_length]))
예제 #4
0
    def set_single_wavelength(self, wavelength):
        """
        If the instrument has only 1 wave length setup
        :param wavelength: wave length in unit A
        :return:
        """
        checkdatatypes.check_float_variable('Monochromator wavelength (A)',
                                            wavelength, (1.E-5, None))

        self._single_wave_length = wavelength
예제 #5
0
    def set_2theta(self, two_theta):
        """
        set 2theta value
        :param two_theta:
        :return:
        """
        checkdatatypes.check_float_variable('Two theta', two_theta,
                                            (-180, 180))

        self._2theta = two_theta

        return
예제 #6
0
    def set_wavelength_calibration(self, wave_length_shift):
        """
        set the wave length shift
        :param wave_length_shift:
        :return:
        """
        checkdatatypes.check_float_variable(
            'Wavelength shift from original value', wave_length_shift,
            (None, None))

        if self._wave_length + wave_length_shift < 0.1:
            raise RuntimeError(
                'Wavelength shift {} to {} results in an unphysical value'.
                format(self._wave_length, wave_length_shift))
예제 #7
0
    def set_experimental_data(self, two_theta, l2, raw_count_vec):
        """ Set experimental data (for a sub-run)
        :param two_theta: detector position
        :param raw_count_vec: detector raw counts
        :return:
        """
        checkdatatypes.check_float_variable('2-theta', two_theta, (-180, 180))
        checkdatatypes.check_numpy_arrays('Detector (raw) counts',
                                          [raw_count_vec], None, False)
        if l2 is not None:
            checkdatatypes.check_float_variable('L2', l2, (1.E-2, None))

        self._detector_2theta = two_theta
        self._detector_l2 = l2
        self._detector_counts = raw_count_vec

        return
예제 #8
0
    def rotate_project_q(self, theta, omega, chi, phi, eta):
        """
        Projection of angular dependent data onto pole sphere. Analytical solution taken from
        Chapter 8.3 in Bob He Two-Dimensional X-ray Diffraction

        _______________________
        :param two_theta:
        :param omega:
        :param chi:
        :param phi:
        :return: 2-tuple as the projection (alpha, beta)
        """
        checkdatatypes.check_float_variable('theta', theta, (None, None))
        checkdatatypes.check_float_variable('Omega', omega, (None, None))
        checkdatatypes.check_float_variable('chi', chi, (None, None))
        checkdatatypes.check_float_variable('phi', phi, (None, None))
        checkdatatypes.check_float_variable('eta', eta, (None, None))

        sp = np.sin(np.deg2rad(phi))
        sw = np.sin(np.deg2rad(omega))
        sc = np.sin(np.deg2rad(chi))
        sg = np.sin(np.deg2rad(eta))
        st = np.sin(np.deg2rad(theta))

        cp = np.cos(np.deg2rad(phi))
        cw = np.cos(np.deg2rad(omega))
        cc = np.cos(np.deg2rad(chi))
        cg = np.cos(np.deg2rad(eta))
        ct = np.cos(np.deg2rad(theta))

        h1 = st * (sp * sc * sw + cp * cw) + ct * cg * sp * cc - ct * sg * (
            sp * sc * cw - cp * sw)
        h2 = -st * (cp * sc * sw - sp * cw) - ct * cg * cp * cc + ct * sg * (
            cp * sc * cw + sp * sw)
        # h3 = st*cc*sw - ct*sg*cc*cw - ct*cg*sc
        h_length = np.sqrt(np.square(h1) + np.square(h2))

        alpha = np.arccos(h_length)
        beta = np.rad2deg(np.arccos(h1 / h_length))
        if h2 < 0:
            beta *= -1.

        return alpha, beta
예제 #9
0
    def set_2theta(self, two_theta, unit='degree'):
        """
        Set 2 theta value
        :param two_theta:
        :param unit: degree or radius
        :return:
        """
        checkdatatypes.check_string_variable('2theta unit', unit,
                                             ['degree', 'radius'])

        if unit == 'degree':
            two_theta_range = (-180., 180)
        else:
            two_theta_range = (-math.pi, math.pi)
        checkdatatypes.check_float_variable('2theta', two_theta,
                                            two_theta_range)

        self._two_theta = two_theta, unit

        return
예제 #10
0
    def __init__(self, num_rows, num_columns, pixel_size_x, pixel_size_y,
                 arm_length, calibrated):
        """
        Initialization of instrument geometry setup for 1 angler camera
        :param num_rows: number of rows of pixels in detector (number of pixels per column)
        :param num_columns: number of columns of pixels in detector (number of pixels per row)
        :param pixel_size_x: pixel size at X direction (along a row)
        :param pixel_size_y: pixel size at Y direction (along a column)
        :param arm_length: arm length
        :param calibrated: flag whether these values are calibrated
        """
        # check inputs
        checkdatatypes.check_float_variable('Arm length', arm_length,
                                            (1E-5, None))
        checkdatatypes.check_float_variable('Pixel size (x)', pixel_size_x,
                                            (1E-7, None))
        checkdatatypes.check_float_variable('Pixel size (y)', pixel_size_y,
                                            (1E-7, None))
        checkdatatypes.check_int_variable('Number of rows in detector',
                                          num_rows, (1, None))
        checkdatatypes.check_int_variable('Number of columns in detector',
                                          num_columns, (1, None))
        checkdatatypes.check_bool_variable(
            'Flag indicating instrument setup been calibrated', calibrated)

        # geometry parameters for raw parameters
        self._arm_length = arm_length

        self._detector_rows = num_rows
        self._detector_columns = num_columns
        self._pixel_size_x = pixel_size_x
        self._pixel_size_y = pixel_size_y
예제 #11
0
    def add_matched_grid(self, grid_pos_x, grid_pos_y, grid_pos_z,
                         param_value_11, param_value_22, param_value_33):
        """
        add an all-direction matched grid
        :param grid_pos_x:
        :param grid_pos_y:
        :param grid_pos_z:
        :param param_value_11:
        :param param_value_22:
        :param param_value_33:
        :return:
        """
        checkdatatypes.check_float_variable('Parameter value for e11',
                                            param_value_11, (None, None))
        checkdatatypes.check_float_variable('Parameter value for e22',
                                            param_value_22, (None, None))
        if param_value_33 is not None:
            checkdatatypes.check_float_variable('Parameter value for e33',
                                                param_value_33, (None, None))

        self.append_row([
            grid_pos_x, grid_pos_y, grid_pos_z, param_value_11, param_value_22,
            param_value_33
        ])
예제 #12
0
 def rotation_z(self, value):
     checkdatatypes.check_float_variable('Rotation along Z direction',
                                         value, (-360, 360))
     self._rotation_z = value
예제 #13
0
 def center_shift_z(self, value):
     checkdatatypes.check_float_variable('Center shift along Z direction',
                                         value, (None, None))
     self._center_shift_z = value
예제 #14
0
    def build_instrument(self, two_theta, l2, instrument_calibration):
        """
        build instrument considering calibration
        step 1: rotate instrument according to the calibration
        step 2: rotate instrument about 2theta
        :param two_theta
        :param instrument_calibration: AnglerCameraDetectorShift or None (no calibration)
        :return:
        """
        # Check input
        checkdatatypes.check_float_variable('2theta', two_theta, (None, None))
        # Check or set L2
        if l2 is None:
            l2 = self._instrument_geom_params.arm_length
        else:
            checkdatatypes.check_float_variable('L2', l2, (1E-2, None))

        # print('[DB...L101] Build instrument: 2theta = {}, arm = {} (diff to default = {})'
        #       ''.format(two_theta, l2, l2 - self._instrument_geom_params.arm_length))

        # make a copy from raw (constant position)
        self._pixel_matrix = self._raw_pixel_matrix.copy()

        # Check and set instrument calibration
        if instrument_calibration is not None:
            # check type
            checkdatatypes.check_type(
                'Instrument calibration', instrument_calibration,
                instrument_geometry.AnglerCameraDetectorShift)

            # shift center
            self._pixel_matrix[:, :,
                               0] += instrument_calibration.center_shift_x
            self._pixel_matrix[:, :,
                               1] += instrument_calibration.center_shift_y

            # rotation around instrument center
            # get rotation matrix at origin (for flip, spin and vertical): all data from calibration value
            rot_x_flip = instrument_calibration.rotation_x * np.pi / 180.
            rot_y_flip = instrument_calibration.rotation_y * np.pi / 180.
            rot_z_spin = instrument_calibration.rotation_z * np.pi / 180.
            calib_matrix = self.generate_rotation_matrix(
                rot_x_flip, rot_y_flip, rot_z_spin)
            # print ('[DB...BAT] Calibration rotation matrix:\n{}'.format(calib_matrix))
            # and rotate at origin
            self._pixel_matrix = self._rotate_detector(self._pixel_matrix,
                                                       calib_matrix)
        # END-IF-ELSE

        # push to +Z at length of detector arm
        arm_l2 = l2
        if instrument_calibration is not None:
            # Apply the shift on Z (arm length)
            arm_l2 += instrument_calibration.center_shift_z
        # END-IF
        self._pixel_matrix[:, :, 2] += arm_l2

        # rotate detector (2theta) if it is not zero
        self.rotate_detector_2theta(two_theta)

        return self._pixel_matrix
예제 #15
0
    def generate_2theta_histogram_vector(min_2theta, num_bins, max_2theta,
                                         pixel_2theta_array, mask_array):
        """Generate a 1-D array for histogram 2theta bins

        Parameters
        ----------
        min_2theta : float or None
            minimum 2theta or None
        num_bins : int
            nubmer of bins
        max_2theta : float  or None
             maximum 2theta and must be integer
        pixel_2theta_array : numpy.ndarray
            2theta of each detector pixel
        mask_array : numpy.ndarray or None
            array of mask

        Returns
        -------
        numpy.ndarray
            2theta values serving as bin boundaries, such its size is 1 larger than num_bins

        """
        # If default value is required: set the default
        if min_2theta is None or max_2theta is None:
            # check inputs
            if mask_array is None:
                checkdatatypes.check_numpy_arrays('Pixel 2theta angles',
                                                  [pixel_2theta_array], 1,
                                                  False)
            else:
                checkdatatypes.check_numpy_arrays(
                    'Pixel 2theta position and mask array',
                    [pixel_2theta_array, mask_array], 1, True)
                # mask
                pixel_2theta_array = pixel_2theta_array[np.where(
                    mask_array == 1)]
            # END-IF

            if min_2theta is None:
                # lower boundary of 2theta for bins is the minimum 2theta angle of all the pixels
                min_2theta = np.min(pixel_2theta_array)
            if max_2theta is None:
                # upper boundary of 2theta for bins is the maximum 2theta angle of all the pixels
                max_2theta = np.max(pixel_2theta_array)
        # END-IF

        step_2theta = (max_2theta - min_2theta) * 1. / num_bins

        # Check inputs
        checkdatatypes.check_float_variable('Minimum 2theta', min_2theta,
                                            (-180, 180))
        checkdatatypes.check_float_variable('Maximum 2theta', max_2theta,
                                            (-180, 180))
        checkdatatypes.check_float_variable('2theta bin size', step_2theta,
                                            (0, 180))
        if min_2theta >= max_2theta:
            raise RuntimeError(
                '2theta range ({}, {}) is invalid for generating histogram'
                ''.format(min_2theta, max_2theta))

        # Create 2theta: these are bin edges from (min - 1/2) to (max + 1/2) with num_bins bins
        # and (num_bins + 1) data points
        vec_2theta = np.arange(num_bins + 1).astype(float) * step_2theta + (
            min_2theta - step_2theta)
        if vec_2theta.shape[0] != num_bins + 1:
            raise RuntimeError(
                'Expected = {} vs {}\n2theta min max  = {}, {}\n2thetas: {}'
                ''.format(num_bins, vec_2theta.shape, min_2theta, max_2theta,
                          vec_2theta))

        # Sanity check
        assert vec_2theta.shape[0] == num_bins + 1, '2theta bins (boundary)\'size ({}) shall be exactly ' \
                                                    '1 larger than specified num_bins ({})' \
                                                    ''.format(vec_2theta.shape, num_bins)

        return vec_2theta