def test_analyse_forces(): from ase.build import molecule from ase.calculators.emt import EMT from ase.optimize import BFGSLineSearch from carmm.analyse.forces import is_converged from ase.constraints import FixAtoms fmax = 0.01 # eV/Angstrom atoms = molecule("CO2") atoms.calc = EMT() # Returns False prior to optimisation (no forces in calculator) opt = BFGSLineSearch(atoms) print(is_converged(atoms, fmax)) assert (is_converged(atoms, fmax) == False) print(atoms.calc.forces) # Returns False if optimisation has not reached to/below fmax opt.run(fmax=fmax * 30) print(is_converged(atoms, fmax)) assert (is_converged(atoms, fmax) == False) # Returns True if optimised to or below desired fmax with constraints c = FixAtoms(indices=[0, 1]) atoms.set_constraint(c) opt.run(fmax=fmax) print(is_converged(atoms, fmax)) assert (is_converged(atoms, fmax) == True) # Returns True if optimised to or below desired fmax without constraints atoms.set_constraint() opt.run(fmax=fmax) print(is_converged(atoms, fmax)) assert (is_converged(atoms, fmax) == True)
def relax_VarianceBreak(structure, calc, label='', niter_max=10, forcemax=0.1): ''' Relax a structure and saves the trajectory based in the index i Parameters ---------- structure : ase Atoms object to be relaxed Returns ------- ''' # Set calculator structure.set_calculator(calc) # loop a number of times to capture if minimization stops with high force # due to the VariansBreak calls niter = 0 # If the structure is already fully relaxed just return it if (structure.get_forces()**2).sum(axis=1).max()**0.5 < forcemax: return structure while (structure.get_forces()** 2).sum(axis=1).max()**0.5 > forcemax and niter < niter_max: dyn = BFGSLineSearch(structure, logfile=label + '.log') vb = VariansBreak(structure, dyn, min_stdev=0.01, N=15) dyn.attach(vb) dyn.run(fmax=forcemax, steps=200) niter += 1 return structure
def prepare_slab_opt(self, slab: Atoms) -> None: ''' Prepare slab optimization with Quantum Espresso ''' balsamcalc_module = __import__('pynta.balsamcalc', fromlist=[self.socket_calculator]) sock_calc = getattr(balsamcalc_module, self.socket_calculator) # n_kpts = IO().get_kpoints(self.repeats_surface) job_kwargs = self.balsam_exe_settings.copy() extra_calc_keywords = self.calc_keywords.copy() # add kpoints and distribute it among nodes = n_kpts # extra_calc_keywords['kpts'] = self.repeats_surface # extra_calc_keywords['job_args'] = '-nk {}'.format(n_kpts) # change how k-points are distrubuted among nodes # job_kwargs.update([('num_nodes', n_kpts)]) slab.pbc = (True, True, False) if self.socket_calculator == 'EspressoBalsamSocketIO': slab.calc = sock_calc(workflow='QE_Socket', job_kwargs=job_kwargs, pseudopotentials=self.pseudopotentials, pseudo_dir=self.pseudo_dir, **extra_calc_keywords) else: slab.calc = sock_calc(workflow='QE_Socket', job_kwargs=job_kwargs, **extra_calc_keywords) fname = os.path.join(self.creation_dir, self.slab_name) opt = BFGSLineSearch(atoms=slab, trajectory=fname + '.traj') opt.run(fmax=0.01) slab.get_potential_energy() slab.get_forces() slab.calc.close() write(fname + '.xyz', slab)
def flosic_optimize(mode, atoms, charge, spin, xc, basis, ecp=None, opt='FIRE', maxstep=0.2, label='OPT_FRMORB', fmax=0.0001, steps=1000, max_cycle=300, conv_tol=1e-5, grid=7, ghost=False, use_newton=False, use_chk=False, verbose=0, debug=False, efield=None, l_ij=None, ods=None, force_consistent=False, fopt='force', fix_fods=False, ham_sic='HOO', vsic_every=1): # ----------------------------------------------------------------------------------- # Input # ----------------------------------------------------------------------------------- # mode ... dft only optimize nuclei positions # flosic only optimize FOD positions (one-shot) # flosic-scf only optimize FOD positions (self-consistent) # atoms ... ase atoms object # charge ... charge # spin ... spin state = alpha - beta # xc ... exchange correlation functional # basis ... GTO basis set # ecp ... if a ECP basis set is used you must give this extra argument # opt ... optimizer (FIRE, LBFGS, ...) # ---------------------------------------------------------------------------------- # Additional/optional input # ---------------------------------------------------------------------------------- # maxstep ... stepwidth of the optimizer # label ... label for the outputs (logfile and trajectory file) # fmax ... maximum force # steps ... maximum steps for the optimizer # max_cycle ... maxium scf cycles # conv_tol ... energy threshold # grid ... numerical mesh # ghost ... use ghost atom at positions of FODs # use_newton ... use newton scf cycle # use_chk ... restart from chk fiels # verbose ... output verbosity # debug ... extra output for debugging reasons # efield ... applying a external efield # l_ij ... developer option: another optimitzation criterion, do not use for production # ods ... developer option orbital damping sic, rescale SIC, do not use for production # force_cosistent ... ase option energy consistent forces # fopt ... optimization trarget, default FOD forces # fix_fods ... freeze FODS during the optimization, might use for 1s/2s FODs # ham_sic ... the different unified Hamiltonians HOO and HOOOV opt = opt.upper() mode = mode.lower() if fix_fods != False: c = FixAtoms(fix_fods) atoms.set_constraint(c) # Select the wished mode. # DFT mode if mode == 'dft': [geo, nuclei, fod1, fod2, included] = xyz_to_nuclei_fod(atoms) atoms = nuclei calc = PYFLOSIC(atoms=atoms, charge=charge, spin=spin, xc=xc, basis=basis, mode='dft', ecp=ecp, max_cycle=max_cycle, conv_tol=conv_tol, grid=grid, ghost=ghost, use_newton=use_newton, verbose=verbose, debug=debug, efield=efield, l_ij=l_ij, ods=ods, fopt=fopt, ham_sic=ham_sic, vsic_every=vsic_every) # FLO-SIC one-shot (os) mode if mode == 'flosic-os': calc = PYFLOSIC(atoms=atoms, charge=charge, spin=spin, xc=xc, basis=basis, mode='flosic-os', ecp=ecp, max_cycle=max_cycle, conv_tol=conv_tol, grid=grid, ghost=ghost, use_newton=use_newton, verbose=verbose, debug=debug, efield=efield, l_ij=l_ij, ods=ods, fopt=fopt, ham_sic=ham_sic, vsic_every=vsic_every) # FLO-SIC scf mode if mode == 'flosic-scf': calc = PYFLOSIC(atoms=atoms, charge=charge, spin=spin, xc=xc, basis=basis, mode='flosic-scf', ecp=ecp, max_cycle=max_cycle, conv_tol=conv_tol, grid=grid, ghost=ghost, use_newton=use_newton, verbose=verbose, debug=debug, efield=efield, l_ij=l_ij, ods=ods, fopt=fopt, ham_sic=ham_sic, vsic_every=vsic_every) # Assign the ase-calculator to the ase-atoms object. atoms.set_calculator(calc) # Select the wisehd ase-optimizer. if opt == 'FIRE': dyn = FIRE(atoms, logfile=label + '.log', trajectory=label + '.traj', dt=0.15, maxmove=maxstep) #force_consistent=force_consistent) if opt == 'LBFGS': dyn = LBFGS(atoms, logfile=label + '.log', trajectory=label + '.traj', use_line_search=False, maxstep=maxstep, memory=10) #force_consistent=force_consistent) if opt == 'BFGS': dyn = BFGS(atoms, logfile=label + '.log', trajectory=label + '.traj', maxstep=maxstep) if opt == 'LineSearch': dyn = BFGSLineSearch(atoms, logfile=label + '.log', trajectory=label + '.traj', maxstep=maxstep) #force_consistent = force_consistent) if opt == 'CG': dyn = SciPyFminCG(atoms, logfile=label + '.log', trajectory=label + '.traj', callback_always=False, alpha=70.0, master=None) #force_consistent=force_consistent) if opt == 'GPMin': from ase.optimize import GPMin dyn = GPMin(atoms, logfile=label + '.log', trajectory=label + '.traj', update_prior_strategy='average', update_hyperparams=True) # Run the actuall optimization. dyn.run(fmax=fmax, steps=steps) return atoms
atoms.set_calculator(calc) print(calc.parameters) # test energy call print(atoms.get_potential_energy()) # test force call print(atoms.get_forces()) calc = Psi4('psi4-calc') print(calc.parameters) # test interface with ASE optimizers relax = BFGSLineSearch(atoms) relax.run(fmax = 0.05) # test mutliplicity and charge kwargs atoms = molecule('H2') calc = Psi4(atoms = atoms, charge = 1, multiplicity = 2, reference = 'uhf') print(atoms.get_potential_energy()) del atoms[1]
def mof_bfgs_run(workflow, mof, calc, kpts, steps=100, fmax=0.05, force_nupdown=False): """ Run ASE BFGSLineSearch calculation Args: workflow (class): pymofscreen.screen_phases.worfklow class mof (ASE Atoms object): ASE Atoms object for MOF calc (dict): ASE Vasp calculator kpts (list of ints): k-point grid steps (int): maximum number of steps fmax (int): force tolerance force_nupdown (bool): force NUPDOWN to nearest int Returns: mof (ASE Atoms object): updated ASE Atoms object dyn (class): ASE dynamics class calc_swaps (list of strings): calc swaps """ nprocs = workflow.nprocs ppn = workflow.ppn calc_swaps = workflow.calc_swaps refcode = workflow.refcode stdout_file = workflow.stdout_file calc_swaps = workflow.calc_swaps gamma = workflow.kpts_dict['gamma'] if force_nupdown: init_mags = mof.get_initial_magnetic_moments() summed_mags = np.sum(np.abs(init_mags)) nupdown = int(np.round(summed_mags, 0)) calc.int_params['nupdown'] = nupdown elif workflow.nupdown is not None: calc.int_params['nupdown'] = workflow.nupdown if sum(kpts) == 3: gpt_version = True else: gpt_version = False nprocs = check_nprocs(len(mof), nprocs, ppn) choose_vasp_version(gpt_version, nprocs) calc.input_params['kpts'] = kpts calc.input_params['gamma'] = gamma if calc.int_params['ncore'] is None and calc.int_params['npar'] is None: calc.int_params['ncore'] = int(ppn / 2.0) calc, calc_swaps = update_calc(calc, calc_swaps) mof.set_calculator(calc) dyn = BFGSLineSearch(mof, trajectory='opt.traj') success = False try: dyn.run(fmax=fmax, steps=steps) success = True except: if not os.path.isfile('STOPCAR'): old_error_len = 0 restart_files = ['WAVECAR', 'CHGCAR'] while True: errormsg = get_error_msgs('OUTCAR', refcode, stdout_file) print(errormsg) calc, calc_swaps = update_calc_after_errors( calc, calc_swaps, errormsg) error_len = len(errormsg) if error_len == old_error_len: break clean_files(restart_files) mof = continue_mof() mof.set_calculator(calc) dyn = BFGSLineSearch(mof, trajectory='opt.traj') try: dyn.run(fmax=fmax, steps=steps) success = True except: pass old_error_len = error_len if not success: mof = None return mof, dyn, calc_swaps
def adsorb(db, height=1.2, nlayers=3, nkpts=7, ecut=400): """Adsorb nitrogen in hcp-site on Ru(0001) surface. Do calculations for N/Ru(0001), Ru(0001) and a nitrogen atom if they have not already been done. db: Database Database for collecting results. height: float Height of N-atom above top Ru-layer. nlayers: int Number of Ru-layers. nkpts: int Use a (nkpts * nkpts) Monkhorst-Pack grid that includes the Gamma point. ecut: float Cutoff energy for plane waves. Returns height. """ name = f'Ru{nlayers}-{nkpts}x{nkpts}-{ecut:.0f}' parameters = dict(mode=PW(ecut), eigensolver=Davidson(niter=2), poissonsolver={'dipolelayer': 'xy'}, kpts={'size': (nkpts, nkpts, 1), 'gamma': True}, xc='PBE') # N/Ru(0001): slab = hcp0001('Ru', a=a, c=c, size=(1, 1, nlayers)) z = slab.positions[:, 2].max() + height x, y = np.dot([2 / 3, 2 / 3], slab.cell[:2, :2]) slab.append('N') slab.positions[-1] = [x, y, z] slab.center(vacuum=vacuum, axis=2) # 2: z-axis # Fix first nlayer atoms: slab.constraints = FixAtoms(indices=list(range(nlayers))) id = db.reserve(name=f'N/{nlayers}Ru(0001)', nkpts=nkpts, ecut=ecut) if id is not None: # skip calculation if already done slab.calc = GPAW(txt='N' + name + '.txt', **parameters) optimizer = BFGSLineSearch(slab, logfile='N' + name + '.opt') optimizer.run(fmax=0.01) height = slab.positions[-1, 2] - slab.positions[:-1, 2].max() del db[id] db.write(slab, name=f'N/{nlayers}Ru(0001)', nkpts=nkpts, ecut=ecut, height=height) # Clean surface (single point calculation): id = db.reserve(name=f'{nlayers}Ru(0001)', nkpts=nkpts, ecut=ecut) if id is not None: del slab[-1] # remove nitrogen atom slab.calc = GPAW(txt=name + '.txt', **parameters) slab.get_forces() del db[id] db.write(slab, name=f'{nlayers}Ru(0001)', nkpts=nkpts, ecut=ecut) # Nitrogen atom: id = db.reserve(name='N-atom', ecut=ecut) if id is not None: # Create spin-polarized nitrogen atom: molecule = Atoms('N', magmoms=[3]) molecule.center(vacuum=4.0) # Remove parameters that make no sense for an isolated atom: del parameters['kpts'] del parameters['poissonsolver'] # Calculate energy: molecule.calc = GPAW(txt=name + '.txt', **parameters) molecule.get_potential_energy() del db[id] db.write(molecule, name='N-atom', ecut=ecut) return height
water = molecule('H2O') print(water) print(water.positions) #iron = bulk('Fe', cubic = True) #view(iron) calc = EMT() water.set_calculator(calc) energy = water.get_potential_energy() forces = water.get_forces() print(energy) print(forces) relax = BFGSLineSearch(atoms=water) relax.run( fmax=0.05) # relax the structure until the maximum force is 0.05 eV/A print(water.positions) #view(water) O2 = molecule('O2') O2.set_calculator(EMT()) dyn = QuasiNewton(O2) dyn.run() E_O2 = O2.get_potential_energy() H2 = molecule('H2') H2.set_calculator(EMT())
def example(): from ase.calculators.lj import LennardJones from theforce.util.flake import Hex from ase.io.trajectory import Trajectory from ase.optimize import BFGSLineSearch from ase.io import Trajectory # initial state + dft calculator ini_atoms = TorchAtoms(positions=Hex().array(), cutoff=3.0) dftcalc = LennardJones() ini_atoms.set_calculator(dftcalc) BFGSLineSearch(ini_atoms).run(fmax=0.01) vel = np.random.uniform(-1., 1., size=ini_atoms.positions.shape) * 1. vel -= vel.mean(axis=0) ini_atoms.set_velocities(vel) # use a pretrained model by writing it to the checkpoint # (alternatively set, for example, itrain=10*[5] in mlmd) pre = """GaussianProcessPotential([PairKernel(RBF(signal=3.2251566545458794, lengthscale=tensor([0.1040])), 0, 0, factor=PolyCut(3.0, n=2))], White(signal=0.1064043798026091, requires_grad=True))""".replace( '\n', '') with open('gp.chp', 'w') as chp: chp.write(pre) # run(md) mlmd(ini_atoms, 3.0, 0.5, 0.03, tolerance=0.18, max_steps=100, soap=False, itrain=10 * [3], retrain_every=5, retrain=5) # recalculate all with the actual calculator and compare traj = Trajectory('md.traj') energies = [] forces = [] dum = 0 for atoms in traj: dum += 1 e = atoms.get_potential_energy() f = atoms.get_forces() dftcalc.calculate(atoms) ee = dftcalc.results['energy'] ff = dftcalc.results['forces'] energies += [(e, ee)] forces += [(f.reshape(-1), ff.reshape(-1))] import pylab as plt get_ipython().run_line_magic('matplotlib', 'inline') fig, axes = plt.subplots(1, 2, figsize=(8, 3)) axes[0].scatter(*zip(*energies)) axes[0].set_xlabel('ml') axes[0].set_ylabel('dft') a, b = (np.concatenate(v) for v in zip(*forces)) axes[1].scatter(a, b) axes[1].set_xlabel('ml') axes[1].set_ylabel('dft') fig.tight_layout() fig.text(0.2, 0.8, 'energy') fig.text(0.7, 0.8, 'forces')
with open('%s_results.txt' % prefix, 'w') as fout: fout.write('id evaluations\n') # Loop over all molecules in the bechmark set for i in range(1, 31): atoms = read('%02d.xyz' % i) calc = QChem(label='calculations/%s/mol_%02d' % (prefix, i), scratch='calculations/%s/scratch' % prefix, nt=4, jobtype='force', method='HF', basis='STO-3G', scf_algorithm='DIIS_GDM', max_scf_cycles='500', scf_convergence='7', charge=0, multiplicity=1) atoms.set_calculator(EvalCountingCalculator(calc)) # Do first evaluation atoms.get_forces() # and switch scf_guess to read calc.set(scf_guess='read') opt = BFGSLineSearch(atoms) opt.run(fmax=0.01) # Append to the results file with open('%s_results.txt' % prefix, 'a') as fout: fout.write('%2d % 3d\n' % (i, atoms.calc.n_evals)) sum_evals += atoms.calc.n_evals with open('%s_results.txt' % prefix, 'a') as fout: fout.write('sum % 3d\n' % sum_evals)