def bond_with_H_length(heavy, geom): element = heavy.element.name if element == "C": if geom == 4: return 1.09 if geom == 3: return 1.08 if geom == 2: return 1.056 elif element == "N": return N_H elif element == "O": # can't rely on water being in chain "water" anymore... if heavy.num_bonds == 0 or heavy.num_bonds == 2 \ and len([nb for nb in heavy.neighbors if nb.element.number > 1]) == 0: return 0.9572 return 0.96 elif element == "S": return 1.336 from chimerax.atomic import Element return Element.bond_length(heavy.element, Element.get_element(1))
def hyd_positions(heavy, include_lone_pairs=False): """Return list of positions for hydrogens attached to this atom. If a hydrogen could be in one of several positions, don't return any of those. """ # first, find known attached atoms bonded_heavys = [] hyds = [] for atom in heavy.neighbors: if atom.element.number > 1: bonded_heavys.append(atom) else: hyds.append(atom) # convert to Points hyd_locs = [] for hyd in hyds: hyd_locs.append(hyd._hb_coord) if hyd_locs and not include_lone_pairs: # explicit hydrogens "win" over atom types return hyd_locs if heavy.idatm_type in type_info: info = type_info[heavy.idatm_type] geom = info.geometry if include_lone_pairs: subs = geom else: subs = info.substituents bonded_locs = hyd_locs[:] for b_heavy in bonded_heavys: bonded_locs.append(b_heavy._hb_coord) else: return hyd_locs known_subs = len(bonded_locs) if known_subs >= subs or known_subs == 0: return hyd_locs # above eliminates 'single' geometry if known_subs == 1 and geom == tetrahedral: # rotamer return hyd_locs max_subs = geom if max_subs - subs > 0: # the "empty" bond could be anywhere return hyd_locs heavy_loc = heavy._hb_coord bond_len = Element.bond_length(heavy.element, "H") if geom == planar: coplanar = [] for b_heavy in bonded_heavys: try: bh_geom = type_info[b_heavy.idatm_type].geometry except KeyError: bh_geom = None if bh_geom != planar: continue for atom in b_heavy.neighbors: if atom != heavy: coplanar.append(atom._hb_coord) else: coplanar = None hyd_locs = hyd_locs + list( bond_positions(heavy_loc, geom, bond_len, bonded_locs, coplanar=coplanar)) return hyd_locs
def _find_donors(structure, d_params, limited_donors, generic_don_info): don_atoms = [] don_data = [] std_donors = {} for dp in d_params: group_key, donorIndex, geom_type, tau_sym, arg_list, test_dist = dp if group_key: groups = find_group(group_key, [structure]) else: # generic donors groups = [] for atom in structure.atoms: if atom in std_donors: continue if atom.element.number not in [7, 8, 16]: continue if limited_donors and atom not in limited_donors: continue # oxygen, nitrogen, or sulfur try: expect_bonds = type_info[atom.idatm_type].substituents except KeyError: expect_bonds = 0 num_bonds = atom.num_bonds # screen out the partial terminal N that AddH can leave, since the geometry is # problematic and the H direction isn't really determined if atom.idatm_type == "Npl" and num_bonds == 2 \ and 1 in [n.element.number for n in atom.neighbors]: continue if num_bonds < expect_bonds: groups.append([atom]) continue for bonded in atom.neighbors: if bonded.element.number == 1: groups.append([atom]) break if verbose: for g in groups: print("generic donor:", g[0]) if groups and geom_type == theta_tau: # extend probe distance by H-bond length so that all relevant acceptors will be found test_dist = test_dist + Element.bond_length( groups[0][donorIndex].element, 'H') for group in groups: donor_atom = group[donorIndex] if limited_donors and donor_atom not in limited_donors: continue if donor_atom in std_donors: if group_key != std_donors[donor_atom] and not ( # conflicts of non-ring groups with ring # groups not considered a problem (non-ring # groups "win") group_key[0] in _ring_funcs and std_donors[donor_atom][0] not in _ring_funcs): global _problem _problem = ("donor", donor_atom, std_donors[donor_atom], group_key) continue if donor_atom.is_missing_heavy_template_neighbors( no_template_okay=True): global _truncated _truncated.add(donor_atom) continue std_donors[donor_atom] = group_key don_atoms.append(donor_atom) don_data.append((geom_type, tau_sym, arg_list, test_dist)) return don_atoms, don_data
# index of donor in group, # type of donor geometry # degree of tau symmetry # argument tuple used when geometry-check function is called # # in argument tuple, conversions will occur before function gets called. # namely: # positive floats are assumed to be distances, and will be squared # integers are assumed to be angles in degrees, and will be # converted to radians import sys water = sys.intern("water") theta_tau = sys.intern('theta_tau') upsilon_tau = sys.intern('upsilon_tau') OH_bond_dist = Element.bond_length("O", "H") donor_params = [ # neutral carboxylic acid [[['O3', ['Cac', H]], [1, 1, 0]], 0, upsilon_tau, 2, (2.87, 103, -128, 140, -30, 2.87, 103, -128, 155, -30, 150, 2.87, 103, -128, 140, -30, 150)], # protonated nitrogen double-bonded to carbon [ [['Npl', [['C2', [explicit_single_bond, explicit_single_bond]], H, H]], [1, 1, 0, 0, 0, 0]], 0, upsilon_tau, 4, ( 3.17,