Пример #1
0
 def test_topotomo_tilts(self):
     # tests cases from ma2285 experiment on id11, omega offset = -90
     T = np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]])
     al = Lattice.from_symbol('Al')
     p = HklPlane(0, 0, 2, lattice=al)
     rod = [0.1449, -0.0281, 0.0616]
     o = Orientation.from_rodrigues(rod)
     (ut, lt) = o.topotomo_tilts(p, T)
     self.assertAlmostEqual(180 / np.pi * ut, 2.236, 3)
     self.assertAlmostEqual(180 / np.pi * lt, 16.615, 3)
     # use test case from AlLi_sam8_dct_cen_
     p = HklPlane(2, 0, 2, lattice=al)
     rod = [0.0499, -0.3048, 0.1040]
     o = Orientation.from_rodrigues(rod)
     (ut, lt) = o.topotomo_tilts(p, T)
     self.assertAlmostEqual(180 / np.pi * ut, -11.04, 2)
     self.assertAlmostEqual(180 / np.pi * lt, -0.53, 2)
     # test case from ma3921
     T = Orientation.compute_instrument_transformation_matrix(-1.2, 0.7, 90)
     Ti7Al = Lattice.hexagonal(0.2931, 0.4694)  # nm
     (h, k, l) = HklPlane.four_to_three_indices(-1, 2, -1, 0)
     p = HklPlane(h, k, l, Ti7Al)
     o = Orientation.from_rodrigues([0.7531, 0.3537, 0.0621])
     (ut, lt) = o.topotomo_tilts(p, T)
     self.assertAlmostEqual(180 / np.pi * ut, 11.275, 2)
     self.assertAlmostEqual(180 / np.pi * lt, -4.437, 2)
Пример #2
0
 def test_HklPlane_normal(self):
     ZrO2 = Lattice.tetragonal(3.64, 5.27)
     p = HklPlane(1, 1, 1, ZrO2)
     n = p.normal()
     self.assertAlmostEqual(n[0], 0.635, 3)
     self.assertAlmostEqual(n[1], 0.635, 3)
     self.assertAlmostEqual(n[2], 0.439, 3)
Пример #3
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
Пример #4
0
 def test_equality(self):
     p1 = HklPlane(1, 1, 1)
     p2 = HklPlane(1, 1, 1)
     p3 = HklPlane(-1, 1, 1)
     self.assertEqual(p1, p2)
     self.assertTrue(p1 == p2)
     self.assertTrue(p1 != p3)
Пример #5
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))
Пример #6
0
 def test_topotomo_tilts(self):
     al = Lattice.from_symbol('Al')
     p = HklPlane(0, 0, 2, lattice=al)
     rod = [0.1449, -0.0281, 0.0616]
     o = Orientation.from_rodrigues(rod)
     (ut, lt) = o.topotomo_tilts(p)
     self.assertAlmostEqual(180 / np.pi * ut, 2.236, 3)
     self.assertAlmostEqual(180 / np.pi * lt, -16.615, 3)
     # use test case from AlLi_sam8_dct_cen_
     p = HklPlane(2, 0, 2, lattice=al)
     rod = [0.0499, -0.3048, 0.1040]
     o = Orientation.from_rodrigues(rod)
     (ut, lt) = o.topotomo_tilts(p)
     self.assertAlmostEqual(180 / np.pi * ut, -11.04, 2)
     self.assertAlmostEqual(180 / np.pi * lt, 0.53, 2)
Пример #7
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
Пример #8
0
 def test_indexation(self):
     """Verify indexing solution from a known Laue pattern."""
     euler_angles = (191.9, 69.9, 138.9)  # degrees, /!\ not in fz
     orientation = Orientation.from_euler(euler_angles)
     # list of plane normals, obtained from the detector image
     hkl_normals = np.array(
         [[0.11066932863248755, 0.8110118739480003, 0.5744667440465002],
          [0.10259261224575777, 0.36808036454584847, -0.9241166599236196],
          [0.12497400210731163, 0.38160000643453934, 0.9158400154428944],
          [0.21941448008210823, 0.5527234994434788, -0.8039614537359691],
          [0.10188581412204267, -0.17110594738052967, -0.9799704259066699],
          [0.10832511255237177, -0.19018912890874434, 0.975752922227471],
          [0.13621754927492466, -0.8942526135605741, 0.4263297343719016],
          [0.04704092862601945, -0.45245473334950004, -0.8905458243704446]])
     miller_indices = [(3, -5, 0), (5, 4, -2), (2, -5, -1), (3, -4, -5),
                       (2, -2, 3), (-3, 4, -3), (3, -4, 3), (3, -2, 3),
                       (-5, 5, -1), (5, -5, 1)]
     hkl_planes = []
     for indices in miller_indices:
         (h, k, l) = indices
         hkl_planes.append(HklPlane(h, k, l, self.ni))
     solutions = index(hkl_normals,
                       hkl_planes,
                       tol_angle=0.5,
                       tol_disorientation=3.0)
     final_orientation = Orientation(solutions[0])
     angle, ax1, ax2 = final_orientation.disorientation(
         orientation, crystal_structure=Symmetry.cubic)
     self.assertLess(angle * 180 / np.pi, 1.0)
Пример #9
0
 def test_select_lambda(self):
     """Verify the wavelength diffracted by a given hkl plane."""
     orientation = Orientation.cube()
     hkl = HklPlane(-1, -1, -1, self.ni)
     (the_lambda, theta) = select_lambda(hkl, orientation)
     self.assertAlmostEqual(the_lambda, 5.277, 3)
     self.assertAlmostEqual(theta * 180 / np.pi, 35.264, 3)
Пример #10
0
 def test_scattering_vector(self):
     Fe_fcc = Lattice.face_centered_cubic(0.287)  # FCC iron
     hkl = HklPlane(2, 0, 0, Fe_fcc)
     Gc = hkl.scattering_vector()
     self.assertAlmostEqual(np.linalg.norm(Gc),
                            1 / hkl.interplanar_spacing())
     Al_fcc = Lattice.face_centered_cubic(0.405)
     hkl = HklPlane(0, 0, 2, lattice=Al_fcc)
     Gc = hkl.scattering_vector()
     self.assertAlmostEqual(np.linalg.norm(Gc),
                            1 / hkl.interplanar_spacing())
Пример #11
0
    def setup(self, omega_step, grain_ids=None):
        """Setup the forward simulation.

        :param float omega_step: the angular integration step (in degrees) use to compute the diffraction comditions.
        :param list grain_ids: a list of grain ids to restrict the forward simulation (use all grains by default).
        """
        assert self.exp.source.min_energy == self.exp.source.max_energy  # monochromatic case
        lambda_keV = self.exp.source.max_energy
        self.omegas = np.linspace(0.0,
                                  360.0,
                                  num=int(360.0 / omega_step),
                                  endpoint=False)
        self.reflections = []
        for omega in self.omegas:
            self.reflections.append([])
        if grain_ids:
            # make a list of the grains selected for the forward simulation
            grains = [
                self.exp.sample.microstructure.get_grain(gid)
                for gid in grain_ids
            ]
        else:
            grains = self.exp.sample.microstructure.grains
        for g in grains:
            for plane in self.hkl_planes:
                (h, k, i,
                 l) = HklPlane.three_to_four_indices(*plane.miller_indices())
                try:
                    (w1, w2) = g.dct_omega_angles(plane,
                                                  lambda_keV,
                                                  verbose=False)
                except ValueError:
                    if self.verbose:
                        print(
                            'plane {} does not fulfil the Bragg condition for grain {:d}'
                            .format((h, k, i, l), g.id))
                    continue
                # add angles for Friedel pairs
                w3 = (w1 + 180.) % 360
                w4 = (w2 + 180.) % 360
                if self.verbose and g.id == self.check:
                    print(
                        'grain %d, angles for plane %d%d%d: w1=%.3f and w2=%.3f | delta=%.1f'
                        % (g.id, h, k, l, w1, w2, w1 - w2))
                    print('(%3d, %3d, %3d, %3d) -- %6.2f & %6.2f' %
                          (h, k, i, l, w1, w2))
                self.reflections[int(w1 / omega_step)].append(
                    [g.id, (h, k, l)])
                self.reflections[int(w2 / omega_step)].append(
                    [g.id, (h, k, l)])
                self.reflections[int(w3 / omega_step)].append(
                    [g.id, (-h, -k, -l)])
                self.reflections[int(w4 / omega_step)].append(
                    [g.id, (-h, -k, -l)])
Пример #12
0
    def test_dct_omega_angles(self):
        # test with a BCC Titanium lattice
        lambda_keV = 30
        lambda_nm = 1.2398 / lambda_keV
        a = 0.3306  # lattice parameter in nm
        Ti_bcc = Lattice.cubic(a)
        (h, k, l) = (0, 1, 1)
        hkl = HklPlane(h, k, l, lattice=Ti_bcc)
        o = Orientation.from_euler((103.517, 42.911, 266.452))
        theta = hkl.bragg_angle(lambda_keV, verbose=False)

        gt = o.orientation_matrix(
        )  # our B (here called gt) corresponds to g^{-1} in Poulsen 2004
        A = h * gt[0, 0] + k * gt[1, 0] + l * gt[2, 0]
        B = -h * gt[0, 1] - k * gt[1, 1] - l * gt[2, 1]
        C = -2 * a * np.sin(
            theta
        )**2 / lambda_nm  # the minus sign comes from the main equation
        Delta = 4 * (A**2 + B**2 - C**2)
        self.assertEqual(Delta > 0, True)
        t1 = (B - 0.5 * np.sqrt(Delta)) / (A + C)
        t2 = (B + 0.5 * np.sqrt(Delta)) / (A + C)
        # verifying A cos(w) + B sin(w) = C:'
        for t in (t1, t2):
            x = A * (1 - t**2) / (1 + t**2) + B * 2 * t / (1 + t**2)
            self.assertAlmostEqual(x, C, 2)
        # verifying (A + C) * t**2 - 2 * B * t + (C - A) = 0'
        for t in (t1, t2):
            self.assertAlmostEqual((A + C) * t**2 - 2 * B * t + (C - A), 0.0,
                                   2)
        (w1, w2) = o.dct_omega_angles(hkl, lambda_keV, verbose=False)
        self.assertAlmostEqual(w1, 196.709, 2)
        self.assertAlmostEqual(w2, 28.334, 2)
        # test with an FCC Aluminium-Lithium lattice
        a = 0.40495  # lattice parameter in nm
        Al_fcc = Lattice.face_centered_cubic(a)
        hkl = HklPlane(-1, 1, 1, Al_fcc)
        o = Orientation.from_rodrigues([0.0499, -0.3048, 0.1040])
        w1, w2 = o.dct_omega_angles(hkl, 40, verbose=False)
        self.assertAlmostEqual(w1, 109.2, 1)
        self.assertAlmostEqual(w2, 296.9, 1)
Пример #13
0
 def test_select_lambda(self):
     """Verify that the rotating crystal conditions correspond to the selected wave length diffracted 
     after rotating the crystal in both positions."""
     hkl_dif = HklPlane(2, 0, 2, self.al)
     lambda_keV = 40.0
     w1, w2 = self.g4.dct_omega_angles(hkl_dif, lambda_keV, verbose=False)
     for omega in [w1, w2]:
         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]])
         o_rot = Orientation(np.dot(self.g4.orientation_matrix(), R.T))
         self.assertAlmostEqual(
             select_lambda(hkl_dif, o_rot, verbose=False)[0], lambda_keV, 6)
Пример #14
0
 def set_diffracting_famillies(self, hkl_list):
     """Set the list of diffracting hk planes using a set of families."""
     symmetry = self.exp.get_sample().get_material().get_symmetry()
     hkl_planes = []
     for hkl in hkl_list:
         # here we set include_friedel_pairs to False as we take it into account in the calculation
         planes = HklPlane.get_family(hkl,
                                      include_friedel_pairs=True,
                                      crystal_structure=symmetry)
         for plane in planes:  # fix the lattice
             plane.set_lattice(self.exp.get_sample().get_material())
         hkl_planes.extend(planes)
     self.set_hkl_planes(hkl_planes)
Пример #15
0
 def test_110_normal_monoclinic(self):
     """Testing (110) plane normal in monoclinic crystal structure.
     This test comes from
     http://www.mse.mtu.edu/~drjohn/my3200/stereo/sg5.html
     corrected for a few errors in the html page.
     In this test, the lattice is defined with the c-axis aligned with the Z direction of the Cartesian frame.
     """
     Mg2Si = Lattice.from_parameters(1.534,
                                     0.405,
                                     0.683,
                                     90.,
                                     106.,
                                     90.,
                                     x_aligned_with_a=False)
     a = Mg2Si.matrix[0]
     b = Mg2Si.matrix[1]
     c = Mg2Si.matrix[2]
     self.assertAlmostEqual(a[0], 1.475, 3)
     self.assertAlmostEqual(a[1], 0., 3)
     self.assertAlmostEqual(a[2], -0.423, 3)
     self.assertAlmostEqual(b[0], 0., 3)
     self.assertAlmostEqual(b[1], 0.405, 3)
     self.assertAlmostEqual(b[2], 0., 3)
     self.assertAlmostEqual(c[0], 0., 3)
     self.assertAlmostEqual(c[1], 0., 3)
     self.assertAlmostEqual(c[2], 0.683, 3)
     p = HklPlane(1, 1, 1, Mg2Si)
     Gc = p.scattering_vector()
     self.assertAlmostEqual(Gc[0], 1.098, 3)
     self.assertAlmostEqual(Gc[1], 2.469, 3)
     self.assertAlmostEqual(Gc[2], 1.464, 3)
     self.assertAlmostEqual(p.interplanar_spacing(), 0.325, 3)
     Ghkl = np.dot(Mg2Si.matrix, Gc)
     self.assertEqual(Ghkl[0], 1.)  # h
     self.assertEqual(Ghkl[1], 1.)  # k
     self.assertEqual(Ghkl[2], 1.)  # l
Пример #16
0
    def test_gnomonic_projection_point(self):
        """Verify that the gnomonic projection of two diffracted points on a detector give access to the angle 
        between the lattice plane normals."""
        olivine = Lattice.orthorhombic(
            1.022, 0.596, 0.481)  # nm Barret & Massalski convention
        orientation = Orientation.cube()
        p1 = HklPlane(2, 0, -3, olivine)
        p2 = HklPlane(3, -1, -3, olivine)
        detector = RegArrayDetector2d(size=(512, 512),
                                      u_dir=[0, -1, 0],
                                      v_dir=[0, 0, -1])
        detector.pixel_size = 0.200  # mm, 0.1 mm with factor 2 binning
        detector.ucen = 235
        detector.vcen = 297
        detector.ref_pos = np.array([131., 0., 0.]) + \
                           (detector.size[0] / 2 - detector.ucen) * detector.u_dir * detector.pixel_size + \
                           (detector.size[1] / 2 - detector.vcen) * detector.v_dir * detector.pixel_size  # mm

        angle = 180 / np.pi * np.arccos(np.dot(p1.normal(), p2.normal()))
        # test the gnomonic projection for normal and not normal X-ray incidence
        for ksi in [0.0, 1.0]:  # deg
            Xu = np.array(
                [np.cos(ksi * np.pi / 180), 0.,
                 np.sin(ksi * np.pi / 180)])
            OC = detector.project_along_direction(
                Xu
            )  # C is the intersection of the direct beam with the detector
            K1 = diffracted_vector(p1, orientation, Xu=Xu)
            K2 = diffracted_vector(p2, orientation, Xu=Xu)
            R1 = detector.project_along_direction(K1, origin=[0., 0., 0.])
            R2 = detector.project_along_direction(K2, origin=[0., 0., 0.])
            OP1 = gnomonic_projection_point(R1, OC=OC)[0]
            OP2 = gnomonic_projection_point(R2, OC=OC)[0]
            hkl_normal1 = OP1 / np.linalg.norm(OP1)
            hkl_normal2 = (OP2 / np.linalg.norm(OP2))
            # the projection must give the normal to the diffracting plane
            for i in range(3):
                self.assertAlmostEqual(hkl_normal1[i], p1.normal()[i], 6)
                self.assertAlmostEqual(hkl_normal2[i], p2.normal()[i], 6)
            angle_gp = 180 / np.pi * np.arccos(np.dot(hkl_normal1,
                                                      hkl_normal2))
            self.assertAlmostEqual(angle, angle_gp, 6)
Пример #17
0
def plot_all_dif_spots(gid, detector, hkl_miller=None, uv=None, lattice=None, lambda_keV=None,
                       spots=True, dif_spots_image=None, max_value=None, positions=True, debye_rings=True, suffix=''):
    plt.figure(figsize=(13, 8))
    # plt.figure()
    if spots and dif_spots_image is not None:
        if not max_value:
            max_value = dif_spots_image.max()
        plt.imshow(dif_spots_image.T, cmap=cm.gray, vmin=0, vmax=max_value)
    families = []
    indices = []
    colors = 'crbgmy'  # crbgmycrbgmycrbgmycrbgmy'  # use a cycler here
    t = np.linspace(0.0, 2 * np.pi, num=37)
    if positions or debye_rings:
        if hkl_miller is None:
            raise ValueError(
                'The list of miller indices of each reflection must be provided using variable g_hkl_miller')
        for i, (h, k, l) in enumerate(hkl_miller):
            l = [abs(h), abs(k), abs(l)]
            # l.sort()  # miller indices are now sorted, should use the lattice symmetry here
            family_name = '%d%d%d' % (l[0], l[1], l[2])
            if families.count(family_name) == 0:
                families.append(family_name)
                indices.append(i)
        indices.append(len(hkl_miller))
        print(families, indices)
        # now plot each family
        for i in range(len(families)):
            family = families[i]
            c = colors[i % len(colors)]
            if positions and uv is not None:
                plt.plot(uv[indices[i]:indices[i + 1], 0], uv[indices[i]:indices[i + 1], 1],
                         's', color=c, label=family)
            if debye_rings and lattice is not None and lambda_keV:
                theta = HklPlane(int(family[0]), int(family[1]), int(family[2]), lattice).bragg_angle(lambda_keV)
                L = detector.ref_pos[0] / detector.pixel_size * np.tan(2 * theta)  # 2 theta distance on the detector
                print('2theta = %g, L = %g' % (2 * theta * 180 / np.pi, L))
                plt.plot(0.5 * detector.size[0] + L * np.cos(t), 0.5 * detector.size[1] + L * np.sin(t), '--', color=c)
    plt.title('grain %d diffraction spot locations on the detector' % gid)
    # plt.legend(numpoints=1, loc='center')
    plt.legend(numpoints=1, ncol=2, bbox_to_anchor=(1.02, 1), loc=2)
    # plt.axis('equal')
    plt.axis([0, 2047, 2047, 0])
    plt.savefig('g%d%s_difspot_positions.pdf' % (gid, suffix))
Пример #18
0
 def setup(self, omega_step):
     """Setup the forward simulation."""
     assert self.exp.source.min_energy == self.exp.source.max_energy  # monochromatic case
     lambda_keV = self.exp.source.max_energy
     self.omegas = np.linspace(0.0,
                               360.0,
                               num=int(360.0 / omega_step),
                               endpoint=False)
     self.reflections = []
     for omega in self.omegas:
         self.reflections.append([])
     for g in self.exp.sample.microstructure.grains:
         for plane in self.hkl_planes:
             (h, k, i,
              l) = HklPlane.three_to_four_indices(*plane.miller_indices())
             try:
                 (w1, w2) = g.dct_omega_angles(plane,
                                               lambda_keV,
                                               verbose=False)
             except ValueError:
                 if self.verbose:
                     print(
                         'plane {} does not fulfil the Bragg condition for grain {:d}'
                         .format((h, k, i, l), g.id))
                 continue
             # add angles for Friedel pairs
             w3 = (w1 + 180.) % 360
             w4 = (w2 + 180.) % 360
             if self.verbose and g.id == self.check:
                 print(
                     'grain %d, angles for plane %d%d%d: w1=%.3f and w2=%.3f | delta=%.1f'
                     % (g.id, h, k, l, w1, w2, w1 - w2))
                 print('(%3d, %3d, %3d, %3d) -- %6.2f & %6.2f' %
                       (h, k, i, l, w1, w2))
             self.reflections[int(w1 / omega_step)].append(
                 [g.id, (h, k, l)])
             self.reflections[int(w2 / omega_step)].append(
                 [g.id, (h, k, l)])
             self.reflections[int(w3 / omega_step)].append(
                 [g.id, (-h, -k, -l)])
             self.reflections[int(w4 / omega_step)].append(
                 [g.id, (-h, -k, -l)])
Пример #19
0
 def test_scattering_vector_th(self):
     """ compute the scattering vector using the formal definition and compare it with the components obtained 
     using the reciprocal lattice. 
     The formulae are available in the Laue Atlas p61, one typo in Eq. 6.1 was corrected. """
     (a, b, c) = self.hex._lengths
     (alpha, beta, gamma) = np.radians(self.hex._angles)
     delta = pi / 2 - gamma
     chi = gamma - atan(
         (cos(alpha) - cos(gamma) * cos(beta)) / (cos(beta) * cos(delta)))
     epsilon = pi / 2 - acos(
         (cos(alpha) + cos(beta)) / (cos(chi) + cos(gamma - chi)))
     psi = acos(sin(epsilon) * cos(delta + chi))
     for (hp, kp, lp) in [(1, 1, 1), [1, 2, 0]]:
         # compute the h, k, l in the Cartesian coordinate system
         h = hp / a
         k = (a / hp - b / kp * cos(gamma)) / (a / hp * b / kp * cos(delta))
         l = (lp / c - hp / a * cos(beta) -
              kp / b * cos(psi)) / cos(epsilon)
         Gc = HklPlane(hp, kp, lp, self.hex).scattering_vector()
         self.assertAlmostEqual(Gc[0], h, 7)
         self.assertAlmostEqual(Gc[1], k, 7)
         self.assertAlmostEqual(Gc[2], l, 7)
Пример #20
0
    def fsim_grain(self, gid=1):
        self.grain = self.exp.get_sample().get_microstructure().get_grain(gid)
        sample = self.exp.get_sample()
        lattice = sample.get_microstructure().get_lattice()
        source = self.exp.get_source()
        detector = self.exp.get_active_detector()
        data = np.zeros_like(detector.data)
        if self.verbose:
            print('Forward Simulation for grain %d' % self.grain.id)
        sample.geo.discretize_geometry(grain_id=self.grain.id)
        # we use either the hkl planes for this grain or the ones defined for the whole simulation
        if hasattr(self.grain,
                   'hkl_planes') and len(self.grain.hkl_planes) > 0:
            print('using hkl from the grain')
            hkl_planes = [
                HklPlane(h, k, l, lattice)
                for (h, k, l) in self.grain.hkl_planes
            ]
        else:
            if len(self.hkl_planes) == 0:
                print(
                    'warning: no reflection defined for this simulation, using all planes with max miller=%d'
                    % self.max_miller)
                self.set_hkl_planes(
                    build_list(lattice=lattice, max_miller=self.max_miller))
            hkl_planes = self.hkl_planes
        n_hkl = len(hkl_planes)
        positions = sample.geo.get_positions(
        )  # size n_vox, with 3 elements items
        n_vox = len(positions)
        Xu_vectors, thetas, the_energies, X_vectors, K_vectors = LaueForwardSimulation.fsim_laue(
            self.grain.orientation, hkl_planes, positions, source.position)
        OR_vectors = [
            detector.project_along_direction(
                origin=positions[i_vox],
                direction=K_vectors[i_vox * n_hkl + i_hkl])
            for i_vox in range(n_vox) for i_hkl in range(n_hkl)
        ]  # size nb_vox * n_hkl
        uv = [detector.lab_to_pixel(OR)[0].astype(np.int) for OR in OR_vectors]
        # now construct a boolean list to select the diffraction spots
        if source.min_energy is None and source.max_energy is None:
            # TODO use the use_energy_limits attribute
            energy_in = [True for k in range(len(the_energies))]
        else:
            energy_in = [
                source.min_energy < the_energies[k] < source.max_energy
                for k in range(len(the_energies))
            ]
        uv_in = [
            0 < uv[k][0] < detector.get_size_px()[0]
            and 0 < uv[k][1] < detector.get_size_px()[1]
            for k in range(len(uv))
        ]  # size n, diffraction located on the detector
        spot_in = [uv_in[k] and energy_in[k] for k in range(len(uv))]
        if self.verbose:
            print('%d diffraction events on the detector among %d' %
                  (sum(spot_in), len(uv)))

        # now sum the counts on the detector individual pixels
        for k in range(len(uv)):
            if spot_in[k]:
                data[uv[k][0], uv[k][1]] += 1
        return data
Пример #21
0
 def test_bragg_angle(self):
     l = Lattice.cubic(0.287)  # FCC iron
     hkl = HklPlane(2, 0, 0, l)  # 200 reflection at 8 keV is at 32.7 deg
     self.assertAlmostEqual(hkl.bragg_angle(8), 0.5704164)
Пример #22
0
    base_name = os.path.splitext(__file__)[0]
    s3d = Scene3D(display=False, ren_size=(800, 800), name=base_name, background=black)

    # create a python Grain object from the image data
    orientation = Orientation.from_rodrigues(np.array([0.3889, -0.0885, 0.3268]))
    grain = Grain(1, orientation)
    grain_data = HST_read(im_file, header_size=0, autoparse_filename=True, verbose=True)
    grain.position = ndimage.measurements.center_of_mass(grain_data, grain_data)
    print 'grain position:', grain.position
    grain.volume = ndimage.measurements.sum(grain_data)  # label is 1.0 here
    grain.add_vtk_mesh(grain_data, contour=False)

    print 'adding bounding box'
    grain_bbox = box_3d(size=np.shape(grain_data), line_color=white)
    print 'adding grain with slip planes'
    hklplanes = [HklPlane(1, 1, 1)]
    grain_with_planes = grain_3d(grain, hklplanes, show_normal=False, \
                                 plane_opacity=1.0, show_orientation=True)
    tr = vtk.vtkTransform()
    tr.Translate(grain.position)
    grain_with_planes.SetUserTransform(tr)

    print 'adding a lattice to picture the grain orientation'
    lat_size = 20
    l = Lattice.face_centered_cubic(lat_size)
    cubic = lattice_3d_with_planes(l, hklplanes, crystal_orientation=grain.orientation, \
                                   show_normal=True, plane_opacity=1.0, origin='mid', sphereColor=grey,
                                   sphereRadius=0.1)
    apply_translation_to_actor(cubic, (lat_size, lat_size, lat_size))

    print 'adding axes'
Пример #23
0
 def test_SchimdFactor(self):
     o = Orientation.from_euler([0., 0., 0.])
     ss = SlipSystem(HklPlane(1, 1, 1), HklDirection(0, 1, -1))
     self.assertAlmostEqual(o.schmid_factor(ss), 0.4082, 4)
Пример #24
0
im_file = os.path.join(data_dir, scan)

print('create a python Grain object')
orientation = Orientation.from_rodrigues(np.array([0.3889, -0.0885, 0.3268]))
grain = Grain(1, orientation)
grain_data = HST_read(im_file, autoparse_filename=True, verbose=True)
grain.position = ndimage.measurements.center_of_mass(grain_data, grain_data)
grain.volume = ndimage.measurements.sum(grain_data)  # label is 1.0 here
grain.add_vtk_mesh(grain_data, contour=False)
# grain.save_vtk_repr() # save the grain mesh in vtk format

print('adding bounding box')
grain_bbox = box_3d(size=np.shape(grain_data), line_color=white)

print('adding grain with slip planes')
p1 = HklPlane(1, 1, 1)
p2 = HklPlane(1, 1, -1)
hklplanes = [p1]
grain_with_planes = add_grain_to_3d_scene(grain, hklplanes, show_orientation=True)
tr = vtk.vtkTransform()
tr.Translate(grain.position)
grain_with_planes.SetUserTransform(tr)

print('creating 3d renderer')
ren = vtk.vtkRenderer()
ren.SetBackground(0.0, 0.0, 0.0)
ren.AddActor(grain_bbox)
ren.AddActor(grain_with_planes)
cam = setup_camera(size=np.shape(grain_data))
cam.Dolly(0.9)
ren.SetActiveCamera(cam)
Пример #25
0
    def fsim_grain(self, gid=1):
        self.grain = self.exp.get_sample().get_microstructure().get_grain(gid)
        sample = self.exp.get_sample()
        lattice = sample.get_microstructure().get_lattice()
        source = self.exp.get_source()
        detector = self.exp.get_active_detector()
        data = np.zeros_like(detector.data)
        if self.verbose:
            print('Forward Simulation for grain %d' % self.grain.id)
        sample.geo.discretize_geometry(grain_id=self.grain.id)
        # we use either the hkl planes for this grain or the ones defined for the whole simulation
        if hasattr(self.grain,
                   'hkl_planes') and len(self.grain.hkl_planes) > 0:
            print('using hkl from the grain')
            hkl_planes = [
                HklPlane(h, k, l, lattice)
                for (h, k, l) in self.grain.hkl_planes
            ]
        else:
            if len(self.hkl_planes) == 0:
                print(
                    'warning: no reflection defined for this simulation, using all planes with max miller=%d'
                    % self.max_miller)
                self.set_hkl_planes(
                    build_list(lattice=lattice, max_miller=self.max_miller))
            hkl_planes = self.hkl_planes
        n_hkl = len(hkl_planes)
        gt = self.grain.orientation_matrix().transpose()

        # here we use list comprehension to avoid for loops
        d_spacings = [hkl.interplanar_spacing()
                      for hkl in hkl_planes]  # size n_hkl
        G_vectors = [hkl.scattering_vector() for hkl in hkl_planes
                     ]  # size n_hkl, with 3 elements items
        Gs_vectors = [gt.dot(Gc)
                      for Gc in G_vectors]  # size n_hkl, with 3 elements items
        positions = sample.geo.get_positions(
        )  # size n_vox, with 3 elements items
        n_vox = len(positions)  # total number of discrete positions
        Xu_vectors = [
            (pos - source.position) / np.linalg.norm(pos - source.position)
            for pos in positions
        ]  # size n_vox
        thetas = [
            np.arccos(np.dot(Xu, Gs / np.linalg.norm(Gs))) - np.pi / 2
            for Xu in Xu_vectors for Gs in Gs_vectors
        ]  # size n_vox * n_hkl
        the_energies = [
            lambda_nm_to_keV(2 * d_spacings[i_hkl] *
                             np.sin(thetas[i_Xu * n_hkl + i_hkl]))
            for i_Xu in range(n_vox) for i_hkl in range(n_hkl)
        ]  # size n_vox * n_hkl
        X_vectors = [
            np.array(Xu_vectors[i_Xu]) / 1.2398 *
            the_energies[i_Xu * n_hkl + i_hkl] for i_Xu in range(n_vox)
            for i_hkl in range(n_hkl)
        ]  # size n_vox * n_hkl
        K_vectors = [
            X_vectors[i_Xu * n_hkl + i_hkl] + Gs_vectors[i_hkl]
            for i_Xu in range(n_vox) for i_hkl in range(n_hkl)
        ]  # size n_vox * n_hkl
        OR_vectors = [
            detector.project_along_direction(
                origin=positions[i_vox],
                direction=K_vectors[i_vox * n_hkl + i_hkl])
            for i_vox in range(n_vox) for i_hkl in range(n_hkl)
        ]  # size nb_vox * n_hkl
        uv = [detector.lab_to_pixel(OR)[0].astype(np.int) for OR in OR_vectors]
        # now construct a boolean list to select the diffraction spots
        if source.min_energy is None and source.max_energy is None:
            # TODO use the use_energy_limits attribute
            energy_in = [True for k in range(len(the_energies))]
        else:
            energy_in = [
                source.min_energy < the_energies[k] < source.max_energy
                for k in range(len(the_energies))
            ]
        uv_in = [
            0 < uv[k][0] < detector.get_size_px()[0]
            and 0 < uv[k][1] < detector.get_size_px()[1]
            for k in range(len(uv))
        ]  # size n, diffraction located on the detector
        spot_in = [uv_in[k] and energy_in[k] for k in range(len(uv))]
        if self.verbose:
            print('%d diffraction events on the detector among %d' %
                  (sum(spot_in), len(uv)))

        # now sum the counts on the detector individual pixels
        for k in range(len(uv)):
            if spot_in[k]:
                data[uv[k][0], uv[k][1]] += 1
        return data
Пример #26
0
Hkl planes are added to the lattice and displayed.
'''
# Create the Renderer and RenderWindow
ren = vtk.vtkRenderer()
ren.SetBackground(white)

# crystal orientation
o = Orientation.from_euler((15.0, -45.0, 0.0))
o = None

# hexagonal lattice
a = 1.0  # 0.321 # nm
c = 1.5  # 0.521 # nm
l = Lattice.hexagonal(a, c)
grid = hexagonal_lattice_grid(l)
print(np.array(HklPlane.four_to_three_indices(1, 0, -1, 0)) /
      0.6)  # prismatic 1
print(np.array(HklPlane.four_to_three_indices(0, 1, -1, 0)) /
      0.6)  # prismatic 2
print(np.array(HklPlane.four_to_three_indices(0, 1, -1, 1)) / 0.6 *
      3)  # pyramidal 1
print(np.array(HklPlane.four_to_three_indices(1, 1, -2, 2)) / 0.6 *
      3)  # pyramidal 2
print(np.array(HklPlane.four_to_three_indices(0, 0, 0, 1)))  # basal
p1 = HklPlane(2., 1, 0, lattice=l)  # attach the plane to the hexagonal lattice
p2 = HklPlane(-1, 2, 0, lattice=l)
p3 = HklPlane(-3., 6., 5., lattice=l)
p4 = HklPlane(3, 9, 10, lattice=l)
p5 = HklPlane(0, 0, 1, lattice=l)  # basal
hklplanes = [p3, p5]
hexagon = vtk.vtkAssembly()
Пример #27
0
    def plot_sst(self, ax=None, mk='s', ann=False):
        """ Create the inverse pole figure in the unit standard triangle.

        :param ax: a reference to a pyplot ax to draw the poles.
        :param mk: marker used to plot the poles (square by default).
        :param bool ann: Annotate the pole with the coordinates of the vector if True (False by default).
        """
        # first draw the boundary of the symmetry domain limited by 3 hkl plane normals, called here A, B and C
        symmetry = self.lattice._symmetry
        if symmetry is Symmetry.cubic:
            sst_poles = [(0, 0, 1), (1, 0, 1), (1, 1, 1)]
            ax.axis([-0.05, 0.45, -0.05, 0.40])
        elif symmetry is Symmetry.hexagonal:
            sst_poles = [(0, 0, 1), (2, -1, 0), (1, 0, 0)]
            ax.axis([-0.05, 1.05, -0.05, 0.6])
        else:
            print('unssuported symmetry: %s' % symmetry)
        A = HklPlane(*sst_poles[0], lattice=self.lattice)
        B = HklPlane(*sst_poles[1], lattice=self.lattice)
        C = HklPlane(*sst_poles[2], lattice=self.lattice)
        self.plot_line_between_crystal_dir(A.normal(),
                                           B.normal(),
                                           ax=ax,
                                           col='k')
        self.plot_line_between_crystal_dir(B.normal(),
                                           C.normal(),
                                           ax=ax,
                                           col='k')
        self.plot_line_between_crystal_dir(C.normal(),
                                           A.normal(),
                                           ax=ax,
                                           col='k')
        # display the 3 crystal axes
        poles = [A, B, C]
        v_align = ['top', 'top', 'bottom']
        for i in range(3):
            hkl = poles[i]
            c_dir = hkl.normal()
            c = c_dir + self.z
            c /= c[2]  # SP'/SP = r/z with r=1
            pole_str = '%d%d%d' % hkl.miller_indices()
            if symmetry is Symmetry.hexagonal:
                pole_str = '%d%d%d%d' % HklPlane.three_to_four_indices(
                    *hkl.miller_indices())
            ax.annotate(pole_str, (c[0], c[1] - (2 * (i < 2) - 1) * 0.01),
                        xycoords='data',
                        fontsize=12,
                        horizontalalignment='center',
                        verticalalignment=v_align[i])

        # now plot the sample axis
        for grain in self.microstructure.grains:
            # move to the fundamental zone
            g = grain.orientation_matrix()
            # compute axis and apply SST symmetry
            if self.axis == 'Z':
                axis = self.z
            elif self.axis == 'Y':
                axis = self.y
            else:
                axis = self.x
            axis_rot = self.sst_symmetry(g.dot(axis))
            label = ''
            if self.map_field == 'grain_id':
                label = 'grain ' + str(grain.id)
            self.plot_crystal_dir(axis_rot,
                                  mk=mk,
                                  col=self.get_color_from_field(grain),
                                  ax=ax,
                                  ann=ann,
                                  lab=label)
            if self.verbose:
                print('plotting %s in crystal CS: %s' % (self.axis, axis_rot))
        ax.axis('off')
        ax.set_title('%s-axis SST inverse %s projection' %
                     (self.axis, self.proj))
Пример #28
0
                      verbose=True)
grain.position = ndimage.measurements.center_of_mass(grain_data, grain_data)
print('grain position: %s' % str(grain.position))
grain.volume = ndimage.measurements.sum(grain_data)  # label is 1.0 here
grain.add_vtk_mesh(grain_data, contour=False)

print('adding bounding box')
grain_bbox = box_3d(size=np.shape(grain_data), line_color=white)
print('adding grain with slip planes')

z_offsets = np.linspace(-50, 50, 6, endpoint=True)
print(z_offsets)
plane_origins = np.zeros((len(z_offsets), 3), dtype=float)
plane_origins[:, 2] = z_offsets

hkl_planes = [HklPlane(1, 1, 1)] * len(z_offsets)
grain_with_planes = grain_3d(grain, hkl_planes,  plane_origins=plane_origins, show_normal=False, \
                         plane_opacity=1.0, show_orientation=False)
tr = vtk.vtkTransform()
tr.Translate(grain.position)
grain_with_planes.SetUserTransform(tr)

print('adding axes')
axes = axes_actor(length=100, fontSize=60)
axes.GetXAxisCaptionActor2D().GetCaptionTextProperty().SetColor(grey)

print('setting up camera')
cam = setup_camera(size=np.shape(grain_data))
cam.Dolly(0.9)

# add all actors to the 3d scene and render
Пример #29
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
Пример #30
0
 def test_multiplicity(self):
     """Int Tables of Crystallography Vol. 1 p 32."""
     self.assertEqual(
         HklPlane(1, 0, 0).multiplicity(symmetry=Symmetry.cubic), 6)
     for h in range(1, 4):
         self.assertEqual(
             HklPlane(h, 0, 0).multiplicity(symmetry=Symmetry.tetragonal),
             4)
         self.assertEqual(
             HklPlane(0, h, 0).multiplicity(symmetry=Symmetry.tetragonal),
             4)
         self.assertEqual(
             HklPlane(h, h, 0).multiplicity(symmetry=Symmetry.tetragonal),
             4)
         self.assertEqual(
             HklPlane(-h, h, 0).multiplicity(symmetry=Symmetry.tetragonal),
             4)
         self.assertEqual(
             HklPlane(h, h, 1).multiplicity(symmetry=Symmetry.tetragonal),
             8)
         self.assertEqual(
             HklPlane(-h, h, 1).multiplicity(symmetry=Symmetry.tetragonal),
             8)
     self.assertEqual(
         HklPlane(0, 0, 1).multiplicity(symmetry=Symmetry.tetragonal), 2)
     self.assertEqual(
         HklPlane(1, 0, 2).multiplicity(symmetry=Symmetry.tetragonal), 8)
     self.assertEqual(
         HklPlane(-1, 0, 2).multiplicity(symmetry=Symmetry.tetragonal), 8)
     self.assertEqual(
         HklPlane(0, 1, 2).multiplicity(symmetry=Symmetry.tetragonal), 8)
     self.assertEqual(
         HklPlane(0, -1, 2).multiplicity(symmetry=Symmetry.tetragonal), 8)
     self.assertEqual(
         HklPlane(1, 2, 0).multiplicity(symmetry=Symmetry.tetragonal), 8)
     self.assertEqual(
         HklPlane(-1, 2, 0).multiplicity(symmetry=Symmetry.tetragonal), 8)
     self.assertEqual(
         HklPlane(1, 2, 3).multiplicity(symmetry=Symmetry.tetragonal), 16)