/// <summary> /// Count bonds connecting two heavy atoms /// </summary> /// <param name="mol"></param> /// <returns></returns> public static int GetHeavyBondCount(IAtomContainer mol) { int hbCnt = 0; for (int bi = 0; bi < mol.getBondCount(); bi++) { IBond b = mol.getBond(bi); if (b.getAtomCount() != 2) { continue; } IAtom a = b.getAtom(0); // first atom if (a.getAtomicNumber().intValue() == 1 || // do not count hydrogens a.getSymbol().Equals("H")) { a = b.getAtom(1); // second atom } if (a.getAtomicNumber().intValue() == 1 || // do not count hydrogens a.getSymbol().Equals("H")) { continue; } hbCnt++; } return(hbCnt); }
/// <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> /// 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="atom"> an atom in the structure </param> /// <returns> the atom is a hydrogen and it can be suppressed (implicit) </returns> private static bool suppressibleHydrogen(IAtomContainer container, IAtom atom) { // 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); } // molecule hydrogen with implicit H? if (atom.getImplicitHydrogenCount() != null && atom.getImplicitHydrogenCount().intValue() != 0) { return(false); } // molecule hydrogen List <IAtom> neighbors = container.getConnectedAtomsList(atom) as List <IAtom>; if (neighbors.Count == 1 && neighbors[0].getSymbol().Equals("H")) { return(false); } // what about bridging hydrogens? // hydrogens with atom-atom mapping? return(true); }
/// <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); }
/// <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> /// 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); }
/** * Check for the other atoms nearby in the fragment. * * @param candidateOxygen * the candidate oxygen atom * @param frag * the frag * @param proton * the proton * * @return true, if successful * @throws CloneNotSupportedException * @throws CDKException */ private IAtomContainer checkForCompleteNeutralLoss(IAtomContainer frag, IAtom candidateAtom, double neutralLossMass) { IAtomContainer ret = new AtomContainer(); // create a copy from the original fragment var part = new List<IBond>(); part = traverse(frag, candidateAtom, part); var fragCopy = makeAtomContainer(candidateAtom, part); // set properties again var properties = frag.getProperties(); fragCopy.setProperties(properties); // now get the other atoms from the neutral loss var atomsToFind = new List<string>(); var addHydrogen = false; // one hydrogen is lost with the neutral loss if (neutralLoss[neutralLossMass].HydrogenDifference == -1) { foreach (var isotope in neutralLoss[neutralLossMass].ElementalComposition.isotopes().ToWindowsEnumerable<IIsotope>()) { var c = neutralLoss[neutralLossMass].ElementalComposition.getIsotopeCount(isotope); for (var i = 0; i < c; i++) { atomsToFind.Add(isotope.getSymbol()); } } } else { foreach (var isotope in neutralLoss[neutralLossMass].TopoFragment.isotopes().ToWindowsEnumerable<IIsotope>()) { var c = neutralLoss[neutralLossMass].ElementalComposition.getIsotopeCount(isotope); for (var i = 0; i < c; i++) { atomsToFind.Add(isotope.getSymbol()); } addHydrogen = true; } } // at most 2 bonds between the oxygen and other atoms (at most 1 H and 2 // C) var count = neutralLoss[neutralLossMass].Distance; // list storing all atoms to be removed later on if complete neutral // loss was found var foundAtoms = new List<IAtom>(); // list storing all bonds to remove var foundBonds = new List<IBond>(); // list storing all bonds already checked var checkedBonds = new List<IBond>(); // list storing all checked atoms var checkedAtoms = new List<IAtom>(); // queue storing all bonds to check for a particular distance var bondQueue = new List<IBond>(); // List storing all bonds to be checked for the next distance var bondsFurther = new List<IBond>(); // get all bonds from this atom distance = 1 var bondList = fragCopy.getConnectedBondsList(candidateAtom); foreach (var bond in bondList.ToWindowsEnumerable<IBond>()) { if (bond != null) { bondQueue.Add(bond); } } var hydrogenStartAtom = neutralLoss[neutralLossMass].HydrogenOnStartAtom; var firstBonds = true; while (count > 0) { IBond currentBond = null; if (bondQueue.Count > 0) { currentBond = bondQueue[bondQueue.Count - 1]; bondQueue.RemoveAt(bondQueue.Count - 1); } // check for already tried bonds if (checkedBonds.Contains(currentBond) && currentBond != null) { continue; } else if (currentBond != null) { checkedBonds.Add(currentBond); } if (currentBond != null) { foreach (var atom in currentBond.atoms().ToWindowsEnumerable<IAtom>()) { // check for already tried atoms if (checkedAtoms.Contains(atom)) { continue; } else { checkedAtoms.Add(atom); } if (firstBonds && atom.getSymbol().Equals("H")) { hydrogenStartAtom--; } // thats the starting atom if (atom.getSymbol().Equals(candidateAtom.getSymbol())) { var removed = atomsToFind.Remove(candidateAtom.getSymbol()); if (removed) { foundAtoms.Add(atom); // remove bond if (!foundBonds.Contains(currentBond)) { foundBonds.Add(currentBond); } } // this bond has to be removed else if (!foundBonds.Contains(currentBond) && atomsToFind.Contains(atom.getSymbol())) { foundBonds.Add(currentBond); } continue; } // found atom...remove it from the atoms to find list // do not remove atoms from ring if (atomsToFind.Contains(atom.getSymbol()) && !allRings.contains(atom) && atomsToFind.Count > 0) { var removed = atomsToFind.Remove(atom.getSymbol()); if (removed) { foundAtoms.Add(atom); } else { continue; } if (!foundBonds.Contains(currentBond)) { foundBonds.Add(currentBond); } continue; } // only walk along C-Atoms! if (!atom.getSymbol().Equals("C")) { continue; } // get new bonds var bondsToAddTemp = fragCopy.getConnectedBondsList(atom); foreach (var bond in bondsToAddTemp.ToWindowsEnumerable<IBond>()) { if (bond != null) { bondsFurther.Add(bond); } } } } // break condition if (currentBond == null && bondQueue.Count == 0 && bondsFurther.Count == 0) { break; } // now check if the queue is empty...checked all bonds in this // distance if (bondQueue.Count == 0) { count--; // set new queue data foreach (var bond in bondsFurther) { if (bond != null) { bondQueue.Add(bond); } } // reinitialize bondsFurther = new List<IBond>(); // the initially connected bonds are all checked! firstBonds = false; } } // found complete neutral loss if (atomsToFind.Count == 0) { foreach (var atom in foundAtoms) { fragCopy.removeAtomAndConnectedElectronContainers(atom); } // TODO add hydrogen somewhere if (addHydrogen) { var props = fragCopy.getProperties(); props.put("hydrogenAddFromNL", "1"); fragCopy.setProperties(props); } // add fragment to return if enough H were connected and fragment is // still connected if (hydrogenStartAtom <= 0) { ret.add(fragCopy); } } return ret; }