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)
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)
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
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)
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")
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
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
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)
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
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)