/// <summary> /// Is the {@code atom} a suppressible hydrogen and can be represented as /// implicit. A hydrogen is suppressible if it is not an ion, not the major /// isotope (i.e. it is a deuterium or tritium atom) and is not molecular /// hydrogen. /// </summary> /// <param name="container"> the structure </param> /// <param name="graph"> adjacent list representation </param> /// <param name="v"> vertex (atom index) </param> /// <returns> the atom is a hydrogen and it can be suppressed (implicit) </returns> private static bool suppressibleHydrogen(IAtomContainer container, int[][] graph, int v) { IAtom atom = container.getAtom(v); // is the atom a hydrogen if (!"H".Equals(atom.getSymbol())) { return(false); } // is the hydrogen an ion? if (GetFormalCharge(atom) != 0) { return(false); } // is the hydrogen deuterium / tritium? if (GetMassNumber(atom) != 1) { return(false); } // hydrogen is either not attached to 0 or 2 neighbors if (graph[v].Length != 1) { return(false); } // okay the hydrogen has one neighbor, if that neighbor is not a // hydrogen (i.e. molecular hydrogen) then we can suppress it return(!"H".Equals(container.getAtom(graph[v][0]).getSymbol())); }
/// <summary> /// MolfileV3000ToAtomContainer /// </summary> /// <param name="molfile"></param> /// <returns></returns> public static IAtomContainer MolfileV3000ToAtomContainer(string molfile) { // Extract any mass info before conversion to avoid losing our custom info in conversion Dictionary <int, int> map = new Dictionary <int, int>(); if (molfile.Contains(" MASS=")) { map = ExtractMassAttributes(ref molfile); } cdk.io.DefaultChemObjectReader cor; java.io.StringReader sr = new java.io.StringReader(molfile); cor = new MDLV3000Reader(sr); cor.setReaderMode(IChemObjectReader.Mode.RELAXED); IAtomContainer mol = (IAtomContainer)cor.read(new AtomContainer()); cor.close(); for (int ai = 0; ai < mol.getAtomCount(); ai++) { IAtom a = mol.getAtom(ai); if (map.ContainsKey(ai + 1)) { a.setMassNumber(new java.lang.Integer(map[ai + 1])); } else { a.setMassNumber(null); } } ConfigureAtomContainer(mol); return(mol); }
/// <summary> /// RemovePseudoAtoms /// </summary> /// <param name="mol"></param> /// <returns>Pseudo atom count</returns> public static int RemovePseudoAtoms(IAtomContainer mol) { List <IAtom> pseudoAtoms = new List <IAtom>(); for (int ai = 0; ai < mol.getAtomCount(); ai++) { IAtom atom = mol.getAtom(ai); if (atom is IPseudoAtom) { pseudoAtoms.Add(atom); } } if (pseudoAtoms.Count == 0) { return(0); } foreach (IAtom atom in pseudoAtoms) { mol.removeAtomAndConnectedElectronContainers(atom); } AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(mol); mol = AtomContainerManipulator.suppressHydrogens(mol); GetHydrogenAdder().addImplicitHydrogens(mol); return(pseudoAtoms.Count); }
/// <summary> /// Cdk Isotope Conversion Test /// </summary> /// <param name="smiles"></param> /// <returns></returns> public string CdkIsotopeConversionTest( string smiles) { // Initial mol object creation from Smiles string msg = "CDK Conversion Test, Smiles: " + smiles + "\r\n\r\n"; IAtomContainer mol1 = SmilesToAtomContainer(smiles); mol1.getAtom(0).setMassNumber(new java.lang.Integer(-1)); // try neg value int isotope1 = mol1.getAtom(0).getMassNumber().intValue(); msg += "Smiles -> Obj isotope: " + isotope1 + "\r\n\r\n"; // Mol object to V2000 & back string v2000 = AtomContainerToMolfile(mol1); // obj to molfile msg += "Obj -> CDK V2000\r\n==================================\r\n " + v2000 + "\r\n\r\n"; IAtomContainer molV2000 = MolfileToAtomContainer(v2000); // molfile to obj int isotopeV2 = molV2000.getAtom(0).getMassNumber().intValue(); msg += "V2000 -> Obj isotope: " + isotopeV2 + "\r\n\r\n"; string v2000b = AtomContainerToMolfile(molV2000); // obj back to molfile // Mol object to V3000 & back string v3000 = AtomContainerToMolFileV3000(mol1); // obj to molfile msg += "Obj -> CDK V3000\r\n==================================\r\n " + v3000 + "\r\n\r\n"; IAtomContainer molV3000 = MolfileToAtomContainer(v3000); // molfile to obj int isotopeV3 = mol1.getAtom(0).getMassNumber().intValue(); msg += "V3000 -> Obj isotope: " + isotopeV3 + "\r\n\r\n"; string v3000b = AtomContainerToMolFileV3000(molV3000); // obj back to molfile return(msg); }
/// <summary> /// Remove the following features from a molecule /// - Atom non-standard mass /// - Stereo chemistry /// - explicit hydrogens /// </summary> /// <param name="src"></param> /// <returns>Modified mol</returns> public static IAtomContainer RemoveIsotopesStereoExplicitHydrogens( IAtomContainer src) { IAtom[] atoms = new IAtom[src.getAtomCount()]; IBond[] bonds = new IBond[src.getBondCount()]; IChemObjectBuilder builder = src.getBuilder(); for (int i = 0; i < atoms.Length; i++) { IAtom atom = src.getAtom(i); IAtom atom2 = (IAtom)builder.newInstance(typeof(IAtom), atom.getSymbol()); SetImplicitHydrogenCount(atom2, GetImplicitHydrogenCount(atom)); atom2.setPoint2d(atom.getPoint2d()); atoms[i] = atom2; } for (int i = 0; i < bonds.Length; i++) { IBond bond = src.getBond(i); int u = src.getAtomNumber(bond.getAtom(0)); int v = src.getAtomNumber(bond.getAtom(1)); IBond bond2 = (IBond)builder.newInstance(typeof(IBond), atoms[u], atoms[v]); bond2.setIsAromatic(bond.isAromatic()); bond2.setIsInRing(bond.isInRing()); bond2.setOrder(bond.getOrder()); bond2.setFlag(CDKConstants.ISAROMATIC, bond.getFlag(CDKConstants.ISAROMATIC)); bond2.setFlag(CDKConstants.SINGLE_OR_DOUBLE, bond.getFlag(CDKConstants.SINGLE_OR_DOUBLE)); bonds[i] = bond2; } IAtomContainer dest = (IAtomContainer)builder.newInstance(typeof(IAtomContainer)); dest.setAtoms(atoms); dest.setBonds(bonds); AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(dest); dest = AtomContainerManipulator.suppressHydrogens(dest); GetHydrogenAdder().addImplicitHydrogens(dest); return(dest); }
static List <IAtom> GetAttachmentAtoms( IAtomContainer mol, int attachmentNo) { List <IAtom> atoms = new List <IAtom>(); for (int ai = 0; ai < mol.getAtomCount(); ai++) { IAtom atom = mol.getAtom(ai); int massNo = Math.Abs(GetMassNumber(atom)); if (massNo == attachmentNo || massNo == 12 || massNo == 21) // 12 & 21 values occur at atoms with two attachments { //SetMassNumber(atom, 0); // clear attachment number (isotope) (can't may need later, e.g.12 value for two attachements to same atom) atoms.Add(atom); } } return(atoms); }
/// <summary> /// GetHeavyAtomCount /// </summary> /// <param name="mol"></param> /// <returns></returns> public static int GetHeavyAtomCount(IAtomContainer mol) { int haCnt = 0; for (int ai = 0; ai < mol.getAtomCount(); ai++) { IAtom atom = mol.getAtom(ai); if (atom.getAtomicNumber().intValue() == 1 || // do not count hydrogens atom.getSymbol().Equals("H")) { continue; } else { haCnt++; } } return(haCnt); }
/// <summary> /// (Converted from Java to C# for possible later modification) /// Suppress any explicit hydrogens in the provided container. Only hydrogens /// that can be represented as a hydrogen count value on the atom are /// suppressed. The container is updated and no elements are copied, please /// use either <seealso cref="#copyAndSuppressedHydrogens"/> if you would to preserve /// the old instance. /// </summary> /// <param name="org"> the container from which to remove hydrogens </param> /// <returns> the input for convenience </returns> /// <seealso cref= #copyAndSuppressedHydrogens </seealso> public IAtomContainer suppressHydrogens(IAtomContainer org) { bool anyHydrogenPresent = false; for (int ai = 0; ai < org.getAtomCount(); ai++) { IAtom atom = org.getAtom(ai); if ("H".Equals(atom.getSymbol())) { anyHydrogenPresent = true; break; } } if (!anyHydrogenPresent) { return(org); } // we need fast adjacency checks (to check for suppression and // update hydrogen counts) int[][] graph = GraphUtil.toAdjList(org); int nOrgAtoms = org.getAtomCount(); int nOrgBonds = org.getBondCount(); int nCpyAtoms = 0; int nCpyBonds = 0; ISet <IAtom> hydrogens = new HashSet <IAtom>(); IAtom[] cpyAtoms = new IAtom[nOrgAtoms]; // filter the original container atoms for those that can/can't // be suppressed for (int v = 0; v < nOrgAtoms; v++) { IAtom atom = org.getAtom(v); if (suppressibleHydrogen(org, graph, v)) { hydrogens.Add(atom); incrementImplHydrogenCount(org.getAtom(graph[v][0])); } else { cpyAtoms[nCpyAtoms++] = atom; } } // none of the hydrogens could be suppressed - no changes need to be made if (hydrogens.Count == 0) { return(org); } org.setAtoms(cpyAtoms); // we now update the bonds - we have auxiliary variable remaining that // bypasses the set membership checks if all suppressed bonds are found IBond[] cpyBonds = new IBond[nOrgBonds - hydrogens.Count]; int remaining = hydrogens.Count; for (int bi = 0; bi < org.getBondCount(); bi++) { IBond bond = org.getBond(bi); if (remaining > 0 && (hydrogens.Contains(bond.getAtom(0)) || hydrogens.Contains(bond.getAtom(1)))) { remaining--; continue; } cpyBonds[nCpyBonds++] = bond; } // we know how many hydrogens we removed and we should have removed the // same number of bonds otherwise the container is strange if (nCpyBonds != cpyBonds.Length) { throw new System.ArgumentException("number of removed bonds was less than the number of removed hydrogens"); } org.setBonds(cpyBonds); return(org); }
/// <summary> /// Convert isotope labels to hilighting. /// </summary> /// <param name="mol"></param> /// <returns></returns> public string ConvertIsotopeValuesToHilighting( IAtomContainer mol) { bool hilight; string molfile2 = ""; bool clearAttachmentPointLabels = true; bool hilightAttachmentBond = true; List <int> atomSet = new List <int>(); List <int> bondSet = new List <int>(); for (int bi = 0; bi < mol.getBondCount(); bi++) { IBond b = mol.getBond(bi); if (b.getAtomCount() != 2) { continue; } IAtom a1 = b.getAtom(0); IAtom a2 = b.getAtom(1); if (hilightAttachmentBond) { hilight = (GetMassNumber(a1) != 0 && GetMassNumber(a2) != 0); } else { hilight = (GetMassNumber(a1) < 0 && GetMassNumber(a2) < 0); } if (hilight) { bondSet.Add(bi); } } //String posMap = ""; // debug (note that hydrogens can get repositioned) for (int ai = 0; ai < mol.getAtomCount(); ai++) // scan atoms for hilighting and reset isotope values { IAtom a = mol.getAtom(ai); hilight = GetMassNumber(a) < 0; if (hilight) { atomSet.Add(ai); } //posMap += ai.ToString() + ", " + a.getSymbol() + ", " + hilight + "\r\n"; // debug int massNo = GetMassNumber(a); if (massNo == hilightIsotopeValue) { a.setMassNumber(null); // set back to original value } else if (massNo < 0) { if (clearAttachmentPointLabels) { a.setMassNumber(null); } else { SetMassNumber(a, -massNo); // set back to positive } } } //mol = GenerateCoordinates(mol); // (should already be done) try { molfile2 = AtomContainerToMolFileV3000(mol); } catch (Exception ex) { ex = ex; } if (Lex.IsUndefined(molfile2)) // couldn't convert to v3000, just return unhilighted v2000 file { molfile2 = AtomContainerToMolfile(mol); return(molfile2); } string txt = "MDLV30/HILITE"; if (atomSet.Count > 0) { txt += " " + BuildV3000KeywordList("ATOMS", atomSet); } if (bondSet.Count > 0) { txt += " " + BuildV3000KeywordList("BONDS", bondSet); } txt = BuildV3000Lines(txt); bool hasCollection = Lex.Contains(molfile2, "M V30 END COLLECTION"); if (hasCollection) // already have collection begin and end { txt = txt + "M V30 END COLLECTION"; molfile2 = Lex.Replace(molfile2, "M V30 END COLLECTION", txt); } else // add collection begin & end { txt = "M V30 BEGIN COLLECTION\n" + txt + "M V30 END COLLECTION\n" + "M V30 END CTAB"; molfile2 = Lex.Replace(molfile2, "M V30 END CTAB", txt); } return(molfile2); }
/// <summary> /// Remove explicit and implicit hydrogens bonded to positive nitrogens /// </summary> /// <param name="org"></param> /// <returns></returns> public int RemoveHydrogensBondedToPositiveNitrogens(IAtomContainer org) { int chg, impHydCnt; int implicitHydRemoved = 0; HashSet <IAtom> atomsToRemove = new HashSet <IAtom>(); HashSet <IBond> bondsToRemove = new HashSet <IBond>(); int nOrgAtoms = org.getAtomCount(); int nOrgBonds = org.getBondCount(); // Get H atoms and their bonds to pos-charged Nitrogen, adjusting charge for (int bi = 0; bi < org.getBondCount(); bi++) { IBond bond = org.getBond(bi); if (bond.getAtomCount() != 2) { continue; } IAtom a1 = bond.getAtom(0); IAtom a2 = bond.getAtom(1); if (a1.getSymbol() == "H" && a2.getSymbol() == "N" && GetFormalCharge(a2) > 0) { chg = GetFormalCharge(a2) - 1; SetFormalCharge(a2, chg); atomsToRemove.Add(a1); bondsToRemove.Add(bond); } else if (a2.getSymbol() == "H" && a1.getSymbol() == "N" && GetFormalCharge(a1) > 0) { chg = GetFormalCharge(a1) - 1; SetFormalCharge(a1, chg); atomsToRemove.Add(a2); bondsToRemove.Add(bond); } } // Check for implicit H attached to pos-charged N for (int ai = 0; ai < nOrgAtoms; ai++) { IAtom a = org.getAtom(ai); if (a.getSymbol() == "N" && GetFormalCharge(a) > 0 && GetImplicitHydrogenCount(a) > 0) { chg = GetFormalCharge(a) - 1; SetFormalCharge(a, chg); impHydCnt = GetImplicitHydrogenCount(a) - 1; SetImplicitHydrogenCount(a, impHydCnt); implicitHydRemoved++; } } if (implicitHydRemoved > 0) { implicitHydRemoved = implicitHydRemoved; // debug } if (atomsToRemove.Count == 0) { return(implicitHydRemoved); // just return if no explicit H to remove } // Get list of atoms to keep IAtom[] cpyAtoms = new IAtom[nOrgAtoms - atomsToRemove.Count]; int nCpyAtoms = 0; for (int ai = 0; ai < nOrgAtoms; ai++) { IAtom atom = org.getAtom(ai); if (!atomsToRemove.Contains(atom)) { cpyAtoms[nCpyAtoms++] = atom; } } org.setAtoms(cpyAtoms); // Get list of bonds to keep IBond[] cpyBonds = new IBond[nOrgBonds - bondsToRemove.Count]; int nCpyBonds = 0; for (int bi = 0; bi < org.getBondCount(); bi++) { IBond bond = org.getBond(bi); if (!bondsToRemove.Contains(bond)) { cpyBonds[nCpyBonds++] = bond; } } org.setBonds(cpyBonds); return(atomsToRemove.Count + implicitHydRemoved); }