def surface_energy(bulk, z_offset): Nat = bulk.get_number_of_atoms() # shift so cut is through shuffle plane bulk.positions[:, 2] += z_offset bulk.wrap() # relax atom positions, holding cell fixed # vac = relax_atoms(vac, fmax=fmax) # compute surface formation energy as difference of bulk and expanded cell ebulk = bulk.get_potential_energy() print 'bulk cell energy', ebulk bulk.cell[2, :] += [0.0, 0.0, 10.0] np.random.seed(75) bulk.positions += (np.random.rand((Nat * 3)) * 0.1).reshape([Nat, 3]) bulk = relax_atoms(bulk, tol=fmax, traj_file="model-" + model.name + "-surface-energy-111-relaxed.opt.xyz") eexp = bulk.get_potential_energy() ase.io.write(sys.stdout, bulk, format='extxyz') print 'expanded cell energy', eexp e_form = 0.5 * (eexp - ebulk) / np.linalg.norm( np.cross(bulk.cell[0, :], bulk.cell[1, :])) print 'relaxed 111 surface formation energy', e_form return e_form
def fourfold_defect_energy(bulk): Nat = bulk.get_number_of_atoms() defect = bulk.copy() defect.set_calculator(bulk.get_calculator()) # modify atom positions so that relaxation creates a fourfold defect p = defect.get_positions() # p[0,0] += 1.2 # p[0,1] += 1.2 # p[1,0] -= 1.2 # p[1,1] -= 1.2 # from CASTEP relaxed structure p[0, :] += (0.81, 0.81, -0.43) p[1, :] -= (0.81, 0.81, -0.43) defect.set_positions(p) ase.io.write(sys.stdout, defect, format='extxyz') # relax atom positions, holding cell fixed print "JOE test relaxing defect" defect = relax_atoms(defect, tol=tol, traj_file="model-" + model.name + "-test-fourfold-defect.opt.xyz", method="lbfgs") print "JOE test done relaxing defect" ase.io.write(sys.stdout, defect, format='extxyz') # compute formation energy as difference of bulk and int energies print 'bulk energy', bulk_energy print 'defect energy', defect.get_potential_energy() e_form = defect.get_potential_energy() - bulk_energy print 'defect formation energy', e_form return e_form
def surface_energy(bulk): Nat = bulk.get_number_of_atoms() # relax atom positions, holding cell fixed # vac = relax_atoms(vac, fmax=fmax) # compute surface formation energy as half the difference of bulk and expanded cell print "len(bulk)", len(bulk) ebulk = bulk.get_potential_energy() print 'bulk cell energy', ebulk bulk.cell[2, :] += [0.0, 0.0, 10.0] ase.io.write(sys.stdout, bulk, format='extxyz') # relax expanded cell bulk = relax_atoms(bulk, tol=fmax, method='lbfgs', traj_file="model-" + model.name + "-surface-energy-100-relaxed.opt.xyz", use_armijo=False) eexp = bulk.get_potential_energy() ase.io.write(sys.stdout, bulk, format='extxyz') print 'expanded cell energy', eexp e_form = 0.5 * (eexp - ebulk) / np.linalg.norm( np.cross(bulk.cell[0, :], bulk.cell[1, :])) print 'relaxed 100 surface formation energy', e_form return e_form
def vacancy_energy(bulk, remove_index=0): Nat = bulk.get_number_of_atoms() vac = bulk.copy() vac.set_calculator(bulk.get_calculator()) nl = NeighborList([a0*sqrt(3.0)/4*0.6]*len(bulk), self_interaction=False, bothways=True) nl.update(bulk) indices, offsets = nl.get_neighbors(remove_index) offset_factor=0.13 for i, offset in zip(indices, offsets): ri = vac.positions[remove_index] - (vac.positions[i] + dot(offset, vac.get_cell())) vac.positions[i] += offset_factor*ri offset_factor += 0.01 del vac[remove_index] # remove an atom to introduce a vacancy # perturb positions vac.rattle(0.1) ## try: model.calculator.set(local_gap_error='local_gap_error') vac.get_potential_energy() unrelaxed_local_gap_error_max = amax(model.calculator.results['local_gap_error']) unrelaxed_local_gap_error_sum = sum(model.calculator.results['local_gap_error']) except: unrelaxed_local_gap_error_max = None unrelaxed_local_gap_error_sum = None if isinstance(model, Potential): model.calculator.set(local_gap_error='') # relax atom positions, holding cell fixed vac = relax_atoms(vac, tol=fmax, traj_file="model-"+model.name+"-test-vacancy-energy.opt.xyz") vac.write("model-"+model.name+"test-vacancy-energy-relaxed.xyz") ## try: model.calculator.set(local_gap_error='local_gap_error') vac.get_potential_energy() relaxed_local_gap_error_max = amax(model.calculator.results['local_gap_error']) relaxed_local_gap_error_sum = sum(model.calculator.results['local_gap_error']) except: relaxed_local_gap_error_max = None relaxed_local_gap_error_sum = None if isinstance(model, Potential): model.calculator.set(local_gap_error='') ## # compute vacancy formation energy as difference of bulk and vac energies print 'bulk cell energy', bulk_energy print 'vacancy cell energy', vac.get_potential_energy() e_form = vac.get_potential_energy() - bulk_energy*vac.get_number_of_atoms()/bulk.get_number_of_atoms() print 'vacancy formation energy', e_form return (e_form, unrelaxed_local_gap_error_max, unrelaxed_local_gap_error_sum, relaxed_local_gap_error_max, relaxed_local_gap_error_sum)
def surface_energy(n, bulk, ebulk_per_atom, e111): tmp = ase.io.read(os.path.dirname(__file__) + '/si111_' + str(n) + 'x' + str(n) + '_8layer.xyz', index=':', format='extxyz') surf = tmp[0] # adjust lattice constant L = surf.get_cell() bulkL = bulk.get_cell() scaling_factor = bulkL[0, 0] * n / L[0, 0] surf.set_cell(L * scaling_factor, scale_atoms=True) fixed_list = np.where(surf.arrays['move_mask'] == 0)[0] c = FixAtoms(fixed_list) surf.set_constraint(c) # relax atom positions of the reconstructed surface, holding cell fixed surfNat = surf.get_number_of_atoms() #surf.positions += (np.random.rand((surfNat*3))*0.1).reshape([surfNat,3]) surf = relax_atoms(surf, tol=fmax, traj_file="model-" + model.name + "-surface-energy-111-" + str(n) + "x" + str(n) + "-reconstruction-relaxed.opt.xyz") ase.io.write(sys.stdout, surf, format='extxyz') esurf = surf.get_potential_energy() print '111 ' + str(n) + 'x' + str( n) + ' reconstructed surface cell energy', esurf surf_area = np.linalg.norm(np.cross(surf.cell[0, :], surf.cell[1, :])) e_form = (esurf - surfNat * ebulk_per_atom) / surf_area - e111 print '111 ' + str(n) + 'x' + str( n) + ' reconstructed surface formation energy', e_form return e_form
remove_index_f = None initial.arrays['ind'] = array([i for i in range(len(initial))]) offset_factor = 0.13 for i, offset in zip(indices, offsets): ri = initial.positions[remove_index] - (initial.positions[i] + dot(offset, initial.get_cell())) if remove_index_f is None: remove_index_f = i print "initial offset ", i, offset_factor, ri initial.positions[i] += offset_factor * ri offset_factor += 0.01 del initial[remove_index] initial.set_calculator(model.calculator) initial = relax_atoms(initial, tol=tol, traj_file=None) #initial = ase.io.read(os.path.join("initial-relax", "castep.castep")) initial.set_calculator(model.calculator) print 'initial energy', initial.get_potential_energy() e_form = initial.get_potential_energy( ) - e_bulk_per_atom * initial.get_number_of_atoms() print 'vacancy formation energy', e_form # make final final = bulk.copy() nl = NeighborList([a0 * sqrt(3.0) / 4 * 0.6] * len(final), self_interaction=False, bothways=True) nl.update(final)