def relax_atoms(outpath, atoms): from ase import optimize if os.path.exists(outpath): parprint(f'Found existing {outpath}') return world.barrier() parprint(f'Relaxing structure... ({outpath})') dyn = optimize.FIRE(atoms) dyn.run(fmax=0.05) # FIXME: consider using something else to write, like pymatgen.io.vasp.Poscar with significant_figures=15. # ASE always writes {:11.8f} in frac coords, which can be a dangerous amount of rounding # for large unit cells. atoms.write(outpath, format='vasp')
from ase.build import molecule from ase import optimize from ase.vibrations.infrared import InfraRed from gpaw.cluster import Cluster from gpaw import GPAW, FermiDirac h = 0.22 atoms = Cluster(molecule('H2')) atoms.minimal_box(3.5, h=h) # relax the molecule calc = GPAW(h=h, occupations=FermiDirac(width=0.1)) atoms.calc = calc dyn = optimize.FIRE(atoms) dyn.run(fmax=0.05) atoms.write('relaxed.traj') # finite displacement for vibrations ir = InfraRed(atoms) ir.run()
def supercell_ionic_relaxation(superCellDefect, optimizer_type = 'QuasiNewton', ladder_begin = 0, ladder_end = 2, charge=0): # structure relaxation witht he calculator already existing in the atoms object # returns the potential energy of the supercell before and after the relaxation as a tuple # usage: BR, AR = supercell_ionic_relaxation(defect_supercell) # if log == False, both potential energy will be 0 # added support for different types of optimizer # local optimizer: QuasiNewton, BFGS, LBFGS, GPMin, MDMin and FIRE. # preconditioned optimizer: to be added # global optimizer: to be added # added support for the jacob's ladder # the ladder: # LDA, # PBE, # revPBE # RPBE, # PBE0, # B3LYP. # ladder_begin, beginning step of the ladder, included # ladder_end, ending step of the ladder, NOT INCLUDED potential_energy_BR = 0.0 potential_energy_AR = 0.0 ladder = ['LDA', 'PBE', 'revPBE', 'RPBE', 'PBE0', 'B3LYP'] # calc = superCellDefect.get_calculator() # calc_backup = calc.get_xc_functional() # if log: # io.write('defect_supercell_before_relaxation.cube', superCellDefect) # potential_energy_BR = superCellDefect.get_potential_energy() # else: # pass if ladder_end > len(ladder): ladder_end = len(ladder) # loop climbing the ladder for calc_step in ladder[ ladder_begin : ladder_end ]: # print('=====================', file = log_file) # print('starting:', file = log_file) # print(calc_step, file = log_file) calc = GPAW(mode='fd', kpts={'size': (2, 2, 2), 'gamma': False}, xc=calc_step, charge=charge, occupations=FermiDirac(0.01) ) # calc.set(xc = calc_step) superCellDefect.set_calculator(calc) if optimizer_type == 'QuasiNewton': relax = optimize.QuasiNewton(superCellDefect) elif optimizer_type == 'BFGS': relax = optimize.BFGS(superCellDefect) elif optimizer_type == 'LBFGS': relax = optimize.BFGSLineSearch(superCellDefect) elif optimizer_type == 'GPMin': relax = optimize.GPMin(superCellDefect) elif optimizer_type == 'FIRE': relax = optimize.FIRE(superCellDefect) elif optimizer_type == 'MDMin': relax = optimize.MDMin(superCellDefect) else: print('optimizer not supported at the moment, falling back to QuasiNewton') relax = optimize.QuasiNewton(superCellDefect) relax.run(fmax = 0.05) potential_current = superCellDefect.get_potential_energy() # print('lattice energy after relaxation: %5.7f eV' % potential_current, file = log_file) # print('=====================', file = log_file) # put the original xc back to the calculator # calc.set(xc = calc_backup) # relax = QuasiNewton(superCellDefect) # relax.run(fmax=0.05) # if log: # io.write('defect_supercell_after_relaxation.cube', superCellDefect) # potential_energy_AR = superCellDefect.get_potential_energy() # else: # pass return potential_energy_BR, potential_energy_AR
def relax_standard(atoms, calc, fmax=5e-2, smax=1e-4, variable_cell=False, trajfile=None, logfile=None, maxsteps=10000, verbose=False, dEmin=1e-3, optimizer='BFGSLineSearch', ucf=False): """ Locally optimizes the geometry using the non-preconditioned optimizers. Cell optimization is done by alternating between fixed-cell and variable-cell relaxations. atoms: the Atoms object calc: a calculator instance to attach to the Atoms object fmax: the force convergence criterion (in eV/Angstrom) smax: the stress convergence criterion (in eV/Angstrom^3) variable_cell: whether to also optimize the cell vectors trajfile: filename of the trajectory to attach to the optimizers logfile: filename of the logfile for the optimizers maxsteps: maximum allowed total number of ionic steps verbose: whether to print output or remain silent dEmin: minimum (absolute) energy difference for the main loop iterations; if the energy difference is smaller, the minimization is aborted optimizer: name of the ASE optimizer ucf: whether to use a UnitCellFilter (True) or StrainFilter(False) during the variable-cell relaxations """ if variable_cell: atoms.set_pbc(True) else: smax = None atoms.wrap() atoms.set_calculator(calc) nsteps = 0 if trajfile is not None: if os.path.exists(trajfile): os.remove(trajfile) traj = Trajectory(trajfile, 'a', atoms) else: traj = None niter = 0 maxiter = 100 steps = 50 if variable_cell else 125 while nsteps < maxsteps and niter < maxiter: try: if optimizer in ['BFGS', 'BFGSLineSearch', 'LBFGSLineSearch']: dyn = getattr(optimize, optimizer)(atoms, logfile=logfile, maxstep=0.2) elif optimizer == 'FIRE': dyn = optimize.FIRE(atoms, logfile=logfile, dt=0.025, finc=1.25, dtmax=0.3, maxmove=0.2) if traj is not None: dyn.attach(traj) vb = VarianceError(atoms, dyn) dyn.attach(vb) dyn.run(fmax=fmax, steps=steps) nsteps += dyn.get_number_of_steps() except (RuntimeError, np.linalg.linalg.LinAlgError) as err: # Sometimes, BFGS can fail due to # numpy.linalg.linalg.LinAlgError: # Eigenvalues did not converge nsteps += dyn.get_number_of_steps() dyn = optimize.FIRE(atoms, logfile=logfile, dt=0.05, finc=1.25, dtmax=0.3, maxmove=0.2) if traj is not None: dyn.attach(traj) vb = VarianceError(atoms, dyn) dyn.attach(vb) try: dyn.run(fmax=fmax, steps=steps) except RuntimeError: pass nsteps += dyn.get_number_of_steps() if variable_cell: filt = UnitCellFilter(atoms) if ucf else StrainFilter(atoms) dyn = optimize.MDMin(filt, dt=0.05, logfile=logfile) if traj is not None: dyn.attach(traj) dyn.run(fmax=fmax, steps=5) nsteps += dyn.get_number_of_steps() niter += 1 if is_converged(atoms, fmax=fmax, smax=smax): break E = atoms.get_potential_energy() F = atoms.get_forces() S = atoms.get_stress() if variable_cell else None if verbose: print('Done E=%8.3f, maxF=%5.3f, maxS=%5.3e, ncalls=%d'% \ (E, (F ** 2).sum(axis=1).max() ** 0.5, 0. if S is None else np.max(np.abs(S)), nsteps)) finalize(atoms, energy=E, forces=F, stress=S) return atoms
txt='polyethene.cal') calc3 = Hotbit(SCC=True, coulomb_solver=MultipoleExpansion(8, 3, (1, 1, 5)), verbose_SCC=True, kpts=(1, 1, 20), mixer={ 'name': 'anderson', 'convergence': 1e-6 }, txt='polyethene.cal') for calc in [calc2, calc3]: atoms.set_calculator(calc) # Relax (twist) the structure q = optimize.FIRE(atoms, trajectory='polyethene.trj', logfile=None) q.run(fmax=0.5) # Displace atoms from their equilibrium positions and check forces atoms.rattle(0.1) # Check electrostatics only # atoms.set_initial_charges([1.0,1.0,1.0,1.0,-1.0,-1.0,-1.0,-1.0]) # atoms.set_calculator(calc.st.es) # Check forces from finite differences ffd, f0, err = check_forces(atoms, dx=1e-6) if debug: print "Finite differences forces:" print ffd print "Analytical forces:"
box = 5. # box dimension h = 0.25 # grid spacing width = 0.01 # Fermi width nbands = 6 # bands in GS calculation nconv = 4 # bands in GS calculation to converge R = 2.99 # starting distance iex = 1 # excited state index d = 0.01 # step for numerical force evaluation exc = 'LDA' # xc for the linear response TDDFT kernel s = Cluster([Atom('Na'), Atom('Na', [0, 0, R])]) s.minimal_box(box, h=h) c = GPAW(h=h, nbands=nbands, eigensolver='cg', occupations=FermiDirac(width=width), setups={'Na': '1'}, convergence={'bands':nconv}) c.calculate(s) lr = LrTDDFT(c, xc=exc, eps=0.1, jend=nconv-1) ex = ExcitedState(lr, iex, d=d) s.set_calculator(ex) ftraj='relax_ex' + str(iex) ftraj += '_box' + str(box) + '_h' + str(h) ftraj += '_d' + str(d) + '.traj' traj = io.PickleTrajectory(ftraj, 'w', s) dyn = optimize.FIRE(s) dyn.attach(traj.write) dyn.run(fmax=0.05)