def read_geoms(xyz_fns, in_bohr=False, coord_type="cart", define_prims=None, typed_prims=None): if isinstance(xyz_fns, str): xyz_fns = [xyz_fns, ] geoms = list() geom_kwargs = { "coord_type": coord_type, } # Dont supply coord_kwargs with coord_type == "cart" if coord_type != "cart": geom_kwargs["coord_kwargs"] = { "define_prims": define_prims, "typed_prims": typed_prims, } for fn in xyz_fns: if "*" in fn: cwd = Path(".") geom = [geom_loader(xyz_fn, **geom_kwargs) for xyz_fn in natsorted(cwd.glob(fn))] # Simplify this to use geom_loader... elif fn.endswith(".xyz"): geom = [geom_loader(fn, **geom_kwargs), ] elif fn.endswith(".trj"): geom = geom_loader(fn, **geom_kwargs) elif fn.endswith(".pdb"): geom = [geom_loader(fn, **geom_kwargs), ] elif fn.endswith(".cjson"): geom = [geom_loader(fn, **geom_kwargs), ] else: continue geoms.extend(geom) # Try to parse as inline xyz formatted string if len(geoms) == 0: try: atoms_coords = split_xyz_str(fn) # We excpect the coordinates to be given in Angstrom geoms = [Geometry(atoms, coords/BOHR2ANG, **geom_kwargs) for atoms, coords in atoms_coords] except AssertionError: raise Exception("Could not parse supplied 'xyz' values as either " ".xyz, .trj or xyz-formatted string.!" ) # Original coordinates are in bohr, but pysisyphus expects them # to be in Angstrom, so right now they are already multiplied # by ANG2BOHR. We revert this. if in_bohr: for geom in geoms: geom.coords *= BOHR2ANG return geoms
def test_ohch3f_anion(calc_cls, calc_kwargs, ref_cycle, ccl_dist, oc_dist): """Example (R1) from https://aip.scitation.org/doi/pdf/10.1063/1.3457903?class=pdf See Fig. 2 and Fig. 4 """ geom = geom_loader("lib:ohch3f_anion_cs.xyz") # OH group is a fragment fragment_indices = [ (5, 6), ] gamma = 100 calc = calc_cls(charge=-1, **calc_kwargs) afir = AFIR(calc, fragment_indices, gamma, ignore_hydrogen=True) geom.set_calculator(afir) opt = RFOptimizer(geom, dump=True, trust_max=0.3) opt.run() assert opt.is_converged assert opt.cur_cycle == ref_cycle # Broken C-Cl bond c3d = geom.coords3d assert np.linalg.norm(c3d[0] - c3d[4]) == pytest.approx(ccl_dist, abs=1e-4) # Formed O-C bond assert np.linalg.norm(c3d[0] - c3d[5]) == pytest.approx(oc_dist, abs=1e-4)
def test_block_davidson_acet(precon, ref_cyc, ref_nu, this_dir): geom = geom_loader("lib:acet_tm.xyz") calc = XTB(pal=2) geom.set_calculator(calc) mw_H = geom.mw_hessian H = geom.eckart_projection(mw_H) w, v = np.linalg.eigh(H) inds = [16, 8] rg = np.random.default_rng(20180325) def get_guess(vec, masses_rep, scale=5e-3): return NormalMode(vec + scale * rg.random(*vec.shape), masses_rep) guess_modes = [get_guess(v[:, ind], geom.masses_rep) for ind in inds] hessian_precon = None if precon: hessian_precon = np.loadtxt(this_dir / "hessian_precon") result = geom_davidson( geom, guess_modes, hessian_precon=hessian_precon, start_precon=5, print_level=1, ) nu = result.nus[result.mode_inds[0]] assert result.converged assert result.cur_cycle == ref_cyc assert nu == pytest.approx(ref_nu)
def test_turbomole_hessian_compare(this_dir): geom = geom_loader("lib:h2o_bp86_def2svp_opt.xyz") qce_kwargs = { "program": "turbomole", "model": { "method": "b-p", "basis": "def2-SVP", }, "keywords": { "ri": True, "grid": "m5", } } qce_calc = QCEngine(**qce_kwargs) geom.set_calculator(qce_calc) H = geom.hessian ref_geom = geom.copy() control_path = this_dir / "h2o_bp86_def2svp_control" ref_calc = Turbomole(control_path) ref_geom.set_calculator(ref_calc) H_ref = ref_geom.hessian assert geom.energy == pytest.approx(ref_geom.energy) np.testing.assert_allclose(H, H_ref, rtol=2e-4)
def test_oniom_md(): calc_dict = { "high": { "type": "pypsi4", "method": "scf", "basis": "sto-3g", }, "low": { "type": "pyxtb", }, } high_inds = (4, 5, 6) from pysisyphus.calculators.ONIOM import ONIOM oniom = ONIOM(calc_dict, high_inds) geom = geom_loader("lib:acetaldehyd_oniom.xyz") geom.set_calculator(oniom) v0 = .005 * np.random.rand(*geom.coords.shape) md_kwargs = { "v0": v0, "t": 40, "dt": 0.5, } md_result = md(geom, **md_kwargs) from pysisyphus.xyzloader import make_trj_str coords = md_result.coords.reshape(-1, len(geom.atoms), 3) * BOHR2ANG trj_str = make_trj_str(geom.atoms, coords) with open("md.trj", "w") as handle: handle.write(trj_str)
def test_gradient(calcs, ref_energy, ref_force_norm): geom = geom_loader("lib:acetaldehyd_oniom.xyz", coord_type="redund") real = set(range(len(geom.atoms))) high = [4, 5, 6] for key, calc in calcs.items(): calc["pal"] = 2 calc["mult"] = 1 calc["charge"] = 0 models = { "high": { "inds": high, "calc": "high", }, } # layers = ["high"] # No layers specified layers = None oniom = ONIOM(calcs, models, geom, layers) assert oniom.layer_num == 2 geom.set_calculator(oniom) # Calculate forces forces = geom.forces energy = geom.energy assert np.linalg.norm(forces) == pytest.approx(ref_force_norm) assert energy == pytest.approx(ref_energy)
def test_backtransform_hessian(): geom = geom_loader("lib:azetidine_hf_321g_opt.xyz", coord_type="redund") H_fn = "H" cH_fn = "cH" f_fn = "f" cf_fn = "cf" calc = PySCF(basis="321g", pal=2) geom.set_calculator(calc) f = geom.forces np.savetxt(f_fn, f) cf = geom.cart_forces np.savetxt(cf_fn, cf) H = geom.hessian np.savetxt(H_fn, H) cH = geom.cart_hessian np.savetxt(cH_fn, cH) f_ref = np.loadtxt(f_fn) cf_ref = np.loadtxt(cf_fn) H_ref = np.loadtxt(H_fn) cH_ref = np.loadtxt(cH_fn) # norm = np.linalg.norm(cf_ref) # print(f"norm(cart. forces)={norm:.6f}") int_ = geom.internal int_gradient_ref = -f_ref H = int_.transform_hessian(cH_ref, int_gradient_ref) np.testing.assert_allclose(H, H_ref) cH = int_.backtransform_hessian(H, int_gradient_ref) np.testing.assert_allclose(cH, cH_ref, atol=1.5e-7)
def test_hf_abstraction_dvv(calc_cls, kwargs_, this_dir): geom = geom_loader("lib:hfabstraction_hf321g_displ_forward.xyz") calc_kwargs = { "pal": 2, } calc_kwargs.update(kwargs_) if "control_path" in calc_kwargs: calc_kwargs["control_path"] = this_dir / calc_kwargs["control_path"] print("Using", calc_cls) calc = calc_cls(**calc_kwargs) geom.set_calculator(calc) irc_kwargs = { "dt0": 0.5, "v0": 0.04, "downhill": True, "max_cycles": 150, } dvv = DampedVelocityVerlet(geom, **irc_kwargs) dvv.run() c3d = geom.coords3d * BOHR2ANG def bond(i, j): return np.linalg.norm(c3d[i] - c3d[j]) assert bond(2, 7) == pytest.approx(0.93, abs=0.01) assert bond(4, 7) == pytest.approx(2.42, abs=0.01) assert bond(2, 0) == pytest.approx(2.23, abs=0.01)
def test_pyscf_stocastic(): geom = geom_loader("lib:benzene_and_no.xyz") def calc_getter(calc_number): calc_kwargs = { "charge": +1, "mult": 1, "pal": 2, "basis": "321g", "calc_number": calc_number, } calc = PySCF(**calc_kwargs) return calc stoc_kwargs = { "calc_getter": calc_getter, "cycle_size": 3, "max_cycles": 3, "radius": 5., "seed": 20180325, "fragments": (list(range(12)), ), "rmsd_thresh": .2, "random_displacement": True, } stoc = FragmentKick(geom, **stoc_kwargs) stoc.run() assert stoc.cur_cycle == 2 assert len(stoc.new_geoms) == 4 assert min(stoc.new_energies) == pytest.approx(-357.605594464)
def test_afir(): """Example (R1) from https://aip.scitation.org/doi/pdf/10.1063/1.3457903?class=pdf See Fig. 2 and Fig. 4 """ geom = geom_loader("lib:ohch3f_anion_cs.xyz") # OH group is a fragment fragment_indices = [ (5, 6), ] calc = PySCF(basis="6-31g*", xc="b3lyp", pal=2, charge=-1) gamma = 100 afir = AFIR(calc, fragment_indices, gamma) geom.set_calculator(afir) opt = RFOptimizer(geom, dump=True, trust_max=.3) opt.run() assert opt.is_converged assert opt.cur_cycle == 47 # Broken C-Cl bond c3d = geom.coords3d assert np.linalg.norm(c3d[0] - c3d[4]) == pytest.approx(4.805665, abs=1e-4) # Formed O-C bond assert np.linalg.norm(c3d[0] - c3d[5]) == pytest.approx(2.674330, abs=1e-4)
def test_qcengine_openmm(): """ conda install -c omnia -c conda-forge openmm conda install -c omnia -c conda-forge openforcefield """ geom = geom_loader("lib:h2o_guess.xyz") qce_kwargs = { "program": "openmm", "model": { "method": "openmm", "basis": "openff-1.0.0", "offxml": "openff-1.0.0.offxml", "connectivity": ((0, 1, 1), (0, 2, 1)), }, } qce = QCEngine(**qce_kwargs) geom.set_calculator(qce) forces = geom.forces energy = geom.energy norm = np.linalg.norm(forces) assert energy == pytest.approx(6.4193809337e+20) assert norm == pytest.approx(1.4649609864e+22)
def test_geom_to_pdb(this_dir): geom = geom_loader(this_dir / "five_chloroforms_xtbopt.xyz") pdb_str = geom_to_pdb_str(geom, detect_fragments=True) # Reference pdb with open(this_dir / "five_chloroforms_ref.pdb") as handle: ref = handle.read() assert pdb_str == ref
def assert_geom(ref_fn, zmat_fn, atol=2.5e-5): zmat = zmat_from_fn(zmat_fn) geom = geom_from_zmat(zmat) ref = geom_loader(ref_fn) rmsd = kabsch_rmsd(geom.coords3d, ref.coords3d, translate=True) print(f"RMSD: {rmsd:.6f}") assert rmsd == pytest.approx(0., abs=atol)
def test_linear_dihedrals(): geom = geom_loader("lib:dihedral_gen_test.cjson", coord_type="redund") typed_prims = geom.internal.typed_prims pd = PrimTypes.PROPER_DIHEDRAL need_diheds = ((2, 7, 0, 5), (2, 7, 0, 4), (3, 7, 0, 4), (2, 7, 0, 5)) for dihed in need_diheds: assert ((pd, *dihed) in typed_prims) or ((pd, *dihed[::-1]) in typed_prims)
def test_redox(inp_1, inp_2, calc_cls, gas_kwargs, solv_kwargs): geom_1 = geom_loader(inp_1["xyz"], coord_type="redund") charge_1 = inp_1["charge"] mult_1 = inp_1["mult"] opt_1 = inp_1["opt"] geom_2 = geom_loader(inp_2["xyz"], coord_type="redund") charge_2 = inp_2["charge"] mult_2 = inp_2["mult"] opt_2 = inp_2["opt"] gas_calc_number = 0 def calc_getter_gas(calc_kwargs): nonlocal gas_calc_number calc = calc_cls(**gas_kwargs, calc_number=gas_calc_number, **calc_kwargs) gas_calc_number += 1 return calc solv_calc_number = 0 def calc_getter_solv(calc_kwargs): nonlocal solv_calc_number calc = calc_cls(**solv_kwargs, calc_number=gas_calc_number, **calc_kwargs) solv_calc_number += 1 return calc result_1 = run_calculations(geom_1, charge_1, mult_1, calc_getter_gas, calc_getter_solv, opt=opt_1) print() result_2 = run_calculations(geom_2, charge_2, mult_2, calc_getter_gas, calc_getter_solv, opt=opt_2) calculate_potential(result_1, result_2, T=298.15)
def test_energy(): geom = geom_loader("lib:alkyl17_sto3g_opt.xyz") real = set(range(len(geom.atoms))) medmin = set((0, 1, 2, 3, 4, 5, 6, 46, 47, 48, 49, 50, 51, 52)) med = list(real - medmin) h1 = list(range(13, 22)) h2 = list(range(31, 40)) calcs = { "real": { "route": "HF/STO-3G", }, "medium": { "route": "HF/3-21G", }, "high1": { "route": "HF/6-31G", }, "high2": { "route": "HF/6-311G", }, } for key, calc in calcs.items(): calc["type"] = "g16" calc["pal"] = 2 calc["mult"] = 1 calc["charge"] = 0 models = { "med": { # "inds": (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14), "inds": med, "calc": "medium", }, "h1": { # "inds": (4, 5, 6), "inds": h1, "calc": "high1", }, "h2": { # "inds": (10, 11, 12), "inds": h2, "calc": "high2", } } layers = ["med", ["h1", "h2"]] oniom = ONIOM(calcs, models, geom, layers) assert oniom.layer_num == 3 geom.set_calculator(oniom) assert geom.energy == pytest.approx(-661.3512410069466)
def test_h2o_opt(): geom = geom_loader("lib:h2o.xyz", coord_type="redund") calc = Dalton(basis="3-21G") geom.set_calculator(calc) opt = RFOptimizer(geom, thresh="gau_tight") opt.run() assert opt.is_converged assert opt.cur_cycle == 4 assert geom.energy == pytest.approx(-75.58595976)
def test_get_fragments(): geom = geom_loader("lib:benzene_and_chlorine.xyz") # Only define chlorine fragment and determine second fragment automatically fragments = ((12, 13), ) kwargs = { "fragments": fragments, } fkick = FragmentKick(geom, **kwargs) _, benz_frag = fkick.fragments assert benz_frag.tolist() == list(range(12))
def azetidine(): geom = geom_loader("lib:azetidine_hf_321g_opt.xyz", coord_type="redund") psi4_kwargs = { "method": "hf", "basis": "3-21g", "pal": 2, } calc = Psi4(**psi4_kwargs) geom.set_calculator(calc) return geom
def as_pdb(fn): if not fn.endswith(".pdb"): geom = geom_loader(fn) pdb_str = geom_to_pdb_str(geom) pdb_fn = str(Path(fn).with_suffix(".pdb")) with open(pdb_fn, "w") as handle: handle.write(pdb_str) print(f"Converted '{fn}' to PDB format ('{pdb_fn}')") fn = pdb_fn return fn
def test_water_hf_precon_opt(opt_cls, precon, ref_cycles): geom = geom_loader("lib:h2o_shaken.xyz") calc = PySCF(basis="sto3g") geom.set_calculator(calc) opt = opt_cls(geom, thresh="gau_tight", max_cycles=100, precon=precon) opt.run() assert opt.is_converged assert opt.cur_cycle == ref_cycles assert geom.energy == pytest.approx(-74.96590119)
def test_allene_opt(): geom = geom_loader("lib:08_allene.xyz", coord_type="redund") calc = PySCF(basis="321g", pal=1) geom.set_calculator(calc) opt = RFOptimizer(geom, thresh="gau_tight") opt.run() assert opt.is_converged # assert opt.cur_cycle == 7 assert geom.energy == pytest.approx(-115.21991342)
def test_electronic_embedding(calc_key, embedding, ref_energy, ref_force_norm): geom = geom_loader("lib:oniom_ee_model_system.xyz", coord_type="redund") all_ = set(range(len(geom.atoms))) high = list(sorted(all_ - set((21, 20, 19, 15, 14, 13)))) calcs_dict = { "g16": ({ "real": { "type": "g16", "route": "hf sto-3g" }, "high": { "type": "g16", "route": "hf 3-21g" }, }), "pyscf": ({ "real": { "type": "pyscf", "basis": "sto3g", }, "high": { "type": "pyscf", "basis": "321g" }, }), } calcs = calcs_dict[calc_key] for key, calc in calcs.items(): calc["pal"] = 2 calc["mult"] = 1 calc["charge"] = 0 models = { "high": { "inds": high, "calc": "high", }, } oniom_kwargs = { "embedding": embedding, } oniom = ONIOM(calcs, models, geom, **oniom_kwargs) geom.set_calculator(oniom) # Calculate forces and energy forces = geom.forces energy = geom.energy assert energy == pytest.approx(ref_energy) assert np.linalg.norm(forces) == pytest.approx(ref_force_norm)
def test_hcn_iso_gs2(step_length): geom = geom_loader("lib:hcn_iso_hf_sto3g_ts_opt.xyz") calc = PySCF(basis="sto3g") geom.set_calculator(calc) irc_kwargs = { "step_length": step_length, } irc = GonzalezSchlegel(geom, **irc_kwargs) irc.run() assert irc.forward_is_converged assert irc.backward_is_converged
def test_pdb_write(this_dir): geom = geom_loader("lib:h2o.xyz") pdb_str = geom_to_pdb_str(geom) # with open("h2o.pdb", "w") as handle: # handle.write(pdb_str) # Reference pdb with open(this_dir / "h2o_ref.pdb") as handle: ref = handle.read() assert pdb_str == ref
def test_numhess(xyz_fn, coord_type, ref_rms): geom = geom_loader(xyz_fn, coord_type=coord_type) # Interestingly enough the test will fail with keep_chk == True ... # as the RMS value will be much higher calc = PySCF(basis="321g", pal=2, keep_chk=False) geom.set_calculator(calc) H = geom.hessian nH = numhess(geom) assert compare_hessians(H, nH, ref_rms)
def test_hcn_irc(irc_cls, irc_kwargs, fw_cycle, bw_cycle): geom = geom_loader("lib:hcn_iso_hf_sto3g_ts_opt.xyz") calc = PySCF(basis="sto3g", ) geom.set_calculator(calc) irc = irc_cls(geom, **irc_kwargs, rms_grad_thresh=1e-4) irc.run() # approx. +- 0.5 kJ/mol assert irc.forward_energies[0] == pytest.approx( -91.67520894777218) #, abs=2.2e-4) assert irc.backward_energies[-1] == pytest.approx(-91.64442379051056)
def test_opt_linear_dihedrals(): geom = geom_loader("lib:dihedral_gen_test.cjson", coord_type="redund") geom.set_calculator(XTB()) opt_kwargs = { "thresh": "gau_tight", } opt = RFOptimizer(geom, **opt_kwargs) opt.run() assert opt.is_converged assert opt.cur_cycle == 16 assert geom.energy == pytest.approx(-10.48063133)
def test_kick(): geom = geom_loader("lib:benzene_and_chlorine.xyz") stoc_kwargs = { "cycle_size": 10, "radius": 1.25, "seed": 1532002565, "max_cycles": 5, } stoc = Kick(geom, **stoc_kwargs) stoc.run() assert stoc.cur_cycle == 4 assert len(stoc.new_geoms) == 9 assert min(stoc.new_energies) == pytest.approx(-24.9688182)
def test_baker_tsopt(name, results_bag): charge, mult, ref_energy = get_baker_ts_data()[name] geom = geom_loader( f"lib:baker_ts/{name}", coord_type="redund", coord_kwargs={ "rebuild": True, }, ) # geom.jmol() calc_kwargs = { "charge": charge, "mult": mult, "pal": 1, } print(f"@Running {name}") geom.set_calculator(PySCF(basis="321g", **calc_kwargs)) # geom.set_calculator(ORCA(keywords="HF 3-21G", **calc_kwargs)) if geom.coord_type != "cart": geom = augment_bonds(geom) opt_kwargs = { "thresh": "baker", "max_cycles": 50, "trust_radius": 0.1, "trust_max": 0.3, "min_line_search": True, "max_line_search": True, } opt = RSPRFOptimizer(geom, **opt_kwargs) # opt = RSIRFOptimizer(geom, **opt_kwargs) # opt = TRIM(geom, **opt_kwargs) opt.run() # Without symmetry restriction this lower lying TS will be obtained. # if name.startswith("22_"): # ref_energy = -242.25695787 results_bag.cycles = opt.cur_cycle + 1 results_bag.is_converged = opt.is_converged results_bag.energy = geom.energy results_bag.ref_energy = ref_energy print(f"\t@Converged: {opt.is_converged}, {opt.cur_cycle+1} cycles") assert geom.energy == pytest.approx(ref_energy) print("\t@Energies match!") return opt.cur_cycle + 1