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_descriptors(self, atom: Chem.Atom) -> dict: return { 'name': self._get_pdb_atomname(atom), 'rtype': atom.GetProp('_rType'), 'mtype': ' X ', 'partial': atom.GetDoubleProp('_GasteigerCharge') }
def _get_origin(cls, atom: Chem.Atom) -> List[str]: if atom.HasProp('_Origin'): o = atom.GetProp('_Origin') if o != 'none': return json.loads(o) else: return [] else: return []
def stereochemistry(atom: Atom) -> str: """CIP sterochemistry label (string). """ mol = atom.GetOwningMol() if not mol.HasProp('_CIPLabelsAssigned'): rdCIPLabeler.AssignCIPLabels(mol) mol.SetProp('_CIPLabelsAssigned', '1') return atom.GetProp('_CIPCode') if atom.HasProp('_CIPCode') else ''
def _add_bond_if_possible(self, mol, first: Chem.Atom, second: Chem.Atom, provenance='other_novel'): """ This method is used by _copy_bonding, but triggered when force=False :param mol: :param first: :param second: :param provenance: :return: """ # --- Prep first_idx = first.GetIdx() second_idx = second.GetIdx() present_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) if second.HasProp('_ring_bond'): bt = getattr(Chem.BondType, second.GetProp('_ring_bond')) else: bt = None # === Bond already exists series ============================================ # --- Bond already exists and not bond type is specified if present_bond is not None and bt is None: self.journal.debug( f'Bond between {first_idx} and {second_idx} already exists') return True # exists # --- Bond already exists but has an error elif present_bond is not None and present_bond.GetBondType() is None: present_bond.SetBondType(Chem.BondType.SINGLE) return True # --- Bond already exists and matches the expected bond type elif present_bond is not None and bt.name == present_bond.GetBondType( ).name: return True # --- Bond already exists but does not match the expected bond type elif present_bond is not None: present_bond.SetBondType(bt) return True # === Assess if new bond should be added ============================================ # --- Don't add if it would make a triangle elif self._is_would_be_triangle(first, second): self.journal.debug( f'Bond between {first_idx} and {second_idx} would make a triangle, skipping' ) return False # --- Don't add if it would make a square elif self._is_would_be_square(first, second): self.journal.debug( f'Bond between {first_idx} and {second_idx} would make a square, skipping' ) return False # --- Don't add if it would ruin the warhead elif self._is_connected_warhead(second, first): self.journal.debug( f'Bond between {first_idx} and {second_idx} would break a warhead, skipping' ) return False # --- New bond is green lit elif self._assess_atom_for_possible_bonding( first, bt) and self._assess_atom_for_possible_bonding( second, bt): mol.AddBond(first_idx, second_idx, bt if bt is not None else Chem.BondType.SINGLE) new_bond = mol.GetBondBetweenAtoms(first_idx, second_idx) BondProvenance.set_bond(new_bond, provenance) return True # --- New bond is no go else: # len(Chem.GetMolFrags(mol, sanitizeFrags=False)) ought to be checked. # however, join_neighboring gets called by emergency bonding so should be fine. return False # too bonded etc.