def bulk_with_nano_particle(self): atoms = bulk("Al", a=4.05) * (10, 10, 10) surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] layers = [4, 7, 3] lc = 4.05 nano_part = FaceCenteredCubic('Mg', surfaces, layers, latticeconstant=lc) nano_part_pos = nano_part.get_positions() com = np.mean(nano_part_pos, axis=0) nano_part_pos -= com cell = atoms.get_cell() diag = 0.5 * np.sum(cell, axis=0) atoms_pos = atoms.get_positions() - diag # Insert the nano particles for i in range(nano_part_pos.shape[0]): diff = atoms_pos - nano_part_pos[i, :] lengths = np.sum(diff**2, axis=1) indx = np.argmin(lengths) atoms[indx].symbol = nano_part[i].symbol return atoms
def get_cubic_nano_particle(layer=0): from ase.cluster.cubic import FaceCenteredCubic from ase.geometry import get_layers surfaces = [(1, 0, 0), (0, 1, 0), (0, 0, 1)] layers = cubic_np_layer[layer] lc = 4.05 atoms = FaceCenteredCubic('Si', surfaces, layers, latticeconstant=lc) tags, array = get_layers(atoms, (1, 0, 0)) for t, atom in zip(tags, atoms): if t % 2 == 0: atom.symbol = "Mg" print(atoms.get_chemical_formula()) return atoms
def get_nanoparticle(): from ase.cluster.cubic import FaceCenteredCubic from ase.geometry import get_layers surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] layers = [10, 13, 9] lc = 4.05 atoms = FaceCenteredCubic('Si', surfaces, layers, latticeconstant=lc) tags, array = get_layers(atoms, (1, 0, 0)) for t, atom in zip(tags, atoms): if t % 2 == 0: atom.symbol = "Mg" print(atoms.get_chemical_formula()) atoms.rotate(90, 'z', rotate_cell=True) return atoms
def _spherical_nano_particle_matches(self, conc_init): # Construct a spherical nano particle from ase.cluster.cubic import FaceCenteredCubic from random import choice surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] layers = [6, 9, 5] lc = 4.05 nanoparticle = FaceCenteredCubic('Al', surfaces, layers, latticeconstant=lc) nanoparticle.info = {"lc": lc} symbs = ["Mg", "Si"] for atom in nanoparticle: atom.symbol = choice(symbs) inert1, inert2 = self._nano_particle_matches(conc_init, nanoparticle) match, msg = self._two_covariance_tensors_matches(inert1, inert2) return match, msg
def test_xrdebye(): tolerance = 1E-5 # previously calculated values expected_get = 116850.37344 expected_xrd = np.array([18549.274677, 52303.116995, 38502.372027]) expected_saxs = np.array([372650934.006398, 280252013.563702, 488123.103628]) # test system -- cluster of 587 silver atoms atoms = FaceCenteredCubic('Ag', [(1, 0, 0), (1, 1, 0), (1, 1, 1)], [6, 8, 8], 4.09) xrd = XrDebye(atoms=atoms, wavelength=wavelengths['CuKa1'], damping=0.04, method='Iwasa', alpha=1.01, warn=True) # test get() obtained_get = xrd.get(s=0.09) assert np.abs((obtained_get - expected_get) / expected_get) < tolerance # test XRD obtained_xrd = xrd.calc_pattern(x=np.array([15, 30, 50]), mode='XRD') assert np.allclose(obtained_xrd, expected_xrd, rtol=tolerance) # test SAXS obtained_saxs = xrd.calc_pattern(x=np.array([0.021, 0.09, 0.53]), mode='SAXS') assert np.allclose(obtained_saxs, expected_saxs, rtol=tolerance)
def test_turbomole_au13(): from ase.cluster.cubic import FaceCenteredCubic from ase.calculators.turbomole import Turbomole surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] layers = [1, 2, 1] atoms = FaceCenteredCubic('Au', surfaces, layers, latticeconstant=4.08) params = { 'title': 'Au13-', 'task': 'energy', 'basis set name': 'def2-SV(P)', 'total charge': -1, 'multiplicity': 1, 'use dft': True, 'density functional': 'pbe', 'use resolution of identity': True, 'ri memory': 1000, 'use fermi smearing': True, 'fermi initial temperature': 500, 'fermi final temperature': 100, 'fermi annealing factor': 0.9, 'fermi h**o-lumo gap criterion': 0.09, 'fermi stopping criterion': 0.002, 'scf energy convergence': 1.e-4, 'scf iterations': 250 } calc = Turbomole(**params) atoms.calc = calc calc.calculate(atoms) # use the get_property() method print(calc.get_property('energy')) print(calc.get_property('dipole')) # test restart params = {'task': 'gradient', 'scf energy convergence': 1.e-6} calc = Turbomole(restart=True, **params) assert calc.converged calc.calculate() print(calc.get_property('energy')) print(calc.get_property('forces')) print(calc.get_property('dipole'))
def build_system(self, name): if self.bond_length is None: b = 2 * covalent_radii[atomic_numbers[name]] else: b = self.bond_length return FaceCenteredCubic(name, [(1, 0, 0)], [1], latticeconstant=b * sqrt(2))
def Octahedron(symbol, length, cutoff=0, latticeconstant=None, alloy=False): """ Returns Face Centered Cubic clusters of the octahedral class depending on the choice of cutoff. ============================ ======================= Type Condition ============================ ======================= Regular octahedron cutoff = 0 Truncated octahedron cutoff > 0 Regular truncated octahedron length = 3 * cutoff + 1 Cuboctahedron length = 2 * cutoff + 1 ============================ ======================= Parameters: symbol: string or sequence of int The chemical symbol or atomic number of the element(s). length: int Number of atoms on the square edges of the complete octahedron. cutoff (optional): int Number of layers cut at each vertex. latticeconstant (optional): float The lattice constant. If not given, then it is extracted form ase.data. alloy (optional): bool If true the L1_2 structure is used. Default is False. """ # Check length and cutoff if length < 2: raise ValueError("The length must be greater than one.") if cutoff < 0 or length < 2 * cutoff + 1: raise ValueError( "The cutoff must fulfill: > 0 and <= (length - 1) / 2.") # Create cluster surfaces = [(1, 1, 1), (1, 0, 0)] if length % 2 == 0: center = np.array([0.5, 0.5, 0.5]) layers = [length / 2, length - 1 - cutoff] else: center = np.array([0.0, 0.0, 0.0]) layers = [(length - 1) / 2, length - 1 - cutoff] if not alloy: return FaceCenteredCubic(symbol, surfaces, layers, latticeconstant, center) else: return L1_2(symbol, surfaces, layers, latticeconstant, center)
def xrd(): # test system -- cluster of 587 silver atoms atoms = FaceCenteredCubic('Ag', [(1, 0, 0), (1, 1, 0), (1, 1, 1)], [6, 8, 8], 4.09) return XrDebye(atoms=atoms, wavelength=wavelengths['CuKa1'], damping=0.04, method='Iwasa', alpha=1.01, warn=True)
def test_model_cell(angle=0, extra_space=2): surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] layers = [3, 4, 5] lc = 3.61000 cell = FaceCenteredCubic('Cu', surfaces, layers, latticeconstant=lc) cell[46].number = 50 m = create_model(cell, extra_space=extra_space, pbc=False) m2 = rotate_model(m, cell, angle) return m2, cell
def sphericalFCC(elem, latticeconstant, nlayers): r""" Geneartes spherical cluster of atoms of FCC metal Parameters ---------- elem: string symbol of chemical element. lattice constant: float lattice constant in Angstr. nlayers: number of atomic layers passed to FaceCenteredCubic. Guards the radius of cluster Returns ------- ase.Atoms object Example -------- >>> atoms = sphericalFCC('Ag', 4.09, 8) """ # 1. generate cubical cluster surfaces = [(1, 0, 0)] layers = [nlayers] atoms = FaceCenteredCubic(elem, surfaces, layers, latticeconstant) atoms.center() # 2. cut al lextra atom from cube to make it spherical Xmin = atoms.positions[:, 0].min() Xmax = atoms.positions[:, 0].max() C = (Xmin+Xmax)/2.0 R = C ia = 0 while ia < len(atoms): x2 = (atoms.positions[ia, 0] - C)**2 y2 = (atoms.positions[ia, 1] - C)**2 z2 = (atoms.positions[ia, 2] - C)**2 if (x2 + y2 + z2) > R**2: del atoms[ia] else: ia += 1 return atoms
def read_and_do_montecarlo(filename): d = SurfaceMonteCarloData() d.read(filename) print "Starting "+str(len(d))+" sims." surfaces = data.fcc.surface_names #for n in range(0,len(d)): for n in range(world.rank,len(d),world.size): file = outdir+"/a%05i.amc.gz" % n if not os.path.exists(file): layers = d[n][1] # Really d[n]["layers"] atoms = FaceCenteredCubic(d.atomic_number, surfaces, layers,latticeconstant=d.lattice_constant) resizecluster(atoms, d.fitsize) print "Resized number of atoms:", len(atoms) do_monte_carlo(atoms,n,outdir) world.barrier()#Let the cpu's wait until all in same state.
def read_and_do_montecarlo(filename, use_gas): d = SurfaceMonteCarloData() d.read(filename) print "Starting " + str(len(d)) + " sims." surfaces = data.fcc.surface_names #Only one worker should create the filename outdir = determine_create_dirname(filename) #for n in range(0,len(d)): for n in range(world.rank, len(d), world.size): layers = d[n][1] # Really d[n]["layers"] multiplicity = d.get_multiplicity(n) atoms = FaceCenteredCubic(d.atomic_number, surfaces, layers, latticeconstant=d.lattice_constant) print "Number of atoms:", len(atoms) resizecluster(atoms, d.fitsize) print "Resized number of atoms:", len(atoms) do_monte_carlo(atoms, n, outdir, use_gas, multiplicity) world.barrier() #Let the cpu's wait until all in same state.
from ase.md.verlet import VelocityVerlet from ase import units # Use Asap for a huge performance increase if it is installed use_asap = True if use_asap: from asap3 import EMT size = 4 else: from ase.calculators.emt import EMT size = 2 # Set up a nanoparticle atoms = FaceCenteredCubic('Cu', surfaces=[[1, 0, 0], [1, 1, 0], [1, 1, 1]], layers=(size, size, size), vacuum=4) # Describe the interatomic interactions with the Effective Medium Theory atoms.set_calculator(EMT()) # Do a quick relaxation of the cluster qn = QuasiNewton(atoms) qn.run(0.001, 10) # Set the momenta corresponding to T=1200K MaxwellBoltzmannDistribution(atoms, 1200 * units.kB) Stationary(atoms) # zero linear momentum ZeroRotation(atoms) # zero angular momentum # We want to run MD using the VelocityVerlet algorithm.
dist = 0.001 energy += self.A / dist**self.alpha return energy def __repr__(self): return 'Repulsion potential' def copy(self): return CentralRepulsion(self, R=self.R, A=self.A, alpha=self.alpha) if __name__ == '__main__': from ase.cluster.cubic import FaceCenteredCubic from ase.calculators.emt import EMT from ase.md.verlet import VelocityVerlet from ase.units import fs atoms = FaceCenteredCubic('Ag', [(1, 0, 0)], [1], 4.09) atoms.center(10) atoms.set_calculator(EMT()) c = ConstantForce(10, [0, 1, 0]) # y=dircted force atoms.set_constraint(c) md = VelocityVerlet(atoms, 1*fs, trajectory='cf_test.traj', logfile='-') md.run(100) # from ase.visualize import view # view(atoms)
def Nanoparticle_Builder(metal,lc,surfaces,layers,adsorbate,site,coverage,cell_height,subsys_height,unmasked_layers,E_cut,kpoints,ads_cutoff,ads111,ads100,subsys111_relaxed,subsys100_relaxed,relax): ### ### Function to set up the Nanoparticle base ### #Input pparameters # metal: The metal comprising the substrate/nanoparticle. For example 'Au'. # lc: Lattice constant. For example 4.0800. # surfaces: The surfaces in the NP. For example [(1, 0, 0),(1, 1, 1)]. # layers: The number of layers from the cetner of the NP to each surface. For example: [6,5] # adsorbate: The molecule to be adsorbed on top. Should be an object which ase can read. For example: molecule('CO') # site: Either 'OnTop' or 'Hollow'. Should be 'OnTop' for 100% coverages. # coverage: Desired coverage. Must be 1/n where n is whole number. # cell_height: The height of the subsystem unit cell. For example 6*lc. # subsys_height: Height of subsystem - no. of atom layers. For example: 4. If reading the relaxed subsystem from a traj file MAKE SURE THE HEIGHTS MATCH. # unmasked_layers: The number of layers in the NP subsystem (from the top) that is allowed to move during DFT relaxation. # E_cut: Cutoff energy for DFT PW. # kpoints: k-point grid in the first Brillouin zone. # ads_cutoff: The cutoff for adsorption energy. This determines whether adsorption has occurred for a surface or not. # ads111: If providing a relaxed subsystem, this is the adsorption energy for the 111 surface. # ads100: If providing a relaxed subsystem, this is the adsorption energy for the 100 surface. # subsys111_relaxed: This is an ASE object containing the relaxed subsystem for 111. Necessary to skip DFT. # subsys100_relaxed: This is an ASE object containing the relaxed subsystem for 100. Necessary to skip DFT. # relax: A boolean to determine whether or not DFT calculations have to be run or not. If relax=False, make sure to provide subsys111_relaxed and subsys100_relaxed along with ads111 and ads100. if site==None: site='OnTop' if cell_height==None: cell_height=6*lc if subsys_height==None: subsys_height=3 if unmasked_layers==None: unmasked_layers=1 if E_cut==None: E_cut=200 if kpoints==None: kpoints=(6,6,1) if ads_cutoff==None: ads_cutoff=0 #The bulk structure is created. Nanoparticle = FaceCenteredCubic(metal, surfaces, layers, latticeconstant=lc) Reference = FaceCenteredCubic(metal, surfaces, layers, latticeconstant=lc) #A reference is made for TEM imaging without adsorbates. ##Alternative wulff_construction-based setup. This requires N_atoms and surf_energies list to be set up (for gold, use surf_energies=[1.23,1]). #Nanoparticle = wulff_construction(metal, surfaces, surf_energies,size=N_atoms, 'fcc',rounding='above', latticeconstant=lc) #Reference=wulff_construction(metal, surfaces, surf_energies,size=N_atoms, 'fcc',rounding='above', latticeconstant=lc) surf_atoms=[] #This list will contain indeces for each atom that is on a surface of the nanoparticle. #Each surface is rotated to the top of the unit cell. The corresponding surface atoms are then the atoms with highest y-position. for i in Nanoparticle.get_surfaces(): Nanoparticle.rotate(i,[0,1,0],center="COU") y_max=0 for j in Nanoparticle: if j.position[1]>y_max: y_max=j.position[1] for j in Nanoparticle: if round(j.position[1],2)==round(y_max,2): surf_atoms.append(j.index) Nanoparticle.rotate([0,1,0],i,center="COU") #Now we need to identify the edge atoms. These are the atoms that are part of 2 or more surfaces in the nanoparticle. #Therefore, they will be the atoms that appear more than once in surf_atoms: marked=[] edge_atoms=[] for i in surf_atoms: if i in marked: edge_atoms.append(i) else: marked.append(i) #A subsystem of the bulk is defined. This will be the basis of the DFT calculation. We also define relevant functions to #translate between bulk atom coordinates and the subsystem coordinates. def sizesetup(coverage): #Define the function to set up the size of the unit cell. invconverage = math.floor(1/coverage) for i in range(1,invconverage+1): for j in range(1,invconverage+1): if j/i**2==coverage: return (i,j) break #This function wraps lattice coordinates (i,j) back into the corresponding coordinate in the unit cell. def coordreference(i,j,ucx,ucy,direction): if direction==1: ri = i%ucx ry = j%ucy if direction==3: #If the unit cell is not orthogonal: if ucx%2!=0 and ucy%2!=0: ri = i%ucx ry = j%ucy #If the unit cell is orthogonal: else: i = i+j/2-(j%ucy)/2 #Moving along j also corresponds to movement along i. ri = i%ucx ry = j%ucy return (ri,ry) ss = sizesetup(coverage) ucx = ss[0] ucy = ss[0] height = subsys_height n_adsorbates=ss[1] #Check if the requirement for orthogonal unit cell is met: if ss[0]%2==0: orthogonal=True else: orthogonal=False size = [ucx,ucy,height] #Size of the FCC bulk structure. #Set up subsystems for the 111 and 100 directions. subsys111 = fcc111(symbol=metal, size=size,a=lc, vacuum=None,orthogonal=orthogonal) subsys100=fcc100(symbol=metal, size=size,a=lc, vacuum=None, orthogonal=True) # Give all atoms in top layer a coordinate atomorigo = ucx*ucy*(height-1) n = ucx*ucy*height subsys_coordinates={} i = 0 j = 0 for q in range(atomorigo,n): if (i==ucx): j += 1 i = 0 subsys_coordinates[q] = [i,j,0] i += 1 #Now we have to find a set of basis vectors describing the subsystem surface. if ss[0]>1: #For 111: v1_111=subsys111[atomorigo+1].position-subsys111[atomorigo].position v1_111=np.array([v1_111[0],v1_111[1],0]) v2_111=subsys111[atomorigo+ss[0]].position-subsys111[atomorigo].position v2_111=np.array([v2_111[0],v2_111[1],0]) #For 100: v1_100=subsys100[atomorigo+1].position-subsys100[atomorigo].position v1_100=np.array([v1_100[0],v1_100[1],0]) v2_100=subsys100[atomorigo+ss[0]].position-subsys100[atomorigo].position v2_100=np.array([v2_100[0],v2_100[1],0]) else: v1_111=np.array([0,0,0]) v2_111=np.array([0,0,0]) v1_100=np.array([0,0,0]) v2_100=np.array([0,0,0]) #Now we add adsorbates matching the coverage. They are added along the diagonal in the unit cell. if site=='OnTop': position100=[0,0,0] position111=[0,0,0] else: position100=1/2*v1_100+1/2*v2_100 position111=1/2*v1_111+[0,1/2*v2_111[1],0] zig=True #If zig is false, then the 111 adsorbate won't zag. zags=0 adsorbate_atom_links=[]#This list will link adsorbates to an atom in the surface. for i in range(0,n_adsorbates): zig = not zig if zig and i>1: zags=zags+1 for j in adsorbate: j.tag=i scale=ss[0]/n_adsorbates adsorbate_atom_links.append([i*scale,i*scale]) pos111=position111+i*scale*v1_111+i*scale*v2_111-zags*v1_111 pos100=position100+i*scale*v1_100+i*scale*v2_100 add_adsorbate(subsys111,adsorbate,height=1*lc,position=(pos111[0],pos111[1]),mol_index=0) add_adsorbate(subsys100,adsorbate,height=1*lc,position=(pos100[0],pos100[1]),mol_index=0) subsys111.set_cell([subsys111.cell[0],subsys111.cell[1],([0.,0.,cell_height])]) subsys100.set_cell([subsys100.cell[0],subsys100.cell[1],([0.,0.,cell_height])]) #Create vectors with initial coordinates for each atom. Offsets from these coordinates are found after the DFT is run. x111_i=[] y111_i=[] z111_i=[] x100_i=[] y100_i=[] z100_i=[] for i in range(0,n): x111_i.append(subsys111[i].position[0]) y111_i.append(subsys111[i].position[1]) z111_i.append(subsys111[i].position[2]) x100_i.append(subsys100[i].position[0]) y100_i.append(subsys100[i].position[1]) z100_i.append(subsys100[i].position[2]) if relax: #A subsystem of the bulk is defined. This will be the basis of the DFT calculation. We also define relevant functions to #translate between bulk atom coordinates and the subsystem coordinates. ss = sizesetup(coverage) ucx = ss[0] ucy = ss[0] height = subsys_height n_adsorbates=ss[1] #Check if the requirement for orthogonal unit cell is met: if ss[0]%2==0: orthogonal=True else: orthogonal=False size = [ucx,ucy,height] #Size of the FCC bulk structure. Preferably size_z is odd. #Redefine subsystem for energy calculations: subsys111 = fcc111(symbol=metal, size=size,a=lc, vacuum=None,orthogonal=orthogonal) subsys100=fcc100(symbol=metal, size=size,a=lc, vacuum=None, orthogonal=True) # Give all atoms in top layer a coordinate atomorigo = ucx*ucy*(height-1) n = ucx*ucy*height subsys_coordinates={} i = 0 j = 0 for q in range(atomorigo,n): if (i==ucx): j += 1 i = 0 subsys_coordinates[q] = [i,j,0] i += 1 # Calculate system energies: energyfile = open('energies-%s-%s.txt' % (str(coverage),"butanethiolate_hollow"), 'w') energies = {} for i in ['adsorbate', 'subsys111', 'subsys100']: system = globals()[i].copy() if i=='adsorbate': system.center(vacuum=5) system.set_pbc((1,1,0)) else: system.set_cell([system.cell[0],system.cell[1],([0.,0.,cell_height])]) calc = GPAW(mode=PW(E_cut),kpts=kpoints,xc='BEEF-vdW',txt='energy-%s.txt' % i) system.set_calculator(calc) energy = system.get_potential_energy() energies[i] = energy #Now we have to find a set of basis vectors describing the subsystem surface. if ss[0]>1: #For 111: v1_111=subsys111[atomorigo+1].position-subsys111[atomorigo].position v1_111=np.array([v1_111[0],v1_111[1],0]) v2_111=subsys111[atomorigo+ss[0]].position-subsys111[atomorigo].position v2_111=np.array([v2_111[0],v2_111[1],0]) #For 100: v1_100=subsys100[atomorigo+1].position-subsys100[atomorigo].position v1_100=np.array([v1_100[0],v1_100[1],0]) v2_100=subsys100[atomorigo+ss[0]].position-subsys100[atomorigo].position v2_100=np.array([v2_100[0],v2_100[1],0]) else: v1_111=np.array([0,0,0]) v2_111=np.array([0,0,0]) v1_100=np.array([0,0,0]) v2_100=np.array([0,0,0]) #Now we add adsorbates matching the coverage. They are added along the diagonal in the unit cell. if site=='OnTop': position100=[0,0,0] position111=[0,0,0] else: position100=1/2*v1_100+1/2*v2_100 position111=1/2*v1_111+[0,1/2*v2_111[1],0] zig=True #If zig is false, then the 111 adsorbate won't zag. zags=0 #This is the number of zags that have been performed. adsorbate_atom_links=[]#This list will link adsorbates to an atom in the surface. for i in range(0,n_adsorbates): zig = not zig if zig and i>1: zags=zags+1 for j in adsorbate: j.tag=i scale=ss[0]/n_adsorbates adsorbate_atom_links.append([i*scale,i*scale]) #pos111=position111+((i*scale)/2)*v1_111+[0,i*scale*v2_111[1],0] pos111=position111+i*scale*v1_111+i*scale*v2_111-zags*v1_111 pos100=position100+i*scale*v1_100+i*scale*v2_100 add_adsorbate(subsys111,adsorbate,height=1*lc,position=(pos111[0],pos111[1]),mol_index=0) add_adsorbate(subsys100,adsorbate,height=1*lc,position=(pos100[0],pos100[1]),mol_index=0) subsys111.set_cell([subsys111.cell[0],subsys111.cell[1],([0.,0.,cell_height])]) #subsys110.set_cell([subsys110.cell[0],subsys110.cell[1],([0.,0.,cell_height])]) subsys100.set_cell([subsys100.cell[0],subsys100.cell[1],([0.,0.,cell_height])]) #Create vectors with initial coordinates for each atom. Offsets from these coordinates are found after the DFT is run. x111_i=[] y111_i=[] z111_i=[] x100_i=[] y100_i=[] z100_i=[] for i in range(0,n): x111_i.append(subsys111[i].position[0]) y111_i.append(subsys111[i].position[1]) z111_i.append(subsys111[i].position[2]) x100_i.append(subsys100[i].position[0]) y100_i.append(subsys100[i].position[1]) z100_i.append(subsys100[i].position[2]) #The calculator is set. calc111 = GPAW(mode=PW(E_cut),kpts=kpoints, xc='BEEF-vdW',txt='calc111.out') subsys111.set_calculator(calc111) #The bottom layers of the subsystem are masked such that these atoms do not move during QuasiNewton minimization/relaxation. mask = [i.tag > unmasked_layers and i.symbol==metal for i in subsys100] fixedatoms=FixAtoms(mask=mask) subsys111.set_constraint(fixedatoms) #The subsystem is relaxed until all forces on atoms are below fmax=0.02. relax = QuasiNewton(subsys111, trajectory='relax111.traj') relax.run(fmax=0.02) #The calculator is set. calc100 = GPAW(mode=PW(E_cut),kpts=kpoints, xc='BEEF-vdW',txt='calc100.out') subsys100.set_calculator(calc100) #The bottom layer of the subsystem is masked such that these atoms do not move during QuasiNewton minimization/relaxation. subsys100.set_constraint(fixedatoms) #The subsystem is relaxed until all forces on atoms are below fmax=0.02. relax = QuasiNewton(subsys100, trajectory='relax100.traj') relax.run(fmax=0.02) ## Calculate new energies for i in ['subsys111', 'subsys100']: system = globals()[i] energy = system.get_potential_energy() energies["relax"+i[6:]] = energy e_bond = {} e_bond['subsys111'] = energies['relax111'] - energies['subsys111'] - n_adsorbates*energies['adsorbate'] e_bond['subsys100'] = energies['relax100'] - energies['subsys100'] - n_adsorbates*energies['adsorbate'] print(energies,e_bond, file=energyfile) energyfile.close() ads111=e_bond['subsys111'] ads100=e_bond['subsys100'] if subsys100_relaxed!=None: subsys100=subsys100_relaxed if subsys111_relaxed!=None: subsys111=subsys111_relaxed #Check if adsorption has occurred. If not, remove adsorbates from corresponding subsystem. if ads111>=ads_cutoff: subsys111_prov=subsys111.copy() subsys111=Atoms() for i in subsys111_prov: if i.symbol==metal: subsys111.append(i) if ads100>=ads_cutoff: subsys100_prov=subsys100.copy() subsys100=Atoms() for i in subsys100_prov: if i.symbol==metal: subsys100.append(i) #Now to find offsets for each atom in the subsystems after DFT: x111_offset=[] y111_offset=[] z111_offset=[] x100_offset=[] y100_offset=[] z100_offset=[] for i in range(0,n): x111_offset.append(subsys111[i].position[0]-x111_i[i]) y111_offset.append(subsys111[i].position[1]-y111_i[i]) z111_offset.append(subsys111[i].position[2]-z111_i[i]) x100_offset.append(subsys100[i].position[0]-x100_i[i]) y100_offset.append(subsys100[i].position[1]-y100_i[i]) z100_offset.append(subsys100[i].position[2]-z100_i[i]) # Define dictionary of indexed surfaces for use in TEM indexed_surfaces= {} #Sadly, we now have to do all the rotations again: surface_coordinates={} #For convenience this dictionary will contain v1,v2 coordinates for all the surfaces - indexed by their #respective origo atom's index. for i in Nanoparticle.get_surfaces(): surface=[] #This list will contain the atoms on the specific surface at the top. Nanoparticle.rotate(i,[0,1,0],center="COU") y_max=0 for j in Nanoparticle: if j.position[1]>y_max and j.symbol==metal: y_max=j.position[1] for j in Nanoparticle: if round(j.position[1],2)==round(y_max,2) and j.symbol==metal: surface.append(j.index) #Now surface contains the indeces of atoms of the specific surface that is at the top in this rotation. direction=abs(i[0])+abs(i[1])+abs(i[2]) #This number determines the surface direction family - 100, 110, 111. #Define a dictionary with all indeces of atoms of surface i indexed_surfaces[tuple(i)] = surface #Find maximum z and x values for the surface: x_max=0 z_max=0 for k in surface: if Nanoparticle[k].position[0]>x_max: x_max=Nanoparticle[k].position[0] if Nanoparticle[k].position[2]>z_max: z_max=Nanoparticle[k].position[2] x_min=x_max z_min=z_max for k in surface: if Nanoparticle[k].position[0]<x_min: x_min=Nanoparticle[k].position[0] if Nanoparticle[k].position[2]<z_min: z_min=Nanoparticle[k].position[2] bot_row=[] #This will contain the indeces of the bottom (low z) row of atoms. #Find the atoms in the bottom row: for k in surface: if round(Nanoparticle[k].position[2],1)==round(z_min,1): bot_row.append(k) #Find the atom in the corner of the surface: corner_atom=bot_row[0] for k in bot_row: if Nanoparticle[k].position[0]<Nanoparticle[corner_atom].position[0]: corner_atom=k distance_1=2*lc #The distance between corner_atom and the nearest neighbour is at least smaller than this. neighbour_1="d" #placeholder for neighbour 1. neighbour_2="d" #placeholder for neighbour 2. ## Find the unit cell neighbours to corner_atom. v1=[] v2=[] for k in surface: if k!=corner_atom and k in edge_atoms: #The v1-axis should lie along some edge. if np.linalg.norm(Nanoparticle[k].position-Nanoparticle[corner_atom].position)<distance_1: distance_1=np.linalg.norm(Nanoparticle[k].position-Nanoparticle[corner_atom].position) neighbour_1=k #Construct the first basis vector for the surface using the first nearest neighbour coordinate. v1=Nanoparticle[neighbour_1].position-Nanoparticle[corner_atom].position v1[1]=0 #The y-coordinate of the surface basis vector is set to 0. # To find the second neighbour, we have to align the v1 vector with the x-axis: Nanoparticle.rotate(v1,[1,0,0],center='COU') for k in surface: if k!=corner_atom and k!=neighbour_1: dist_vector=Nanoparticle[k].position-Nanoparticle[corner_atom].position # We require that the angle between dist_vector and v1 is <=90. if math.acos(round(np.dot(dist_vector,v1)/(np.linalg.norm(dist_vector)*np.linalg.norm(v1)),5))<=90: # We check for a dist_vector which corresponds to one of the lattice vectors defined for the subsystem. if direction==1: if round(dist_vector[0],5)==round(v2_100[0],5) and round(dist_vector[2],5)==round(v2_100[1],5): neighbour_2=k if round(dist_vector[0],5)==round(v2_100[0],5) and round(dist_vector[2],5)==-round(v2_100[1],5): neighbour_2=k if direction==3: if round(dist_vector[0],5)==round(v2_111[0],5) and round(dist_vector[2],5)==round(v2_111[1],5): neighbour_2=k if round(dist_vector[0],5)==round(v2_111[0],5) and round(dist_vector[2],5)==-round(v2_111[1],5): neighbour_2=k # Rotate the system back after finding the second neighbour. Nanoparticle.rotate([1,0,0],v1,center='COU') #Construct the second basis vector for the surface using the nearest neighbour coordinate. v2=Nanoparticle[neighbour_2].position-Nanoparticle[corner_atom].position v2[1]=0 #The y-coordinate of the surface basis vector is set to 0. Transform_matrix=np.linalg.inv(np.array([v1,v2,[0,1,0]]).transpose()) #This transforms x-y-z coordinates to v1-v2-y. #Now to find v1,v2-coordinates for all the atoms in the surface and replace them with atoms from DFT subsystem accordingly: surface.sort for k in surface: if k not in edge_atoms: flag = False #Flag to determine wether the z-axis was flipped. #Find the coordinate of the atom in v1,v2-basis. coordinate=np.round(Transform_matrix.dot(Nanoparticle[k].position-Nanoparticle[corner_atom].position),0) #We want the origo of the surface system to be off the surface edge. Therefore, we translate the coordinates: coordinate[0]=coordinate[0]-1 coordinate[1]=coordinate[1]-1 reference=coordreference(coordinate[0],coordinate[1],ucx,ucy,direction) #This references the matching atom in the subsystem #The system is rotated again such that the bottom row of atoms lie along the x-direction. Nanoparticle.rotate(v1,[1,0,0],center="COU") #Check if v2 is in the positive z-direction. If not, rotate the system 180 degrees: if Nanoparticle[neighbour_2].position[2]-Nanoparticle[corner_atom].position[2]<0: Nanoparticle.rotate([0,0,-1],[0,0,1],center='COU') flag = True #Flag is set indicating the system has been flipped. for l in subsys_coordinates: if subsys_coordinates[l]==[reference[0],reference[1],0]: #This atom in the subsystem matches the atom in the Nanoparticle surface. if direction==1: #Apply the corresponding offset from the 100 list: Nanoparticle[k].position=Nanoparticle[k].position+[x100_offset[l],z100_offset[l],y100_offset[l]] if direction==3: #Apply the corresponding offset from the 111 list: Nanoparticle[k].position=Nanoparticle[k].position+[x111_offset[l],z111_offset[l],y111_offset[l]] if [reference[0],reference[1]] in adsorbate_atom_links: #Checks if the subsystem reference atom is linked to an adsorbate molecule. for u in range(0,len(adsorbate_atom_links)): #Find the linked adsorbate molecule tag (it's the index of adsorbate_atom_links) if adsorbate_atom_links[u] == [reference[0],reference[1]]: #Check if the reference coordinates exists in the list of linked atoms coordinates. adsorbate_tag=u #This is the tag assigned to the adsorbate that is linked to the reference atom. #Calculate the reference atom's index in the subsystem (from the v1/v2-coordinates). tagged_atom_index=int(atomorigo+((adsorbate_atom_links[adsorbate_tag][1])%ucy)*ucx+adsorbate_atom_links[adsorbate_tag][0]%ucx) if direction==1: for m in subsys100: if m.symbol!=metal and m.tag==adsorbate_tag: #Single out the adsorbate with the correct tag. m_old_position=m.position.copy() #Save the adsorbate's original position. m.position=m.position-subsys100[tagged_atom_index].position #Calculate the vector from the reference atom to the adsorbate. #Now calculate and set the position to that which the adsorbate atom should have in the Nanoparticle system: m.position=[m.position[0]+Nanoparticle[k].position[0],m.position[2]+Nanoparticle[k].position[1],m.position[1]+Nanoparticle[k].position[2]] Nanoparticle.append(m) #Finally, add the adsorbate. m.position=m_old_position #Reset the subsystem (set the adsorbate position to it's old, saved value). if direction==3: #Do exactly the same below as for the 100 surface above: for m in subsys111: if m.symbol!=metal and m.tag==adsorbate_tag: m_old_position=m.position.copy() m.position=m.position-subsys111[tagged_atom_index].position m.position=[m.position[0]+Nanoparticle[k].position[0],m.position[2]+Nanoparticle[k].position[1],m.position[1]+Nanoparticle[k].position[2]] Nanoparticle.append(m) m.position=m_old_position #Check if the z-axis was flipped. If it was, flip it back: if flag: Nanoparticle.rotate([0,0,1],[0,0,-1],center='COU') #The system is then rotated back. Nanoparticle.rotate([1,0,0],v1,center="COU") #First the x-axis alignment. Nanoparticle.rotate([0,1,0],i,center="COU") #Now rotate the surface back to it's original direction. ## Find the actual coverage of the Nanoparticle: ## This procedure is outdated, but it still works. #First we need to count the number of surface atoms (including edges). First we turn surf_atoms into a dictionary and back into # a list in order to remove duplicate values (edge atoms should only be counted once): surf_atoms = list(dict.fromkeys(surf_atoms)) #The number of surf atoms is then: n_surf_atoms=len(surf_atoms) #Now to count the number of adsorbed molecules. First we count the number of non-gold atoms: non_gold_atoms=0 for i in Nanoparticle: if i.symbol!=metal: non_gold_atoms+=1 #Then we count the number of atoms in the adsorbate molecules: adsorbate_size=len(adsorbate) #The number of adsorbed molecules: n_adsorbate=non_gold_atoms/adsorbate_size #The actual coverage is then: actual_coverage=n_adsorbate/n_surf_atoms Nanoparticle.center(vacuum=4) #Center the nanoparticle for TEM imaging. return Nanoparticle,indexed_surfaces,subsys111,subsys100 #Depending on what is needed, return the different objects.
def create_fcc_cluster_atoms(layers): surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] # layers = [4, 4, 4] lc = 3.61000 cluster = FaceCenteredCubic("Cu", surfaces, layers, latticeconstant=lc) return Atoms(cluster.symbols, cluster.positions, cell=cluster.cell)
atoms.set_cell([10, 10, 10]) atoms.center() struct = AseAtomsAdaptor.get_structure(atoms) add_to_dict(struct, 'I2') # nano-particles import ase from ase.cluster.cubic import FaceCenteredCubic surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] layers = [3, 3, 3] lc = 3.61000 atoms = FaceCenteredCubic('Cu', surfaces, layers, latticeconstant=lc, vacuum=10) add_to_dict(AseAtomsAdaptor.get_structure(atoms), 'Cu_cluster') from ase.cluster import Octahedron atoms = Octahedron(['Pt', 'Au'], length=3, alloy=True, latticeconstant=4) atoms.set_cell([15] * 3) atoms.center() add_to_dict(AseAtomsAdaptor.get_structure(atoms), 'PtAu_cluster') from ase.cluster import Icosahedron atoms = Icosahedron( 'Pt',
# pass def __repr__(self): return 'Push atoms out of the cell back to the cell' def copy(self): return ConstantForce(a=self.index, force=self.force) if __name__ == '__main__': from ase.cluster.cubic import FaceCenteredCubic from ase.calculators.emt import EMT from ase.md.verlet import VelocityVerlet from ase.units import fs from constantforce import ConstantForce atoms = FaceCenteredCubic( 'Ag', [(1, 0, 0)], [1], 4.09) atoms.center(10) atoms.pbc = True atoms.set_calculator( EMT() ) cf = ConstantForce( 10, [0,1,0] ) # y=dircted force ic = ImprisonConstraint() atoms.set_constraint( [cf, ic] ) md = VelocityVerlet( atoms, 1*fs, trajectory = 'cf_test.traj', logfile='-' ) md.run(200) #~ from ase.visualize import view #~ view(atoms)
"""generates atoms object from .smc file and views in ase gui usage: python viewCluster.py smcfile where smcfile is the full path to .smc file """ import sys from montecarlo import * from ase.cluster.cubic import FaceCenteredCubic import ase from data import fcc from atommontecarlodata import AtomMonteCarloData from ase.visualize import view if len(sys.argv) < 2: print >>sys.stderr, __doc__ sys.exit(1) #Store path to file pp = str(sys.argv[1]) nconf= int(sys.argv[2]) #Instantiate d as SurfaceM.. object d = SurfaceMonteCarloData() #Read data from file to d d.read(pp) surfaces = fcc.surface_names #Construct atoms atoms = FaceCenteredCubic('Au', surfaces, d[nconf][1], latticeconstant=4.055) view(atoms) #View atoms #sys.exit("Script Terminated with code 0")
from ase.cluster.cubic import FaceCenteredCubic from ElectroLens import view surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] layers = [6, 9, 5] lc = 3.61000 atoms = FaceCenteredCubic('Cu', surfaces, layers, latticeconstant=lc) view(atoms)
"""Tests for XrDebye class""" from __future__ import print_function from ase.utils.xrdebye import XrDebye, wavelengths from ase.cluster.cubic import FaceCenteredCubic import numpy as np tolerance = 1E-5 # previously calculated values expected_get = 116850.37344 expected_xrd = np.array([18549.274677, 52303.116995, 38502.372027]) expected_saxs = np.array([372650934.006398, 280252013.563702, 488123.103628]) # test system -- cluster of 587 silver atoms atoms = FaceCenteredCubic('Ag', [(1, 0, 0), (1, 1, 0), (1, 1, 1)], [6, 8, 8], 4.09) xrd = XrDebye(atoms=atoms, wavelength=wavelengths['CuKa1'], damping=0.04, method='Iwasa', alpha=1.01, warn=True) # test get() obtained_get = xrd.get(s=0.09) assert np.abs((obtained_get - expected_get) / expected_get) < tolerance # test XRD obtained_xrd = xrd.calc_pattern(x=np.array([15, 30, 50]), mode='XRD') assert np.allclose(obtained_xrd, expected_xrd, rtol=tolerance) # test SAXS
s_new = struc.copy() s_new.rotate(angle, axis) pbc = Atoms(s_new.symbols.numbers, positions=s_new.positions, cell=s_new.cell) return pbc #p_struc def get_perturbed_struc(struc, eps): s_new = struc.copy() pos = s_new.positions pos[0,0] += eps pbc = Atoms(s_new.symbols.numbers, positions=pos, cell=s_new.cell) return pbc #p_struc surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] layers = [2, 2, 2] lc = 3.61000 cu = FaceCenteredCubic('Cu', surfaces, layers, latticeconstant=lc, vacuum=10) rcut = 3.0 eps = 1e-8 #TrainData = resource_filename("pyxtal_ff", "datasets/Si/UCSD/test.json") TrainData = resource_filename("pyxtal_ff", "datasets/Si/PyXtal/Si4.json") parameters = {'lmax': 2} system = ['Si'] descriptor = {'type': 'Bispectrum', 'parameters': parameters, 'Rc': 3.0, 'N_train': 10, 'stress': True, } descriptor_comp = {'type': 'Bispectrum',
from ase.cluster.cubic import FaceCenteredCubic from ase.calculators.turbomole import Turbomole surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] layers = [1, 2, 1] atoms = FaceCenteredCubic('Au', surfaces, layers, latticeconstant=4.08) params = { 'title': 'Au13-', 'task': 'energy', 'basis set name': 'def2-SV(P)', 'total charge': -1, 'multiplicity': 1, 'use dft': True, 'density functional': 'pbe', 'use resolution of identity': True, 'ri memory': 1000, 'use fermi smearing': True, 'fermi initial temperature': 500, 'fermi final temperature': 100, 'fermi annealing factor': 0.9, 'fermi h**o-lumo gap criterion': 0.09, 'fermi stopping criterion': 0.002, 'scf energy convergence': 1.e-4, 'scf iterations': 250 } calc = Turbomole(**params) atoms.set_calculator(calc) calc.calculate(atoms)
# creates: culayer.png truncated.png from ase.io import write from ase.cluster.cubic import FaceCenteredCubic #from ase.cluster.hexagonal import HexagonalClosedPacked #import numpy as np surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] layers = [6, 9, 5] lc = 3.61000 culayer = FaceCenteredCubic('Cu', surfaces, layers, latticeconstant=lc) culayer.rotate(6, 'x', rotate_cell=True) culayer.rotate(2, 'y', rotate_cell=True) write('culayer.pov', culayer, show_unit_cell=0).render() surfaces = [(1, 0, 0), (1, 1, 1), (1, -1, 1)] layers = [6, 5, -1] trunc = FaceCenteredCubic('Cu', surfaces, layers) trunc.rotate(6, 'x', rotate_cell=True) trunc.rotate(2, 'y', rotate_cell=True) write('truncated.pov', trunc, show_unit_cell=0).render() # This does not work! #surfaces = [(0, 0, 0, 1), (1, 1, -2, 0), (1, 0, -1, 1)] #layers = [6, 6, 6] #graphite = Graphite('C', surfaces, layers, latticeconstant=(2.461, 6.708)) #write('graphite.pov', graphite).render() # surfaces = [(0, 0, 0, 1), (1, 1, -2, 0), (1, 0, -1, 1)] # layers = [6, 6, 6] # magn = HexagonalClosedPacked('Mg', surfaces, layers)
for i in range(3): if atom.position[i] < self.margin: atom.momentum[i] = abs(atom.momentum[i]) if atom.position[i] > cell[i,i]-self.margin: atom.momentum[i] = -abs(atom.momentum[i]) if __name__ == '__main__': # test from ase.cluster.cubic import FaceCenteredCubic from ase.calculators.emt import EMT from ase.md.nvtberendsen import NVTBerendsen from ase.io.trajectory import Trajectory from ase.md.velocitydistribution import MaxwellBoltzmannDistribution, Stationary, ZeroRotation from ase.units import fs, kB atoms = FaceCenteredCubic( 'Pt', [(1, 0, 0), (1, 1, 0), (1, 1, 1)], [2, 3, 1], 4.09) atoms.center(vacuum=5) atoms.set_calculator( EMT() ) T = 8000 # K -- try to vaporize MaxwellBoltzmannDistribution(atoms, kB*T) Stationary(atoms) ZeroRotation(atoms) #dyn = NVTBerendsen(atoms, 1*fs, T, 500*fs, logfile='-') dyn = NVTBerendsen(atoms, 1*fs, T, 500*fs, logfile='-') traj = Trajectory('borders_test.traj', 'w', atoms) dyn.attach(traj.write, interval=10) fr = Freeze(atoms) #fr = Mirror(atoms) dyn.attach( fr, interval=20 ) dyn.run(5000) traj.close()