Ejemplo n.º 1
0
 /// <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);
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Read a bracket atom from the buffer. A bracket atom optionally defines
        /// isotope, chirality, hydrogen count, formal charge and the atom class.
        /// <para>
        /// bracket_atom ::= '[' isotope? symbol chiral? hcount? charge? class? ']'
        /// </para>
        /// </summary>
        /// <param name="buffer">a character buffer</param>
        /// <returns>a bracket atom</returns>
        /// <exception cref="InvalidSmilesException">if the bracket atom did not match the grammar, invalid symbol, missing closing bracket or invalid chiral specification.</exception>
        public IAtom ReadBracketAtom(CharBuffer buffer)
        {
            int start = buffer.Position;

            bool arbitraryLabel = false;

            if (!buffer.HasRemaining())
            {
                throw new InvalidSmilesException("Unclosed bracket atom, SMILES may be truncated", buffer);
            }

            var isotope  = buffer.GetNumber();
            var aromatic = buffer.NextChar >= 'a' && buffer.NextChar <= 'z';
            var element  = Element.Read(buffer);

            if (element == Element.Unknown)
            {
                hasAstrix = true;
            }

            if (strict && element == null)
            {
                throw new InvalidSmilesException("unrecognised element symbol, SMILES may be truncated: ", buffer);
            }

            if (element != null && aromatic)
            {
                g.AddFlags(Graph.HAS_AROM);
            }

            // element isn't aromatic as per the OpenSMILES specification
            if (strict && aromatic && !element.IsAromatic(Element.AromaticSpecification.OpenSmiles))
            {
                throw new InvalidSmilesException("abnormal aromatic element", buffer);
            }

            if (element == null)
            {
                arbitraryLabel = true;
            }

            configuration = Configuration.Read(buffer);

            var hCount    = ReadHydrogens(buffer);
            var charge    = ReadCharge(buffer);
            var atomClass = ReadClass(buffer);

            if (!arbitraryLabel && !buffer.GetIf(']'))
            {
                if (strict)
                {
                    throw InvalidSmilesException.InvalidBracketAtom(buffer);
                }
                else
                {
                    arbitraryLabel = true;
                }
            }

            if (arbitraryLabel)
            {
                var end   = buffer.Position;
                int depth = 1;
                while (buffer.HasRemaining())
                {
                    char c = buffer.Get();
                    if (c == '[')
                    {
                        depth++;
                    }
                    else if (c == ']')
                    {
                        depth--;
                        if (depth == 0)
                        {
                            break;
                        }
                    }
                    end++;
                }
                if (depth != 0)
                {
                    throw new InvalidSmilesException("unparsable label in bracket atom",
                                                     buffer,
                                                     buffer.Position - 1);
                }
                var label = buffer.Substr(start, end);
                hasAstrix = true;
                return(new AtomImpl.BracketAtom(label));
            }

            return(new AtomImpl.BracketAtom(isotope,
                                            element,
                                            hCount,
                                            charge,
                                            atomClass,
                                            aromatic));
        }
Ejemplo n.º 3
0
        /// <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}");
                    }
                }
            }
        }