예제 #1
0
 def test_misorientation_matrix(self):
     for test_euler in self.test_eulers:
         o = Orientation.from_euler(test_euler)
         g = o.orientation_matrix()
         delta = np.dot(g, g.T)
         self.assertEqual(
             Orientation.misorientation_angle_from_delta(delta), 0.0)
예제 #2
0
 def test_solve_trig_equation(self):
     x1, x2 = Orientation.solve_trig_equation(2, -6, 3)
     self.assertAlmostEqual(x1, 3.9575 * 180 / np.pi, 2)
     self.assertAlmostEqual(x2, 6.1107 * 180 / np.pi, 2)
     x1, x2 = Orientation.solve_trig_equation(5, 4, 6)
     self.assertAlmostEqual(x1, 0.3180 * 180 / np.pi, 2)
     self.assertAlmostEqual(x2, 1.0314 * 180 / np.pi, 2)
예제 #3
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)
예제 #4
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)
예제 #5
0
 def test_misorientation_axis(self):
     o1 = Orientation.copper()
     o2 = Orientation.s3()
     (angle, axis, axis_xyz) = o1.disorientation(o2, crystal_structure=Symmetry.triclinic)
     self.assertAlmostEqual(180 / np.pi * angle, 19.38, 2)  # check value of 19.576
     val = np.array([-0.71518544, -0.60383062, -0.35199199])
     for i in range(3):
         self.assertAlmostEqual(axis[i], val[i], 6)
예제 #6
0
 def test_OrientationMatrix2Euler(self):
     for test_euler in self.test_eulers:
         o = Orientation.from_euler(test_euler)
         g = o.orientation_matrix()
         calc_euler = Orientation.OrientationMatrix2Euler(g)
         calc_euler2 = Orientation.OrientationMatrix2EulerSF(g)
         for i in range(3):
             self.assertAlmostEquals(calc_euler[i], test_euler[i])
예제 #7
0
 def test_misorientation_angle(self):
     o1 = Orientation.from_euler((0., 0., 0.))
     o2 = Orientation.from_euler((60., 0., 0.))
     self.assertAlmostEqual(
         180 / np.pi *
         o1.disorientation(o2, crystal_structure=Symmetry.triclinic)[0], 60)
     self.assertAlmostEqual(
         180 / np.pi *
         o1.disorientation(o2, crystal_structure=Symmetry.cubic)[0], 30)
예제 #8
0
 def test_IPF_color(self):
     o1 = Orientation.cube()  # 001 // Z
     o2 = Orientation.from_euler([35.264, 45., 0.])  # 011 // Z
     o3 = Orientation.from_euler([0., 54.736, 45.])  # 111 // Z
     orientations = [o1, o2, o3]
     targets = [np.array([1., 0., 0.]), np.array([0., 1., 0.]), np.array([0., 0., 1.])]
     for case in range(2):
         o = orientations[case]
         print(o)
         target = targets[case]
         col = o.get_ipf_colour()
         print(col)
         for i in range(3):
             self.assertAlmostEqual(col[i], target[i])
예제 #9
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)
예제 #10
0
 def load_grain(self, gid=1):
     print('loading grain from file 4_grains/phase_01/grain_%04d.mat' % gid)
     with h5py.File(
             os.path.join(self.exp.get_sample().data_dir,
                          '4_grains/phase_01/grain_%04d.mat' %
                          gid)) as gmat:
         g = Grain(gid, Orientation.from_rodrigues(gmat['R_vector'][()]))
         g.om_exp = gmat['om_exp'][0, :]
         g.uv_exp = gmat['uv_exp'][:, :]
         g.center = gmat['center'][:, 0]
         try:
             ref_included = gmat['proj/included'][0][0]
             g.included = gmat[ref_included][0, :]
             ref_ondet = gmat['proj/ondet'][0][0]
             g.ondet = gmat[ref_ondet][0, :]
             # grab the projection stack
             ref_stack = gmat['proj']['stack'][0][0]
             g.stack_exp = gmat[ref_stack][()].transpose(
                 1, 2, 0)  # now in [ndx, u, v] form
             g.hklsp = gmat['allblobs/hklsp'][:, :]
         except AttributeError:
             # classic file organization
             g.included = gmat['proj/included'][0, :]
             g.ondet = gmat['proj/ondet'][0, :]
             g.stack_exp = gmat['proj/stack'][()].transpose(
                 1, 2, 0)  # now in [ndx, u, v] form
             # for the Ti7AL data set, we have to hack around the DCT + TT work in progress
             #ref_hklsp = gmat['allblobs/hklsp'][()][0][0]
             #g.hklsp = gmat[ref_hklsp][:, :]
             g.hklsp = gmat['allblobs/hklsp'][:, :]
     self.grain = g
     if self.verbose:
         print('experimental proj stack shape: {}'.format(
             g.stack_exp.shape))
예제 #11
0
    def execute(self, iren, event):
        """instruction block executed when a TimerEvent is captured by the vtkRotateActorAroundAxis.

        If the time is not in [start, end] nothing is done. Otherwise the transform matrix corresponding
        to the 3D rotation is applied to the actor.

        The transform matrix for this increment is the result of the multiplication of the rotation matrix
        for the current angle with the initial 4x4 matrix before any rotation (we keep a record of this in
        the `user_transform_matrix` attribute).

        :param vtkRenderWindowInteractor iren: the vtk render window interactor.
        :param event: the captures event.
        """
        do = vtkAnimation.pre_execute(self)
        if not do:
            return
        t1 = self.time_anim_starts
        t2 = self.time_anim_ends
        angle = (self.scene.timer_count - t1) / float(t2 - t1) * self.angle
        from pymicro.crystal.microstructure import Orientation
        om = Orientation.Axis2OrientationMatrix(self.axis, angle)
        m = vtk.vtkMatrix4x4()  # row major order, 16 elements matrix
        m.Identity()
        for j in range(3):
            for i in range(3):
                m.SetElement(j, i, om[i, j])
        # compute the transformation matrix for this increment
        t = vtk.vtkTransform()
        t.SetMatrix(self.user_transform_matrix)
        t.Concatenate(m)
        self._actor.SetUserTransform(t)
        vtkAnimation.post_execute(self, iren, event)
예제 #12
0
    def plot_ipf(self, **kwargs):
        """ Create the inverse pole figure for direction Z.

        :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).
        
        """
        ax = kwargs.get('ax')
        self.plot_pf_background(ax, labels=False)
        # now plot the sample axis
        for grain in self.microstructure.grains:
            g = Orientation.Rodrigues2OrientationMatrix(grain['orientation'])
            if self.axis == 'Z':
                axis = self.z
            elif self.axis == 'Y':
                axis = self.y
            else:
                axis = self.x
            axis_rot = g.dot(axis)
            kwargs['col'] = self.get_color_from_field(grain)
            self.plot_crystal_dir(axis_rot, **kwargs)
            if self.verbose:
                print('plotting ', self.axis, ' in crystal CS:', axis_rot)
        ax.axis([-1.1, 1.1, -1.1, 1.1])
        ax.axis('off')
        ax.set_title('%s-axis inverse %s projection' % (self.axis, self.proj))
예제 #13
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)
예제 #14
0
    def execute(self, iren, event):
        '''instruction block executed when a TimerEvent is captured by the vtkRotateActorAroundAxis.

        If the time is not in [start, end] nothing is done. Otherwise the
        transform matrix corresponding to the 3D rotation is applied to the actor.
        '''
        do = vtkAnimation.pre_execute(self)
        if not do:
            return
        t1 = self.time_anim_starts
        t2 = self.time_anim_ends
        angle = (self.scene.timer_count - t1) / float(t2 - t1) * self.angle
        from pymicro.crystal.microstructure import Orientation
        om = Orientation.Axis2OrientationMatrix(self.axis, angle)
        m = vtk.vtkMatrix4x4()  # row major order, 16 elements matrix
        m.Identity()
        for j in range(3):
            for i in range(3):
                m.SetElement(j, i, om[i, j])
        t = vtk.vtkTransform()
        #t.SetMatrix(self.user_transform_matrix)
        t.SetMatrix(self.actor.GetUserTransform().GetMatrix())
        t.Concatenate(m)
        self.actor.SetUserTransform(t)
        vtkAnimation.post_execute(self, iren, event)
예제 #15
0
def poll_system(g_list, dis_tol=1.0, verbose=False):
    """
    Poll system to sort a series of orientation matrices determined by the indexation procedure.

    For each orientation matrix, check if it corresponds to an existing solution, if so: vote for it,
    if not add a new solution to the list
    :param list g_list: the list of orientation matrices (should be in the fz)
    :param float dis_tol: angular tolerance (degrees)
    :param bool verbose: activate verbose mode (False by default)
    :return: a tuple composed by the most popular orientation matrix, the corresponding vote number and the confidence index
    """
    solution_indices = [0]
    votes = [0]
    vote_index = np.zeros(len(g_list), dtype=int)
    dis_tol_rad = dis_tol * pi / 180
    from pymicro.crystal.microstructure import Orientation
    for i in range(len(g_list)):
        g = g_list[i]
        # rotations are already in the fundamental zone
        for j in range(len(solution_indices)):
            index = solution_indices[j]
            delta = np.dot(g, g_list[index].T)
            # compute misorientation angle in radians
            angle = Orientation.misorientation_angle_from_delta(delta)
            if verbose:
                print('j=%d -- angle=%f' % (j, angle))
            if angle <= dis_tol_rad:
                votes[j] += 1
                vote_index[i] = j
                if verbose:
                    print('angle (deg) is %.2f' % (180 / pi * angle))
                    print('vote list is now %s' % votes)
                    print('solution_indices list is now %s' % solution_indices)
                break
            elif j == len(solution_indices) - 1:
                solution_indices.append(i)
                votes.append(1)
                vote_index[i] = len(votes) - 1
                if verbose:
                    print('vote list is now %s' % votes)
                    print('solution_indices list is now %s' % solution_indices)
                break
    index_result = np.argwhere(votes == np.amax(votes)).flatten()
    if verbose:
        print('Max vote =', np.amax(votes))
        print('index result:', index_result)
        print('Number of equivalent solutions :', len(index_result))
        print(type(index_result))
        print(index_result.shape)
    final_orientation_matrix = []
    for n in range(len(index_result)):
        solutions = g_list[solution_indices[index_result[n]]]
        if verbose:
            print('Solution number {0:d} is'.format(n+1), solutions)
        final_orientation_matrix.append(solutions)
    result_vote = max(votes)
    ci = confidence_index(votes)
    vote_field = [votes[i] for i in vote_index]
    return final_orientation_matrix, result_vote, ci, vote_field
예제 #16
0
 def setUp(self):
     print('testing the Microstructure class')
     self.test_eulers = [(45., 45, 0.), (10., 20, 30.), (191.9, 69.9, 138.9)]
     self.micro = Microstructure()
     self.micro.name = 'test'
     for i in range(len(self.test_eulers)):
         euler = self.test_eulers[i]
         self.micro.grains.append(Grain(i + 1, Orientation.from_euler(euler)))
예제 #17
0
 def test_move_to_fundamental_zone(self):
     o = Orientation.from_euler([191.9, 69.9, 138.9])
     # move rotation to cubic FZ
     o_fz = o.move_to_FZ(symmetry=Symmetry.cubic, verbose=False)
     # double check new orientation in is the FZ
     self.assertTrue(o_fz.inFZ(symmetry=Symmetry.cubic))
     # verify new Euler angle values
     val = np.array([303.402, 44.955, 60.896])
     for i in range(3):
         self.assertAlmostEqual(o_fz.euler[i], val[i], 3)
예제 #18
0
    def create_pf_contour(self, ax=None, ang_step=10):
        """Compute the distribution of orientation and plot it using contouring.

        This plot the distribution of orientation in the microstructure
        associated with this PoleFigure instance, as a continuous
        distribution using angular bining with the specified step.
        the distribution is constructed at runtime by discretizing the
        angular space and counting the number of poles in each bin.
        Then the plot_pf_contour method is called to actually plot the data.

        .. warning::

           This function has not been tested properly, use at your own risk.

        :param ax: a reference to a pyplot ax to draw the contours.
        :param int ang_step: angular step in degrees to use for constructing
            the orientation distribution data (10 degrees by default)
        
        """
        # discretise the angular space (azimuth and altitude)
        ang_step *= np.pi / 180  # change to radians
        n_phi = int(1 + 2 * np.pi / ang_step)
        n_psi = int(1 + 0.5 * np.pi / ang_step)
        phis = np.linspace(0, 2 * np.pi, n_phi)
        psis = np.linspace(0, np.pi / 2, n_psi)
        xv, yv = np.meshgrid(phis, psis)
        values = np.zeros((n_psi, n_phi), dtype=int)
        for grain in self.microstructure.grains:
            g = Orientation.Rodrigues2OrientationMatrix(grain['orientation'])
            gt = g.transpose()
            for hkl_plane in self.poles:
                c = hkl_plane.normal()
                c_rot = gt.dot(c)
                # handle poles pointing down
                if c_rot[2] < 0:
                    c_rot *= -1  # make unit vector have z>0
                if c_rot[1] >= 0:
                    phi = np.arccos(c_rot[0] /
                                    np.sqrt(c_rot[0]**2 + c_rot[1]**2))
                else:
                    phi = 2 * np.pi - np.arccos(
                        c_rot[0] / np.sqrt(c_rot[0]**2 + c_rot[1]**2))
                psi = np.arccos(c_rot[2])  # since c_rot is normed
                i_phi = int((phi + 0.5 * ang_step) / ang_step) % n_phi
                j_psi = int((psi + 0.5 * ang_step) / ang_step) % n_psi
                values[j_psi, i_phi] += 1
        if self.proj == 'stereo':  # double check which one is flat/stereo
            x = (2 * yv / np.pi) * np.cos(xv)
            y = (2 * yv / np.pi) * np.sin(xv)
        else:
            x = np.sin(yv) * np.cos(xv)
            y = np.sin(yv) * np.sin(xv)
        # close the pole figure by duplicating azimuth=0
        values[:, -1] = values[:, 0]
        self.plot_pf_contour(ax, x, y, values)
예제 #19
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)
예제 #20
0
 def test_small_disorientation(self):
     o_ref = Orientation(np.array([[-0.03454188, 0.05599919, -0.99783313],
                                   [-0.01223192, -0.99837784, -0.05560633],
                                   [-0.99932839, 0.01028467, 0.03517083]]))
     o_12 = Orientation(np.array([[-0.03807341, -0.06932796, -0.99686712],
                                  [-0.0234124, -0.99725469, 0.07024911],
                                  [-0.99900064, 0.02601367, 0.03634576]]))
     (angle, axis, axis_xyz) = o_ref.disorientation(o_12, crystal_structure=Symmetry.cubic)
     self.assertAlmostEqual(angle * 180 / np.pi, 7.24, 2)
     o_ref_fz = o_ref.move_to_FZ(symmetry=Symmetry.cubic, verbose=False)
     o_12_fz = o_12.move_to_FZ(symmetry=Symmetry.cubic, verbose=False)
     delta = np.dot(o_ref_fz.orientation_matrix(), o_12_fz.orientation_matrix().T)
     mis_angle = Orientation.misorientation_angle_from_delta(delta)
     self.assertAlmostEqual(mis_angle * 180 / np.pi, 7.24, 2)
예제 #21
0
 def test_apply_orientation_to_actor(self):
     o = Orientation.from_rodrigues([0.0885, 0.3889, 0.3268])
     Bt = o.orientation_matrix().transpose(
     )  # to go from crystal to lab coordinate Vl = Bt.Vc
     l = Lattice.cubic(1.0)
     (a, b, c) = l._lengths
     grid = lattice_grid(l)
     actor = lattice_edges(grid)
     apply_orientation_to_actor(actor, o)
     m = actor.GetUserTransform().GetMatrix()
     for i in range(3):
         for j in range(3):
             self.assertEqual(Bt[i, j], m.GetElement(i, j))
예제 #22
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))
예제 #23
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)
예제 #24
0
    def get_color_from_field(self, grain):
        """Get the color of the given grain according to the chosen field.

        This function will return the color associated with the given grain.
        Depending on how the pole figure has been configured (see the
        `set_map_field` function), it will be obtained from:

         * the grain id, according to the `Microstructure.rand_cmap` function
         * ipf the colour will reflect the orientation according to the IPF
            coloring scheme
         * the field value mapped on a pyplot color map if the lut field of
            the PoleFigure instance is a string.
         * a color directly read from the lut field; in this case the field
            value must reflect the category of the given grain.

        :param grain: the `Grain` instance.
        :return: the color as a 3 element numpy array representing the rgb values.
        
        """
        if self.map_field:
            if self.map_field == 'grain_id':
                col = Microstructure.rand_cmap().colors[grain['idnumber']]
            elif self.map_field == 'ipf':
                if self.axis == 'X':
                    axis = np.array([1., 0., 0.])
                elif self.axis == 'Y':
                    axis = np.array([0., 1., 0.])
                else:
                    axis = np.array([0., 0., 1.])
                col = Orientation.from_rodrigues(
                    grain['orientation']).get_ipf_colour(axis=axis)
            else:
                # retrieve the position of the grain in the list
                rank = self.microstructure.get_grain_ids().tolist().index(
                    grain['idnumber'])
                if type(self.lut) is str:
                    # get the color map from pyplot
                    color_map = cm.get_cmap(self.lut, 256)
                    # use the field value for this grain and the field range bounds
                    color = int(255 * max(
                        min((self.field[rank] - self.field_min_level) /
                            float(self.field_max_level - self.field_min_level),
                            1.0), 0.0))
                    col = color_map(np.arange(256))[color]
                else:
                    col = self.lut[
                        self.field[rank]]  # directly access the color
            return col
        else:
            return np.array([0., 0., 0.])
예제 #25
0
    def plot_euler(phi1, Phi, phi2, **kwargs):
        '''Directly plot a pole figure for a single orientation given its
        three Euler angles.

        ::

          PoleFigure.plot_euler(10, 20, 30)

        :param float phi1: first Euler angle (in degree).
        :param float Phi: second Euler angle (in degree).
        :param float phi2: third Euler angle (in degree).
        '''
        PoleFigure.plot(Orientation.from_euler(np.array([phi1, Phi, phi2])),
                        **kwargs)
예제 #26
0
 def test_angle_zone(self):
     """Verify the angle between X and a particular zone axis expressed
     in (X, Y, Z), given a crystal orientation."""
     # euler angles in degrees
     phi1 = 89.4
     phi = 92.0
     phi2 = 86.8
     orientation = Orientation.from_euler([phi1, phi, phi2])
     gt = orientation.orientation_matrix().transpose()
     # zone axis
     uvw = HklDirection(1, 0, 5, self.ni)
     ZA = gt.dot(uvw.direction())
     if ZA[0] < 0:
         ZA *= -1  # make sur the ZA vector is going forward
     psi0 = np.arccos(np.dot(ZA, np.array([1., 0., 0.])))
     self.assertAlmostEqual(psi0 * 180 / np.pi, 9.2922, 3)
예제 #27
0
 def test_grain_geometry(self):
     m = Microstructure(name='test', autodelete=True)
     grain_map = np.ones((8, 8, 8), dtype=np.uint8)
     m.set_grain_map(grain_map, voxel_size=1.0)
     grain = m.grains.row
     grain['idnumber'] = 1
     grain['orientation'] = Orientation.from_euler([10, 20, 30]).rod
     grain.append()
     m.grains.flush()
     m.recompute_grain_bounding_boxes()
     m.recompute_grain_centers()
     m.recompute_grain_volumes()
     bb1 = m.compute_grain_bounding_box(gid=1)
     self.assertEqual(bb1, ((0, 8), (0, 8), (0, 8)))
     c1 = m.compute_grain_center(gid=1).tolist()
     self.assertEqual(c1, [0., 0., 0.])
     self.assertEqual(m.compute_grain_volume(gid=1), 512)
예제 #28
0
    def plot_pf(self, ax=None, mk='o', ann=False):
        """Create the direct pole figure.

        :param ax: a reference to a pyplot ax to draw the poles.
        :param mk: marker used to plot the poles (disc by default).
        :param bool ann: Annotate the pole with the coordinates of the vector
            if True (False by default).
            
        """
        self.plot_pf_background(ax)
        kwargs = {'ax': ax, 'mk': mk, 'ann': ann}
        if self.resize_markers:
            # compute the max grain volume to normalize
            volume_max = max(self.microstructure.get_grain_volumes())
        for grain in self.microstructure.grains:
            g = Orientation.Rodrigues2OrientationMatrix(grain['orientation'])
            gt = g.transpose()
            if self.resize_markers:
                kwargs['mksize'] = 0.15 * np.sqrt(
                    grain['volume'] / volume_max) * 1000
            label = ''
            if self.map_field == 'grain_id':
                label = 'grain ' + str(grain['idnumber'])
            kwargs['lab'] = label

            for i, hkl_plane in enumerate(self.poles):
                if i > 0:
                    kwargs['lab'] = ''
                c = hkl_plane.normal()
                c_rot = gt.dot(c)
                if self.verbose:
                    h, k, l = hkl_plane.miller_indices()
                    print('plotting (%d%d%d) with normal %s in sample CS '
                          '(corrected for pf axis): %s' % (h, k, l, c, c_rot))
                col = self.get_color_from_field(grain)
                kwargs['col'] = col
                self.plot_pf_dir(c_rot, **kwargs)
        ax.axis([-1.1, 1.1, -1.1, 1.1])
        if self.pflegend and self.map_field == 'grain_id':
            ax.legend(bbox_to_anchor=(0.05, 1),
                      loc=1,
                      numpoints=1,
                      prop={'size': 10})
        ax.axis('off')
        ax.set_title('{%s} direct %s projection' % (self.family, self.proj))
예제 #29
0
 def setUp(self):
     """testing the laue module:"""
     self.ni = Lattice.from_symbol('Ni')
     self.al = Lattice.face_centered_cubic(0.40495)
     self.g4 = Orientation.from_rodrigues(
         [0.0499199, -0.30475322, 0.10396082])
     self.spots = np.array([[76, 211], [77, 281], [86, 435], [90, 563],
                            [112, 128], [151, 459], [151, 639], [161, 543],
                            [170, 325], [176, 248], [189, 70], [190, 375],
                            [213, 670], [250, 167], [294, 54], [310, 153],
                            [323, 262], [358, 444], [360, 507], [369, 163],
                            [378, 535], [384, 86], [402, 555], [442, 139],
                            [444, 224], [452, 565], [476, 292], [496, 88],
                            [501, 547], [514, 166], [522, 525], [531, 433],
                            [536, 494], [559, 264], [581, 57], [625, 168],
                            [663, 607], [679, 69], [686, 363], [694, 240],
                            [703, 315], [728, 437], [728, 518], [743, 609],
                            [756, 128], [786, 413], [789, 271], [790, 534],
                            [791, 205], [818, 123]])
예제 #30
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)