Exemple #1
0
def build_list(lattice=None, max_miller=3, extinction=None, Laue_extinction=False, max_keV=120.):
    hklplanes = []
    indices = range(-max_miller, max_miller + 1)
    for h in indices:
        for k in indices:
            for l in indices:
                if h == k == l == 0:  # skip (0, 0, 0)
                    continue
                if not extinction :
                    hklplanes.append(HklPlane(h, k, l, lattice))
                if extinction == 'FCC':
                    # take plane if only all odd or all even hkl indices
                    if (h % 2 == 0 and k % 2 == 0 and l % 2 == 0) or (h % 2 == 1 and k % 2 == 1 and l % 2 == 1):
                        hklplanes.append(HklPlane(h, k, l, lattice))
                if extinction == 'BCC':
                    # take plane only if the sum indices is even
                    if ((h**2 + k**2 + l**2) % 2 == 0):
                        hklplanes.append(HklPlane(h, k, l, lattice))
    if Laue_extinction is True:
        lam_min = lambda_keV_to_nm(max_keV)
        val = 2. * lattice._lengths[0] / lam_min # lattice have to be cubic !
        print 'Limit value is %d' % val
        for hkl in hklplanes:
            (h, k, l) = hkl.miller_indices()
            test = h ** 2 + k ** 2 + l ** 2
            if val < test: # TODO check the test
                hklplanes.remove(HklPlane(h, k, l, lattice))

    return hklplanes
Exemple #2
0
    def grain_projection_simulation(self, gid=1):
        """Function to compute all the grain projection in DCT geometry and create a composite image.

        :param int gid: the id of the grain to project (1 default).
        """
        print('forward simulation of grain %d' % gid)
        detector = self.exp.get_active_detector()
        lambda_keV = self.exp.source.max_energy
        lambda_nm = lambda_keV_to_nm(lambda_keV)
        X = np.array([1., 0., 0.]) / lambda_nm
        lattice = self.exp.get_sample().get_material()

        if not hasattr(self, 'grain'):
            # load the corresponding grain
            self.load_grain(gid=gid)

        # compute all the omega values
        print('simulating diffraction spot positions on the detector')
        omegas = np.zeros(2 * len(self.hkl_planes))
        g_uv = np.zeros((2, 2 * len(self.hkl_planes)))
        for i, plane in enumerate(self.hkl_planes):
            #print(plane.miller_indices())
            try:
                w1, w2 = self.grain.dct_omega_angles(plane,
                                                     lambda_keV,
                                                     verbose=False)
            except ValueError:
                # plane does not fulfil the Bragg condition
                continue
            omegas[2 * i] = w1
            omegas[2 * i + 1] = w2
            for j in range(2):
                omega = omegas[2 * i + j]
                omegar = omega * np.pi / 180
                R = np.array([[np.cos(omegar), -np.sin(omegar), 0],
                              [np.sin(omegar),
                               np.cos(omegar), 0], [0, 0, 1]])
                gt = self.grain.orientation_matrix().transpose()
                G = np.dot(R, np.dot(gt, plane.scattering_vector()))
                K = X + G
                # position of the grain at this rotation angle
                g_pos_rot = np.dot(R, self.grain.center)
                pg = detector.project_along_direction(K, g_pos_rot)
                (up, vp) = detector.lab_to_pixel(pg)[0]
                g_uv[:, 2 * i + j] = up, vp
        # check detector flips
        hor_flip = np.dot(detector.u_dir, [0, -1, 0]) < 0
        ver_flip = np.dot(detector.v_dir, [0, 0, -1]) < 0
        if self.verbose:
            print(detector.u_dir)
            print(detector.v_dir)
            print('detector horizontal flip: %s' % hor_flip)
            print('detector vertical flip: %s' % ver_flip)
        # compute the projections
        stack_sim = self.grain_projections(omegas,
                                           gid,
                                           hor_flip=hor_flip,
                                           ver_flip=ver_flip)
        return self.grain_projection_image(g_uv, stack_sim)
Exemple #3
0
    def grain_projection_simulation(self, gid=1, data=None):
        """Function to compute all the grain projection in DCT geometry and create a composite image."""
        print('forward simulation of grain %d' % gid)
        detector = self.exp.get_active_detector()
        lambda_keV = self.exp.source.max_energy
        lambda_nm = lambda_keV_to_nm(lambda_keV)
        X = np.array([1., 0., 0.]) / lambda_nm
        lattice = self.exp.get_sample().get_material()

        if not hasattr(self, 'grain'):
            # load the corresponding grain
            self.load_grain(gid=gid)
        from scipy import ndimage
        if data is None:
            grain_ids = self.exp.get_sample().get_grain_ids()
            print('binarizing grain %d' % gid)
            data = np.where(
                grain_ids[ndimage.find_objects(grain_ids == gid)[0]] == gid, 1,
                0)
        print('shape of binary grain is {}'.format(data.shape))

        # compute all the omega values
        print('simulating diffraction spot positions on the detector')
        omegas = np.zeros(2 * len(self.hkl_planes))
        g_uv = np.zeros((2, 2 * len(self.hkl_planes)))
        for i, plane in enumerate(self.hkl_planes):
            #print(plane.miller_indices())
            try:
                w1, w2 = self.grain.dct_omega_angles(plane,
                                                     lambda_keV,
                                                     verbose=False)
            except ValueError:
                # plane does not fulfil the Bragg condition
                continue
            omegas[2 * i] = w1
            omegas[2 * i + 1] = w2
            for j in range(2):
                omega = omegas[2 * i + j]
                omegar = omega * np.pi / 180
                R = np.array([[np.cos(omegar), -np.sin(omegar), 0],
                              [np.sin(omegar),
                               np.cos(omegar), 0], [0, 0, 1]])
                gt = self.grain.orientation_matrix().transpose()
                G = np.dot(R, np.dot(gt, plane.scattering_vector()))
                K = X + G
                # position of the grain at this rotation angle
                g_pos_rot = np.dot(R, self.grain.center)
                pg = detector.project_along_direction(K, g_pos_rot)
                (up, vp) = detector.lab_to_pixel(pg)[0]
                g_uv[:, 2 * i + j] = up, vp
        # build the 3d projection stack at once
        print('building grain projections stack')
        stack_sim = radiographs(data, omegas)
        stack_sim = stack_sim.transpose(
            2, 0, 1)[:, :, ::
                     -1]  # (u, v) axes correspond to (Y, -Z) for DCT detector
        return self.grain_projection_image(g_uv, stack_sim)
Exemple #4
0
 def test_Bragg_condition(self):
     al = Lattice.from_symbol('Al')
     p = HklPlane(0, 0, 2, lattice=al)
     lambda_keV = 42
     lambda_nm = lambda_keV_to_nm(lambda_keV)
     rod = [0.1449, -0.0281, 0.0616]
     o = Orientation.from_rodrigues(rod)
     (w1, w2) = o.dct_omega_angles(p, lambda_keV, verbose=False)
     # test the two solution of the rotating crystal
     for omega in (w1, w2):
         alpha = o.compute_XG_angle(p, omega, verbose=True)
         theta_bragg = p.bragg_angle(lambda_keV)
         self.assertAlmostEqual(alpha, 180 / np.pi * (np.pi / 2 - theta_bragg))
Exemple #5
0
def dct_projection(orientations, data, dif_grains, omega, lambda_keV, detector, lattice, include_direct_beam=True,
                   att=5, verbose=True):
    '''Work in progress, will replace function in the microstructure module.'''
    full_proj = np.zeros(detector.size, dtype=np.float)
    lambda_nm = lambda_keV_to_nm(lambda_keV)
    omegar = omega * np.pi / 180
    R = np.array([[np.cos(omegar), -np.sin(omegar), 0], [np.sin(omegar), np.cos(omegar), 0], [0, 0, 1]])

    if include_direct_beam:
        # add the direct beam part by computing the radiograph of the sample without the diffracting grains
        data_abs = np.where(data > 0, 1, 0)
        for (gid, (h, k, l)) in dif_grains:
            mask_dif = (data == gid)
            data_abs[mask_dif] = 0  # remove this grain from the absorption
        proj = radiograph(data_abs, omega)
        add_to_image(full_proj, proj[::-1, ::-1] / att, np.array(full_proj.shape) // 2)

    # add diffraction spots
    X = np.array([1., 0., 0.]) / lambda_nm
    for (gid, (h, k, l)) in dif_grains:
        grain_data = np.where(data == gid, 1, 0)
        if np.sum(grain_data) < 1:
            print('skipping grain %d' % gid)
            continue
        local_com = np.array(ndimage.measurements.center_of_mass(grain_data, data))
        print('local center of mass (voxel): {0}'.format(local_com))
        g_center_mm = detector.pixel_size * (local_com - 0.5 * np.array(data.shape))
        print('center of mass (voxel): {0}'.format(local_com - 0.5 * np.array(data.shape)))
        print('center of mass (mm): {0}'.format(g_center_mm))
        # compute scattering vector
        gt = orientations[gid].orientation_matrix().transpose()
        # gt = micro.get_grain(gid).orientation_matrix().transpose()
        p = HklPlane(h, k, l, lattice)
        G = np.dot(R, np.dot(gt, p.scattering_vector()))
        K = X + G
        # position of the grain at this rotation
        g_pos_rot = np.dot(R, g_center_mm)
        pg = detector.project_along_direction(K, g_pos_rot)
        (up, vp) = detector.lab_to_pixel(pg)
        if verbose:
            print('\n* gid=%d, (%d,%d,%d) plane, angle=%.1f' % (gid, h, k, l, omega))
            print('diffraction vector:', K)
            print('postion of the grain at omega=%.1f is ' % omega, g_pos_rot)
            print('up=%d, vp=%d for plane (%d,%d,%d)' % (up, vp, h, k, l))
        data_dif = grain_data[ndimage.find_objects(data == gid)[0]]
        proj_dif = radiograph(data_dif, omega)  # (Y, Z) coordinate system
        add_to_image(full_proj, proj_dif[::-1, ::-1], (up, vp), verbose)  # (u, v) axes correspond to (-Y, -Z)
    return full_proj
Exemple #6
0
def compute_Laue_pattern(orientation, detector, hkl_planes=None, Xu=np.array([1., 0., 0.]), use_friedel_pair=False,
                         spectrum=None, spectrum_thr=0., r_spot=5, color_field='constant', inverted=False,
                         show_direct_beam=False, verbose=False):
    """
    Compute a transmission Laue pattern. The data array of the given
    `Detector2d` instance is initialized with the result.
    
    The incident beam is assumed to be along the X axis: (1, 0, 0) but can be changed to any direction. 
    The crystal can have any orientation using an instance of the `Orientation` class. 
    The `Detector2d` instance holds all the geometry (detector size and position).

    A parameter controls the meaning of the values in the diffraction spots in the image. It can be just a constant 
    value, the diffracted beam energy (in keV) or the intensity as computed by the :py:meth:`diffracted_intensity` 
    method.

    :param orientation: The crystal orientation.
    :param detector: An instance of the Detector2d class.
    :param list hkl_planes: A list of the lattice planes to include in the pattern.
    :param Xu: The unit vector of the incident X-ray beam (default along the X-axis).
    :param bool use_friedel_pair: also consider the Friedel pair of each lattice plane in the list as candidate for diffraction. 
    :param spectrum: A two columns array of the spectrum to use for the calculation.
    :param float spectrum_thr: The threshold to use to determine if a wave length is contributing or not.
    :param int r_spot: Size of the spots on the detector in pixel (5 by default)
    :param str color_field: a traing describing, must be 'constant', 'energy' or 'intensity'
    :param bool inverted: A flag to control if the pattern needs to be inverted.
    :param bool show_direct_beam: A flag to control if the direct beam is shown.
    :param bool verbose: activate verbose mode (False by default).
    :return: the computed pattern as a numpy array.
    """
    detector.data = np.zeros(detector.size, dtype=np.float32)
    # create a small square image for one spot
    spot = np.ones((2 * r_spot + 1, 2 * r_spot + 1), dtype=np.uint8)
    max_val = np.iinfo(np.uint8).max  # 255 here
    direct_beam_lab = detector.project_along_direction(Xu)
    direct_beam_pix = detector.lab_to_pixel(direct_beam_lab)[0]
    if show_direct_beam:
        add_to_image(detector.data, max_val * 3 * spot, (direct_beam_pix[0], direct_beam_pix[1]))
    if spectrum is not None:
        print('using spectrum')
        #indices = np.argwhere(spectrum[:, 1] > spectrum_thr)
        E_min = min(spectrum) #float(spectrum[indices[0], 0])
        E_max = max(spectrum) #float(spectrum[indices[-1], 0])
        lambda_min = lambda_keV_to_nm(E_max)
        lambda_max = lambda_keV_to_nm(E_min)
        #if verbose:
        print('energy bounds: [{0:.1f}, {1:.1f}] keV'.format(E_min, E_max))

    for hkl in hkl_planes:
        (the_energy, theta) = select_lambda(hkl, orientation, Xu=Xu, verbose=False)
        if the_energy < 0:
            if use_friedel_pair:
                if verbose:
                    print('switching to Friedel pair')
                hkl = hkl.friedel_pair()
                (the_energy, theta) = select_lambda(hkl, orientation, Xu=Xu, verbose=False)
            else:
                continue
        assert(the_energy >= 0)
        if spectrum is not None:
            if the_energy < E_min or the_energy > E_max:
                #print('skipping reflection {0:s} which would diffract at {1:.1f}'.format(hkl.miller_indices(), abs(the_energy)))
                continue
                #print('including reflection {0:s} which will diffract at {1:.1f}'.format(hkl.miller_indices(), abs(the_energy)))
        K = diffracted_vector(hkl, orientation, Xu=Xu, use_friedel_pair=False, verbose=verbose)
        if K is None or np.dot(Xu, K) == 0:
            continue  # skip diffraction // to the detector
        d = np.dot((detector.ref_pos - np.array([0., 0., 0.])), detector.w_dir) / np.dot(K, detector.w_dir)
        if d < 0:
            if verbose:
                print('skipping diffraction not towards the detector')
            continue

        R = detector.project_along_direction(K, origin=[0., 0., 0.])
        (u, v) = detector.lab_to_pixel(R)[0]
        if verbose and u >= 0 and u < detector.size[0] and v >= 0 and v < detector.size[1]:
            print('* %d%d%d reflexion' % hkl.miller_indices())
            print('diffracted beam will hit the detector at (%.3f, %.3f) mm or (%d, %d) pixels' % (R[1], R[2], u, v))
            print('diffracted beam energy is {0:.1f} keV'.format(abs(the_energy)))
            print('Bragg angle is {0:.2f} deg'.format(abs(theta * 180 / pi)))
        # mark corresponding pixels on the image detector
        if color_field == 'constant':
            add_to_image(detector.data, max_val * spot, (u, v))
        elif color_field == 'energy':
            add_to_image(detector.data, abs(the_energy) * spot.astype(float), (u, v))
        elif color_field == 'intensity':
            I = diffracted_intensity(hkl, I0=max_val, verbose=verbose)
            add_to_image(detector.data, I * spot, (u, v))
        else:
            raise ValueError('unsupported color_field: %s' % color_field)
    if inverted:
        # np.invert works only with integer types
        print('casting to uint8 and inverting image')
        # limit maximum to max_val (255) and convert to uint8
        over = detector.data > 255
        detector.data[over] = 255
        detector.data = detector.data.astype(np.uint8)
        detector.data = np.invert(detector.data)
    return detector.data
Exemple #7
0
    def dct_projection(self, omega, include_direct_beam=True, att=5):
        """Function to compute a full DCT projection at a given omega angle.

        :param float omega: rotation angle in degrees.
        :param bool include_direct_beam: flag to compute the transmission through the sample.
        :param float att: an attenuation factor used to limit the gray levels in the direct beam.
        :return: the dct projection as a 2D numpy array
        """
        if len(self.reflections) == 0:
            print(
                'empty list of reflections, you should run the setup function first'
            )
            return None
        grain_ids = self.exp.get_sample().get_grain_ids()
        detector = self.exp.get_active_detector()
        lambda_keV = self.exp.source.max_energy
        lattice = self.exp.get_sample().get_material()
        index = np.argmax(self.omegas > omega)
        dif_grains = self.reflections[
            index -
            1]  # grains diffracting between omegas[index - 1] and omegas[index]
        # intialize image result
        full_proj = np.zeros(detector.get_size_px(), dtype=np.float)
        lambda_nm = lambda_keV_to_nm(lambda_keV)
        omegar = omega * np.pi / 180
        R = np.array([[np.cos(omegar), -np.sin(omegar), 0],
                      [np.sin(omegar), np.cos(omegar), 0], [0, 0, 1]])

        if include_direct_beam:
            # add the direct beam part by computing the radiograph of the sample without the diffracting grains
            data_abs = np.where(grain_ids > 0, 1, 0)
            for (gid, (h, k, l)) in dif_grains:
                mask_dif = (grain_ids == gid)
                data_abs[mask_dif] = 0  # remove this grain from the absorption
            proj = radiograph(
                data_abs, omega
            )[:, ::-1]  # (u, v) axes correspond to (Y, -Z) for DCT detector
            add_to_image(full_proj, proj / att, np.array(full_proj.shape) // 2)

        # add diffraction spots
        X = np.array([1., 0., 0.]) / lambda_nm
        for (gid, (h, k, l)) in dif_grains:
            grain_data = np.where(grain_ids == gid, 1, 0)
            if np.sum(grain_data) < 1:
                print('skipping grain %d' % gid)
                continue
            local_com = np.array(
                ndimage.measurements.center_of_mass(grain_data, grain_ids))
            print('local center of mass (voxel): {0}'.format(local_com))
            g_center_mm = detector.get_pixel_size() * (
                local_com - 0.5 * np.array(grain_ids.shape))
            print('center of mass (voxel): {0}'.format(
                local_com - 0.5 * np.array(grain_ids.shape)))
            print('center of mass (mm): {0}'.format(g_center_mm))
            # compute scattering vector
            gt = self.exp.get_sample().get_microstructure().get_grain(
                gid).orientation_matrix().transpose()
            p = HklPlane(h, k, l, lattice)
            G = np.dot(R, np.dot(gt, p.scattering_vector()))
            K = X + G
            # position of the grain at this rotation angle
            g_pos_rot = np.dot(R, g_center_mm)
            pg = detector.project_along_direction(K, g_pos_rot)
            up, vp = detector.lab_to_pixel(pg)[0]
            if self.verbose:
                print('\n* gid=%d, (%d,%d,%d) plane, angle=%.1f' %
                      (gid, h, k, l, omega))
                print('diffraction vector:', K)
                print('postion of the grain at omega=%.1f is ' % omega,
                      g_pos_rot)
                print('up=%d, vp=%d for plane (%d,%d,%d)' % (up, vp, h, k, l))
            data_dif = grain_data[ndimage.find_objects(grain_ids == gid)[0]]
            proj_dif = radiograph(data_dif, omega)  # (Y, Z) coordinate system
            add_to_image(full_proj, proj_dif[:, ::-1], (up, vp),
                         self.verbose)  # (u, v) axes correspond to (Y, -Z)
        return full_proj