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 _get_atom_valence(self, atom: Chem.Atom): """ Cannot get the normal way as it cannot be sanitised. :param atom: :return: """ valence = 0 for bond in atom.GetBonds(): valence += bond.GetBondTypeAsDouble() return valence - atom.GetFormalCharge()
def get_atom_type(self, atom: Chem.Atom) -> int: """ Get the atom type (represented as the index in self.atom_types) of the given atom `atom` Args: atom (Chem.Atom): The input atom Returns: int: The atom type as int """ atom_symbol = atom.GetSymbol() atom_charge = atom.GetFormalCharge() atom_hs = atom.GetNumExplicitHs() return self.atom_types.index((atom_symbol, atom_charge, atom_hs))
def atom_to_string(atom: Chem.Atom) -> str: return '{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}'.format( atom.GetChiralTag(), atom.GetDegree(), atom.GetExplicitValence(), atom.GetFormalCharge(), atom.GetHybridization(), atom.GetIsAromatic(), atom.GetMass(), atom.GetNumExplicitHs(), atom.GetNumImplicitHs(), atom.GetNumRadicalElectrons(), atom.GetTotalDegree(), atom.GetTotalNumHs(), atom.GetTotalValence(), atom.IsInRing() )
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 _parse_atom(self, atom: Chem.Atom) -> None: self.log.debug( f'Parsing {atom.GetSymbol()} at position {atom.GetIdx()}') if atom.GetSymbol() == '*': neighbor = atom.GetNeighbors()[0] n_name = self._get_PDBInfo_atomname(neighbor) if self.is_aminoacid() and neighbor.GetSymbol() == 'N': # atom_name, index, connect_type, connect_name self.CONNECT.append([n_name, 1, 'LOWER_CONNECT', 'LOWER']) elif self.is_aminoacid() and neighbor.GetSymbol() == 'C': # atom_name, index, connect_type, connect_name self.CONNECT.append([n_name, 2, 'UPPER_CONNECT', 'UPPER']) elif self.is_aminoacid(): i = max(3, len(self.CONNECT) + 1) self.CONNECT.append([n_name, i, 'CONNECT']) else: self.CONNECT.append([n_name, len(self.CONNECT) + 1, 'CONNECT']) else: d = self._get_atom_descriptors( atom) # dict of 'name', 'rtype': 'mtype', 'partial' self.ATOM.append(d) formal = atom.GetFormalCharge() if formal != 0: self.CHARGE.append([d['name'], formal])
def _copy_atom(atom: Chem.Atom) -> Chem.Atom: new_atom = Chem.Atom(atom.GetSymbol()) new_atom.SetFormalCharge(atom.GetFormalCharge()) new_atom.SetNumRadicalElectrons(atom.GetNumRadicalElectrons()) return new_atom
def charge(atom: Atom) -> int: """Formal charge (int). """ return atom.GetFormalCharge()