private static ISet <IBond> FindCutBonds(IAtomContainer mol, EdgeToBondMap bmap, int[][] adjlist) { var cuts = new HashSet <IBond>(); var numAtoms = mol.Atoms.Count; for (int i = 0; i < numAtoms; i++) { var atom = mol.Atoms[i]; var deg = adjlist[i].Length; var elem = atom.AtomicNumber; if (elem == 6 && deg <= 2 || deg < 2) { continue; } foreach (var w in adjlist[i]) { var bond = bmap[i, w]; if (adjlist[w].Length >= 2 && !bond.IsInRing) { cuts.Add(bond); } } } return(cuts); }
private static List <IAtomContainer> GenerateFragments(IAtomContainer mol) { var bmap = EdgeToBondMap.WithSpaceFor(mol); var adjlist = GraphUtil.ToAdjList(mol, bmap); Cycles.MarkRingAtomsAndBonds(mol, adjlist, bmap); var cuts = FindCutBonds(mol, bmap, adjlist); var atmidx = new Dictionary <IAtom, int>(); foreach (var atom in mol.Atoms) { atmidx[atom] = atmidx.Count; } // frags are ordered by biggest to smallest var frags = new List <IAtomContainer>(); foreach (var cut in cuts) { if (frags.Count >= MaxFragment) { break; } frags.AddRange(MakeCut(cut, mol, atmidx, adjlist)); } frags.Sort(delegate(IAtomContainer a, IAtomContainer b) { return(-a.Bonds.Count.CompareTo(b.Bonds.Count)); }); return(frags); }
/// <summary> /// Computes <see cref="SMARTSAtomInvariants"/> and stores on the <see cref="Key"/> or /// each <see cref="IAtom"/> in the <paramref name="container"/>. The <see cref="IMolecularEntity.IsInRing"/> /// is also set for each bond. This configuration /// includes the ring information as used by the Daylight implementation. /// That is the Smallest Set of Smallest Rings (SSSR) is used and only the /// smallest ring is stored for the <see cref="RingSize"/> . /// </summary> /// <example> /// <code> /// IAtomContainer container = ...; /// SMARTSAtomInvariants.ConfigureDaylightWithRingInfo(container); /// foreach (var atom in container.Atoms) { /// SMARTSAtomInvariants inv = atom.GetProperty<SMARTSAtomInvariants>(SMARTSAtomInvariants.Key); /// } /// </code> /// </example> /// <param name="container">the container to configure</param> public static void ConfigureDaylightWithRingInfo(IAtomContainer container) { var map = EdgeToBondMap.WithSpaceFor(container); var graph = GraphUtil.ToAdjList(container, map); ConfigureDaylight(container, graph, map, true); }
/// <summary> /// Obtain the MMFF symbolic types to the atoms of the provided structure. /// </summary> /// <param name="container">container structure representation</param> /// <returns>MMFF symbolic types for each atom index</returns> public string[] SymbolicTypes(IAtomContainer container) { var bonds = EdgeToBondMap.WithSpaceFor(container); var graph = GraphUtil.ToAdjList(container, bonds); return(SymbolicTypes(container, graph, bonds, new HashSet <IBond>())); }
/// <summary> /// Create a state for matching subgraphs using the Ullmann refinement /// procedure. /// </summary> /// <param name="container1">query container</param> /// <param name="container2">target container</param> /// <param name="g1">query container adjacency list</param> /// <param name="g2">target container adjacency list</param> /// <param name="bonds1">query container bond map</param> /// <param name="bonds2">target container bond map</param> /// <param name="atomMatcher">method of matching atom semantics</param> /// <param name="bondMatcher">method of matching bond semantics</param> public UllmannState(IAtomContainer container1, IAtomContainer container2, int[][] g1, int[][] g2, EdgeToBondMap bonds1, EdgeToBondMap bonds2, AtomMatcher atomMatcher, BondMatcher bondMatcher) { this.bondMatcher = bondMatcher; this.g1 = g1; this.g2 = g2; this.bond1 = bonds1; this.bonds2 = bonds2; this.m1 = new int[g1.Length]; this.m2 = new int[g2.Length]; Arrays.Fill(m1, UNMAPPED); Arrays.Fill(m2, UNMAPPED); // build up compatibility matrix matrix = new CompatibilityMatrix(g1.Length, g2.Length); for (int i = 0; i < g1.Length; i++) { for (int j = 0; j < g2.Length; j++) { if (g1[i].Length <= g2[j].Length && atomMatcher.Matches(container1.Atoms[i], container2.Atoms[j])) { matrix.Set1(i, j); } } } }
/// <summary> /// Use the provided query and target to obtain the bond instances. /// </summary> /// <param name="query">the structure to be found</param> /// <param name="target">the structure being searched</param> public BondMaper(IAtomContainer query, IAtomContainer target) { this.bonds1 = EdgeToBondMap.WithSpaceFor(query); this.bonds2 = EdgeToBondMap.WithSpaceFor(target); this.g1 = GraphUtil.ToAdjList(query, bonds1); GraphUtil.ToAdjList(target, bonds2); }
/// <summary> /// Given the assigned preliminary MMFF atom types (symbs[]) update these to the aromatic types. /// To begin, all the 5 and 6 member aromatic cycles are discovered. The symbolic types of five /// and six member cycles are then update with <see cref="UpdateAromaticTypesInFiveMemberRing(int[], string[])"/> /// and <see cref="UpdateAromaticTypesInSixMemberRing(int[], string[])"/>. /// </summary> /// <param name="container">structure representation</param> /// <param name="symbs">vector of symbolic types for the whole structure</param> /// <param name="bonds">edge to bond map lookup</param> /// <param name="graph">adjacency list graph representation of structure</param> /// <param name="mmffArom">set of bonds that are aromatic</param> public void Assign(IAtomContainer container, string[] symbs, EdgeToBondMap bonds, int[][] graph, ISet <IBond> mmffArom) { var contribution = new int[graph.Length]; var doubleBonds = new int[graph.Length]; Arrays.Fill(doubleBonds, -1); SetupContributionAndDoubleBonds(container, bonds, graph, contribution, doubleBonds); var cycles = FindAromaticRings(CyclesOfSizeFiveOrSix(container, graph), contribution, doubleBonds); foreach (var cycle in cycles) { int len = cycle.Length - 1; if (len == 6) { UpdateAromaticTypesInSixMemberRing(cycle, symbs); } if (len == 5 && NormaliseCycle(cycle, contribution)) { UpdateAromaticTypesInFiveMemberRing(cycle, symbs); } // mark aromatic bonds for (int i = 1; i < cycle.Length; i++) { mmffArom.Add(bonds[cycle[i], cycle[i - 1]]); } } }
public void RecogniseLeftHandedGlyceraldehyde() { var m = new AtomContainer(); m.Atoms.Add(Atom("C", 0, 0.80d, 1.24d)); m.Atoms.Add(Atom("C", 0, 0.80d, 0.42d)); m.Atoms.Add(Atom("O", 1, 0.09d, 1.66d)); m.Atoms.Add(Atom("O", 0, 1.52d, 1.66d)); m.Atoms.Add(Atom("O", 0, -0.02d, 0.42d)); m.Atoms.Add(Atom("C", 2, 0.80d, -0.41d)); m.Atoms.Add(Atom("H", 1, 1.63d, 0.42d)); m.Atoms.Add(Atom("O", 1, 1.52d, -0.82d)); m.AddBond(m.Atoms[0], m.Atoms[1], BondOrder.Single); m.AddBond(m.Atoms[0], m.Atoms[2], BondOrder.Single); m.AddBond(m.Atoms[0], m.Atoms[3], BondOrder.Double, BondStereo.EZByCoordinates); m.AddBond(m.Atoms[1], m.Atoms[4], BondOrder.Single); m.AddBond(m.Atoms[1], m.Atoms[5], BondOrder.Single); m.AddBond(m.Atoms[1], m.Atoms[6], BondOrder.Single); m.AddBond(m.Atoms[5], m.Atoms[7], BondOrder.Single); EdgeToBondMap bondMap = EdgeToBondMap.WithSpaceFor(m); int[][] graph = GraphUtil.ToAdjList(m, bondMap); FischerRecognition recogniser = new FischerRecognition(m, graph, bondMap, Stereocenters.Of(m)); var elements = recogniser.Recognise(new[] { Projection.Fischer }).ToReadOnlyList(); Assert.AreEqual(1, elements.Count); AssertTetrahedralCenter(elements[0], m.Atoms[1], TetrahedralStereo.AntiClockwise, m.Atoms[0], m.Atoms[6], m.Atoms[5], m.Atoms[4]); }
/// <summary> /// Find the bonds of a <paramref name="molecule"/> which this model determined were aromatic. /// </summary> /// <example> /// <include file='IncludeExamples.xml' path='Comments/Codes[@id="NCDK.Aromaticities.Aromaticity_Example.cs+FindBonds"]/*' /> /// </example> /// <param name="molecule">the molecule to apply the model to</param> /// <returns>the set of bonds which are aromatic</returns> /// <exception cref="CDKException">a problem occurred with the cycle perception - one can retry with a simpler cycle set</exception> public IEnumerable <IBond> FindBonds(IAtomContainer molecule) { // build graph data-structures for fast cycle perception var bondMap = EdgeToBondMap.WithSpaceFor(molecule); var graph = GraphUtil.ToAdjList(molecule, bondMap); // initial ring/cycle search and get the contribution from each atom RingSearch ringSearch = new RingSearch(molecule, graph); var electrons = model.Contribution(molecule, ringSearch); // obtain the subset of electron contributions which are >= 0 (i.e. // allowed to be aromatic) - we then find the cycles in this subgraph // and 'lift' the indices back to the original graph using the subset // as a lookup var subset = Subset(electrons); var subgraph = GraphUtil.Subgraph(graph, subset); // for each cycle if the electron sum is valid add the bonds of the // cycle to the set or aromatic bonds foreach (var cycle in cycles.Find(molecule, subgraph, subgraph.Length).GetPaths()) { if (CheckElectronSum(cycle, electrons, subset)) { for (int i = 1; i < cycle.Length; i++) { yield return(bondMap[subset[cycle[i]], subset[cycle[i - 1]]]); } } } yield break; }
public void RequireAtLeastTwoProjectedSubstituents() { var m = new AtomContainer(); m.Atoms.Add(Atom("O", 0, -0.71d, 1.24d)); m.Atoms.Add(Atom("C", 0, 0.00d, 0.83d)); m.Atoms.Add(Atom("O", 0, 0.71d, 1.24d)); m.Atoms.Add(Atom("C", 1, 0.00d, 0.00d)); m.Atoms.Add(Atom("C", 2, -0.67d, -0.48d)); m.Atoms.Add(Atom("C", 2, -0.41d, -1.27d)); m.Atoms.Add(Atom("C", 2, 0.41d, -1.27d)); m.Atoms.Add(Atom("N", 1, 0.67d, -0.48d)); m.AddBond(m.Atoms[6], m.Atoms[5], BondOrder.Single); m.AddBond(m.Atoms[1], m.Atoms[0], BondOrder.Double, BondStereo.EZByCoordinates); m.AddBond(m.Atoms[2], m.Atoms[1], BondOrder.Single); m.AddBond(m.Atoms[3], m.Atoms[1], BondOrder.Single); m.AddBond(m.Atoms[5], m.Atoms[4], BondOrder.Single); m.AddBond(m.Atoms[4], m.Atoms[3], BondOrder.Single); m.AddBond(m.Atoms[3], m.Atoms[7], BondOrder.Single); m.AddBond(m.Atoms[6], m.Atoms[7], BondOrder.Single); EdgeToBondMap bondMap = EdgeToBondMap.WithSpaceFor(m); int[][] graph = GraphUtil.ToAdjList(m, bondMap); Stereocenters stereocenters = new Stereocenters(m, graph, bondMap); stereocenters.CheckSymmetry(); CyclicCarbohydrateRecognition recon = new CyclicCarbohydrateRecognition(m, graph, bondMap, stereocenters); var elements = recon.Recognise(new[] { Projection.Haworth }).ToReadOnlyList(); Assert.IsTrue(elements.Count == 0); }
internal AdjListCache(IAtomContainer mol) { this.bmap = EdgeToBondMap.WithSpaceFor(mol); this.g = GraphUtil.ToAdjList(mol, bmap); this.numAtoms = mol.Atoms.Count; this.numBonds = mol.Bonds.Count; this.tInit = DateTime.Now.Ticks; }
public override Mappings MatchAll(IAtomContainer target) { var bonds2 = EdgeToBondMap.WithSpaceFor(target); var g2 = GraphUtil.ToAdjList(target, bonds2); var iterable = new UllmannIterable(query, target, g1, g2, bonds1, bonds2, atomMatcher, bondMatcher); var mappings = new Mappings(query, target, iterable); return(Filter(mappings, query, target)); }
/// <summary> /// Determine the stereocenter atoms in the provided container based on connectivity. /// </summary> /// <example> /// <include file='IncludeExamples.xml' path='Comments/Codes[@id="NCDK.Stereo.Stereocenters_Example.cs+Of"]/*' /> /// </example> /// <param name="container">input container</param> /// <returns>the stereocenters</returns> public static Stereocenters Of(IAtomContainer container) { var bondMap = EdgeToBondMap.WithSpaceFor(container); var g = GraphUtil.ToAdjList(container, bondMap); var stereocenters = new Stereocenters(container, g, bondMap); stereocenters.CheckSymmetry(); return(stereocenters); }
/// <summary> /// Non-public constructor for-now the atom/bond semantics are fixed. /// </summary> /// <param name="query">the query structure</param> /// <param name="atomMatcher">how atoms should be matched</param> /// <param name="bondMatcher">how bonds should be matched</param> private Ullmann(IAtomContainer query, AtomMatcher atomMatcher, BondMatcher bondMatcher) { this.query = query; this.atomMatcher = atomMatcher; this.bondMatcher = bondMatcher; this.bonds1 = EdgeToBondMap.WithSpaceFor(query); this.g1 = GraphUtil.ToAdjList(query, bonds1); DetermineFilters(query); }
public void Mannitol() { var m = new AtomContainer(); m.Atoms.Add(Atom("C", 2, -0.53d, 6.25d)); m.Atoms.Add(Atom("C", 1, -0.53d, 5.42d)); m.Atoms.Add(Atom("O", 1, 0.18d, 6.66d)); m.Atoms.Add(Atom("O", 1, -1.36d, 5.42d)); m.Atoms.Add(Atom("C", 1, -0.53d, 4.60d)); m.Atoms.Add(Atom("O", 1, -1.36d, 4.60d)); m.Atoms.Add(Atom("C", 1, -0.53d, 3.77d)); m.Atoms.Add(Atom("O", 1, 0.29d, 3.77d)); m.Atoms.Add(Atom("C", 1, -0.53d, 2.95d)); m.Atoms.Add(Atom("O", 1, 0.29d, 2.95d)); m.Atoms.Add(Atom("C", 2, -0.53d, 2.12d)); m.Atoms.Add(Atom("O", 1, 0.05d, 1.54d)); m.AddBond(m.Atoms[0], m.Atoms[1], BondOrder.Single); m.AddBond(m.Atoms[0], m.Atoms[2], BondOrder.Single); m.AddBond(m.Atoms[1], m.Atoms[3], BondOrder.Single); m.AddBond(m.Atoms[1], m.Atoms[4], BondOrder.Single); m.AddBond(m.Atoms[4], m.Atoms[5], BondOrder.Single); m.AddBond(m.Atoms[4], m.Atoms[6], BondOrder.Single); m.AddBond(m.Atoms[6], m.Atoms[7], BondOrder.Single); m.AddBond(m.Atoms[6], m.Atoms[8], BondOrder.Single); m.AddBond(m.Atoms[8], m.Atoms[9], BondOrder.Single); m.AddBond(m.Atoms[8], m.Atoms[10], BondOrder.Single); m.AddBond(m.Atoms[10], m.Atoms[11], BondOrder.Single); EdgeToBondMap bondMap = EdgeToBondMap.WithSpaceFor(m); int[][] graph = GraphUtil.ToAdjList(m, bondMap); FischerRecognition recogniser = new FischerRecognition(m, graph, bondMap, Stereocenters.Of(m)); var elements = recogniser.Recognise(new[] { Projection.Fischer }).ToReadOnlyList(); Assert.AreEqual(4, elements.Count); AssertTetrahedralCenter(elements[0], m.Atoms[1], TetrahedralStereo.AntiClockwise, m.Atoms[0], m.Atoms[1], m.Atoms[4], m.Atoms[3]); AssertTetrahedralCenter(elements[1], m.Atoms[4], TetrahedralStereo.AntiClockwise, m.Atoms[1], m.Atoms[4], m.Atoms[6], m.Atoms[5]); AssertTetrahedralCenter(elements[2], m.Atoms[6], TetrahedralStereo.AntiClockwise, m.Atoms[4], m.Atoms[7], m.Atoms[8], m.Atoms[6]); AssertTetrahedralCenter(elements[3], m.Atoms[8], TetrahedralStereo.AntiClockwise, m.Atoms[6], m.Atoms[9], m.Atoms[10], m.Atoms[8]); m.SetStereoElements(elements); }
/// <summary> /// Assign MMFF Symbolic atom types. The symbolic type can be accessed with /// <see cref="IAtomType.AtomTypeName"/>. An atom of unknown type is assigned the /// symbolic type <c>"UNK"</c>. /// All atoms, including hydrogens must be explicitly represented. /// </summary> /// <param name="mol">molecule</param> /// <returns>all atoms had a type assigned</returns> public virtual bool AssignAtomTypes(IAtomContainer mol) { // preconditions need explicit hydrogens foreach (var atom in mol.Atoms) { if (atom.ImplicitHydrogenCount == null || atom.ImplicitHydrogenCount > 0) { throw new ArgumentException("Hydrogens must be explicit nodes, each must have a zero (non-null) impl H count."); } } // conversion to faster data structures var edgeMap = EdgeToBondMap.WithSpaceFor(mol); var adjList = GraphUtil.ToAdjList(mol, edgeMap); mol.SetProperty(MMFF_ADJLIST_CACHE, adjList); mol.SetProperty(MMFF_EDGEMAP_CACHE, edgeMap); var aromBonds = new HashSet <IBond>(); var oldArom = GetAromatics(mol); // note: for MMFF we need to remove current aromatic flags for type // assignment (they are restored after) foreach (var chemObj in oldArom) { chemObj.IsAromatic = false; } var atomTypes = mmffAtomTyper.SymbolicTypes(mol, adjList, edgeMap, aromBonds); bool hasUnkType = false; for (int i = 0; i < mol.Atoms.Count; i++) { if (atomTypes[i] == null) { mol.Atoms[i].AtomTypeName = "UNK"; hasUnkType = true; } else { mol.Atoms[i].AtomTypeName = atomTypes[i]; } } // restore aromatic flags and mark the MMFF aromatic bonds foreach (var chemObj in oldArom) { chemObj.IsAromatic = true; } foreach (var bond in aromBonds) { bond.SetProperty(MMFF_AROM, true); } return(!hasUnkType); }
/// <summary> /// Required information to recognise stereochemistry. /// </summary> /// <param name="container">input structure</param> /// <param name="graph">adjacency list representation</param> /// <param name="bonds">edge to bond index</param> /// <param name="stereocenters">location and type of asymmetries</param> public FischerRecognition(IAtomContainer container, int[][] graph, EdgeToBondMap bonds, Stereocenters stereocenters) { this.container = container; this.graph = graph; this.bonds = bonds; this.stereocenters = stereocenters; }
/// <summary> /// Create a perception method for the provided container, graph /// representation and bond map. /// </summary> /// <param name="container">native CDK structure representation</param> /// <param name="graph">graph representation (adjacency list)</param> /// <param name="bondMap">fast lookup bonds by atom index</param> internal Stereocenters(IAtomContainer container, int[][] graph, EdgeToBondMap bondMap) { this.container = container; this.bondMap = bondMap; this.g = graph; this.ringSearch = new RingSearch(container, graph); this.elements = new StereoElement[g.Length]; this.stereocenters = new CenterType[g.Length]; this.numStereoElements = CreateElements(); }
/// <summary> /// Non-public constructor for-now the atom/bond semantics are fixed. /// </summary> /// <param name="query">the query structure</param> /// <param name="atomMatcher">how atoms should be matched</param> /// <param name="bondMatcher">how bonds should be matched</param> /// <param name="substructure">substructure search</param> private VentoFoggia(IAtomContainer query, AtomMatcher atomMatcher, BondMatcher bondMatcher, bool substructure) { this.query = query; this.atomMatcher = atomMatcher; this.bondMatcher = bondMatcher; this.bonds1 = EdgeToBondMap.WithSpaceFor(query); this.g1 = GraphUtil.ToAdjList(query, bonds1); this.subgraph = substructure; DetermineFilters(query); }
/// <summary> /// Determine the set of atoms that are available to have a double-bond. /// </summary> /// <param name="graph">adjacent list representation</param> /// <param name="atoms">array of atoms</param> /// <param name="bonds">map of atom indices to bonds</param> /// <returns>atoms that can require a double-bond</returns> private static BitArray IsAvailable(int[][] graph, IAtom[] atoms, EdgeToBondMap bonds) { var available = new BitArray(atoms.Length); // for all atoms, select those that require a double-bond for (int i = 0; i < atoms.Length; i++) { var atom = atoms[i]; // preconditions if (atom.FormalCharge == null) { throw new ArgumentException($"atom {i + 1} had unset formal charge"); } if (atom.ImplicitHydrogenCount == null) { throw new ArgumentException($"atom {i + 1} had unset implicit hydrogen count"); } if (!atom.IsAromatic) { continue; } // count preexisting pi-bonds, a higher bond order causes a skip int nPiBonds = 0; foreach (var w in graph[i]) { var order = bonds[i, w].Order; if (order == BondOrder.Double) { nPiBonds++; } else if (order.Numeric() > 2) { goto continue_ATOMS; } } // check if a pi bond can be assigned var element = atom.AtomicNumber; var charge = atom.FormalCharge.Value; var valence = graph[i].Length + atom.ImplicitHydrogenCount.Value + nPiBonds; if (IsAvailable(element, charge, valence)) { available.Set(i, true); } continue_ATOMS: ; } return(available); }
/// <summary> /// Create a VF state for matching isomorphisms. The query is passed first /// and should read as, find container1 in container2. /// </summary> /// <param name="container1">the molecule to search for (query)</param> /// <param name="container2">the molecule to search in (target)</param> /// <param name="g1">adjacency list of the query</param> /// <param name="g2">adjacency list of the target</param> /// <param name="bonds1">bond lookup of the query</param> /// <param name="bonds2">bond lookup of the target</param> /// <param name="atomMatcher">what semantic attributes (symbol, charge, query) determines atoms to be compatible</param> /// <param name="bondMatcher">what semantic attributes (order/aromatic, query) determines bonds to be compatible</param> public VFState(IAtomContainer container1, IAtomContainer container2, int[][] g1, int[][] g2, EdgeToBondMap bonds1, EdgeToBondMap bonds2, AtomMatcher atomMatcher, BondMatcher bondMatcher) : base(g1, g2) { this.container1 = container1; this.container2 = container2; this.bonds1 = bonds1; this.bonds2 = bonds2; this.atomMatcher = atomMatcher; this.bondMatcher = bondMatcher; }
/// <summary> /// Helper method to obtain the neighbouring bonds from an adjacency list /// graph and edge->bond map. /// </summary> /// <param name="v">vertex</param> /// <param name="g">graph (adj list)</param> /// <param name="bondMap">map of edges to bonds</param> /// <returns>neighboring bonds</returns> private static IBond[] Neighbors(int v, int[][] g, EdgeToBondMap bondMap) { var ws = g[v]; var bonds = new IBond[ws.Length]; for (int i = 0; i < ws.Length; i++) { bonds[i] = bondMap[v, ws[i]]; } return(bonds); }
/// <summary> /// Create a state for matching benzene to naphthalene Benzene: /// InChI=1/C6H6/c1-2-4-6-5-3-1/h1-6H Naphthalene: InChI=1/C10H8/c1-2-6-10-8-4-3-7-9(10)5-1/h1-8H /// </summary> UllmannState CreateBenzeneToNaphthalene(AtomMatcher atomMatcher, BondMatcher bondMatcher) { IAtomContainer container1 = TestMoleculeFactory.MakeBenzene(); IAtomContainer container2 = TestMoleculeFactory.MakeNaphthalene(); EdgeToBondMap bonds1 = EdgeToBondMap.WithSpaceFor(container1); EdgeToBondMap bonds2 = EdgeToBondMap.WithSpaceFor(container2); int[][] g1 = GraphUtil.ToAdjList(container1, bonds1); int[][] g2 = GraphUtil.ToAdjList(container2, bonds2); return(new UllmannState(container1, container2, g1, g2, bonds1, bonds2, atomMatcher, bondMatcher)); }
/// <summary> /// Create a match for the following parameters. /// </summary> /// <param name="container1">query structure</param> /// <param name="container2">target structure</param> /// <param name="g1">query adjacency list</param> /// <param name="g2">target adjacency list</param> /// <param name="bonds1">query bond map</param> /// <param name="bonds2">target bond map</param> /// <param name="atomMatcher">how atoms are matched</param> /// <param name="bondMatcher">how bonds are matched</param> public UllmannIterable(IAtomContainer container1, IAtomContainer container2, int[][] g1, int[][] g2, EdgeToBondMap bonds1, EdgeToBondMap bonds2, AtomMatcher atomMatcher, BondMatcher bondMatcher) { this.container1 = container1; this.container2 = container2; this.g1 = g1; this.g2 = g2; this.bonds1 = bonds1; this.bonds2 = bonds2; this.atomMatcher = atomMatcher; this.bondMatcher = bondMatcher; }
private static bool IsAromPath(int[] path, EdgeToBondMap bmap) { int end = path.Length - 1; for (int i = 0; i < end; i++) { if (!bmap[path[i], path[i + 1]].IsAromatic) { return(false); } } return(true); }
/// <summary> /// Create a match for the following parameters. /// </summary> /// <param name="container1">query structure</param> /// <param name="container2">target structure</param> /// <param name="g1">query adjacency list</param> /// <param name="g2">target adjacency list</param> /// <param name="bonds1">query bond map</param> /// <param name="bonds2">target bond map</param> /// <param name="atomMatcher">how atoms are matched</param> /// <param name="bondMatcher">how bonds are matched</param> /// <param name="subgraph">perform subgraph search</param> public VFIterable(IAtomContainer container1, IAtomContainer container2, int[][] g1, int[][] g2, EdgeToBondMap bonds1, EdgeToBondMap bonds2, AtomMatcher atomMatcher, BondMatcher bondMatcher, bool subgraph) { this.container1 = container1; this.container2 = container2; this.g1 = g1; this.g2 = g2; this.bonds1 = bonds1; this.bonds2 = bonds2; this.atomMatcher = atomMatcher; this.bondMatcher = bondMatcher; this.subgraph = subgraph; }
/// <summary> /// Convert a cycle in <see cref="int"/>[] representation to an <see cref="IRing"/> /// but first map back using the given <paramref name="mapping"/>. /// </summary> /// <param name="container">atom container</param> /// <param name="edges">edge map</param> /// <param name="cycle">vertex walk forming the cycle, first and last vertex the same</param> /// <returns>a new ring</returns> private static IRing ToRing(IAtomContainer container, EdgeToBondMap edges, int[] cycle, int[] mapping) { var len = cycle.Length - 1; var atoms = new IAtom[len]; var bonds = new IBond[len]; for (int i = 0; i < len; i++) { atoms[i] = container.Atoms[mapping[cycle[i]]]; bonds[i] = edges[mapping[cycle[i]], mapping[cycle[i + 1]]]; atoms[i].IsInRing = true; } var ring = container.Builder.NewRing(atoms, bonds); return(ring); }
/// <summary> /// Create a new layout refiner for the provided molecule. /// </summary> /// <param name="mol">molecule to refine</param> internal LayoutRefiner(IAtomContainer mol, ISet <IAtom> afix, ISet <IBond> bfix) { this.mol = mol; this.afix = afix; this.bfix = bfix; this.bondMap = EdgeToBondMap.WithSpaceFor(mol); this.adjList = GraphUtil.ToAdjList(mol, bondMap); this.idxs = new Dictionary <IAtom, int>(); foreach (var atom in mol.Atoms) { idxs[atom] = idxs.Count; } this.atoms = mol.Atoms.ToArray(); // buffers for storing coordinates this.buffer1 = new Vector2[atoms.Length]; this.buffer2 = new Vector2[atoms.Length]; this.backup = new Vector2[atoms.Length]; for (int i = 0; i < buffer1.Length; i++) { buffer1[i] = new Vector2(); buffer2[i] = new Vector2(); backup[i] = new Vector2(); } this.stackBackup = new IntStack(atoms.Length); this.visited = new bool[atoms.Length]; this.congestion = new Congestion(mol, adjList); // note, this is lazy so only does the shortest path when needed // and does |V| search at maximum this.apsp = new AllPairsShortestPaths(mol); // index ring systems, idx -> ring system number (rnum) int rnum = 1; this.ringsystems = new int[atoms.Length]; for (int i = 0; i < atoms.Length; i++) { if (atoms[i].IsInRing && ringsystems[i] == 0) { TraverseRing(ringsystems, i, rnum++); } } }
/// <summary> /// Assign a Kekulé representation to the aromatic systems of a compound. /// </summary> /// <param name="ac">structural representation</param> /// <exception cref="CDKException">a Kekulé form could not be assigned</exception> public static void Kekulize(IAtomContainer ac) { // storage of pairs of atoms that have pi-bonded var matching = Matching.WithCapacity(ac.Atoms.Count); // exract data structures for efficient access var atoms = ac.Atoms.ToArray(); var bonds = EdgeToBondMap.WithSpaceFor(ac); var graph = GraphUtil.ToAdjList(ac, bonds); // determine which atoms are available to have a pi bond placed var available = IsAvailable(graph, atoms, bonds); // attempt to find a perfect matching such that a pi bond is placed // next to each available atom. if not found the solution is ambiguous if (!matching.Perfect(graph, available)) { throw new CDKException("Cannot assign Kekulé structure without randomly creating radicals."); } // propagate bond order information from the matching foreach (var bond in ac.Bonds) { if (bond.Order == BondOrder.Unset && bond.IsAromatic) { bond.Order = BondOrder.Single; } } for (int v = BitArrays.NextSetBit(available, 0); v >= 0; v = BitArrays.NextSetBit(available, v + 1)) { var w = matching.Other(v); var bond = bonds[v, w]; // sanity check, something wrong if this happens if (bond.Order.Numeric() > 1) { throw new CDKException("Cannot assign Kekulé structure, non-sigma bond order has already been assigned?"); } bond.Order = BondOrder.Double; available.Set(w, false); } }
/// <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); }