Example #1
0
def csl_elem_div_thm_l2(t0, l_g2n_g2):
    """
    The csl basis vectors are obtained from the diagonal matrix using the
    algorithm specified in doi:10.1107/S056773947601231X. There are two
    algorithms specified based on numerators or denominators of the T0 matrix.
    The denominators are used in this function.

    Parameters
    ---------------
    T0: numpy array
        The transformation matrix in G1n reference frame

    l_g2n_g2: numpy array
        The 'new' basis vectors of g2 lattice (g2n) in g2 reference frame

    Returns
    ------------
    l_csl_g2: numpy array
        The CSL basis vectors in g2 reference frame
    """
    t0 = np.array(t0)
    l2 = np.array(l_g2n_g2)

    if t0.shape[0] == 3:
        q1 = int_man.rat(np.array(t0[0, 0]), 1e-06)[1][0][0]
        q2 = int_man.rat(np.array(t0[1, 1]), 1e-06)[1][0][0]
        q3 = int_man.rat(np.array(t0[2, 2]), 1e-06)[1][0][0]
        l_csl_g2 = np.dot(l2, np.array([[q1, 0, 0], [0, q2, 0], [0, 0, q3]]))
    elif t0.shape[0] == 2:
        q1 = int_man.rat(np.array(t0[0, 0]), 1e-06)[1][0][0]
        q2 = int_man.rat(np.array(t0[1, 1]), 1e-06)[1][0][0]
        l_csl_g2 = np.dot(l2, np.array([[q1, 0, 0], [0, q2, 0]]))
    return l_csl_g2
Example #2
0
def csl_elem_div_thm_l1(T0, l_g1n_g1):
    """
    The csl basis vectors are obtained from the diagonal matrix using the
    algorithm specified in doi:10.1107/S056773947601231X. There are two
    algorithms specified based on numerators or denominators of the T0 matrix.
    The numerators are used in this function.

    Parameters
    ---------------
    T0: numpy array
        The transformation matrix in G1n reference frame

    l_g1n_g1: numpy array
        The 'new' basis vectors of g1 lattice (g1n) in g1 reference frame

    Returns
    ------------
    l_csl_g1: numpy array
        The CSL basis vectors in g1 reference frame
    """
    T0 = np.array(T0)
    L1 = np.array(l_g1n_g1)

    if T0.shape[0] == 3:
        p1 = int_man.rat(np.array(T0[0, 0]), 1e-06)[0][0][0]
        p2 = int_man.rat(np.array(T0[1, 1]), 1e-06)[0][0][0]
        p3 = int_man.rat(np.array(T0[2, 2]), 1e-06)[0][0][0]
        l_csl_g1 = np.dot(L1, np.array([[p1, 0, 0], [0, p2, 0], [0, 0, p3]]))
    elif T0.shape[0] == 2:
        p1 = int_man.rat(np.array(T0[0, 0]), 1e-06)[0][0][0]
        p2 = int_man.rat(np.array(T0[1, 1]), 1e-06)[0][0][0]
        l_csl_g1 = np.dot(L1, np.array([[p1, 0, 0], [0, p2, 0]]))
    return l_csl_g1
Example #3
0
def compute_inp_params(lattice, sig_type):
    """
    tau and kmax necessary for possible integer quadruple combinations
    are computed

    Parameters
    ----------------
    lattice: Lattice class
        Attributes of the underlying lattice

    sig_type: {'common', 'specific'}

    Returns
    -----------
    tau: float
        tau is a rational number :math:`= \\frac{\\nu}{\\mu}`

    kmax: float
        kmax is an integer that depends on :math:`\\mu \\ , \\nu`
    """
    lat_params = lattice.lat_params
    cryst_ptgrp = proper_ptgrp(lattice.cryst_ptgrp)

    if cryst_ptgrp == 'D3':
        c_alpha = np.cos(lat_params['alpha'])
        tau = c_alpha / (1 + 2 * c_alpha)
        if sig_type == 'specific':
            [nu, mu] = int_man.rat(tau)
            rho = mu - 3 * nu
            kmax = 4 * mu * rho
        elif sig_type == 'common':
            kmax = []

    if cryst_ptgrp == 'D4':
        tau = (lat_params['a'] ** 2) / (lat_params['c'] ** 2)
        if sig_type == 'specific':
            [nu, mu] = int_man.rat(tau)
            kmax = 4 * mu * nu
        if sig_type == 'common':
            kmax = []

    if cryst_ptgrp == 'D6':
        tau = (lat_params['a'] ** 2) / (lat_params['c'] ** 2)
        if sig_type == 'specific':
            [nu, mu] = int_man.rat(tau)
            if np.remainder(nu, 2) == 0:
                if np.remainder(nu, 4) == 0:
                    kmax = 3 * mu * nu
                else:
                    kmax = 6 * mu * nu
            else:
                kmax = 12 * mu * nu
        if sig_type == 'common':
            kmax = []

    if cryst_ptgrp == 'O':
        tau = 1
        kmax = []

    return tau, kmax
def compute_inp_params(lattice, sig_type):
    """
    tau and kmax necessary for possible integer quadruple combinations
    are computed

    Parameters
    ----------------
    lattice: Lattice class
        Attributes of the underlying lattice

    sig_type: {'common', 'specific'}

    Returns
    -----------
    tau: float
        tau is a rational number :math:`= \\frac{\\nu}{\\mu}`

    kmax: float
        kmax is an integer that depends on :math:`\\mu \\ , \\nu`
    """
    lat_params = lattice.lat_params
    cryst_ptgrp = proper_ptgrp(lattice.cryst_ptgrp)

    if cryst_ptgrp == 'D3':
        c_alpha = np.cos(lat_params['alpha'])
        tau = c_alpha / (1 + 2 * c_alpha)
        if sig_type == 'specific':
            [nu, mu] = int_man.rat(tau)
            rho = mu - 3 * nu
            kmax = 4 * mu * rho
        elif sig_type == 'common':
            kmax = []

    if cryst_ptgrp == 'D4':
        tau = (lat_params['a']**2) / (lat_params['c']**2)
        if sig_type == 'specific':
            [nu, mu] = int_man.rat(tau)
            kmax = 4 * mu * nu
        if sig_type == 'common':
            kmax = []

    if cryst_ptgrp == 'D6':
        tau = (lat_params['a']**2) / (lat_params['c']**2)
        if sig_type == 'specific':
            [nu, mu] = int_man.rat(tau)
            if np.remainder(nu, 2) == 0:
                if np.remainder(nu, 4) == 0:
                    kmax = 3 * mu * nu
                else:
                    kmax = 6 * mu * nu
            else:
                kmax = 12 * mu * nu
        if sig_type == 'common':
            kmax = []

    if cryst_ptgrp == 'O':
        tau = 1
        kmax = []

    return tau, kmax
Example #5
0
def sigma_calc(t_g1tog2_g1):
    """
    Computes the sigma of the transformation matrix

    * if det(T) = det(T^{-1}) then sigma1 = sigma2 is returned
    * if det(T) \\neq det(T^{-1}) then max(sigma1, sigma2) is returned

    """

    R = np.array(t_g1tog2_g1)
    R2 = np.linalg.det(R)*np.linalg.inv(R)
    n1, d1 = int_man.rat(R)
    n2, d2 = int_man.rat(R2)
    # -----------------------------
    Sigma21 = int_man.lcm_array(d1[:])
    # -----------------------------
    Sigma22 = int_man.lcm_array(d2[:])
    Sigma = np.array([Sigma21, Sigma22]).max()
    return Sigma
Example #6
0
    sig_rots = {}
    sig_rots[sig_type] = csl_rots
    save_csl_rots(sig_rots, sig_type, l1)

elif test_case == 5:
    lat_tau = []
    lat_tau.append(1.0/9.0)
    ca_rat = []
    sig_type = 'specific'
    sig_rots = {}
    for tau_vals in lat_tau:
        ca_rat = np.sqrt(1/tau_vals)
        lat_type = 'tP_ca'
        l1 = lat.Lattice(lat_type, ca_rat)
        csl_rots = lit_csl_rots(l1, sig_type)
        [n1, d1] = int_man.rat(tau_vals)
        nu = n1[0][0]
        mu = d1[0][0]
        tau_str = str(nu) + '_' + str(mu)
        sig_rots[tau_str] = csl_rots
        save_csl_rots(sig_rots, sig_type, l1)

elif test_case == 6:
    lat_tau = []
    lat_tau.append(3.0/7.0)
    lat_tau.append(8.0/19.0)
    lat_tau.append(5.0/12.0)
    lat_tau.append(16.0/39.0)
    lat_tau.append(11.0/27.0)
    lat_tau.append(2.0/5.0)
    lat_tau.append(7.0/18.0)
Example #7
0
def csl_rotations(sigma, sig_type, lat_type):
    """
    The function computes the CSL rotation matrices r_g1tog2_g1 corresponding
    to a give sigma and lattice

    Parameters
    ----------
    sigma : int
        Sigma corresponding to the transformation matrix

    sig_type: {'common', 'specific'}
        If the sigma generating function depends on the lattice type, then
        sig_type is 'specific', otherwise it is 'common'

    lat_type: Lattice class
        Attributes of the underlying lattice

    Returns
    -------
    sig_rots: dictionary
    keys: 'N', 'D'
    sig_rots['N'], sig_rots['D']: Numerator and Integer matrices
        The transformation matrix is N/D in the g1 reference frame
        (i.e. r_g1tog2_g1)

    Notes
    -------
    The following steps are considered to obtain the sigma rotation:

    * compute_inp_params: computes tau and kmax that fixes the range of
      integer qudruples sampled
    * mesh_muvw: Creates the integer quadruples that depend on sigma,
      tau, kmax, crystallographic point group
    * eliminate_idrots: Eliminates Identity rotations
    * If specific rotations are desired:
        -  mesh_muvw_fz: Restricts quadruples to fundamental zone
        -  check_fsig_int: Filters out quadruples that do not meet the
           condition specified in this function
    * sigtype_muvw: Filters out quadruple combinations depending on
      the type of sigma rotation
    * eliminate_mults: Eliminates integer quadruples that are same except for
      a scaling factor
    * check_sigma: Returns integer quadruples that result in the sigma rotation
    * compute_tmat: Computes the transformation matrix from the integer
      quadruple
    * disorient_sigmarots: Converts all the transformations to the fundamental
      zone of the corresponding crystallogrphic point group
    * check_sigma_rots: Checks that the transformation matrix is a sigma
      rotation and returns them as numerator and denominator matrices
    """

    cryst_ptgrp = proper_ptgrp(lat_type.cryst_ptgrp)
    lat_type.cryst_ptgrp = cryst_ptgrp

    if cryst_ptgrp in ['T', 'Td', 'Th', 'O', 'Oh']:
        if np.remainder(sigma, 2) == 0:
            return {'N': np.empty(0), 'D': np.empty(0)}

    # Define Parameters
    [tau, kmax] = compute_inp_params(lat_type, sig_type)
    [nu, mu] = int_man.rat(tau)

    if sig_type == 'specific':
        lat_args = {}
        lat_args['mu'] = mu[0][0]
        lat_args['nu'] = nu[0][0]
        lat_args['kmax'] = kmax[0][0]
        # Create Integer Quadruples
        quad_int = mesh_muvw(cryst_ptgrp, sigma, sig_type, lat_args)
        # Restrict to Fundamental Zone
        quad_int = mesh_muvw_fz(quad_int, cryst_ptgrp, sig_type, lat_args)
        # Eliminate Identity Rotations
        quad_int = eliminate_idrots(quad_int)
        # Check $\frac{F}{\Sigma}$ is an iteger and a divisor of kmax
        quad_int = check_fsig_int(quad_int, cryst_ptgrp, sigma, lat_args)
    else:
        quad_int = mesh_muvw(cryst_ptgrp, sigma, sig_type)
        # Eliminate Identity Rotations
        quad_int = eliminate_idrots(quad_int)

    # Keep only 'specific' or 'common' rotations
    quad_int = sigtype_muvw(quad_int, cryst_ptgrp, sig_type)

    # Keep only those quadruples such that gcd(m, U, V, W) = 1
    quad_int = eliminate_mults(quad_int)

    # Compute $\Sigma$ and check with input $\Sigma$
    if sig_type == 'common':
        quad_int = check_sigma(quad_int, sigma, cryst_ptgrp, sig_type)
    if sig_type == 'specific':
        quad_int = check_sigma(quad_int, sigma, cryst_ptgrp,
                               sig_type, lat_args)

    if np.size(quad_int) == 0:
        return {'N': np.empty(0), 'D': np.empty(0)}

    # Compute rotation matrices in G1 lattice
    r_g1tog2_g1 = compute_tmat(quad_int, tau, lat_type)
    l_p_po = lat_type.l_p_po

    # Convert to disorientations to keep the unique rotations
    r_g1tog2_g1 = disorient_sigmarots(r_g1tog2_g1, l_p_po, cryst_ptgrp)

    if np.size(r_g1tog2_g1) == 0:
        return {'N': np.empty(0), 'D': np.empty(0)}
    else:
        # Check that r_g1tog2_g1 are rational with lcm of denominator matrices
        # equal to $\Sigman$
        sig_rots = check_sigma_rots(r_g1tog2_g1, sigma)
        return sig_rots
def csl_rotations(sigma, sig_type, lat_type):
    """
    The function computes the CSL rotation matrices r_g1tog2_g1 corresponding
    to a give sigma and lattice

    Parameters
    ----------
    sigma : int
        Sigma corresponding to the transformation matrix

    sig_type: {'common', 'specific'}
        If the sigma generating function depends on the lattice type, then
        sig_type is 'specific', otherwise it is 'common'

    lat_type: Lattice class
        Attributes of the underlying lattice

    Returns
    -------
    sig_rots: dictionary
    keys: 'N', 'D'
    sig_rots['N'], sig_rots['D']: Numerator and Integer matrices
        The transformation matrix is N/D in the g1 reference frame
        (i.e. r_g1tog2_g1)

    Notes
    -------
    The following steps are considered to obtain the sigma rotation:

    * compute_inp_params: computes tau and kmax that fixes the range of
      integer qudruples sampled
    * mesh_muvw: Creates the integer quadruples that depend on sigma,
      tau, kmax, crystallographic point group
    * eliminate_idrots: Eliminates Identity rotations
    * If specific rotations are desired:
        -  mesh_muvw_fz: Restricts quadruples to fundamental zone
        -  check_fsig_int: Filters out quadruples that do not meet the
           condition specified in this function
    * sigtype_muvw: Filters out quadruple combinations depending on
      the type of sigma rotation
    * eliminate_mults: Eliminates integer quadruples that are same except for
      a scaling factor
    * check_sigma: Returns integer quadruples that result in the sigma rotation
    * compute_tmat: Computes the transformation matrix from the integer
      quadruple
    * disorient_sigmarots: Converts all the transformations to the fundamental
      zone of the corresponding crystallogrphic point group
    * check_sigma_rots: Checks that the transformation matrix is a sigma
      rotation and returns them as numerator and denominator matrices
    """

    cryst_ptgrp = proper_ptgrp(lat_type.cryst_ptgrp)
    lat_type.cryst_ptgrp = cryst_ptgrp

    if cryst_ptgrp in ['T', 'Td', 'Th', 'O', 'Oh']:
        if np.remainder(sigma, 2) == 0:
            return {'N': np.empty(0), 'D': np.empty(0)}

    # Define Parameters
    [tau, kmax] = compute_inp_params(lat_type, sig_type)
    [nu, mu] = int_man.rat(tau)

    if sig_type == 'specific':
        lat_args = {}
        lat_args['mu'] = mu[0][0]
        lat_args['nu'] = nu[0][0]
        lat_args['kmax'] = kmax[0][0]
        # Create Integer Quadruples
        quad_int = mesh_muvw(cryst_ptgrp, sigma, sig_type, lat_args)
        # Restrict to Fundamental Zone
        quad_int = mesh_muvw_fz(quad_int, cryst_ptgrp, sig_type, lat_args)
        # Eliminate Identity Rotations
        quad_int = eliminate_idrots(quad_int)
        # Check $\frac{F}{\Sigma}$ is an iteger and a divisor of kmax
        quad_int = check_fsig_int(quad_int, cryst_ptgrp, sigma, lat_args)
    else:
        quad_int = mesh_muvw(cryst_ptgrp, sigma, sig_type)
        # Eliminate Identity Rotations
        quad_int = eliminate_idrots(quad_int)

    # Keep only 'specific' or 'common' rotations
    quad_int = sigtype_muvw(quad_int, cryst_ptgrp, sig_type)

    # Keep only those quadruples such that gcd(m, U, V, W) = 1
    quad_int = eliminate_mults(quad_int)

    # Compute $\Sigma$ and check with input $\Sigma$
    if sig_type == 'common':
        quad_int = check_sigma(quad_int, sigma, cryst_ptgrp, sig_type)
    if sig_type == 'specific':
        quad_int = check_sigma(quad_int, sigma, cryst_ptgrp, sig_type,
                               lat_args)

    if np.size(quad_int) == 0:
        return {'N': np.empty(0), 'D': np.empty(0)}

    # Compute rotation matrices in G1 lattice
    r_g1tog2_g1 = compute_tmat(quad_int, tau, lat_type)
    l_p_po = lat_type.l_p_po

    # Convert to disorientations to keep the unique rotations
    r_g1tog2_g1 = disorient_sigmarots(r_g1tog2_g1, l_p_po, cryst_ptgrp)

    if np.size(r_g1tog2_g1) == 0:
        return {'N': np.empty(0), 'D': np.empty(0)}
    else:
        # Check that r_g1tog2_g1 are rational with lcm of denominator matrices
        # equal to $\Sigman$
        sig_rots = check_sigma_rots(r_g1tog2_g1, sigma)
        return sig_rots