/// <summary> /// Compute all rings up to an including the <paramref name="maxRingSize"/>. No /// pre-processing is done on the container. /// </summary> /// <param name="atomContainer">the molecule to be searched for rings</param> /// <param name="maxRingSize">Maximum ring size to consider. Provides a possible /// breakout from recursion for complex compounds.</param> /// <returns>a RingSet containing the rings in molecule</returns> /// <exception cref="CDKException">An exception thrown if the threshold was exceeded</exception> public IRingSet FindAllRingsInIsolatedRingSystem(IAtomContainer atomContainer, int maxRingSize) { var edges = EdgeToBondMap.WithSpaceFor(atomContainer); var graph = GraphUtil.ToAdjList(atomContainer, edges); var ac = new AllCycles(graph, maxRingSize, threshold.Value); if (!ac.Completed) { throw new CDKException("Threshold exceeded for AllRingsFinder"); } var ringSet = atomContainer.Builder.NewRingSet(); foreach (var path in ac.GetPaths()) { ringSet.Add(ToRing(atomContainer, edges, path)); } return(ringSet); }
/// <summary> /// Compute all rings up to and including the <paramref name="maxRingSize"/>. The /// container is first partitioned into ring systems which are then processed /// separately. If the molecule has already be partitioned, consider using <see cref="FindAllRingsInIsolatedRingSystem(IAtomContainer, int)"/>. /// </summary> /// <param name="container">The AtomContainer to be searched for rings</param> /// <param name="maxRingSize">Maximum ring size to consider. Provides a possible /// breakout from recursion for complex compounds.</param> /// <returns>A RingSet with all rings in the AtomContainer</returns> /// <exception cref="CDKException">An exception thrown if the threshold was exceeded</exception> public IRingSet FindAllRings(IAtomContainer container, int maxRingSize) { var edges = EdgeToBondMap.WithSpaceFor(container); var graph = GraphUtil.ToAdjList(container, edges); var rs = new RingSearch(container, graph); var ringSet = container.Builder.NewRingSet(); // don't need to run on isolated rings, just need to put vertices in // cyclic order foreach (var isolated in rs.Isolated()) { if (isolated.Length <= maxRingSize) { var ring = ToRing(container, edges, GraphUtil.Cycle(graph, isolated)); ringSet.Add(ring); } } // for each set of fused cyclic vertices run the separate search foreach (var fused in rs.Fused()) { var ac = new AllCycles(GraphUtil.Subgraph(graph, fused), Math.Min(maxRingSize, fused.Length), threshold.Value); if (!ac.Completed) { throw new CDKException("Threshold exceeded for AllRingsFinder"); } foreach (var path in ac.GetPaths()) { IRing ring = ToRing(container, edges, path, fused); ringSet.Add(ring); } } return(ringSet); }
/// <inheritdoc/> public override IBitFingerprint GetBitFingerprint(IAtomContainer container) { var keys = GetKeys(container.Builder); var fp = new BitArray(keys.Count); // init SMARTS invariants (connectivity, degree, etc) SmartsPattern.Prepare(container); int numAtoms = container.Atoms.Count; var bmap = EdgeToBondMap.WithSpaceFor(container); var adjlist = GraphUtil.ToAdjList(container, bmap); for (int i = 0; i < keys.Count; i++) { var key = keys[i]; var pattern = key.Pattern; switch (key.Smarts) { case "[!*]": break; case "[!0]": foreach (IAtom atom in container.Atoms) { if (atom.MassNumber != null) { fp.Set(i, true); break; } } break; // ring bits case "[R]1@*@*@1": // 3M RING bit22 case "[R]1@*@*@*@1": // 4M RING bit11 case "[R]1@*@*@*@*@1": // 5M RING bit96 case "[R]1@*@*@*@*@*@1": // 6M RING bit163, x2=bit145 case "[R]1@*@*@*@*@*@*@1": // 7M RING, bit19 case "[R]1@*@*@*@*@*@*@*@1": // 8M RING, bit101 // handled separately break; case "(*).(*)": // bit 166 (*).(*) we can match this in SMARTS but it's faster to just // count the number of components or in this case try to traverse the // component, iff there are some atoms not visited we have more than // one component bool[] visit = new bool[numAtoms]; if (numAtoms > 1 && VisitPart(visit, adjlist, 0, -1) < numAtoms) { fp.Set(165, true); } break; default: if (key.Count == 0) { if (pattern.Matches(container)) { fp.Set(i, true); } } else { // check if there are at least 'count' unique hits, key.count = 0 // means find at least one match hence we add 1 to out limit if (pattern.MatchAll(container).GetUniqueAtoms().AtLeast(key.Count + 1)) { fp.Set(i, true); } } break; } } // Ring Bits // threshold=126, see AllRingsFinder.Threshold.PubChem_97 if (numAtoms > 2) { AllCycles allcycles = new AllCycles(adjlist, Math.Min(8, numAtoms), 126); int numArom = 0; foreach (int[] path in allcycles.GetPaths()) { // length is +1 as we repeat the closure vertex switch (path.Length) { case 4: // 3M bit22 fp.Set(21, true); break; case 5: // 4M bit11 fp.Set(10, true); break; case 6: // 5M bit96 fp.Set(95, true); break; case 7: // 6M bit163->bit145, bit124 numArom > 1 if (numArom < 2) { if (IsAromPath(path, bmap)) { numArom++; if (numArom == 2) { fp.Set(124, true); } } } if (fp[162]) { fp.Set(144, true); // >0 } else { fp.Set(162, true); // >1 } break; case 8: // 7M bit19 fp.Set(18, true); break; case 9: // 8M bit101 fp.Set(100, true); break; } } } return(new BitSetFingerprint(fp)); }