def get_lindh_k(atoms, coords3d, bonds=None, angles=None, torsions=None): if bonds is None: bonds = list() if angles is None: angles = list() if torsions is None: torsions = list() atoms = [a.lower() for a in atoms] alphas = [get_lindh_alpha(a1, a2) for a1, a2 in it.combinations(atoms, 2)] pair_cov_radii = get_pair_covalent_radii(atoms) cdm = pdist(coords3d) rhos = squareform(np.exp(alphas * (pair_cov_radii**2 - cdm**2))) k_dict = { 2: 0.45, # Stretches/bonds 3: 0.15, # Bends/angles 4: 0.005, # Torsions/dihedrals } ks = list() for inds in it.chain(bonds, angles, torsions): rho_product = 1 for i in range(len(inds) - 1): i1, i2 = inds[i:i + 2] rho_product *= rhos[i1, i2] ks.append(k_dict[len(inds)] * rho_product) return ks
def fischer_guess(geom): cdm = pdist(geom.coords3d) pair_cov_radii = get_pair_covalent_radii(geom.atoms) dihedrals = geom.internal.dihedrals # For the dihedral force constants we also have to count the number # of bonds formed with the centrals atoms of the dihedral. central_atoms = [dh.inds[1:3] for dh in dihedrals] bond_factor = geom.internal.bond_factor bond_mat = squareform(cdm <= (pair_cov_radii * bond_factor)) tors_atom_bonds = dict() for a, b in central_atoms: # Substract 2, as we don't want the bond between a and b, # but this bond will be in both rows of the bond_mat. bond_sum = bond_mat[a].sum() + bond_mat[b].sum() - 2 tors_atom_bonds[(a, b)] = bond_sum dist_mat = squareform(cdm) pair_cov_radii_mat = squareform(pair_cov_radii) def h_bond(bond): a, b = bond.indices r_ab = dist_mat[a, b] r_ab_cov = pair_cov_radii_mat[a, b] return 0.3601 * exp(-1.944 * (r_ab - r_ab_cov)) def h_bend(bend): b, a, c = bend.indices r_ab = dist_mat[a, b] r_ac = dist_mat[a, c] r_ab_cov = pair_cov_radii_mat[a, b] r_ac_cov = pair_cov_radii_mat[a, c] return (0.089 + 0.11 / (r_ab_cov * r_ac_cov)**(-0.42) * exp(-0.44 * (r_ab + r_ac - r_ab_cov - r_ac_cov))) def h_dihedral(dihedral): # import pdb; pdb.set_trace() c, a, b, d = dihedral.indices r_ab = dist_mat[a, b] r_ab_cov = pair_cov_radii_mat[a, b] bond_sum = max(tors_atom_bonds[(a, b)], 0) return (0.0015 + 14.0 * bond_sum**0.57 / (r_ab * r_ab_cov)**4.0 * exp(-2.85 * (r_ab - r_ab_cov))) h_funcs = { 2: h_bond, 3: h_bend, 4: h_dihedral, } h_diag = list() for primitive in geom.internal.primitives: f = h_funcs[len(primitive.indices)] h_diag.append(f(primitive)) H = np.array(np.diagflat(h_diag)) return H
def swart_guess(geom): pair_cov_radii = get_pair_covalent_radii(geom.atoms) cdm = pdist(geom.coords3d) rhos = squareform(np.exp(-cdm / pair_cov_radii + 1)) k_dict = { 2: 0.35, 3: 0.15, 4: 0.005, } k_diag = list() for primitive in geom.internal.primitives: rho_product = 1 for i in range(len(primitive.indices) - 1): i1, i2 = primitive.indices[i:i + 2] rho_product *= rhos[i1, i2] k_diag.append(k_dict[len(primitive.indices)] * rho_product) return np.diagflat(k_diag)
def lindh_guess(geom): """Slightly modified Lindh model hessian as described in [1]. Instead of using the tabulated r_ref,ij values from [1] we will use the 'true' covalent radii as pyberny. The tabulated r_ref,ij value for two carbons (2nd period) is 2.87 Bohr. Carbons covalent radius is ~ 1.44 Bohr, so 2*1.44 Bohr = 2.88 Bohr which fits nicely with the tabulate value. If values for elements > 3rd are requested the alpha values for the 3rd period will be (re)used. """ first_period = "h he".split() def get_alpha(atom1, atom2): if (atom1 in first_period) and (atom2 in first_period): return 1. elif (atom1 in first_period) or (atom2 in first_period): return 0.3949 else: return 0.28 atoms = [a.lower() for a in geom.atoms] alphas = [get_alpha(a1, a2) for a1, a2 in it.combinations(atoms, 2)] pair_cov_radii = get_pair_covalent_radii(geom.atoms) cdm = pdist(geom.coords3d) rhos = squareform(np.exp(alphas * (pair_cov_radii**2 - cdm**2))) k_dict = { 2: 0.45, # Stretches/bonds 3: 0.15, # Bends/angles 4: 0.005, # Torsions/dihedrals } k_diag = list() for prim_int in geom.internal.prim_internals: rho_product = 1 for i in range(len(prim_int.inds) - 1): i1, i2 = prim_int.inds[i:i + 2] rho_product *= rhos[i1, i2] k_diag.append(k_dict[len(prim_int.inds)] * rho_product) H = np.diagflat(k_diag) return H
def atoms_are_too_close(self, geom, factor=.7): """Determine if atoms are too close.""" dist_mat = pdist(geom.coords3d) cov_rad_mat = get_pair_covalent_radii(geom.atoms) too_close = dist_mat < factor*cov_rad_mat return any(too_close)