Exemple #1
0
 def get_rotation_matrix_to(self, new_plane):
     n1 = self.get_normal_vector()
     n2 = new_plane.get_normal_vector()
     length_prod = sqrt(inner(n1, n1) * inner(n2, n2))
     cos_angle = dot(n1, n2) / length_prod
     angle = acos(cos_angle)
     p = cross(n1, n2) / length_prod
     sin_angle = sqrt(inner(p, p))
     assert abs(sin_angle - sin(angle)) < 1e-6
     return rodrigues(p / sin_angle, angle, verbose=True)
Exemple #2
0
 def get_rotation_matrix_to(self, new_plane):
     n1 = self.get_normal_vector()
     n2 = new_plane.get_normal_vector()
     length_prod = sqrt(inner(n1,n1) * inner(n2,n2))
     cos_angle = dot(n1, n2) / length_prod
     angle = acos(cos_angle)
     p = cross(n1, n2) / length_prod
     sin_angle = sqrt(inner(p,p))
     assert abs(sin_angle - sin(angle)) < 1e-6
     return rodrigues(p / sin_angle, angle, verbose=True)
Exemple #3
0
def print_boundary_type(axis, plane, theta):
    if (plane == axis * sum(plane) / sum(axis)).all():
        bt = "twist"
    elif inner(plane, axis) == 0:
        R = rodrigues(axis, theta, verbose=False)
        p2 = dot(linalg.inv(R), plane)
        plane2 = csl.scale_to_integers(p2)
        bt = "tilt (%i %i %i) (%i %i %i)" % (tuple(plane) + tuple(plane2))
    else:
        bt = "mixed"
    return bt
Exemple #4
0
def print_boundary_type(axis, plane, theta):
    if (plane == axis * sum(plane) / sum(axis)).all():
        bt = "twist"
    elif inner(plane, axis) == 0:
        R = rodrigues(axis, theta, verbose=False)
        p2 = dot(linalg.inv(R), plane)
        plane2 = csl.scale_to_integers(p2)
        bt = "tilt (%i %i %i) (%i %i %i)" % (tuple(plane) + tuple(plane2))
    else:
        bt = "mixed"
    return bt
Exemple #5
0
def print_details(hkl, m, n):
    sigma = get_cubic_sigma(hkl, m, n)
    theta = get_cubic_theta(hkl, m, n)
    print "sigma=%d, theta=%.3f, m=%d, n=%d, axis=[%d,%d,%d]" % (
            sigma, degrees(theta), m, n, hkl[0], hkl[1], hkl[2])
    R = rodrigues(hkl, theta)
    print
    print "R * sigma =\n%s" % (R * sigma)
    C = find_csl_matrix(sigma, R)
    print "CSL primitive cell (det=%s):\n%s" % (det(C), C)
    ## optional, for FCC
    #C = pc2fcc(C)
    #C = beautify_matrix(C)
    #print_matrix("CSL cell for fcc:", C)

    Cp = make_parallel_to_axis(C, col=2, axis=hkl)
    if (Cp != C).any():
        print "after making z || %s:\n%s" % (hkl, Cp)
    pbc = find_orthorhombic_pbc(Cp)
    print_matrix("Minimal(?) orthorhombic PBC", pbc)
Exemple #6
0
def test_rotmono_adjust():
    lattice = make_zincblende_lattice(symbols=("Si", "C"), a=4.36)
    a = lattice.unit_cell.a
    dimensions = [10 * a, 10 * a, 10 * a]
    theta = radians(float(sys.argv[1]))

    d = dimensions[0]
    n_ = d * sin(theta) / a
    m_ = d / (a * cos(theta))
    n = round(n_)
    m = round(m_)
    new_th = 0.5 * asin(2. * n / m)
    new_d = m * a * cos(new_th)
    print "theta =", degrees(new_th), "  d =", new_d
    dimensions[0] = new_d
    dimensions[1] = round(dimensions[1] / a) * a
    theta = new_th

    rot_mat = rotmat.rodrigues((0, 1, 0), theta, verbose=False)
    config = RotatedMonocrystal(lattice, dimensions, rot_mat)
    config.generate_atoms()
    config.export_atoms("monotest.cfg", format="atomeye")
Exemple #7
0
def _get_orthorhombic_pbc(m):
    """\
    the input is matrix 3x3, the output is diagonal.
    Distorts the input matrix such that the output
    is orthorhombic with the same volume as the
    space defined by the input matrix.
    """
    if is_diagonal(m):
        return m
    else:
        # x, y, z === unit vector in orthogonal cartesian space
        x, y, z = numpy.identity(3)
        # xi, yi, zi === initial matrix (m)
        xi, yi, zi = m
        # xf, yf, zf === final matrix (orthorhombic matrix)
        #
        # rotate full_pbc to make xi colinear with x
        angle = -1.0*numpy.sign(xi[0])*math.acos(xi[0]/linalg.norm(xi))
        ortho = numpy.dot(m, rodrigues(z, angle))
        # yf (zf) is the projection of the rotated yi (zi) onto y (z)
        ortho = numpy.diag(numpy.diagonal(ortho))
        return ortho
Exemple #8
0
def _get_orthorhombic_pbc(m):
    """\
    the input is matrix 3x3, the output is diagonal.
    Distorts the input matrix such that the output
    is orthorhombic with the same volume as the
    space defined by the input matrix.
    """
    if is_diagonal(m):
        return m
    else:
        # x, y, z === unit vector in orthogonal cartesian space
        x, y, z = numpy.identity(3)
        # xi, yi, zi === initial matrix (m)
        xi, yi, zi = m
        # xf, yf, zf === final matrix (orthorhombic matrix)
        #
        # rotate full_pbc to make xi colinear with x
        angle = -1.0 * numpy.sign(xi[0]) * math.acos(xi[0] / linalg.norm(xi))
        ortho = numpy.dot(m, rodrigues(z, angle))
        # yf (zf) is the projection of the rotated yi (zi) onto y (z)
        ortho = numpy.diag(numpy.diagonal(ortho))
        return ortho
Exemple #9
0
def main():
    opts = parse_args()

    # R is a matrix that transforms lattice in the bottom monocrystal
    # to lattice in the upper monocrystal
    R = rodrigues(opts.axis, opts.theta)

    if opts.sigma:
        # C is CSL primitive cell
        C = csl.find_csl_matrix(opts.sigma, R)
        print_matrix("CSL primitive cell", C)

        ## and now we determine CSL for fcc lattice
        #C = csl.pc2fcc(C)
        #C = csl.beautify_matrix(C)
        #print_matrix("CSL cell for fcc:", C)
    else:
        C = identity(3)

    # CSL-lattice must be periodic is our system.
    # * PBC box must be orthonormal
    # * boundaries must be perpendicular to z axis of PBC box

    print "CSL cell with z || [%s %s %s]" % tuple(opts.plane),
    Cp = csl.make_parallel_to_axis(C, col=2, axis=opts.plane)
    print_matrix("", Cp)

    min_pbc = csl.find_orthorhombic_pbc(Cp)
    print_matrix("Minimal(?) orthorhombic PBC", min_pbc)

    min_dim = []
    pbct = min_pbc.transpose().astype(float)
    rot = zeros((3, 3))
    for i in range(3):
        length = sqrt(inner(pbct[i], pbct[i]))
        rot[i] = pbct[i] / length
        min_dim.append(length)
    invrot = rot.transpose()
    assert (numpy.abs(invrot - linalg.inv(rot)) < 1e-9).all(), "%s != %s" % (
                                                     invrot, linalg.inv(rot))
    #print "hack warning: min_dim[1] /= 2."
    #min_dim[1] /= 2.

    if "," in opts.lattice_name:
        name1, name2 = opts.lattice_name.split(",")
        lattice1 = get_named_lattice(name1)
        lattice2 = get_named_lattice(name2)
    else:
        lattice1 = get_named_lattice(opts.lattice_name)
        lattice2 = deepcopy(lattice1)

    if opts.lattice_shift:
        lattice1.shift_nodes(opts.lattice_shift)
        lattice2.shift_nodes(opts.lattice_shift)

    # the anti-phase GB can be made by swapping two species in one grain
    if opts.antiphase:
        assert lattice2.count_species() == 2
        lattice2.swap_node_atoms_names()

    a = lattice1.unit_cell.a
    opts.find_dim([i * a for i in min_dim])

    #rot_mat1 = rodrigues(opts.axis, rot1)
    #rot_mat2 = rodrigues(opts.axis, rot2)
    rot_mat1 = dot(linalg.inv(R), invrot)
    rot_mat2 = invrot
    #print "rot1", "det=%g" % linalg.det(rot_mat1), rot_mat1
    #print "rot2", "det=%g" % linalg.det(rot_mat2), rot_mat2

    title = get_command_line()
    if opts.mono1:
        config = RotatedMonocrystal(lattice1, opts.dim, rot_mat1,
                                    title=title)
    elif opts.mono2:
        config = RotatedMonocrystal(lattice2, opts.dim, rot_mat2,
                                    title=title)
    else:
        config = Bicrystal(lattice1, lattice2, opts.dim, rot_mat1, rot_mat2,
                           title=title)
    config.generate_atoms(z_margin=opts.vacuum)

    if not opts.mono1 and not opts.mono2 and opts.remove_dist > 0:
        print "Removing atoms in distance < %s ..." % opts.remove_dist
        config.remove_close_neighbours(opts.remove_dist)

    if opts.remove_dist2:
        a_atoms = []
        b_atoms = []
        a_name = config.atoms[0].name
        for i in config.atoms:
            if i.name == a_name:
                a_atoms.append(i)
            else:
                b_atoms.append(i)
        config.atoms = []
        for aa in a_atoms, b_atoms:
            print "Removing atoms where %s-%s distance is < %s ..." % (
                                     aa[0].name, aa[0].name, opts.remove_dist2)
            config.remove_close_neighbours(distance=opts.remove_dist2, atoms=aa)
            config.atoms += aa

    if opts.edge:
        z1, z2 = opts.edge
        sel = [n for n, a in enumerate(config.atoms)
               if 0 < a.pos[1] <= config.pbc[1][1] / 2. and z1 < a.pos[2] < z2]
        print "edge: %d atoms is removed" % len(sel)
        for i in reversed(sel):
            del config.atoms[i]

    if opts.all:
        #config.output_all_removal_possibilities(opts.output_filename)
        config.apply_all_possible_cutoffs_to_stgb(opts.output_filename,
                                                  single_cutoff=True)
        return

    if opts.allall:
        config.apply_all_possible_cutoffs_to_stgb(opts.output_filename,
                                                  single_cutoff=False)
        return

    config.export_atoms(opts.output_filename)
Exemple #10
0
def parse_args():
    if len(sys.argv) < 7:
        print usage
        sys.exit()

    opts = BicrystalOptions()
    opts.axis = csl.parse_miller(sys.argv[1])
    print "-------> rotation axis: [%i %i %i]" % tuple(opts.axis)

    opts.parse_sigma_and_find_theta(sys.argv[3])

    plane = sys.argv[2]
    if plane == "twist":
        opts.plane = opts.axis.copy()
    elif plane.startswith("m"):
        m_plane = csl.parse_miller(plane[1:])
        if inner(m_plane, opts.axis) != 0:
            raise ValueError("Axis must be contained in median plane.")
        R = rodrigues(opts.axis, opts.theta / 2., verbose=False)
        plane_ = dot(R, m_plane)
        opts.plane = csl.scale_to_integers(plane_)
    else:
        opts.plane = csl.parse_miller(plane)
    print "-------> boundary plane: (%i %i %i)" % tuple(opts.plane)
    bt = print_boundary_type(opts.axis, opts.plane, opts.theta)
    print "         boundary type:", bt

    opts.req_dim = [float(eval(i, math.__dict__)) for i in sys.argv[4:7]]

    options = sys.argv[7:-1]
    for i in options:
        if i == "nofit":
            assert opts.fit is None
            opts.fit = False
        if i == "nozfit":
            assert opts.zfit is None
            opts.zfit = False
        elif i == "mono1":
            assert opts.mono1 is None
            opts.mono1 = True
        elif i == "mono2":
            assert opts.mono2 is None
            opts.mono2 = True
        elif i == "all":
            assert opts.all is None and opts.allall is None
            opts.all = True
        elif i == "allall":
            assert opts.allall is None and opts.all is None
            opts.allall = True
        elif i.startswith("remove:"):
            assert opts.remove_dist is None
            opts.remove_dist = float(i[7:])
        elif i.startswith("remove2:"):
            assert opts.remove_dist2 is None
            opts.remove_dist2 = float(i[8:])
        elif i.startswith("vacuum:"):
            assert opts.vacuum is None
            opts.vacuum = float(i[7:]) * 10. #nm -> A
        elif i.startswith("lattice:"):
            opts.lattice_name = i[8:]
        elif i.startswith("shift:"):
            s = i[6:].split(",")
            if len(s) != 3:
                raise ValueError("Wrong format of shift parameter")
            opts.lattice_shift = [float(i) for i in s]
        elif i.startswith("edge:"):
            try:
                z1, z2 = i[5:].split(",")
                opts.edge = (float(z1), float(z2))
            except (TypeError, ValueError):
                raise ValueError("Wrong format of edge parameter")
        else:
            raise ValueError("Unknown option: %s" % i)
    # default values
    if opts.fit is None:
        opts.fit = True
    if opts.zfit is None:
        opts.zfit = True
    if opts.mono1 is None:
        opts.mono1 = False
    if opts.mono2 is None:
        opts.mono2 = False
    #if opts.remove_dist is None:
    #    opts.remove_dist = 0.8 * opts.atom_min_dist

    opts.output_filename = sys.argv[-1]
    return opts
Exemple #11
0
def main():
    opts = parse_args()

    # R is a matrix that transforms lattice in the bottom monocrystal
    # to lattice in the upper monocrystal
    R = rodrigues(opts.axis, opts.theta)

    if opts.sigma:
        # C is CSL primitive cell
        C = csl.find_csl_matrix(opts.sigma, R)
        print_matrix("CSL primitive cell", C)

        ## and now we determine CSL for fcc lattice
        #C = csl.pc2fcc(C)
        #C = csl.beautify_matrix(C)
        #print_matrix("CSL cell for fcc:", C)
    else:
        C = identity(3)

    # CSL-lattice must be periodic is our system.
    # * PBC box must be orthonormal
    # * boundaries must be perpendicular to z axis of PBC box

    print "CSL cell with z || [%s %s %s]" % tuple(opts.plane),
    Cp = csl.make_parallel_to_axis(C, col=2, axis=opts.plane)
    print_matrix("", Cp)

    min_pbc = csl.find_orthorhombic_pbc(Cp)
    print_matrix("Minimal(?) orthorhombic PBC", min_pbc)

    min_dim = []
    pbct = min_pbc.transpose().astype(float)
    rot = zeros((3, 3))
    for i in range(3):
        length = sqrt(inner(pbct[i], pbct[i]))
        rot[i] = pbct[i] / length
        min_dim.append(length)
    invrot = rot.transpose()
    assert (numpy.abs(invrot - linalg.inv(rot)) <
            1e-9).all(), "%s != %s" % (invrot, linalg.inv(rot))
    #print "hack warning: min_dim[1] /= 2."
    #min_dim[1] /= 2.

    if "," in opts.lattice_name:
        name1, name2 = opts.lattice_name.split(",")
        lattice1 = get_named_lattice(name1)
        lattice2 = get_named_lattice(name2)
    else:
        lattice1 = get_named_lattice(opts.lattice_name)
        lattice2 = deepcopy(lattice1)

    if opts.lattice_shift:
        lattice1.shift_nodes(opts.lattice_shift)
        lattice2.shift_nodes(opts.lattice_shift)

    # the anti-phase GB can be made by swapping two species in one grain
    if opts.antiphase:
        assert lattice2.count_species() == 2
        lattice2.swap_node_atoms_names()

    a = lattice1.unit_cell.a
    opts.find_dim([i * a for i in min_dim])

    #rot_mat1 = rodrigues(opts.axis, rot1)
    #rot_mat2 = rodrigues(opts.axis, rot2)
    rot_mat1 = dot(linalg.inv(R), invrot)
    rot_mat2 = invrot
    #print "rot1", "det=%g" % linalg.det(rot_mat1), rot_mat1
    #print "rot2", "det=%g" % linalg.det(rot_mat2), rot_mat2

    title = get_command_line()
    if opts.mono1:
        config = RotatedMonocrystal(lattice1, opts.dim, rot_mat1, title=title)
    elif opts.mono2:
        config = RotatedMonocrystal(lattice2, opts.dim, rot_mat2, title=title)
    else:
        config = Bicrystal(lattice1,
                           lattice2,
                           opts.dim,
                           rot_mat1,
                           rot_mat2,
                           title=title)
    config.generate_atoms(z_margin=opts.vacuum)

    if not opts.mono1 and not opts.mono2 and opts.remove_dist > 0:
        print "Removing atoms in distance < %s ..." % opts.remove_dist
        config.remove_close_neighbours(opts.remove_dist)

    if opts.remove_dist2:
        a_atoms = []
        b_atoms = []
        a_name = config.atoms[0].name
        for i in config.atoms:
            if i.name == a_name:
                a_atoms.append(i)
            else:
                b_atoms.append(i)
        config.atoms = []
        for aa in a_atoms, b_atoms:
            print "Removing atoms where %s-%s distance is < %s ..." % (
                aa[0].name, aa[0].name, opts.remove_dist2)
            config.remove_close_neighbours(distance=opts.remove_dist2,
                                           atoms=aa)
            config.atoms += aa

    if opts.edge:
        z1, z2 = opts.edge
        sel = [
            n for n, a in enumerate(config.atoms)
            if 0 < a.pos[1] <= config.pbc[1][1] / 2. and z1 < a.pos[2] < z2
        ]
        print "edge: %d atoms is removed" % len(sel)
        for i in reversed(sel):
            del config.atoms[i]

    if opts.all:
        #config.output_all_removal_possibilities(opts.output_filename)
        config.apply_all_possible_cutoffs_to_stgb(opts.output_filename,
                                                  single_cutoff=True)
        return

    if opts.allall:
        config.apply_all_possible_cutoffs_to_stgb(opts.output_filename,
                                                  single_cutoff=False)
        return

    config.export_atoms(opts.output_filename)
Exemple #12
0
def parse_args():
    if len(sys.argv) < 7:
        print usage
        sys.exit()

    opts = BicrystalOptions()
    opts.axis = csl.parse_miller(sys.argv[1])
    print "-------> rotation axis: [%i %i %i]" % tuple(opts.axis)

    opts.parse_sigma_and_find_theta(sys.argv[3])

    plane = sys.argv[2]
    if plane == "twist":
        opts.plane = opts.axis.copy()
    elif plane.startswith("m"):
        m_plane = csl.parse_miller(plane[1:])
        if inner(m_plane, opts.axis) != 0:
            raise ValueError("Axis must be contained in median plane.")
        R = rodrigues(opts.axis, opts.theta / 2., verbose=False)
        plane_ = dot(R, m_plane)
        opts.plane = csl.scale_to_integers(plane_)
    else:
        opts.plane = csl.parse_miller(plane)
    print "-------> boundary plane: (%i %i %i)" % tuple(opts.plane)
    bt = print_boundary_type(opts.axis, opts.plane, opts.theta)
    print "         boundary type:", bt

    opts.req_dim = [float(eval(i, math.__dict__)) for i in sys.argv[4:7]]

    options = sys.argv[7:-1]
    for i in options:
        if i == "nofit":
            assert opts.fit is None
            opts.fit = False
        if i == "nozfit":
            assert opts.zfit is None
            opts.zfit = False
        elif i == "mono1":
            assert opts.mono1 is None
            opts.mono1 = True
        elif i == "mono2":
            assert opts.mono2 is None
            opts.mono2 = True
        elif i == "all":
            assert opts.all is None and opts.allall is None
            opts.all = True
        elif i == "allall":
            assert opts.allall is None and opts.all is None
            opts.allall = True
        elif i.startswith("remove:"):
            assert opts.remove_dist is None
            opts.remove_dist = float(i[7:])
        elif i.startswith("remove2:"):
            assert opts.remove_dist2 is None
            opts.remove_dist2 = float(i[8:])
        elif i.startswith("vacuum:"):
            assert opts.vacuum is None
            opts.vacuum = float(i[7:]) * 10.  #nm -> A
        elif i.startswith("lattice:"):
            opts.lattice_name = i[8:]
        elif i.startswith("shift:"):
            s = i[6:].split(",")
            if len(s) != 3:
                raise ValueError("Wrong format of shift parameter")
            opts.lattice_shift = [float(i) for i in s]
        elif i.startswith("edge:"):
            try:
                z1, z2 = i[5:].split(",")
                opts.edge = (float(z1), float(z2))
            except (TypeError, ValueError):
                raise ValueError("Wrong format of edge parameter")
        else:
            raise ValueError("Unknown option: %s" % i)
    # default values
    if opts.fit is None:
        opts.fit = True
    if opts.zfit is None:
        opts.zfit = True
    if opts.mono1 is None:
        opts.mono1 = False
    if opts.mono2 is None:
        opts.mono2 = False
    #if opts.remove_dist is None:
    #    opts.remove_dist = 0.8 * opts.atom_min_dist

    opts.output_filename = sys.argv[-1]
    return opts