def set_new_node(self, k): new_coords = self.new_node_coords(k) new_node = Geometry(self.image_atoms, new_coords) new_node.set_calculator(self.calc_getter()) self.images.insert(k+1, new_node) # print(f"made node {k+1}") return new_node
def test_dimer(rotation_method, ref_cycle): coords = (-0.2, 1.1, 0) geom = Geometry(("X", ), coords) N_raw = np.array((0.83, 0.27, 0.)) # New implementation dimer_kwargs = { "rotation_method": rotation_method, "calculator": AnaPot(), "N_raw": N_raw, "rotation_remove_trans": False, } dimer = Dimer(**dimer_kwargs) geom.set_calculator(dimer) opt_kwargs = { "precon": False, "line_search": None, "max_step_element": 0.25, "thresh": "gau_tight", "max_cycles": 15, } opt = PreconLBFGS(geom, **opt_kwargs) opt.run() # AnaPot().plot_opt(opt) assert opt.is_converged assert opt.cur_cycle == ref_cycle assert geom.energy == pytest.approx(2.80910484)
def prepare_opt(): ethan_xyz = "xyz_files/ethan.xyz" atoms, coords = parse_xyz_file(ethan_xyz) geom = Geometry(atoms, coords.flatten()) geom.set_calculator(ORCA()) return geom, copy.copy(KWARGS)
def write_fragment_geoms(self, atoms, coords): geom = Geometry(atoms, coords) for i, frag in enumerate(self.fragment_indices): frag_geom = geom.get_subgeom(frag) fn = f"frag_geom_{i:02d}.xyz" with open(fn, "w") as handle: handle.write(frag_geom.as_xyz()) self.log(f"Wrote geometry of fragment {i:02d} to {fn}.")
def get_dimer_ends(geom0, N, R, calc_getter): dummy_coords = np.zeros_like(geom0.coords) geom1 = Geometry(geom0.atoms, dummy_coords) geom2 = Geometry(geom0.atoms, dummy_coords) update_dimer_ends(geom0, geom1, geom2, N, R) geom1.set_calculator(calc_getter()) return geom1, geom2
def get_new_image_from_coords(self, coords, index): new_image = Geometry( self.image_atoms, coords, coord_type=self.coord_type, coord_kwargs={ "prim_indices": self.prim_indices, }, ) new_image.set_calculator(self.calc_getter()) self.images.insert(index, new_image) self.log(f"Create new image; insert it before index {index}.") return new_image
def prepare_geometry(xyz_fn, keywords): #blocks = "%pal nprocs 3 end" blocks = "" atoms, coords = parse_xyz_file(THIS_DIR / xyz_fn) coords *= ANG2BOHR geometry = Geometry(atoms, coords.flatten()) geometry.set_calculator(ORCA(keywords, charge=0, mult=1, blocks=blocks)) hessian = geometry.hessian return geometry
def prepare_geometry(): keywords = "HF 4-22GSP TightSCF" xyz_fn = "01_irc_sn2_fluour_transfer_optts.xyz" #blocks = "%pal nprocs 3 end" blocks = "" atoms, coords = parse_xyz_file(THIS_DIR / xyz_fn) coords *= ANG2BOHR geometry = Geometry(atoms, coords.flatten()) geometry.set_calculator(ORCA(keywords, charge=-1, mult=1, blocks=blocks)) hessian = geometry.hessian return geometry, THIS_DIR
def interpolate(self, initial_geom, final_geom): print(f"No. of primitives at initial structure: {initial_geom.coords.size}") print(f"No. of primitives at final structure: {final_geom.coords.size}") typed_prims = form_coordinate_union(initial_geom, final_geom) print("Union of primitives: ", len(typed_prims)) geom1 = Geometry(initial_geom.atoms, initial_geom.cart_coords, coord_type="redund", coord_kwargs={"typed_prims": typed_prims,}, ) geom2 = Geometry(final_geom.atoms, final_geom.cart_coords, coord_type="redund", coord_kwargs={"typed_prims": typed_prims,}, ) dihed_start = geom1.internal.dihed_start initial_tangent = get_tangent(geom1.coords, geom2.coords, dihed_start) initial_diff = np.linalg.norm(initial_tangent) approx_stepsize = initial_diff / (self.between+1) final_prims = geom2.internal.prim_coords geoms = [geom1, ] for i in range(self.between): print(f"Interpolating {i+1:03d}/{self.between:03d}") new_geom = geoms[-1].copy() prim_tangent = get_tangent(new_geom.coords, final_prims, dihed_start) # Form active set B = new_geom.internal.B_prim G = B.dot(B.T) eigvals, eigvectors = np.linalg.eigh(G) U = eigvectors[:, np.abs(eigvals) > 1e-6] reduced_tangent = (np.einsum("i,ij->j", prim_tangent, U) * U).sum(axis=1) reduced_tangent /= np.linalg.norm(reduced_tangent) step = approx_stepsize * reduced_tangent try: new_coords = new_geom.coords + step except ValueError as err: fn = "redund_interpol_fail.trj" write_geoms_to_trj(geoms, fn) print(f"Chosen set of primitives is not valid for step {i} " f"of {self.between}. Wrote interpolation progress to " "'{fn}'." ) raise err new_geom.coords = new_coords geoms.append(new_geom) return geoms[1:]
def test_sqnm_bio_mode(): atoms = "h h".split() coords = ((0, 0, 0), (0, 0, 1)) geom = Geometry(atoms, coords) xtb = XTB() geom.set_calculator(xtb) opt = StabilizedQNMethod(geom) cur_grad = geom.gradient stretch_grad, rem_grad = opt.bio_mode(cur_grad) # There is only one bond in H2, so stretch_gradient == cur_grad and the # remainder should be the zero vector. np.testing.assert_allclose(stretch_grad, cur_grad) np.testing.assert_allclose(np.linalg.norm(rem_grad), 0.) return
def test_lennard_jones(): atoms = Icosahedron("Ar", noshells=2, latticeconstant=3) atoms.set_calculator(ase_LJ()) ase_forces = atoms.get_forces() ase_energy = atoms.get_potential_energy() coords = atoms.positions.flatten() geom = Geometry(atoms.get_chemical_symbols(), coords / BOHR2ANG) geom.set_calculator(LennardJones()) pysis_energy = geom.energy assert pysis_energy == pytest.approx(ase_energy) pysis_forces = geom.forces / BOHR2ANG np.testing.assert_allclose(pysis_forces, ase_forces.flatten(), atol=1e-15)
def get_geoms(coords=None): if coords is None: # left = np.array((0.188646, 1.45698, 0)) # right = np.array((0.950829, 1.54153, 0)) left = np.array((0.354902, 1.34229, 0)) right = np.array((0.881002, 1.71074, 0)) right = np.array((0.77, 1.97, 0)) # Very close # left = np.array((0.531642, 1.41899, 0)) # right = np.array((0.702108, 1.57077, 0)) coords = (right, left) # near_ts = np.array((0.553726, 1.45458, 0)) # coords = (near_ts, ) # left_far = np.array((-0.455116, 0.926978, 0)) # right_far = np.array((-0.185653, 1.02486, 0)) # coords = (left_far, right_far) atoms = ("H") geoms = [Geometry(atoms, c) for c in coords] for geom in geoms: geom.set_calculator(AnaPot()) return geoms
def get_geoms(): initial = np.array((-0.5, 0.5, 0)) final = np.array((0.5, 0.5, 0)) coords = (initial, final) atoms = ("H") geoms = [Geometry(atoms, c) for c in coords] return geoms
def print_internals(geoms, filter_atoms=None, add_prims=""): if filter_atoms is None: filter_atoms = set() filter_set = set(filter_atoms) pi_types = {2: "B", 3: "A", 4: "D"} add_prims = yaml.safe_load(add_prims) for i, geom in enumerate(geoms): print(geom) atom_num = len(geom.atoms) atom_inds = set(range(atom_num)) # Atom indices must superset of filter_atoms invalid = filter_set - atom_inds assert not invalid, \ f"Filter indices {invalid} are outside of the " \ f"valid range for the {i}-th geometry '{geom}' with {atom_num} " \ f"atoms (valid indices: range(0,{atom_num}))." int_geom = Geometry( geom.atoms, geom.coords, coord_type="redund", coord_kwargs={ "define_prims": add_prims, }, ) prim_counter = 0 prev_len = 2 for j, pi in enumerate(int_geom.internal._prim_internals): pi_type = pi_types[len(pi.inds)] val = pi.val len_ = len(pi.inds) if len_ > 2: unit = "°" val = np.rad2deg(val) else: val *= BOHR2ANG unit = " Å" if len_ > prev_len: prim_counter = 0 print() # Continue if we want to filter and there is no intersection # between the atoms of the current primitive and the atoms we # want to filter for. if filter_set and not (set(pi.inds) & filter_set): continue print( f"{j:04d}: {pi_type}{prim_counter:03d}{str(pi.inds): >20} {val: >10.4f}" f"{unit}") prim_counter += 1 prev_len = len_ print(f"Printed {j+1} primitive internals.") print()
def test_lj_external_potential(): atoms = ("X", ) coords = (0., 0., 0.) geom = Geometry(atoms, coords) calc = LennardJones() geom.set_calculator(calc) ref_energy = geom.energy potentials = [ { "type": "logfermi", "beta": 6, "T": 300, "radius": 8, }, ] ext_calc = ExternalPotential(calc, potentials=potentials) geom.set_calculator(ext_calc) ext_energy = geom.energy assert ext_energy == pytest.approx(ref_energy) displ_coords = (9., 0., 0) geom.coords = displ_coords ext_energy = geom.energy assert ext_energy == pytest.approx(0.00570261) forces = geom.forces ref_forces = np.array((-0.0056861, 0., 0.)) np.testing.assert_allclose(forces, ref_forces, atol=1e-6)
def prepare_geometry(keywords=None, xyz_fn=None): this_dir = pathlib.Path(os.path.dirname(os.path.realpath(__file__))) if not keywords: keywords = "HF STO-3G TightSCF" if not xyz_fn: xyz_fn = "hfabstraction_sto3g_ts.xyz" #blocks = "%pal nprocs 3 end" blocks = "" atoms, coords = parse_xyz_file(this_dir / xyz_fn) coords *= ANG2BOHR geometry = Geometry(atoms, coords.flatten()) geometry.set_calculator(ORCA(keywords, charge=0, mult=1, blocks=blocks)) hessian = geometry.hessian return geometry, this_dir
def interpolate_between(self, initial_ind, final_ind, image_num): initial_coords = self.images[initial_ind].coords final_coords = self.images[final_ind].coords step = (final_coords - initial_coords) / (image_num + 1) # initial + i*step i_array = np.arange(1, image_num + 1) atoms = self.images[0].atoms new_coords = initial_coords + i_array[:, None] * step return [Geometry(atoms, nc) for nc in new_coords]
def set_new_frontier_nodes(self): tangent = self.get_tangent() new_left_coords = self.left_frontier.coords + tangent*self.step_length new_left_frontier = Geometry(self.atoms, new_left_coords) new_left_frontier.set_calculator(self.calc_getter()) self.left_string.append(new_left_frontier) new_right_coords = self.right_frontier.coords - tangent*self.step_length new_right_frontier = Geometry(self.atoms, new_right_coords) new_right_frontier.set_calculator(self.calc_getter()) self.right_string.insert(0, new_right_frontier)
def interpolate(self, initial_geom, final_geom): initial_coords = initial_geom.coords final_coords = final_geom.coords # Linear interpolation step = (final_coords - initial_coords) / (self.between + 1) # initial + i*step i_array = np.arange(1, self.between + 1) new_coords = initial_coords + i_array[:, None] * step return [Geometry(self.atoms, nc) for nc in new_coords]
def test_rfoptimizer(): kwargs = { #"max_cycles": 10, "trust_radius": 0.5, "max_step": 0.5, } atoms = ("X", ) # http://www.applied-mathematics.net/optimization/optimizationIntro.html coords = (0.7, -3.3, 0) geom = Geometry(atoms, coords) ap4 = AnaPot4() geom.set_calculator(ap4) opt = RFOptimizer(geom, **kwargs) #opt = SteepestDescent(geom, **kwargs) #opt = BFGS(geom, max_step=1.0) opt.run() rfop = RFOPlotter(ap4, opt, save=True, title=False) rfop.plot() plt.show()
def run_distributed(scheduler=None): init_logging(THIS_DIR, scheduler) atoms = ("H", "H") geoms = list() for i in range(7): bond_length = 0.8 + i * 0.2 print(f"{i}: {bond_length:.02f}") coords = np.array((0., 0., 0., 0., 0., bond_length)) geom = Geometry(atoms, coords) # def2-TZVP / TDDFT td_kwargs = { "keywords": "BP86 def2-TZVP", "charge": 0, "mult": 1, "calc_number": i, "blocks": "%tddft nroots 2 iroot 1 end", #"track": True, "out_dir": THIS_DIR, } # def2-SV(P) / Ground state kwargs = { "keywords": "BP86 def2-SV(P)", "charge": 0, "mult": 1, "calc_number": i, "out_dir": THIS_DIR, } orca = ORCA(**td_kwargs) geom.set_calculator(orca) geoms.append(geom) neb_kwargs = { "dask_cluster": scheduler, } neb = NEB(geoms, **neb_kwargs) forces = neb.forces for f in forces.reshape(-1, 6): print(f, f"{np.linalg.norm(f):.2f}") for geom in neb.images: print(geom.calculator.wfow)
def get_hexagonal_geom(r=2, distort=False): phi = np.array((30, 90, 150, 210, 270, 330)) x, y = pol2cart(2, phi) z = np.zeros_like(x) if distort: y[1] = 3 atoms = "C" * x.size coords3d = np.stack((x, y, z), axis=1) geom = Geometry(atoms, coords3d.flatten()) return geom
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 get_geoms(images=KWARGS["images"]): initial = "xyz_files/hcn.xyz" ts_guess = "xyz_files/hcn_iso_ts.xyz" final = "xyz_files/nhc.xyz" xyz_fns = (initial, ts_guess, final) atoms_coords = [parse_xyz_file(fn) for fn in xyz_fns] geoms = [ Geometry(atoms, coords.flatten()) for atoms, coords in atoms_coords ] geoms = idpp_interpolate(geoms, images_between=images) return geoms, copy.copy(KWARGS)
def test_lj_external_potential_opt(): np.random.seed(20182503) radius = 9 atom_num = 50 coords3d = (np.random.rand(atom_num, 3) - 0.5) * 2 * radius atoms = ("Ar", ) * atom_num geom = Geometry(atoms, coords3d.flatten()) lj_calc = LennardJones() geom.set_calculator(lj_calc) opt_kwargs = { "max_cycles": 250, "precon_update": 50, "c_stab": 0.5, } # opt = QuickMin(geom, **opt_kwargs) opt = PreconLBFGS(geom, **opt_kwargs) opt.run()
def frag_sort(geoms): sorted_geoms = list() for i, geom in enumerate(geoms): print(f"{i:02d}: {geom}") frags = get_fragments(geom.atoms, geom.coords) print(f"\tFound {len(frags)} fragments.\n" "\tResorting atoms and coordinates.") new_indices = list(it.chain(*frags)) new_atoms = [geom.atoms[i] for i in new_indices] new_coords = geom.coords3d[new_indices] sorted_geoms.append(Geometry(new_atoms, new_coords)) return sorted_geoms
def get_geoms(keys=("B", "C", "TSA", "A")): coords_dict = { "A": (-0.558, 1.442, 0), # Minimum A "B": (0.6215, 0.02838, 0), # Minimum B "C": (-0.05, 0.467, 0), # Minimum C "AC": (-0.57, 0.8, 0), # Between A and C "TSA": (-0.822, 0.624, 0) # Saddle point A } coords = [np.array(coords_dict[k]) for k in keys] atoms = ("H") geoms = [Geometry(atoms, c) for c in coords] return geoms
def augment_bonds(geom, root=0, proj=False): assert geom.coord_type != "cart" log(logger, "Trying to augment bonds.") hessian = geom.cart_hessian try: energy = geom.energy except AttributeError: energy = None func = find_missing_bonds_by_projection if proj else find_missing_strong_bonds missing_bonds = func(geom, hessian, root=root) if missing_bonds: aux_bond_pt = PrimTypes.AUX_BOND missing_aux_bonds = [(aux_bond_pt, *mbond) for mbond in missing_bonds] print("\t@Missing bonds:", missing_bonds) new_geom = Geometry( geom.atoms, geom.cart_coords, coord_type=geom.coord_type, coord_kwargs={ "define_prims": missing_aux_bonds, }, ) new_geom.set_calculator(geom.calculator) new_geom.energy = energy new_geom.cart_hessian = hessian return new_geom else: return geom
def get_geom(cls, coords, atoms=("X", ), V_str=None): geom = Geometry(atoms, coords) if V_str: geom.set_calculator(cls(V_str=V_str)) else: geom.set_calculator(cls()) return geom
def cap(geom, high_frag): high_set = set(high_frag) ind_set = set(range(len(geom.atoms))) rest = ind_set - high_set # Determine bond(s) that connect high_frag with the rest # bonds, _, _ = geom.internal.prim_indices bonds = get_bond_sets(geom.atoms, geom.coords3d) bond_sets = [set(b) for b in bonds] # Find all bonds that involve one atom of model. These bonds # connect the model to the real geometry. We want to cap these # bonds. break_bonds = [b for b in bond_sets if len(b & high_set) == 1] # Put capping atoms at every bond to break. # The model fragment size corresponds to the length of the union of # the model set and the atoms in break_bonds. capped_frag = high_set.union(*break_bonds) capped_inds = list(sorted(capped_frag)) # Index map between the new model geometry and the original indices # in the real geometry. atom_map = { model_ind: real_ind for real_ind, model_ind in zip(capped_inds, range(len(capped_inds))) } # g = 0.723886 # Gaussian16 g = 0.709 # Paper g98-ONIOM-implementation c3d = geom.coords3d.copy() new_atoms = list(geom.atoms) link_maps = dict() for bb in break_bonds: to_cap = bb - high_set assert len(to_cap) == 1 r1_ind = list(bb - to_cap)[0] r3_ind = tuple(to_cap)[0] r1 = c3d[r1_ind] r3 = c3d[r3_ind] r2 = r1 + g * (r3 - r1) c3d[r3_ind] = r2 new_atoms[r3_ind] = "H" new_ind = np.sum(np.array(high_frag) < r3_ind) link_map = LinkMap(r1_ind=r1_ind, r3_ind=r3_ind, g=g) link_maps[new_ind] = link_map capped_atoms = [new_atoms[i] for i in capped_inds] capped_coords = c3d[capped_inds].flatten() capped_geom = Geometry(capped_atoms, capped_coords) return capped_geom, atom_map, link_maps