def _get_valence_difference(self, atom: Chem.Atom) -> int: pt = Chem.GetPeriodicTable() valence = self._get_atom_valence(atom) if self._valence_mode == 'max': maxv = max(pt.GetValenceList(atom.GetAtomicNum())) return valence - maxv else: d = pt.GetDefaultValence(atom.GetAtomicNum()) return valence - d
def from_rdkit(cls, rd_atom: Chem.Atom) -> "Atom": """ Build a QUBEKit atom from an rdkit atom instance. """ atomic_number = rd_atom.GetAtomicNum() index = rd_atom.GetIdx() formal_charge = rd_atom.GetFormalCharge() aromatic = rd_atom.GetIsAromatic() bonds = [a.GetIdx() for a in rd_atom.GetNeighbors()] # check for names in the normal places pdb, mol2 and mol if rd_atom.HasProp("_Name"): name = rd_atom.GetProp("_Name") elif rd_atom.HasProp("_TriposAtomName"): name = rd_atom.GetProp("_TriposAtomName") else: try: name = rd_atom.GetMonomerInfo().GetName().strip() except AttributeError: name = None # stereochem if rd_atom.HasProp("_CIPCode"): stereo_code = rd_atom.GetProp("_CIPCode") else: stereo_code = None return cls( atomic_number=atomic_number, atom_index=index, atom_name=name, formal_charge=formal_charge, aromatic=aromatic, stereochemistry=stereo_code, bonds=bonds, )
def assess_atom(atom: Chem.Atom, bt: Chem.BondType) -> Tuple[bool, Chem.BondType]: if atom.GetAtomicNum() > 8: return True, bt elif len(atom.GetNeighbors()) <= 2 and atom.GetIsAromatic(): return True, Chem.BondType.SINGLE elif len(atom_i.GetNeighbors()) <= 3 and not atom.GetIsAromatic(): return True, bt else: return False, bt # too bonded already!
def atom_to_feat(self, atm: Chem.Atom, owning_mol: Chem.Mol, idx): # nb the func GetOwningMol could not be used for mol as would return different object each time this_atms_idx = atm.GetIdx() assert idx == this_atms_idx feat = torch.zeros(len(self), dtype=torch.float32) # One hot encoding of element try: feat[self.atms_to_idx[atm.GetSymbol()]] = 1. except KeyError as ex: warnings.warn(f"Ignoring the symbol {atm.GetSymbol()}") idx_up_to = self.number_atom_options # Atomic Number feat[idx_up_to] = float(atm.GetAtomicNum()) idx_up_to += 1 # Acceptor/donor acceptor_ids, donor_ids = self.get_acceptor_and_donor_ids(owning_mol) # Acceptor feat[idx_up_to] = float(this_atms_idx in acceptor_ids) idx_up_to += 1 # Donor feat[idx_up_to] = float(this_atms_idx in donor_ids) idx_up_to += 1 # Hybridization hyb_idx = self.hybridization(atm.GetHybridization()) if hyb_idx is not None: feat[idx_up_to + hyb_idx] = 1. idx_up_to += self.number_hyb_options # Aromatic feat[idx_up_to] = float(atm.GetIsAromatic()) idx_up_to += 1 # Number of Hydrogens feat[idx_up_to] = float(atm.GetNumImplicitHs()) idx_up_to += 1 return feat
def _AtomHallKierDeltas(atom: Chem.Atom, skipHs: bool = False) -> List[float]: """Calculate Kier & Hall atomic valence delta-values for molecular connectivity. From Kier L. and Hall L., J. Pharm. Sci. (1983), 72(10),1170-1173. """ global periodicTable res = [] n = atom.GetAtomicNum() if n > 1: nV = periodicTable.GetNOuterElecs(n) nHs = atom.GetTotalNumHs() if n < 10: res.append(float(nV - nHs)) else: res.append(float(nV - nHs) / float(n - nV - 1)) elif not skipHs: res.append(0.0) return res
def assess_atom(atom: Chem.Atom, bt: Chem.BondType) -> Tuple[bool, Chem.BondType]: """ True means add, False means delete :param atom: :param bt: :return: """ n_neigh = sum([self._is_count_valid(neigh) for neigh in atom.GetNeighbors()]) if atom.GetAtomicNum() > 8: return True, bt elif atom.HasProp('DELETE'): # if it is to be deleted it should be fine. return True, bt elif n_neigh <= 2 and atom.GetIsAromatic(): return True, Chem.BondType.SINGLE elif n_neigh <= 3 and not atom.GetIsAromatic(): return True, bt else: return False, bt # too bonded already!
def atom_feature(atom: Atom) -> Tuple[torch.Tensor, int]: ''' Extract atom feature vector. Returns: (feature_vec, feature_dim) Features: # item # dim atomic number 25 exp-valence 7 imp-valence 4 hybridization 7 Hs 5 degree 6 formal charge 6 in ring 1 aromatic 1 mass / 100 1 (sum) 63 ''' index = torch.tensor([ ATOM_MAP[atom.GetAtomicNum()], atom.GetExplicitValence(), atom.GetImplicitValence(), HYBRID_MAP[atom.GetHybridization()], atom.GetTotalNumHs(), atom.GetDegree(), atom.GetFormalCharge() + 2, # -2 ~ 3 int(atom.IsInRing()), int(atom.GetIsAromatic()) ]) + OFFSET vec = torch.zeros(ATOM_FDIM) vec[index] = 1.0 vec[-1] = atom.GetMass() / 100 return vec, ATOM_FDIM
def _assess_atom_for_possible_bonding(self, atom: Chem.Atom, bt: Chem.BondType) -> bool: """ Method for add_bond_if_possible True means add, False means delete :param atom: :param bt: :return: """ n_neigh = sum( [self._is_count_valid(neigh) for neigh in atom.GetNeighbors()]) if atom.GetAtomicNum() > 8: return True elif atom.HasProp( 'DELETE'): # if it is to be deleted it should be fine. return True elif n_neigh <= 2 and atom.GetIsAromatic(): return True, Chem.BondType.SINGLE elif n_neigh <= 3 and not atom.GetIsAromatic(): return True else: return False # too bonded already!
def atomic_number(atom: Atom) -> int: """Atomic number (int). """ return atom.GetAtomicNum()