def test_lattice_lindep(): from ase.lattice.cubic import FaceCenteredCubic from ase.lattice.hexagonal import HexagonalClosedPacked from ase.test import must_raise with must_raise(ValueError): # The Miller indices of the surfaces are linearly dependent atoms = FaceCenteredCubic(symbol='Cu', miller=[[1, 1, 0], [1, 1, 0], [0, 0, 1]]) # This one should be OK: atoms = FaceCenteredCubic(symbol='Cu', miller=[[1, 1, 0], [0, 1, 0], [0, 0, 1]]) print(atoms.get_cell()) with must_raise(ValueError): # The directions spanning the unit cell are linearly dependent atoms = FaceCenteredCubic(symbol='Cu', directions=[[1, 1, 0], [1, 1, 0], [0, 0, 1]]) with must_raise(ValueError): # The directions spanning the unit cell are linearly dependent atoms = FaceCenteredCubic(symbol='Cu', directions=[[1, 1, 0], [1, 0, 0], [0, 1, 0]]) # This one should be OK: atoms = FaceCenteredCubic(symbol='Cu', directions=[[1, 1, 0], [0, 1, 0], [0, 0, 1]]) print(atoms.get_cell()) with must_raise((ValueError, NotImplementedError)): # The Miller indices of the surfaces are linearly dependent atoms = HexagonalClosedPacked(symbol='Mg', miller=[[1, -1, 0, 0], [1, 0, -1, 0], [0, 1, -1, 0]]) # This one should be OK # # It is not! The miller argument is broken in hexagonal crystals! # # atoms = HexagonalClosedPacked(symbol='Mg', # miller=[[1, -1, 0, 0], # [1, 0, -1, 0], # [0, 0, 0, 1]]) # print(atoms.get_cell()) with must_raise(ValueError): # The directions spanning the unit cell are linearly dependent atoms = HexagonalClosedPacked(symbol='Mg', directions=[[1, -1, 0, 0], [1, 0, -1, 0], [0, 1, -1, 0]]) # This one should be OK atoms = HexagonalClosedPacked(symbol='Mg', directions=[[1, -1, 0, 0], [1, 0, -1, 0], [0, 0, 0, 1]]) print(atoms.get_cell())
def SurfaceEnergy_Calculator(self, EMT, PARAMETERS): """ The Method calculates and returns the surface energy for the given element along the [0,0,1] and [1,1,1] directions in the FCC crystal structure. """ # The size of the crystals are set " NEED TO THINK ABOUT THESE LATER! " S001 = 3, 3, 5 S111 = 5, 5, 5 # The surfaces (slabs) are created (pbc=(1,1,0) creates periodic boudry conditions # in two of three directions and thus leaves the last direction as two surfaces. Surface001 = FaceCenteredCubic(size=S001, symbol=self.Element, pbc=(1, 1, 0)) Surface111 = FaceCenteredCubic(size=S111, directions=[[1, -1, 0], [1, 1, -2], [1, 1, 1]], symbol=self.Element, pbc=(1, 1, 0)) Surface001.set_calculator(EMT) Surface111.set_calculator(EMT) # A structural relaxsation is run for the surface crystal in order to secure # the correct structure of the crystal. dyn001 = BFGS(Surface001, trajectory='relaxedsurface001.traj') dyn111 = BFGS(Surface111, trajectory='relaxedsurface111.traj') dyn001.run(fmax=0.01) dyn111.run(fmax=0.01) # The referance bulk crystals are created Bulk001 = FaceCenteredCubic(size=S001, symbol=self.Element) Bulk111 = FaceCenteredCubic(size=S111, directions=[[1, -1, 0], [1, 1, -2], [1, 1, 1]], symbol=self.Element) # The calculator is assigned Bulk001.set_calculator(EMT) Bulk111.set_calculator(EMT) # The surface area is calculated # The cross product between the x and y axis in the crystal is determined Cross001 = numpy.cross(Bulk001.get_cell()[:, 0], Bulk001.get_cell()[:, 1]) Cross111 = numpy.cross(Bulk111.get_cell()[:, 0], Bulk111.get_cell()[:, 1]) # The area of the surface is determined from the formular A = |X x Y|. area001 = numpy.sqrt(numpy.dot(Cross001, Cross001)) area111 = numpy.sqrt(numpy.dot(Cross111, Cross111)) # The surface energy is calculated and returned (two surfaces are present in # SurfaceRelaxed) return ((Surface001.get_potential_energy() - Bulk001.get_potential_energy()) / 2 / area001, (Surface111.get_potential_energy() - Bulk111.get_potential_energy()) / 2 / area111)
def atoms(): # (100) oriented block atoms = FaceCenteredCubic(size=(5, 5, 5), symbol=symb, pbc=(1, 1, 0)) assert len(atoms) == 5 * 5 * 5 * 4 c = atoms.get_cell() checkang(c[0], c[1], pi / 2) checkang(c[0], c[2], pi / 2) checkang(c[1], c[2], pi / 2) assert np.abs(5 * a0 - c[2, 2]) < 1e-10 return atoms
def C44_Calculator(self, EMT, PARAMETERS): # Return 0 is used when the method is not desired to be used # return 0 """ This method uses the given EMT calculator to calculate and return the value of the matrix element C44 for a system of atoms of a given element type. The calculation is done by using that: C44 = 1 / Volume * d^2/depsilon^2 (E_system) where epsilon is the displacement in one direction of the system along one axis diveded by the highth of the system. """ # An atom object is created and the calculator attached atoms = FaceCenteredCubic(size=(self.Size, self.Size, self.Size), symbol=self.Element) atoms.set_calculator(EMT) # The volume of the sample is calculated Vol = atoms.get_volume() # The value of the relative displacement, epsilon, is set epsilon = 1. / 1000 # The matrix used to change the unitcell by n*epsilon is initialized LMM = numpy.array([[1, 0, -10 * epsilon], [0, 1, 0], [0, 0, 1]]) # The original unit cell is conserved OCell = atoms.get_cell() # The array for storing the energies is initialized E_calc = numpy.zeros(20) # The numerical value of C44 is calculated for i in range(20): # The new system cell based on the pertubation epsilon is set atoms.set_cell(numpy.dot(OCell, LMM), scale_atoms=True) # The energy of the system is calculated E_calc[i] = atoms.get_potential_energy() # The value of LMM is updated LMM[0, 2] += epsilon # A polynomial fit is made for the energy as a function of epsilon # The displaced axis is defined da = numpy.arange(-10, 10) * epsilon # The fit is made Poly = numpyfit.polyfit(da, E_calc, 2) # Now C44 can be estimated from this fit by the second derivative of Poly = a * x^2 + b * x + c , multiplied # with 1 / (2 * Volume) of system C44 = 2. / Vol * Poly[0] return C44
def test_minimum_image_convention(dim): size = 2 if dim == 2: pbc = [True, True, False] else: pbc = [True, True, True] atoms = FaceCenteredCubic(size=[size, size, size], symbol='Cu', latticeconstant=2, pbc=pbc) if dim == 2: cell = atoms.cell.uncomplete(atoms.pbc) atoms.set_cell(cell, scale_atoms=False) d0 = atoms.get_distances(0, np.arange(len(atoms)), mic=True) if dim == 2: U = np.array([[1, 2, 0], [0, 1, 0], [0, 0, 1]]) else: U = np.array([[1, 2, 2], [0, 1, 2], [0, 0, 1]]) assert np.linalg.det(U) == 1 atoms.set_cell(U.T @ atoms.cell, scale_atoms=False) atoms.wrap() d1 = atoms.get_distances(0, np.arange(len(atoms)), mic=True) assert_allclose(d0, d1) vnbrlist = NeighborListMic(atoms.get_positions(), atoms.cell, atoms.pbc) d2 = np.linalg.norm(vnbrlist, axis=1) assert_allclose(d0, d2) nl = NeighborList(np.ones(len(atoms)) * 2 * size * np.sqrt(3), bothways=True, primitive=PrimitiveNeighborList) nl.update(atoms) indices, offsets = nl.get_neighbors(0) d3 = float("inf") * np.ones(len(atoms)) for i, offset in zip(indices, offsets): p = atoms.positions[i] + offset @ atoms.get_cell() d = np.linalg.norm(p - atoms.positions[0]) d3[i] = min(d3[i], d) assert_allclose(d0, d3)
def Surface110(self, EMT, PARAMETERS): """ The Method calculates and returns the surface energy for the given element along the [1,1,0] direction in the FCC crystal structure. """ # The size of the crystals are set: S110 = 3, 5, 5 # The surfaces (slabs) are created (pbc=(1,1,0) creates periodic boudry conditions # in two of three directions and thus leaves the last direction as two surfaces. Surface110 = FaceCenteredCubic(size=S110, directions=[[1, -1, 0], [0, 0, 1], [1, 1, 0]], symbol=self.Element, pbc=(1, 1, 0)) Surface110.set_calculator(EMT) # A structural relaxsation is run for the surface crystal in order to secure # the correct structure of the crystal. dyn001 = BFGS(Surface110, logfile=None) dyn001.run(fmax=0.01) # The referance bulk crystals are created Bulk110 = FaceCenteredCubic(size=S110, directions=[[1, -1, 0], [0, 0, 1], [1, 1, 0]], symbol=self.Element) # The calculator is assigned Bulk110.set_calculator(EMT) # The surface area is calculated # The cross product between the x and y axis in the crystal is determined Cross110 = numpy.cross(Bulk110.get_cell()[:, 0], Bulk110.get_cell()[:, 1]) # The area of the surface is determined from the formular A = |X x Y|. area110 = numpy.sqrt(numpy.dot(Cross110, Cross110)) # The surface energy is calculated and returned (two surfaces are present in # SurfaceRelaxed) return ((Surface110.get_potential_energy() - Bulk110.get_potential_energy()) / 2 / area110)
def test_minimum_image_convention(): import numpy as np from numpy.testing import assert_allclose from ase.lattice.cubic import FaceCenteredCubic from ase.neighborlist import mic as NeighborListMic from ase.neighborlist import NeighborList, PrimitiveNeighborList size = 2 atoms = FaceCenteredCubic(size=[size, size, size], symbol='Cu', latticeconstant=2, pbc=(1, 1, 1)) d0 = atoms.get_distances(0, np.arange(len(atoms)), mic=True) U = np.array([[1, 2, 2], [0, 1, 2], [0, 0, 1]]) assert np.linalg.det(U) == 1 atoms.set_cell(U.T @ atoms.cell, scale_atoms=False) atoms.wrap() d1 = atoms.get_distances(0, np.arange(len(atoms)), mic=True) assert_allclose(d0, d1) vnbrlist = NeighborListMic(atoms.get_positions(), atoms.cell, atoms.pbc) d2 = np.linalg.norm(vnbrlist, axis=1) assert_allclose(d0, d2) nl = NeighborList(np.ones(len(atoms)) * 2 * size * np.sqrt(3), bothways=True, primitive=PrimitiveNeighborList) nl.update(atoms) indices, offsets = nl.get_neighbors(0) d3 = float("inf") * np.ones(len(atoms)) for i, offset in zip(indices, offsets): p = atoms.positions[i] + offset @ atoms.get_cell() d = np.linalg.norm(p - atoms.positions[0]) d3[i] = min(d3[i], d) assert_allclose(d0, d3)
def MakeAtoms(elem1, elem2=None): if elem2 is None: elem2 = elem1 a1 = reference_states[elem1]['a'] a2 = reference_states[elem2]['a'] a0 = (0.5 * a1**3 + 0.5 * a2**3)**(1.0 / 3.0) * 1.03 if ismaster: print "Z1 = %i, Z2 = %i, a0 = %.5f" % (elem1, elem2, a0) # 50*50*50 would be big enough, but some vacancies are nice. atoms = FaceCenteredCubic(symbol='Cu', size=(51, 51, 51)) nremove = len(atoms) - 500000 assert nremove > 0 remove = np.random.choice(len(atoms), nremove, replace=False) del atoms[remove] if elem1 != elem2: z = atoms.get_atomic_numbers() z[np.random.choice(len(atoms), len(atoms) / 2, replace=False)] = elem2 atoms.set_atomic_numbers(z) if isparallel: # Move this contribution into position uc = atoms.get_cell() x = mpi.world.rank % cpuLayout[0] y = (mpi.world.rank // cpuLayout[0]) % cpuLayout[1] z = mpi.world.rank // (cpuLayout[0] * cpuLayout[1]) assert (0 <= x < cpuLayout[0]) assert (0 <= y < cpuLayout[1]) assert (0 <= z < cpuLayout[2]) offset = x * uc[0] + y * uc[1] + z * uc[2] new_uc = cpuLayout[0] * uc[0] + cpuLayout[1] * uc[1] + cpuLayout[ 2] * uc[2] atoms.set_cell(new_uc, scale_atoms=False) atoms.set_positions(atoms.get_positions() + offset) # Distribute atoms. Maybe they are all on the wrong cpu, but that will # be taken care of. atoms = MakeParallelAtoms(atoms, cpuLayout) MaxwellBoltzmannDistribution(atoms, T * units.kB) return atoms
def MakeAtoms(elem1, elem2=None): if elem2 is None: elem2 = elem1 a1 = reference_states[elem1]['a'] a2 = reference_states[elem2]['a'] a0 = (0.5 * a1**3 + 0.5 * a2**3)**(1.0/3.0) * 1.03 if ismaster: print "Z1 = %i, Z2 = %i, a0 = %.5f" % (elem1, elem2, a0) # 50*50*50 would be big enough, but some vacancies are nice. atoms = FaceCenteredCubic(symbol='Cu', size=(51,51,51)) nremove = len(atoms) - 500000 assert nremove > 0 remove = np.random.choice(len(atoms), nremove, replace=False) del atoms[remove] if elem1 != elem2: z = atoms.get_atomic_numbers() z[np.random.choice(len(atoms), len(atoms)/2, replace=False)] = elem2 atoms.set_atomic_numbers(z) if isparallel: # Move this contribution into position uc = atoms.get_cell() x = mpi.world.rank % cpuLayout[0] y = (mpi.world.rank // cpuLayout[0]) % cpuLayout[1] z = mpi.world.rank // (cpuLayout[0] * cpuLayout[1]) assert(0 <= x < cpuLayout[0]) assert(0 <= y < cpuLayout[1]) assert(0 <= z < cpuLayout[2]) offset = x * uc[0] + y * uc[1] + z * uc[2] new_uc = cpuLayout[0] * uc[0] + cpuLayout[1] * uc[1] + cpuLayout[2] * uc[2] atoms.set_cell(new_uc, scale_atoms=False) atoms.set_positions(atoms.get_positions() + offset) # Distribute atoms. Maybe they are all on the wrong cpu, but that will # be taken care of. atoms = MakeParallelAtoms(atoms, cpuLayout) MaxwellBoltzmannDistribution(atoms, T * units.kB) return atoms
def test_fcc_directions_ok(): atoms = FaceCenteredCubic(symbol='Cu', directions=[[1, 1, 0], [0, 1, 0], [0, 0, 1]]) print(atoms.get_cell())
def test_fcc_ok(): atoms = FaceCenteredCubic(symbol='Cu', miller=[[1, 1, 0], [0, 1, 0], [0, 0, 1]]) print(atoms.get_cell())
directed (bool): whether the old one was directed or not """ nbr_list_reverse = torch.stack( [nbr_list[:, 0], nbr_list[:, 2], nbr_list[:, 1]], dim=-1) new_nbrs = torch.cat([nbr_list, nbr_list_reverse], dim=0) return new_nbrs if __name__ == "__main__": from ase.lattice.cubic import FaceCenteredCubic atoms = FaceCenteredCubic(symbol='H', size=(3, 3, 3), latticeconstant=1.679, pbc=True) from ase.neighborlist import neighbor_list i, j, d = neighbor_list("ijD", atoms, cutoff=2.5, self_interaction=False) print("ASE calculated {} pairs".format(i.shape[0])) xyz = torch.Tensor(atoms.get_positions()) cell = torch.Tensor(atoms.get_cell()) cutoff = 2.5 nbr_list, offsets = generate_nbr_list(xyz, cutoff, cell) print("torchmd calculated {} pairs".format(nbr_list.shape[0] * 2))
pi = np.pi d = 4.08 atoms = FaceCenteredCubic('Au', latticeconstant=d, directions=((0, 1, 1), (1, 0, 1), (1, 1, 0)), align=False) calc = Hotbit(SCC=False, kpts=(8, 8, 8), txt='bs.cal') atoms.set_calculator(calc) atoms.get_potential_energy() # reciprocal lattice vectors V = atoms.get_volume() a, b, c = atoms.get_cell() a_ = 2 * pi / V * np.cross(b, c) b_ = 2 * pi / V * np.cross(c, a) c_ = 2 * pi / V * np.cross(a, b) gamma = np.array((0, 0, 0)) # a path which connects the L-points and gamma-point kpts, distances, label_points = interpolate_path( (-a_ / 2, a_ / 2, gamma, -b_ / 2, b_ / 2, gamma, -c_ / 2, c_ / 2, gamma, (-a_ - b_ - c_) / 2, (a_ + b_ + c_) / 2), 500) labels = [ "$-a$", '$a$', '$\Gamma$', '$-b$', '$b$', '$\Gamma$', '$-c$', '$c$', '$\Gamma$', '$-a-b-c$', '$a+b+c$' ]
e3 = atoms.get_potential_energy() ReportTest("e3 correct", e3, ecorrect, 0.001) atoms.set_pbc((1,1,0)) atoms.set_positions(atoms.get_positions()) e4 = atoms.get_potential_energy() ReportTest("e4 correct", e4, ecorrect, 0.001) print "Repeating tests with an atom outside the unit cell." for coordinate in (0,1,2): print "Using coordinate number", coordinate atoms = FaceCenteredCubic(directions=[[1,0,0],[0,1,0],[0,0,1]], size=(6,6,6), symbol="Cu", pbc=(1,1,0)) r = atoms.get_positions() uc = atoms.get_cell() r[-1,coordinate] = uc[coordinate,coordinate] * 1.51 atoms.set_positions(r) atoms.set_calculator(EMT()) ecorrect = atoms.get_potential_energy() atoms.set_pbc((0,1,0)) atoms.set_pbc((1,1,0)) e2 = atoms.get_potential_energy() ReportTest("e2 correct", e2, ecorrect, 0.001) atoms.set_pbc((0,1,0)) dummy = atoms.get_potential_energy() assert(fabs(dummy - ecorrect) > 1.0) atoms.set_pbc((1,1,0)) e3 = atoms.get_potential_energy()
import numpy as np from ase.lattice.cubic import FaceCenteredCubic ag = FaceCenteredCubic(directions=[[1, 0, 0], [0, 1, 0], [0, 0, 1]], size=(1, 1, 1), symbol='Ag', latticeconstant=4.0) # these are the reciprocal lattice vectors b1, b2, b3 = np.linalg.inv(ag.get_cell()) ''' g(111) = 1*b1 + 1*b2 + 1*b3 and |g(111)| = 1/d_111 ''' h,k,l = (1, 1, 1) d = 1./np.linalg.norm(h*b1 + k*b2 + l*b3) print('d_111 spacing (method 1) = {0:1.3f} Angstroms'.format(d)) # method #2 hkl = np.array([h, k, l]) G = np.array([b1, b2, b3]) # reciprocal unit cell ''' Gstar is usually defined as this matrix of dot products: Gstar = np.array([[dot(b1,b1), dot(b1,b2), dot(b1,b3)], [dot(b1,b2), dot(b2,b2), dot(b2,b3)], [dot(b1,b3), dot(b2,b3), dot(b3,b3)]]) but I prefer the notationally more compact: Gstar = G .dot. transpose(G) then, 1/d_hkl^2 = hkl .dot. Gstar .dot. hkl ''' Gstar = np.dot(G, G.T) id2 = np.dot(hkl, np.dot(Gstar, hkl))
#some algebra to determine surface normal and the plane of the surface d3 = [2, 1, 1] a1 = np.array([0, 1, 1]) d1 = np.cross(a1, d3) a2 = np.array([0, -1, 1]) d2 = np.cross(a2, d3) #create your slab slab = FaceCenteredCubic(directions=[d1, d2, d3], size=(2, 1, 2), symbol=('Pt'), latticeconstant=3.9) #add some vacuum to your slab uc = slab.get_cell() print(uc) uc[2] += [0, 0, 10] #there are ten layers of vacuum uc = slab.set_cell(uc, scale_atoms=False) #view the slab to make sure it is how you expect view(slab) #some positions needed to place the atom in the correct place x1 = 1.379 x2 = 4.137 x3 = 2.759 y1 = 0.0 y2 = 2.238 z1 = 7.165 z2 = 6.439
def test_center(): # flake8: noqa "Test that atoms.center() works when adding vacuum ()" import numpy as np from math import pi, sqrt, cos from ase import data from ase.lattice.cubic import FaceCenteredCubic def checkang(a, b, phi): "Check the angle between two vectors." cosphi = np.dot(a, b) / sqrt(np.dot(a, a) * np.dot(b, b)) assert np.abs(cosphi - cos(phi)) < 1e-10 symb = "Cu" Z = data.atomic_numbers[symb] a0 = data.reference_states[Z]['a'] # (100) oriented block atoms = FaceCenteredCubic(size=(5, 5, 5), symbol="Cu", pbc=(1, 1, 0)) assert len(atoms) == 5 * 5 * 5 * 4 c = atoms.get_cell() checkang(c[0], c[1], pi / 2) checkang(c[0], c[2], pi / 2) checkang(c[1], c[2], pi / 2) assert np.abs(5 * a0 - c[2, 2]) < 1e-10 # Add vacuum in one direction vac = 10.0 atoms.center(axis=2, vacuum=vac) c = atoms.get_cell() checkang(c[0], c[1], pi / 2) checkang(c[0], c[2], pi / 2) checkang(c[1], c[2], pi / 2) assert np.abs(4.5 * a0 + 2 * vac - c[2, 2]) < 1e-10 # Add vacuum in all directions vac = 4.0 atoms.center(vacuum=vac) c = atoms.get_cell() checkang(c[0], c[1], pi / 2) checkang(c[0], c[2], pi / 2) checkang(c[1], c[2], pi / 2) assert np.abs(4.5 * a0 + 2 * vac - c[0, 0]) < 1e-10 assert np.abs(4.5 * a0 + 2 * vac - c[1, 1]) < 1e-10 assert np.abs(4.5 * a0 + 2 * vac - c[2, 2]) < 1e-10 # Now a general unit cell atoms = FaceCenteredCubic(size=(5, 5, 5), directions=[[1, 0, 0], [0, 1, 0], [1, 0, 1]], symbol="Cu", pbc=(1, 1, 0)) assert len(atoms) == 5 * 5 * 5 * 2 c = atoms.get_cell() checkang(c[0], c[1], pi / 2) checkang(c[0], c[2], pi / 4) checkang(c[1], c[2], pi / 2) assert np.abs(2.5 * a0 - c[2, 2]) < 1e-10 # Add vacuum in one direction vac = 10.0 atoms.center(axis=2, vacuum=vac) c = atoms.get_cell() checkang(c[0], c[1], pi / 2) checkang(c[0], c[2], pi / 4) checkang(c[1], c[2], pi / 2) assert np.abs(2 * a0 + 2 * vac - c[2, 2]) < 1e-10 # Recenter without specifying vacuum atoms.center() c = atoms.get_cell() checkang(c[0], c[1], pi / 2) checkang(c[0], c[2], pi / 4) checkang(c[1], c[2], pi / 2) assert np.abs(2 * a0 + 2 * vac - c[2, 2]) < 1e-10 a2 = atoms.copy() # Add vacuum in all directions vac = 4.0 atoms.center(vacuum=vac) c = atoms.get_cell() checkang(c[0], c[1], pi / 2) checkang(c[0], c[2], pi / 4) checkang(c[1], c[2], pi / 2) assert np.abs(4.5 * a0 + 2 * vac - c[1, 1]) < 1e-10 assert np.abs(2 * a0 + 2 * vac - c[2, 2]) < 1e-10 # One axis at the time: for i in range(3): a2.center(vacuum=vac, axis=i) assert abs(atoms.positions - a2.positions).max() < 1e-12 assert abs(atoms.cell - a2.cell).max() < 1e-12
from ase.lattice.cubic import FaceCenteredCubic from ase.lattice.hexagonal import HexagonalClosedPacked from ase.test import must_raise with must_raise(ValueError): # The Miller indices of the surfaces are linearly dependent atoms = FaceCenteredCubic(symbol='Cu', miller=[[1, 1, 0], [1, 1, 0], [0, 0, 1]]) # This one should be OK: atoms = FaceCenteredCubic(symbol='Cu', miller=[[1, 1, 0], [0, 1, 0], [0, 0, 1]]) print(atoms.get_cell()) with must_raise(ValueError): # The directions spanning the unit cell are linearly dependent atoms = FaceCenteredCubic(symbol='Cu', directions=[[1, 1, 0], [1, 1, 0], [0, 0, 1]]) with must_raise(ValueError): # The directions spanning the unit cell are linearly dependent atoms = FaceCenteredCubic(symbol='Cu', directions=[[1, 1, 0], [1, 0, 0], [0, 1, 0]]) # This one should be OK: atoms = FaceCenteredCubic(symbol='Cu', directions=[[1, 1, 0], [0, 1, 0], [0, 0, 1]]) print(atoms.get_cell()) with must_raise((ValueError, NotImplementedError)): # The Miller indices of the surfaces are linearly dependent
import pylab from box.interpolation import interpolate_path pi = np.pi d = 4.08 atoms = FaceCenteredCubic('Au', latticeconstant=d, directions=((0,1,1),(1,0,1),(1,1,0)), align=False) calc = Hotbit(SCC=False, kpts=(8,8,8), txt='bs.cal') atoms.set_calculator(calc) atoms.get_potential_energy() # reciprocal lattice vectors V = atoms.get_volume() a, b, c = atoms.get_cell() a_ = 2*pi/V*np.cross(b, c) b_ = 2*pi/V*np.cross(c, a) c_ = 2*pi/V*np.cross(a, b) gamma = np.array( (0,0,0) ) # a path which connects the L-points and gamma-point kpts, distances, label_points = interpolate_path((-a_/2, a_/2, gamma, -b_/2, b_/2, gamma, -c_/2, c_/2, gamma, (-a_-b_-c_)/2, (a_+b_+c_)/2), 500) labels = ["$-a$",'$a$','$\Gamma$','$-b$','$b$','$\Gamma$','$-c$','$c$','$\Gamma$','$-a-b-c$','$a+b+c$'] eigs = calc.get_band_energies(kpts,shift=True,rs='k') e_min = np.min(eigs) e_max = np.max(eigs)
print "Temperature is now %.2f K" % (T, ) print "Desired temperature reached!" lgv.set_temperature(T_goal * units.kB) for i in range(2): lgv.run(20) s = atoms.get_stress() p = -(s[0] + s[1] + s[2]) / 3.0 / units.GPa T = atoms.get_kinetic_energy() / (1.5 * atoms.get_number_of_atoms() * units.kB) print "Pressure is %f GPa, desired pressure is %f GPa (T = %.2f K)" % ( p, p_goal, T) dv = (p - p_goal) / bulk print "Adjusting volume by", dv cell = atoms.get_cell() atoms.set_cell(cell * (1.0 + dv / 3.0)) T = atoms.get_kinetic_energy() / (1.5 * atoms.get_number_of_atoms() * units.kB) print "Temperature is now %.2f K" % (T, ) stressstate = array([-2, -1, 0, 0, 0, 0]) * p_goal * units.GPa dyn = NPT(atoms, 5 * units.fs, T_goal * units.kB, stressstate, ttime * units.fs, (ptime * units.fs)**2 * bulk * units.GPa) traj = PickleTrajectory("NPT-atoms.traj", "w", atoms) #dyntraj = ParallelHooverNPTTrajectory("NPT-dyn-traj.nc", dyn, interval = 50) dyn.attach(traj, interval=50) #dyn.Attach(dyntraj) out = open(out1, "w")
def __init__(self, symbol=None, layers=None, positions=None, latticeconstant=None, symmetry=None, cell=None, center=None, multiplicity=1, filename=None, debug=0): self.debug = debug self.multiplicity = multiplicity if filename is not None: # We skip MonteCarloAtoms.__init__, do it manually. self.mc_optim = np.zeros(101, np.intc) self.mc_optim[0] = 10000 # MC optim invalid self.read(filename) return #Find the atomic number if symbol is not None: if isinstance(symbol, str): self.atomic_number = atomic_numbers[symbol] else: self.atomic_number = symbol else: raise Warning('You must specify a atomic symbol or number!') #Find the crystal structure if symmetry is not None: if symmetry.lower() in ['bcc', 'fcc', 'hcp']: self.symmetry = symmetry.lower() else: raise Warning('The %s symmetry does not exist!' % symmetry.lower()) else: self.symmetry = reference_states[self.atomic_number]['symmetry'].lower() if self.debug: print 'Crystal structure:', self.symmetry #Find the lattice constant if latticeconstant is None: if self.symmetry == 'fcc': self.lattice_constant = reference_states[self.atomic_number]['a'] else: raise Warning(('Cannot find the lattice constant ' + 'for a %s structure!' % self.symmetry)) else: self.lattice_constant = latticeconstant if self.debug: print 'Lattice constant(s):', self.lattice_constant #Make the cluster of atoms if layers is not None and positions is None: layers = list(layers) #Make base crystal based on the found symmetry if self.symmetry == 'fcc': if len(layers) != data.lattice[self.symmetry]['surface_count']: raise Warning('Something is wrong with the defined number of layers!') xc = int(np.ceil(layers[1] / 2.0)) + 1 yc = int(np.ceil(layers[3] / 2.0)) + 1 zc = int(np.ceil(layers[5] / 2.0)) + 1 xs = xc + int(np.ceil(layers[0] / 2.0)) + 1 ys = yc + int(np.ceil(layers[2] / 2.0)) + 1 zs = zc + int(np.ceil(layers[4] / 2.0)) + 1 center = np.array((xc, yc, zc)) * self.lattice_constant size = (xs, ys, zs) if self.debug: print 'Base crystal size:', size print 'Center cell position:', center atoms = FaceCenteredCubic(symbol=symbol, size=size, latticeconstant=self.lattice_constant, align=False) else: raise Warning(('The %s crystal structure is not' + ' supported yet.') % self.symmetry) positions = atoms.get_positions() numbers = atoms.get_atomic_numbers() cell = atoms.get_cell() elif positions is not None: numbers = [self.atomic_number] * len(positions) else: numbers = None #Load the constructed atoms object into this object self.set_center(center) MonteCarloAtoms.__init__(self, numbers=numbers, positions=positions, cell=cell, pbc=False) #Construct the particle with the assigned surfasces if layers is not None: self.set_layers(layers)
from __future__ import print_function, division from ase.lattice.cubic import FaceCenteredCubic from ase.lattice.hexagonal import HexagonalClosedPacked from ase.test import must_raise with must_raise(ValueError): # The Miller indices of the surfaces are linearly dependent atoms = FaceCenteredCubic(symbol='Cu', miller=[[1, 1, 0], [1, 1, 0], [0, 0, 1]]) # This one should be OK: atoms = FaceCenteredCubic(symbol='Cu', miller=[[1, 1, 0], [0, 1, 0], [0, 0, 1]]) print(atoms.get_cell()) with must_raise(ValueError): # The directions spanning the unit cell are linearly dependent atoms = FaceCenteredCubic(symbol='Cu', directions=[[1, 1, 0], [1, 1, 0], [0, 0, 1]]) with must_raise(ValueError): # The directions spanning the unit cell are linearly dependent atoms = FaceCenteredCubic(symbol='Cu', directions=[[1, 1, 0], [1, 0, 0], [0, 1, 0]]) # This one should be OK: atoms = FaceCenteredCubic(symbol='Cu', directions=[[1, 1, 0], [0, 1, 0], [0, 0, 1]]) print(atoms.get_cell())
for i2, p2 in enumerate(positions[:i1]): diff = p2 - p1 d2 = np.dot(diff, diff) c6 = (self.sigma**2 / d2)**3 c12 = c6**2 if d2 < self.cutoff**2: self.energy += 4 * self.epsilon * (c12 - c6) - self.shift F = 24 * self.epsilon * (2 * c12 - c6) / d2 * diff self._forces[i1] -= F self._forces[i2] += F self.positions = positions.copy() N = 5 ar = FaceCenteredCubic('Ar', pbc=[(0,0,0)], directions=[[1,0,0],[0,1,0],[0,0,1]], size=[N,N,N]) print ar.get_cell() #view(ar) calc1 = KIMCalculator("ex_model_Ar_P_LJ") ar.set_calculator(calc1) kim_energy = ar.get_potential_energy() print "kim energy = ", kim_energy calc2 = LennardJones(epsilon=epsilon, sigma=sigma, cutoff=cutoff) ar.set_calculator(calc2) ase_energy = ar.get_potential_energy() print "ase energy = ", ase_energy print "difference = ", kim_energy - ase_energy
from asap3 import * from ase.lattice.cubic import FaceCenteredCubic from asap3.Setup.Dislocation import Dislocation from ase.visualize.primiplotter import * print_version(1) splitting = 5 size = (50, 88, 35) #size = (30, 25, 7) Gold = "Au" slab = FaceCenteredCubic(directions=((1, 1, -2), (-1, 1, 0), (1, 1, 1)), size=size, symbol=Gold) basis = slab.get_cell() print basis print "Number of atoms:", len(slab) center = 0.5 * array([basis[0, 0], basis[1, 1], basis[2, 2]]) + array( [0.1, 0.1, 0.1]) offset = 0.5 * splitting * slab.miller_to_direction((-1, 0, 1)) print center d1 = Dislocation(center - offset, slab.miller_to_direction((-1, -1, 0)), slab.miller_to_direction((-2, -1, 1)) / 6.0) d2 = Dislocation(center + offset, slab.miller_to_direction((1, 1, 0)), slab.miller_to_direction((1, 2, 1)) / 6.0) atoms = Atoms(slab) (d1 + d2).apply_to(atoms)
if __name__ == '__main__': from ase.lattice.cubic import FaceCenteredCubic from ase.lattice.bravais import cross a = np.array([0.5, 0, 0]) c = np.array([0, 1, 0], dtype=np.float) b1 = c - a a = np.array([0, 1, 0], np.float) c = np.array([0, 0.5, 0.5]) b2 = c - a a3 = np.array([2, 1, 1], np.float) a1 = cross(b1, a3) a2 = cross(b2, a3) v211 = FaceCenteredCubic(directions=[a1, a2, a3], miller=(None, None, [2, 1, 1]), symbol='Pd', size=(1, 1, 2), debug=0) uc = v211.get_cell() uc[2][2] += 10.0 v211.set_cell(uc) plot_atoms(v211.repeat((2, 2, 1)))
import numpy as np from ase.lattice.cubic import FaceCenteredCubic ag = FaceCenteredCubic(directions=[[1, 0, 0], [0, 1, 0], [0, 0, 1]], size=(1, 1, 1), symbol='Ag', latticeconstant=4.0) # these are the reciprocal lattice vectors b1, b2, b3 = np.linalg.inv(ag.get_cell()) ''' g(111) = 1*b1 + 1*b2 + 1*b3 and |g(111)| = 1/d_111 ''' h, k, l = (1, 1, 1) d = 1. / np.linalg.norm(h * b1 + k * b2 + l * b3) print 'd_111 spacing (method 1) = {0:1.3f} Angstroms'.format(d) #method #2 hkl = np.array([h, k, l]) G = np.array([b1, b2, b3]) #reciprocal unit cell ''' Gstar is usually defined as this matrix of dot products: Gstar = np.array([[dot(b1,b1), dot(b1,b2), dot(b1,b3)], [dot(b1,b2), dot(b2,b2), dot(b2,b3)], [dot(b1,b3), dot(b2,b3), dot(b3,b3)]]) but I prefer the notationally more compact: Gstar = G .dot. transpose(G) then, 1/d_hkl^2 = hkl .dot. Gstar .dot. hkl ''' Gstar = np.dot(G, G.T) id2 = np.dot(hkl, np.dot(Gstar, hkl)) print 'd_111 spacing (method 2) =', np.sqrt(1 / id2) # http://books.google.com/books?id=nJHSqEseuIUC&lpg=PA118&ots=YA9TBldoVH
#some algebra to determine surface normal and the plane of the surface d3=[2,1,1] a1=np.array([0,1,1]) d1=np.cross(a1,d3) a2=np.array([0,-1,1]) d2=np.cross(a2,d3) #create your slab slab =FaceCenteredCubic(directions=[d1,d2,d3], size=(2,1,2), symbol=('Pt'), latticeconstant=3.9) #add some vacuum to your slab uc = slab.get_cell() print(uc) uc[2] += [0,0,10] #there are ten layers of vacuum uc = slab.set_cell(uc,scale_atoms=False) #view the slab to make sure it is how you expect view(slab) #some positions needed to place the atom in the correct place x1 = 1.379 x2 = 4.137 x3 = 2.759 y1 = 0.0 y2 = 2.238 z1 = 7.165 z2 = 6.439
def __init__(self, symbol=None, layers=None, positions=None, latticeconstant=None, symmetry=None, cell=None, center=None, multiplicity=1, filename=None, debug=0): self.debug = debug self.multiplicity = multiplicity if filename is not None: # We skip MonteCarloAtoms.__init__, do it manually. self.mc_optim = np.zeros(101, np.intc) self.mc_optim[0] = 10000 # MC optim invalid self.read(filename) return #Find the atomic number if symbol is not None: if isinstance(symbol, str): self.atomic_number = atomic_numbers[symbol] else: self.atomic_number = symbol else: raise Warning('You must specify a atomic symbol or number!') #Find the crystal structure if symmetry is not None: if symmetry.lower() in ['bcc', 'fcc', 'hcp']: self.symmetry = symmetry.lower() else: raise Warning('The %s symmetry does not exist!' % symmetry.lower()) else: self.symmetry = reference_states[ self.atomic_number]['symmetry'].lower() if self.debug: print 'Crystal structure:', self.symmetry #Find the lattice constant if latticeconstant is None: if self.symmetry == 'fcc': self.lattice_constant = reference_states[ self.atomic_number]['a'] else: raise Warning(('Cannot find the lattice constant ' + 'for a %s structure!' % self.symmetry)) else: self.lattice_constant = latticeconstant if self.debug: print 'Lattice constant(s):', self.lattice_constant #Make the cluster of atoms if layers is not None and positions is None: layers = list(layers) #Make base crystal based on the found symmetry if self.symmetry == 'fcc': if len(layers) != data.lattice[self.symmetry]['surface_count']: raise Warning( 'Something is wrong with the defined number of layers!' ) xc = int(np.ceil(layers[1] / 2.0)) + 1 yc = int(np.ceil(layers[3] / 2.0)) + 1 zc = int(np.ceil(layers[5] / 2.0)) + 1 xs = xc + int(np.ceil(layers[0] / 2.0)) + 1 ys = yc + int(np.ceil(layers[2] / 2.0)) + 1 zs = zc + int(np.ceil(layers[4] / 2.0)) + 1 center = np.array((xc, yc, zc)) * self.lattice_constant size = (xs, ys, zs) if self.debug: print 'Base crystal size:', size print 'Center cell position:', center atoms = FaceCenteredCubic( symbol=symbol, size=size, latticeconstant=self.lattice_constant, align=False) else: raise Warning( ('The %s crystal structure is not' + ' supported yet.') % self.symmetry) positions = atoms.get_positions() numbers = atoms.get_atomic_numbers() cell = atoms.get_cell() elif positions is not None: numbers = [self.atomic_number] * len(positions) else: numbers = None #Load the constructed atoms object into this object self.set_center(center) MonteCarloAtoms.__init__(self, numbers=numbers, positions=positions, cell=cell, pbc=False) #Construct the particle with the assigned surfasces if layers is not None: self.set_layers(layers)
lgv.run(5) T = atoms.get_kinetic_energy() / (1.5 * atoms.get_number_of_atoms() * units.kB) print "Temperature is now %.2f K" % (T,) print "Desired temperature reached!" lgv.set_temperature(T_goal*units.kB) for i in range(2): lgv.run(20) s = atoms.get_stress() p = -(s[0] + s[1] + s[2])/3.0 / units.GPa T = atoms.get_kinetic_energy() / (1.5 * atoms.get_number_of_atoms() * units.kB) print "Pressure is %f GPa, desired pressure is %f GPa (T = %.2f K)" % (p, p_goal, T) dv = (p - p_goal) / bulk print "Adjusting volume by", dv cell = atoms.get_cell() atoms.set_cell(cell * (1.0 + dv/3.0)) T = atoms.get_kinetic_energy() / (1.5 * atoms.get_number_of_atoms() * units.kB) print "Temperature is now %.2f K" % (T,) stressstate = array([-2, -1, 0, 0, 0, 0])*p_goal*units.GPa dyn = NPT(atoms, 5 * units.fs, T_goal*units.kB, stressstate, ttime*units.fs, (ptime*units.fs)**2 * bulk * units.GPa) traj = PickleTrajectory("NPT-atoms.traj", "w", atoms) #dyntraj = ParallelHooverNPTTrajectory("NPT-dyn-traj.nc", dyn, interval = 50) dyn.attach(traj, interval=50) #dyn.Attach(dyntraj) out = open(out1, "w")
from ase.lattice.cubic import FaceCenteredCubic def checkang(a, b, phi): "Check the angle between two vectors." cosphi = np.dot(a,b) / sqrt(np.dot(a,a) * np.dot(b,b)) assert np.abs(cosphi - cos(phi)) < 1e-10 symb = "Cu" Z = data.atomic_numbers[symb] a0 = data.reference_states[Z]['a'] # (100) oriented block atoms = FaceCenteredCubic(size=(5,5,5), symbol="Cu", pbc=(1,1,0)) assert len(atoms) == 5*5*5*4 c = atoms.get_cell() checkang(c[0], c[1], pi/2) checkang(c[0], c[2], pi/2) checkang(c[1], c[2], pi/2) assert np.abs(5 * a0 - c[2,2]) < 1e-10 # Add vacuum in one direction vac = 10.0 atoms.center(axis=2, vacuum=vac) c = atoms.get_cell() checkang(c[0], c[1], pi/2) checkang(c[0], c[2], pi/2) checkang(c[1], c[2], pi/2) assert np.abs(4.5 * a0 + 2* vac - c[2,2]) < 1e-10 # Add vacuum in all directions
d0 = atoms.get_distances(0, np.arange(len(atoms)), mic=True) U = np.array([[1, 2, 2], [0, 1, 2], [0, 0, 1]]) assert np.linalg.det(U) == 1 atoms.set_cell(U.T @ atoms.cell, scale_atoms=False) atoms.wrap() d1 = atoms.get_distances(0, np.arange(len(atoms)), mic=True) assert_allclose(d0, d1) vnbrlist = NeighborListMic(atoms.get_positions(), atoms.cell, atoms.pbc) d2 = np.linalg.norm(vnbrlist, axis=1) assert_allclose(d0, d2) nl = NeighborList(np.ones(len(atoms)) * 2 * size * np.sqrt(3), bothways=True, primitive=PrimitiveNeighborList) nl.update(atoms) indices, offsets = nl.get_neighbors(0) d3 = float("inf") * np.ones(len(atoms)) for i, offset in zip(indices, offsets): p = atoms.positions[i] + offset @ atoms.get_cell() d = np.linalg.norm(p - atoms.positions[0]) d3[i] = min(d3[i], d) assert_allclose(d0, d3)