/// <summary> /// Labels para stereocenter in isolated rings. Any elements which are now /// known to not be stereo centers are also eliminated. /// </summary> /// <param name="symmetry">the symmetry classes of each atom</param> private void LabelIsolatedPara(int[] symmetry) { // auxiliary array, has the symmetry class already been 'visited' var visited = new bool[symmetry.Length + 1]; foreach (var isolated in ringSearch.Isolated()) { var potential = new List <StereoElement>(); var trueCentres = new List <StereoElement>(); var cyclic = new BitArray(1000); foreach (var v in isolated) { cyclic.Set(v, true); if (stereocenters[v] == CenterType.Potential) { potential.Add(elements[v]); } else if (stereocenters[v] == CenterType.True) { trueCentres.Add(elements[v]); } } // there is only 1 potential and 0 true stereocenters in this cycle // the element is not a stereocenter if (potential.Count + trueCentres.Count < 2) { foreach (var element in potential) { stereocenters[element.focus] = CenterType.None; } continue; } List <StereoElement> paraElements = new List <StereoElement>(); foreach (var element in potential) { switch (element.type) { case CoordinateType.Tetracoordinate: { int[] ws = element.neighbors; int nUnique = 0; bool terminal = true; foreach (var w in ws) { if (!cyclic[w]) { if (!visited[symmetry[w]]) { visited[symmetry[w]] = true; nUnique++; } else { if (g[w].Length > 1) { terminal = false; } } } } // reset for next element foreach (var w in ws) { visited[symmetry[w]] = false; } int deg = g[element.focus].Length; if (deg == 3 || (deg == 4 && nUnique == 2)) { paraElements.Add(element); } // remove those we know cannot possibly be stereocenters if (deg == 4 && nUnique == 1 && terminal) { stereocenters[element.focus] = CenterType.None; } } break; case CoordinateType.Tricoordinate: { Tricoordinate either = (Tricoordinate)element; if (stereocenters[either.other] == CenterType.True) { paraElements.Add(element); } } break; } } if (paraElements.Count + trueCentres.Count >= 2) { foreach (var para in paraElements) { stereocenters[para.focus] = CenterType.Para; } } else { foreach (var para in paraElements) { stereocenters[para.focus] = CenterType.None; } } } }
/// <summary> /// Create <see cref="StereoElement"/> /// instance for atoms which support stereochemistry. Each new element is /// considered a potential stereo center - any atoms which have not been /// assigned an element are non stereo centers. /// </summary> /// <returns>the number of elements created</returns> private int CreateElements() { bool[] tricoordinate = new bool[g.Length]; int nElements = 0; // all atoms we don't define as potential are considered // non-stereogenic Arrays.Fill(stereocenters, CenterType.None); for (int i = 0; i < g.Length; i++) { // determine hydrogen count, connectivity and valence int h = container.Atoms[i].ImplicitHydrogenCount.Value; int x = g[i].Length + h; int d = g[i].Length; int v = h; if (x < 2 || x > 4 || h > 1) { continue; } int piNeighbor = 0; foreach (var w in g[i]) { if (GetAtomicNumber(container.Atoms[w]) == 1 && container.Atoms[w].MassNumber == null) { h++; } switch (bondMap[i, w].Order) { case BondOrder.Single: v++; break; case BondOrder.Double: v += 2; piNeighbor = w; break; default: // triple, quadruple or unset? can't be a stereo centre goto GoNext_VERTICES; } } // check the type of stereo chemistry supported switch (SupportedType(i, v, d, h, x)) { case CoordinateType.Bicoordinate: stereocenters[i] = CenterType.Potential; elements[i] = new Bicoordinate(i, g[i]); nElements++; int u = g[i][0]; int w = g[i][1]; if (tricoordinate[u]) { stereocenters[u] = CenterType.Potential; elements[u] = new Tricoordinate(u, i, g[u]); } if (tricoordinate[w]) { stereocenters[w] = CenterType.Potential; elements[w] = new Tricoordinate(w, i, g[w]); } break; case CoordinateType.Tricoordinate: u = i; w = piNeighbor; tricoordinate[u] = true; if (!tricoordinate[w]) { if (elements[w] != null && elements[w].type == CoordinateType.Bicoordinate) { stereocenters[u] = CenterType.Potential; elements[u] = new Tricoordinate(u, w, g[u]); } continue; } stereocenters[w] = CenterType.Potential; stereocenters[u] = CenterType.Potential; elements[u] = new Tricoordinate(u, w, g[u]); elements[w] = new Tricoordinate(w, u, g[w]); nElements++; break; case CoordinateType.Tetracoordinate: elements[i] = new Tetracoordinate(i, g[i]); stereocenters[i] = CenterType.Potential; nElements++; break; default: stereocenters[i] = CenterType.None; break; } GoNext_VERTICES: ; } // link up tetracoordinate atoms accross cumulate systems for (int v = 0; v < g.Length; v++) { if (elements[v] != null && elements[v].type == CoordinateType.Bicoordinate) { int u = elements[v].neighbors[0]; int w = elements[v].neighbors[1]; if (elements[u] != null && elements[w] != null && elements[u].type == CoordinateType.Tricoordinate && elements[w].type == CoordinateType.Tricoordinate) { ((Tricoordinate)elements[u]).other = w; ((Tricoordinate)elements[w]).other = u; } } } return(nElements); }