def do_lattice(bulk, elastic=True): tol = 1e-3 # max force tol for relaxation n_E_vs_V_steps=10 # use one of the routines from utilities module to relax the initial # unit cell and atomic positions bulk = relax_atoms_cell(bulk, tol=tol, traj_file=None, symmetrize=True) print "relaxed bulk" ase.io.write(sys.stdout, bulk, format='extxyz') if elastic: # reset calculator to non-symmetrized one (not optimal, but would otherwise need to have optimizer used by fit_elastic_constants to reset symmetry for each relaxation):w bulk.set_calculator(model.calculator) precon = Exp(3.0) opt = lambda atoms, **kwargs: PreconLBFGS(atoms, precon=precon, **kwargs) elastic_consts = matscipy.elasticity.fit_elastic_constants(bulk, symmetry='cubic', optimizer=opt) c11 = elastic_consts[0][0,0]/GPa c12 = elastic_consts[0][0,1]/GPa c44 = elastic_consts[0][3,3]/GPa V0 = bulk.get_volume() dV = bulk.get_volume()*0.025 E_vs_V=[] f = open("relaxed_E_vs_V_configs.xyz", "w") for i in range(0, -5-1, -1): scaled_bulk = bulk.copy() scaled_bulk.set_cell(scaled_bulk.get_cell()*((V0+i*dV)/V0)**(1.0/3.0), scale_atoms=True) scaled_bulk = relax_atoms_cell(scaled_bulk, tol=tol, traj_file=None, constant_volume=True, method='cg_n', symmetrize=True) # evaluate(scaled_bulk) ase.io.write(f, scaled_bulk, format='extxyz') E_vs_V.insert(0, (scaled_bulk.get_volume()/len(scaled_bulk), scaled_bulk.get_potential_energy()/len(bulk)) ) for i in range(1, 6+1): scaled_bulk = bulk.copy() scaled_bulk.set_cell(scaled_bulk.get_cell()*((V0+i*dV)/V0)**(1.0/3.0), scale_atoms=True) scaled_bulk = relax_atoms_cell(scaled_bulk, tol=tol, traj_file=None, constant_volume=True, method='cg_n', symmetrize=True) # evaluate(scaled_bulk) ase.io.write(f, scaled_bulk, format='extxyz') E_vs_V.append( (scaled_bulk.get_volume()/len(scaled_bulk), scaled_bulk.get_potential_energy()/len(bulk)) ) for (V, E) in E_vs_V: print "EV_final ", V, E if elastic: return (c11, c12, c44, E_vs_V) else: return (E_vs_V)
def defect_energy(a0, e0, filename): tmp = ase.io.read(os.path.dirname(__file__)+"/"+filename, index=':', format='extxyz') defect = tmp[0] # adjust lattice constant # defect.set_cell([2*a0, 2*a0, 2*a0], scale_atoms=True) defect.set_calculator(model.calculator) # relax atom positions and cell # defect.positions += (np.random.rand((66*3))*0.01).reshape([66,3]) defect = relax_atoms_cell(defect, tol=fmax, traj_file="model-"+model.name+"-diinterstitial-"+filename+"-relaxed.opt.xyz") ase.io.write(sys.stdout, defect, format='extxyz') edefect = defect.get_potential_energy() print 'defect relaxed cell energy', edefect e_form = (edefect-66.0 * e0) print 'defect relaxed formation energy', e_form return e_form
def interface_energy(e0, filename): interface = ase.io.read(os.path.join(os.path.dirname(__file__),filename), format='extxyz') # adjust lattice constant interface.set_calculator(model.calculator) # relax atom positions, holding cell fixed interface.positions += 0.01*np.random.random_sample((len(interface),3)) print "pre relax config" ase.io.write(sys.stdout, interface, format='extxyz') print "BOB doing gb relax" interface = relax_atoms_cell(interface, tol=fmax, max_steps=300, traj_file=os.path.splitext(filename)[0]+"-relaxed.opt.xyz") print "post relax config" ase.io.write(sys.stdout, interface, format='extxyz') print "BOB doing gb get pot en" einterface = interface.get_potential_energy() print 'interface relaxed cell energy', einterface e_form = (einterface-len(interface) * e0) area = np.linalg.norm(np.cross(interface.get_cell()[0,:],interface.get_cell()[1,:])) print "got area",area print 'interface relaxed formation energy/area', e_form/(2.0*area) return e_form/(2.0*area)
from ase import Atoms from utilities import relax_atoms_cell, phonons import numpy as np # set up cell try: with open("../model-{}-test-bulk_diamond-properties.json".format( model.name)) as f: j = json.load(f) a0 = j["diamond_a0"] bulk = Atoms(diamond2(a0, 14, 14)) except: bulk = Atoms(diamond2(5.43, 14, 14)) bulk.set_calculator(model.calculator) bulk = relax_atoms_cell(bulk, tol=1.0e-4, traj_file=None) a0 = bulk.get_cell_lengths_and_angles()[0] * np.sqrt(2.0) bulk = Atoms(diamond2(a0, 14, 14)) supercell = [[4, 0, 0], [0, 4, 0], [0, 0, 4]] dx = 0.03 mesh = [16, 16, 16] points = np.array([[0, 0, 0], [0, 0.5, 0.5], [1, 1, 1], [0.5, 0.5, 0.5]]) n_points = 50 phonon_properties = phonons(model, bulk,
# the current model import model a0 = 5.44 # initial guess at lattice constant, cell will be relaxed below fmax = 0.01 # maximum force following relaxtion [eV/A] if not hasattr(model, 'bulk_reference'): # set up the a bulk = Diamond(symbol='Si', latticeconstant=a0) # specify that we will use model.calculator to compute forces, energies and stresses bulk.set_calculator(model.calculator) # use one of the routines from utilities module to relax the initial # unit cell and atomic positions bulk = relax_atoms_cell(bulk, tol=fmax, traj_file=None) else: bulk = model.bulk_reference.copy() bulk.set_calculator(model.calculator) a0 = bulk.cell[0, 0] # get lattice constant from relaxed bulk print "got a0 ", a0 bulk = Diamond(symbol="Si", latticeconstant=a0, directions=[[1, -1, 0], [1, 0, -1], [1, 1, 1]]) bulk.set_calculator(model.calculator) # set up supercell bulk *= (1, 1, 10)
at.set_scaled_positions(np.random.rand(n_at, 3)) while too_close(at, hard_sphere_dist): at.set_scaled_positions(np.random.rand(n_at, 3)) print "initial config" ase.io.write(sys.stdout, at, format="extxyz") at.set_calculator(model.calculator) if os.path.basename(os.path.dirname(model.__file__)) == 'CASTEP_file': model.geom_method = 'tpsd' model.geom_force_tol = tol model.geom_stress_tol = tol model.geom_energy_tol = 1.0e8 model.geom_disp_tol = 1.0e8 print "BOB relax atoms" at = relax_atoms_cell(at, tol=tol) i_minim = -1 converged = True else: config_minim = UnitCellFilter(at) x = config_minim.get_positions() converged = False for i_minim in range(500): config_minim.set_positions(x) grad_f = -config_minim.get_forces() E = config_minim.get_potential_energy() try: pred_err = predictive_error(config_minim.atoms) except: pred_err = None if isinstance(config_minim, UnitCellFilter):
a0 = 5.44 # initial guess at lattice constant, cell will be relaxed below tol = 1e-3 # maximum force following relaxtion [eV/A] N = 2 # number of unit cells in each direction if not hasattr(model, 'bulk_reference_216'): # set up the a bulk = Diamond(symbol='Si', latticeconstant=a0) # specify that we will use model.calculator to compute forces, energies and stresses bulk.set_calculator(model.calculator) # use one of the routines from utilities module to relax the initial # unit cell and atomic positions print "JOE test relaxing bulk" bulk = relax_atoms_cell(bulk, tol=tol, traj_file=None, method='lbfgs') print "JOE test done relaxing bulk" bulk *= (N, N, N) print "JOE test reading bulk E" bulk_energy = bulk.get_potential_energy() print "JOE test done reading bulk E" else: bulk = model.bulk_reference_216 bulk_energy = bulk.get_potential_energy() def fourfold_defect_energy(bulk): Nat = bulk.get_number_of_atoms() defect = bulk.copy() defect.set_calculator(bulk.get_calculator())
def do_lattice(bulk, use_precon=True, elastic=True, tol=1.0e-3): print "unrelaxed bulk" ase.io.write(sys.stdout, bulk, format='extxyz') # use one of the routines from utilities module to relax the initial # unit cell and atomic positions if use_precon: bulk = relax_atoms_cell(bulk, tol=tol, traj_file="bulk.relax.extxyz", symmetrize=True) else: bulk = relax_atoms_cell(bulk, tol=tol, traj_file=None, method='cg_n', symmetrize=True) print "relaxed bulk" ase.io.write(sys.stdout, bulk, format='extxyz') print "calculating elastic constants" precon = None if use_precon: precon = Exp(3.0) opt = lambda atoms, **kwargs: PreconLBFGS(atoms, precon=precon, **kwargs) if elastic: # reset calculator to non-symmetrized one (not optimal, but would otherwise need to have optimizer used by fit_elastic_constants to reset symmetry for each relaxation):w bulk.set_calculator(model.calculator) try: elastic_consts = matscipy.elasticity.fit_elastic_constants( bulk, symmetry='tetragonal_high', optimizer=opt, logfile=sys.stdout) except RuntimeError: # fallback on FIRE if we get a linesearch failure with LBFGS opt = FIRE elastic_consts = matscipy.elasticity.fit_elastic_constants( bulk, symmetry='tetragonal_high', optimizer=opt, logfile=sys.stdout) c11 = elastic_consts[0][0, 0] / GPa c33 = elastic_consts[0][2, 2] / GPa c12 = elastic_consts[0][0, 1] / GPa c13 = elastic_consts[0][0, 2] / GPa c44 = elastic_consts[0][3, 3] / GPa c66 = elastic_consts[0][5, 5] / GPa print "calculating E vs. V" V0 = bulk.get_volume() dV = bulk.get_volume() * 0.025 E_vs_V = [] scaled_bulk = bulk.copy() print "bulk going into E vs. V" ase.io.write(sys.stdout, scaled_bulk, format='extxyz') f = open("relaxed_E_vs_V_configs.xyz", "w") scaled_bulk = bulk.copy() constraints = [] # scaled_bulk.arrays["move_mask_3"] = np.zeros((len(scaled_bulk),3), dtype=np.int) # scaled_bulk.arrays["move_mask_3"][:,0] = 1 # for i in range(len(scaled_bulk)): # constraints.append(FixedLine_forces_only(i, (0.0, 0.0, 1.0))) # scaled_bulk.set_constraint(constraints) for i in range(0, -5 - 1, -1): print "doing volume step", i vcur = scaled_bulk.get_volume() scaled_bulk.set_cell(scaled_bulk.get_cell() * ((V0 + i * dV) / vcur)**(1.0 / 3.0), scale_atoms=True) try: scaled_bulk = relax_atoms_cell(scaled_bulk, tol=tol, traj_file=None, constant_volume=True, method='cg_n', symmetrize=True, max_steps=500) except: break print "done relaxing step", i ase.io.write(f, scaled_bulk, format='extxyz') f.flush() E_vs_V.insert(0, (scaled_bulk.get_volume() / len(bulk), scaled_bulk.get_potential_energy() / len(bulk))) evaluate(scaled_bulk) print "done evaluate step", i print "EV ", i, scaled_bulk.get_volume( ), scaled_bulk.get_potential_energy(), scaled_bulk.get_stress() scaled_bulk = bulk.copy() # scaled_bulk.arrays["move_mask_3"] = np.zeros((len(scaled_bulk),3), dtype=np.int) # scaled_bulk.arrays["move_mask_3"][:,0] = 1 # scaled_bulk.set_constraint(constraints) for i in range(1, 6 + 1): print "doing volume step", i vcur = scaled_bulk.get_volume() scaled_bulk.set_cell(scaled_bulk.get_cell() * ((V0 + i * dV) / vcur)**(1.0 / 3.0), scale_atoms=True) try: scaled_bulk = relax_atoms_cell(scaled_bulk, tol=tol, traj_file=None, constant_volume=True, method='cg_n', symmetrize=True, max_steps=500) except: break print "done relaxing step", i ase.io.write(f, scaled_bulk, format='extxyz') f.flush() E_vs_V.append((scaled_bulk.get_volume() / len(bulk), scaled_bulk.get_potential_energy() / len(bulk))) evaluate(scaled_bulk) print "done evaluate step", i print "EV ", i, scaled_bulk.get_volume( ), scaled_bulk.get_potential_energy(), scaled_bulk.get_stress() for (V, E) in E_vs_V: print "EV_final ", V, E if elastic: return (c11, c33, c12, c13, c44, c66, E_vs_V) else: return (E_vs_V)
def sf_calc(bulk, n_steps, z_offset, p0=None, p1=None, relax_from_configs=None): global bulk_energy p0 = np.array(p0) p1 = np.array(p1) E0 = bulk_energy surf_unrelaxed = np.zeros((n_steps, n_steps), dtype=(float, 3)) surf_relaxed = np.zeros((n_steps, n_steps), dtype=(float, 3)) path_unrelaxed = [] path_relaxed = [] sf = bulk.copy() pos = sf.get_positions() pos[:, 2] += z_offset sf.set_positions(pos) pos = sf.get_scaled_positions() pos -= np.floor(pos) sf.set_scaled_positions(pos) if p0 is not None and p1 is not None: # paths # unrelaxed for i in range(n_steps): print "start path unrelaxed step", i sys.stdout.flush() p = p0 + (p1 - p0) * i / float(n_steps - 1) sf_cur = sf.copy() sf_cur.arrays['move_mask_3'] = np.zeros((len(sf_cur), 3), dtype=int) sf_cur.arrays['move_mask_3'][:, 2] = 1 sf_cur.set_calculator(model.calculator) cell = sf_cur.get_cell() cell[2, :] += cell[0, :] * p[0] + cell[1, :] * p[1] sf_cur.set_cell(cell) E = (sf_cur.get_potential_energy() - E0) / np.linalg.norm( np.cross(cell[0, :], cell[1, :])) path_unrelaxed.append((i / float(n_steps - 1), p[0], p[1], E)) # relaxed sf_cur = sf.copy() sf_cur.arrays['move_mask_3'] = np.zeros((len(sf_cur), 3), dtype=int) sf_cur.arrays['move_mask_3'][:, 2] = 1 sf_cur.set_calculator(model.calculator) dp = (p1 - p0) / float(n_steps - 1) p = p0.copy() cell = sf_cur.get_cell() cell[2, :] += cell[0, :] * p[0] + cell[1, :] * p[1] sf_cur.set_cell(cell) relax_from_configs_i = 0 for i in range(n_steps): print "start path relaxed step", i sys.stdout.flush() if model.name == 'CASTEP_file': sf_cur.calc.fix_all_cell = False sf_cur.set_constraint( [FixCartesian(j, [1, 1, 0]) for j in range(len(sf_cur))]) sf_cur.calc.cell_constraints = ["0 0 1", "0 0 0"] sf_cur.calc._old_atoms = None if debug: ase.io.write(file_unrelaxed, sf_cur, "extxyz") file_unrelaxed.flush() try: sf_cur.set_cell( relax_from_configs[relax_from_configs_i].get_cell(), False) sf_cur.set_positions( relax_from_configs[relax_from_configs_i].get_positions()) print "got sf_cur from 'relax_from_configs'" sys.stdout.flush() except: pass sf_cur_rel = relax_atoms_cell( sf_cur, tol=tol, method='cg_n', max_steps=500, traj_file=None, mask=[False, False, True, False, False, False]) relax_from_configs_i += 1 if debug: ase.io.write(file_relaxed, sf_cur, "extxyz") file_relaxed.flush() print "done relaxation" sys.stdout.flush() E = (sf_cur.get_potential_energy() - E0) / np.linalg.norm( np.cross(cell[0, :], cell[1, :])) path_relaxed.append((i / float(n_steps - 1), p[0], p[1], E)) cell = sf_cur.get_cell() cell[2, :] += cell[0, :] * dp[0] + cell[1, :] * dp[1] sf_cur.set_cell(cell) p += dp return (path_unrelaxed, path_relaxed) else: # surfaces # unrelaxed j_doffset = sf.get_cell()[1, :] * (1.0 / float(n_steps - 1)) for i in range(n_steps): x_i = float(i) / float(n_steps - 1) sf_cur = sf.copy() sf_cur.arrays['move_mask_3'] = np.zeros((len(sf_cur), 3), dtype=int) sf_cur.arrays['move_mask_3'][:, 2] = 1 sf_cur.set_calculator(model.calculator) cell = sf_cur.get_cell() cell[2, :] += cell[0, :] * x_i sf_cur.set_cell(cell) for j in range(n_steps - i): x_j = float(j) / float(n_steps - 1) print(i, j, x_i, x_j) if debug: ase.io.write(file_unrelaxed, sf_cur, "extxyz") file_unrelaxed.flush() E = (sf_cur.get_potential_energy() - E0) / np.linalg.norm( np.cross(cell[0, :], cell[1, :])) surf_unrelaxed[i, j] = (x_i, x_j, E) if i + j != n_steps - 1: surf_unrelaxed[n_steps - j - 1, n_steps - i - 1] = (1.0 - x_j, 1.0 - x_i, E) cell = sf_cur.get_cell() cell[2, :] += j_doffset sf_cur.set_cell(cell, scale_atoms=False) # relaxed relax_from_configs_i = 0 j_doffset = sf.get_cell()[1, :] * (1.0 / float(n_steps - 1)) for i in range(n_steps): x_i = float(i) / float(n_steps - 1) sf_cur = sf.copy() # set constraints # cs = [] # for i_at in range(len(bulk)): # cs.append(FixCartesian(i_at, mask=[0,0,1])) # sf_cur.set_constraint(cs) sf_cur.arrays['move_mask_3'] = np.zeros((len(sf_cur), 3), dtype=int) sf_cur.arrays['move_mask_3'][:, 2] = 1 sf_cur.set_calculator(model.calculator) cell = sf_cur.get_cell() cell[2, :] += cell[0, :] * x_i sf_cur.set_cell(cell) for j in range(n_steps - i): x_j = float(j) / float(n_steps - 1) print(i, j, x_i, x_j) try: sf_cur.set_cell( relax_from_configs[relax_from_configs_i].get_cell(), False) sf_cur.set_positions( relax_from_configs[relax_from_configs_i].get_positions( )) except: pass sf_cur_rel = relax_atoms_cell( sf_cur, tol=tol, method='cg_n', max_steps=500, traj_file=None, mask=[False, False, True, False, False, False]) relax_from_configs_i += 1 if debug: ase.io.write(file_relaxed, sf_cur_rel, "extxyz") file_relaxed.flush() E = (sf_cur_rel.get_potential_energy() - E0) / np.linalg.norm( np.cross(cell[0, :], cell[1, :])) surf_relaxed[i, j] = (x_i, x_j, E) if i + j != n_steps - 1: surf_relaxed[n_steps - j - 1, n_steps - i - 1] = (1.0 - x_j, 1.0 - x_i, E) cell = sf_cur.get_cell() cell[2, :] += j_doffset sf_cur.set_cell(cell, scale_atoms=False) return (surf_unrelaxed, surf_relaxed)
def struct_energy(e0_per_atom, filename): V_unrel = [] V_rel = [] E_unrel = [] E_rel = [] ats = ase.io.read(os.path.dirname(__file__) + "/" + filename, index=':', format='extxyz') for (i, at_orig) in enumerate(ats): at = at_orig.copy() at.set_calculator(model.calculator) # # The commented out bit that follows seems to break CASTEP_file - no minimization runs are set up, apparently because call to relax_atoms_cell doesn't actually trigger a calculate() # unrelaxed_e_per_atom = at.get_potential_energy()/len(at) # print 'at unrelaxed energy per atom', unrelaxed_e_per_atom # E_unrel.append(unrelaxed_e_per_atom-e0_per_atom) # relax fully print "BOB: calling relax_atoms_cell" if os.path.basename(os.path.dirname(model.__file__)) == 'CASTEP_file': at = relax_atoms_cell(at, tol=fmax, traj_file="model-" + model.name + "-RSS-{}-".format(i) + filename + "-relaxed.opt.xyz") else: n_at = len(at) config_minim = UnitCellFilter(at) x = config_minim.get_positions() converged = False for i_minim in range(500): config_minim.set_positions(x) grad_f = -config_minim.get_forces() E = config_minim.get_potential_energy() try: pred_err = predictive_error(config_minim.atoms) except: pred_err = None if isinstance(config_minim, UnitCellFilter): print i, "SD2: {} {} {} {}".format( i_minim, E, np.max(np.abs(grad_f[:n_at])), np.max(np.abs(grad_f[n_at:]))) else: print i, "SD2: {} {} {}".format( i_minim, E, np.max(np.abs(grad_f[:n_at]))) if np.max(np.abs(grad_f[:n_at])) < fmax and np.max( np.abs(grad_f[n_at:])) < fmax: converged = True break if i_minim == 0: alpha = 1.0e-6 else: alpha = np.sum( (x - x_old) * (grad_f - grad_f_old)) / np.sum( (grad_f - grad_f_old)**2) x_old = x.copy() grad_f_old = grad_f.copy() x -= np.abs(alpha) * grad_f print "BOB: done relax_atoms_cell" ase.io.write(sys.stdout, at, format='extxyz') print "BOB: calling get_potential_energy for relaxed" relaxed_e_per_atom = at.get_potential_energy() / len(at) print "BOB: done get_potential_energy for relaxed" print 'at relaxed energy per atom', relaxed_e_per_atom E_rel.append(relaxed_e_per_atom - e0_per_atom) V_rel.append(at.get_volume() / len(at)) # This is a workaround for the problem mentioned above ats = ase.io.read(os.path.dirname(__file__) + "/" + filename, index=':', format='extxyz') for (i, at) in enumerate(ats): at.set_calculator(model.calculator) # relax fully print "BOB: calling get_potential_energy for unrelaxed" unrelaxed_e_per_atom = at.get_potential_energy() / len(at) print "BOB: done get_potential_energy for unrelaxed" print 'at unrelaxed energy per atom', unrelaxed_e_per_atom E_unrel.append(unrelaxed_e_per_atom - e0_per_atom) V_unrel.append(at.get_volume() / len(at)) # end of workaround return (V_unrel, E_unrel, V_rel, E_rel)