def fix_valence_charge(mol: Chem.rdchem.Mol, inplace: bool = False) -> Optional[Chem.rdchem.Mol]: """Fix valence issues that are due to incorrect charges. Args: mol: Input molecule with incorrect valence for some atoms inplace: Whether to modify in place or make a copy. Returns: Fixed molecule via charge correction or original molecule if failed. """ vm = rdMolStandardize.RDKitValidation() # Don't fix something that is not broken if len(vm.validate(mol)) > 0: if not inplace: mol = copy.copy(mol) mol.UpdatePropertyCache(False) for a in mol.GetAtoms(): n_electron = ( a.GetImplicitValence() + a.GetExplicitValence() - dm.PERIODIC_TABLE.GetDefaultValence(a.GetSymbol()) ) a.SetFormalCharge(n_electron) return mol
def check_mol_rdkit(self, clean=False): """ Checks validity of rdmol molecule against internal rules Valence electrons Bond order Charge Fragments Args: self: aemol object rdmol: rdkit molecule object Returns: if clean = True: returns cleaned molecule else: returns null """ if self.rdmol == None: self.to_rdkit() rdkit_vm = mol_std.RDKitValidation() molvs_vm = mol_std.MolVSValidation() rdkit_vm.validate(self.rdmol) molvs_vm.validate(self.rdmol) if clean: lfc = mol_stf.LargestFragmentChooser() idx = self.rdmol.GetProp('_Name') self.rdmol = lfc.choose(rself.rdmol) mol_std.Cleanup(self.rdmol) self.rdmol.SetProp('_Name', idx)
def test9Validate(self): vm = rdMolStandardize.RDKitValidation() mol = Chem.MolFromSmiles("CO(C)C", sanitize=False) msg = vm.validate(mol) self.assertEqual(len(msg), 1) self.assertEqual ("""INFO: [ValenceValidation] Explicit valence for atom # 1 O, 3, is greater than permitted""", msg[0]) vm2 = rdMolStandardize.MolVSValidation( [rdMolStandardize.FragmentValidation()]) # with no argument it also works # vm2 = rdMolStandardize.MolVSValidation() mol2 = Chem.MolFromSmiles( "COc1cccc(C=N[N-]C(N)=O)c1[O-].O.O.O.O=[U+2]=O") msg2 = vm2.validate(mol2) self.assertEqual(len(msg2), 1) self.assertEqual ("""INFO: [FragmentValidation] water/hydroxide is present""", msg2[0]) vm3 = rdMolStandardize.MolVSValidation() mol3 = Chem.MolFromSmiles("C1COCCO1.O=C(NO)NO") msg3 = vm3.validate(mol3) self.assertEqual(len(msg3), 2) self.assertEqual ("""INFO: [FragmentValidation] 1,2-dimethoxyethane is present""", msg3[0]) self.assertEqual ("""INFO: [FragmentValidation] 1,4-dioxane is present""", msg3[1]) atomic_no = [6, 7, 8] allowed_atoms = [Atom(i) for i in atomic_no] vm4 = rdMolStandardize.AllowedAtomsValidation(allowed_atoms) mol4 = Chem.MolFromSmiles("CC(=O)CF") msg4 = vm4.validate(mol4) self.assertEqual(len(msg4), 1) self.assertEqual ("""INFO: [AllowedAtomsValidation] Atom F is not in allowedAtoms list""", msg4[0]) atomic_no = [9, 17, 35] disallowed_atoms = [Atom(i) for i in atomic_no] vm5 = rdMolStandardize.DisallowedAtomsValidation(disallowed_atoms) mol5 = Chem.MolFromSmiles("CC(=O)CF") msg5 = vm4.validate(mol5) self.assertEqual(len(msg5), 1) self.assertEqual ("""INFO: [DisallowedAtomsValidation] Atom F is in disallowedAtoms list""", msg5[0]) msg6 = rdMolStandardize.ValidateSmiles("ClCCCl.c1ccccc1O") self.assertEqual(len(msg6), 1) self.assertEqual ("""INFO: [FragmentValidation] 1,2-dichloroethane is present""", msg6[0])
def check_valency(mol): """Validates the valency of every atom in the molecule. Parameters ---------- mol: rdkit.Chem.Mol A molecule. Returns ------- message: str """ message = rdMolStandardize.RDKitValidation().validate(mol) return message or None
def incorrect_valence(a: Union[Chem.rdchem.Mol, Chem.rdchem.Atom], update: bool = False) -> bool: """Check if an atom connection is not valid or all the atom of a molecule. Args: a: atom or molecule to check for valence issue. update: Update owning molecule property cache first. Returns: Whether the input atom valence is correct. """ if isinstance(a, Chem.rdchem.Mol): a.UpdatePropertyCache(False) vm = rdMolStandardize.RDKitValidation() return len(vm.validate(a)) > 0 if update: m = a.GetOwningMol() m.UpdatePropertyCache(False) return (a.GetImplicitValence() == 0) and ( a.GetExplicitValence() > max(PERIODIC_TABLE.GetValenceList(a.GetSymbol())) )
def fix_valence( mol, inplace: bool = False, allow_ring_break: bool = False ) -> Optional[Chem.rdchem.Mol]: """Identify and try to fix valence issues by removing any supplemental bond that should not be in the graph. Args: mol: input molecule with incorrect valence for some atoms inplace: Whether to modify in place or make a copy allow_ring_break: Whether bond removal involving ring is allowed. Returns: Fixed potential valence issue in molecule or original molecule when nothing is broken of if failed. """ if not inplace: mol = copy.copy(mol) vm = rdMolStandardize.RDKitValidation() if len(vm.validate(mol)) == 0: # don't fix something that is not broken return mol try: m = Chem.RemoveHs( mol, implicitOnly=False, updateExplicitCount=True, sanitize=False, ) m.UpdatePropertyCache(False) # first pass using explicit false count for atom in m.GetAtoms(): while incorrect_valence(atom) and atom.GetTotalNumHs() > 0: cur_hydrogen = atom.GetTotalNumHs() atom.SetNumExplicitHs(max(0, cur_hydrogen - 1)) atom.SetFormalCharge(max(0, atom.GetFormalCharge() - 1)) # atom.SetNumRadicalElectrons(0) atom.UpdatePropertyCache(False) em = Chem.RWMol(m) bonds = em.GetBonds() bonds = [ bond for bond in bonds if any( [ incorrect_valence(bond.GetBeginAtom()), incorrect_valence(bond.GetEndAtom()), ] ) ] for bond in bonds: a1 = bond.GetBeginAtom() a2 = bond.GetEndAtom() if incorrect_valence(a1) or incorrect_valence(a2): mbond = decrease_bond(bond) if allow_ring_break or (mbond or not bond.IsInRing()): em.RemoveBond(a1.GetIdx(), a2.GetIdx()) if mbond is not None: em.AddBond(a1.GetIdx(), a2.GetIdx(), mbond) a1.UpdatePropertyCache(False) a2.UpdatePropertyCache(False) m = em.GetMol() except Exception: return None return m