/// <summary> /// Decide the bond to use for a ring bond. The bond symbol can be present on /// either or both bonded atoms. This method takes those bonds, chooses the /// correct one or reports an error if there is a conflict. /// </summary> /// <remarks> /// Equivalent SMILES: /// <list type="bullet"> /// <item>C=1CCCCC=1</item> /// <item>C=1CCCCC1 (preferred)</item> /// <item>C1CCCCC=1</item> /// </list> /// </remarks> /// <param name="a">a bond</param> /// <param name="b">other bond</param> /// <param name="pos">the position in the string of bond <paramref name="a"/></param> /// <param name="buffer"></param> /// <returns>the bond to use for this edge</returns> /// <exception cref="InvalidSmilesException">ring bonds did not match</exception> public Bond DecideBond(Bond a, Bond b, int pos, CharBuffer buffer) { if (a == b) { return(a); } else if (a == Bond.Implicit) { return(b); } else if (b == Bond.Implicit) { return(a); } if (strict || a.Inverse() != b) { throw new InvalidSmilesException($"Ring closure bonds did not match, '{a}'!='{b}':" + InvalidSmilesException.Display(buffer, pos - buffer.Position, lastBondPos - buffer.Position)); } warnings.Add("Ignored invalid Cis/Trans on ring closure, should flip:" + InvalidSmilesException.Display(buffer, pos - buffer.Position, lastBondPos - buffer.Position)); return(Bond.Implicit); }
/// <summary> /// Create the topologies (stereo configurations) for the chemical graph. The /// topologies define spacial arrangement around atoms. /// </summary> private void CreateTopologies(CharBuffer buffer) { // create topologies (stereo configurations) foreach (var e in configurations) { AddTopology(e.Key, Topology.ToExplicit(g, e.Key, e.Value)); } for (int v = BitArrays.NextSetBit(checkDirectionalBonds, 0); v >= 0; v = BitArrays.NextSetBit(checkDirectionalBonds, v + 1)) { int nUpV = 0; int nDownV = 0; int nUpW = 0; int nDownW = 0; int w = -1; { int d = g.Degree(v); for (int j = 0; j < d; ++j) { Edge e = g.EdgeAt(v, j); Bond bond = e.GetBond(v); if (bond == Bond.Up) { nUpV++; } else if (bond == Bond.Down) { nDownV++; } else if (bond == Bond.Double) { w = e.Other(v); } } } if (w < 0) { continue; } BitArrays.EnsureCapacity(checkDirectionalBonds, w + 1); checkDirectionalBonds.Set(w, false); { int d = g.Degree(w); for (int j = 0; j < d; ++j) { Edge e = g.EdgeAt(w, j); Bond bond = e.GetBond(w); if (bond == Bond.Up) { nUpW++; } else if (bond == Bond.Down) { nDownW++; } } } if (nUpV + nDownV == 0 || nUpW + nDownW == 0) { continue; } if (nUpV > 1 || nDownV > 1) { int offset1 = -1, offset2 = -1; foreach (var e in g.GetEdges(v)) { if (e.Bond.IsDirectional) { if (offset1 < 0) { offset1 = bondStrPos[e]; } else { offset2 = bondStrPos[e]; } } } var errorPos = InvalidSmilesException.Display(buffer, offset1 - buffer.Length, offset2 - buffer.Length); if (strict) { throw new InvalidSmilesException($"Ignored invalid Cis/Trans specification: {errorPos}"); } else { warnings.Add($"Ignored invalid Cis/Trans specification: {errorPos}"); } } if (nUpW > 1 || nDownW > 1) { int offset1 = -1; int offset2 = -1; foreach (var e in g.GetEdges(w)) { if (e.Bond.IsDirectional) { if (offset1 < 0) { offset1 = bondStrPos[e]; } else { offset2 = bondStrPos[e]; } } } var errorPos = InvalidSmilesException.Display(buffer, offset1 - buffer.Length, offset2 - buffer.Length); if (strict) { throw new InvalidSmilesException($"Ignored invalid Cis/Trans specification: {errorPos}"); } else { warnings.Add($"Ignored invalid Cis/Trans specification: {errorPos}"); } } } }