Ejemplo n.º 1
0
        /// <summary>
        /// Generates and assigns abbreviations to a molecule. Abbreviations are first
        /// generated with <see cref="Generate(IAtomContainer)"/> and the filtered based on
        /// the coverage. Currently only abbreviations that cover 100%, or &lt; 40% of the
        /// atoms are assigned.
        /// </summary>
        /// <param name="mol">molecule</param>
        /// <returns>number of new abbreviations</returns>
        /// <seealso cref="Generate(IAtomContainer)"/>
        public int Apply(IAtomContainer mol)
        {
            var newSgroups = Generate(mol);
            var sgroups    = mol.GetCtabSgroups();

            if (sgroups == null)
            {
                sgroups = new List <Sgroup>();
            }
            else
            {
                sgroups = new List <Sgroup>(sgroups);
            }

            var prev = sgroups.Count;

            foreach (var sgroup in newSgroups)
            {
                var coverage = sgroup.Atoms.Count / (double)mol.Atoms.Count;
                // update xml comment if changed!
                if (!sgroup.Bonds.Any() || coverage < 0.4d)
                {
                    sgroups.Add(sgroup);
                }
            }
            mol.SetCtabSgroups(sgroups);
            return(sgroups.Count - prev);
        }
Ejemplo n.º 2
0
        private bool WriteV3000(IAtomContainer container)
        {
            if (paramWriteV3000.IsSet)
            {
                return(true);
            }
            if (container.Atoms.Count > 999)
            {
                return(true);
            }
            if (container.Bonds.Count > 999)
            {
                return(true);
            }
            // check for positional variation, this can be output in base V3000 and not V2000
            var sgroups = container.GetCtabSgroups();

            if (sgroups != null)
            {
                foreach (Sgroup sgroup in sgroups)
                {
                    if (sgroup.Type == SgroupType.ExtMulticenter)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Generate the Sgroup elements for the provided atom contains.
        /// </summary>
        /// <param name="container">molecule</param>
        /// <returns>Sgroup rendering elements</returns>
        IRenderingElement GenerateSgroups(IAtomContainer container, AtomSymbol[] symbols)
        {
            var result  = new ElementGroup();
            var sgroups = container.GetCtabSgroups();

            if (sgroups == null || !sgroups.Any())
            {
                return(result);
            }

            var symbolMap = new Dictionary <IAtom, AtomSymbol>();

            for (int i = 0; i < symbols.Length; i++)
            {
                if (symbols[i] != null)
                {
                    symbolMap[container.Atoms[i]] = symbols[i];
                }
            }

            foreach (var sgroup in sgroups)
            {
                switch (sgroup.Type)
                {
                case SgroupType.CtabAbbreviation:
                    result.Add(GenerateAbbreviationSgroup(container, sgroup));
                    break;

                case SgroupType.CtabMultipleGroup:
                    result.Add(GenerateMultipleSgroup(sgroup));
                    break;

                case SgroupType.CtabAnyPolymer:
                case SgroupType.CtabMonomer:
                case SgroupType.CtabCrossLink:
                case SgroupType.CtabCopolymer:
                case SgroupType.CtabStructureRepeatUnit:
                case SgroupType.CtabMer:
                case SgroupType.CtabGraft:
                case SgroupType.CtabModified:
                    result.Add(GeneratePolymerSgroup(sgroup, symbolMap));
                    break;

                case SgroupType.CtabComponent:
                case SgroupType.CtabMixture:
                case SgroupType.CtabFormulation:
                    result.Add(GenerateMixtureSgroup(sgroup));
                    break;

                case SgroupType.CtabGeneric:
                    // not strictly a polymer but okay to draw as one
                    result.Add(GeneratePolymerSgroup(sgroup, null));
                    break;
                }
            }

            return(result);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// If the molecule has display shortcuts (abbreviations or multiple group sgroups) certain parts
        /// of the structure are hidden from display. This method marks the parts to hide and in the case
        /// of abbreviations, remaps atom symbols. Apart from additional property flags, the molecule
        /// is unchanged by this method.
        /// </summary>
        /// <param name="container">molecule input</param>
        /// <param name="symbolRemap">a map that will hold symbol remapping</param>
        public static void PrepareDisplayShortcuts(IAtomContainer container, IDictionary <IAtom, string> symbolRemap)
        {
            var sgroups = container.GetCtabSgroups();

            if (sgroups == null || !sgroups.Any())
            {
                return;
            }

            // select abbreviations that should be contracted
            foreach (var sgroup in sgroups)
            {
                if (sgroup.Type == SgroupType.CtabAbbreviation)
                {
                    bool?expansion = (bool?)sgroup.GetValue(SgroupKey.CtabExpansion);
                    // abbreviation is displayed as expanded
                    if (expansion ?? false)
                    {
                        continue;
                    }
                    // no or empty label, skip it
                    if (string.IsNullOrEmpty(sgroup.Subscript))
                    {
                        continue;
                    }

                    // only contract if the atoms are either partially or fully highlighted
                    if (CheckAbbreviationHighlight(container, sgroup))
                    {
                        ContractAbbreviation(container, symbolRemap, sgroup);
                    }
                }
                else if (sgroup.Type == SgroupType.CtabMultipleGroup)
                {
                    HideMultipleParts(container, sgroup);
                }
                else if (sgroup.Type == SgroupType.ExtMulticenter)
                {
                    var atoms = sgroup.Atoms;
                    // should only be one bond
                    foreach (var bond in sgroup.Bonds)
                    {
                        var beg = bond.Begin;
                        var end = bond.End;
                        if (atoms.Contains(beg))
                        {
                            StandardGenerator.HideFully(beg);
                        }
                        else
                        {
                            StandardGenerator.HideFully(end);
                        }
                    }
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Safely access the Sgroups of a molecule retuning an empty list
        /// if none are defined..
        /// </summary>
        /// <param name="mol">molecule</param>
        /// <returns>the sgroups</returns>
        private static IList <Sgroup> GetSgroups(IAtomContainer mol)
        {
            var sgroups = mol.GetCtabSgroups();

            if (sgroups == null)
            {
                sgroups = Array.Empty <Sgroup>();
            }
            return(sgroups);
        }
Ejemplo n.º 6
0
 public void PositionalVariation()
 {
     using (MDLV3000Reader reader = new MDLV3000Reader(GetType().Assembly.GetManifestResourceStream(GetType(), "multicenterBond.mol")))
     {
         IAtomContainer container = reader.Read(builder.NewAtomContainer());
         Assert.AreEqual(8, container.Bonds.Count);
         var sgroups = container.GetCtabSgroups();
         Assert.IsNotNull(sgroups);
         Assert.AreEqual(1, sgroups.Count);
         Assert.AreEqual(SgroupType.ExtMulticenter, sgroups[0].Type);
     }
 }
Ejemplo n.º 7
0
        // utility method that safely collects the Sgroup from a molecule
        private static void SafeAddSgroups(List <Sgroup> sgroups, IAtomContainer mol)
        {
            var molSgroups = mol.GetCtabSgroups();

            if (molSgroups != null)
            {
                foreach (var g in molSgroups)
                {
                    sgroups.Add(g);
                }
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Write the bonds of a molecule.
        /// </summary>
        /// <param name="mol">molecule</param>
        /// <param name="idxs">index lookup</param>
        /// <exception cref="IOException">low-level IO error</exception>
        /// <exception cref="CDKException">inconsistent state etc</exception>
        private void WriteBondBlock(IAtomContainer mol, IReadOnlyDictionary <IChemObject, int> idxs)
        {
            if (mol.Bonds.Count == 0)
            {
                return;
            }

            // collect multicenter Sgroups before output
            var sgroups            = mol.GetCtabSgroups();
            var multicenterSgroups = new Dictionary <IBond, Sgroup>();

            if (sgroups != null)
            {
                foreach (var sgroup in sgroups)
                {
                    if (sgroup.Type != SgroupType.ExtMulticenter)
                    {
                        continue;
                    }
                    foreach (var bond in sgroup.Bonds)
                    {
                        multicenterSgroups[bond] = sgroup;
                    }
                }
            }

            writer.Write("BEGIN BOND\n");
            int bondIdx = 0;

            foreach (var bond in mol.Bonds)
            {
                var beg = bond.Begin;
                var end = bond.End;
                if (beg == null || end == null)
                {
                    throw new InvalidOperationException($"Bond {bondIdx} had one or more atoms.");
                }
                int begIdx = FindIdx(idxs, beg);
                int endIdx = FindIdx(idxs, end);
                if (begIdx < 0 || endIdx < 0)
                {
                    throw new InvalidOperationException($"Bond {bondIdx} had atoms not present in the molecule.");
                }

                var stereo = bond.Stereo;

                // swap beg/end if needed
                if (stereo == BondStereo.UpInverted ||
                    stereo == BondStereo.DownInverted ||
                    stereo == BondStereo.UpOrDownInverted)
                {
                    int tmp = begIdx;
                    begIdx = endIdx;
                    endIdx = tmp;
                }

                var order = bond.Order.Numeric();

                if (order < 1 || order > 3)
                {
                    throw new CDKException($"Bond order {bond.Order} cannot be written to V3000");
                }

                writer.Write(++bondIdx)
                .Write(' ')
                .Write(order)
                .Write(' ')
                .Write(begIdx)
                .Write(' ')
                .Write(endIdx);

                switch (stereo)
                {
                case BondStereo.Up:
                case BondStereo.UpInverted:
                    writer.Write(" CFG=1");
                    break;

                case BondStereo.UpOrDown:
                case BondStereo.UpOrDownInverted:
                    writer.Write(" CFG=2");
                    break;

                case BondStereo.Down:
                case BondStereo.DownInverted:
                    writer.Write(" CFG=3");
                    break;

                case BondStereo.None:
                    break;

                default:
                    // warn?
                    break;
                }

                if (multicenterSgroups.TryGetValue(bond, out Sgroup sgroup))
                {
                    var atoms = new List <IAtom>(sgroup.Atoms);
                    atoms.Remove(bond.Begin);
                    atoms.Remove(bond.End);
                    writer.Write(" ATTACH=Any ENDPTS=(").Write(atoms, idxs).Write(')');
                }

                writer.Write('\n');
            }
            writer.Write("END BOND\n");
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Reads the bond atoms, order and stereo configuration.
        /// </summary>
        public void ReadBondBlock(IAtomContainer readData)
        {
            Trace.TraceInformation("Reading BOND block");
            bool foundEND = false;

            while (!foundEND)
            {
                string command = ReadCommand(ReadLine());
                if (string.Equals("END BOND", command, StringComparison.Ordinal))
                {
                    foundEND = true;
                }
                else
                {
                    Debug.WriteLine($"Parsing bond from: {command}");
                    var   tokenizer = Strings.Tokenize(command).GetEnumerator();
                    IBond bond      = readData.Builder.NewBond();
                    // parse the index
                    try
                    {
                        tokenizer.MoveNext();
                        string indexString = tokenizer.Current;
                        bond.Id = indexString;
                    }
                    catch (Exception exception)
                    {
                        string error = "Error while parsing bond index";
                        Trace.TraceError(error);
                        Debug.WriteLine(exception);
                        throw new CDKException(error, exception);
                    }
                    // parse the order
                    try
                    {
                        tokenizer.MoveNext();
                        string orderString = tokenizer.Current;
                        int    order       = int.Parse(orderString, NumberFormatInfo.InvariantInfo);
                        if (order >= 4)
                        {
                            Trace.TraceWarning("Query order types are not supported (yet). File a bug if you need it");
                        }
                        else
                        {
                            bond.Order = BondManipulator.CreateBondOrder((double)order);
                        }
                    }
                    catch (Exception exception)
                    {
                        string error = "Error while parsing bond index";
                        Trace.TraceError(error);
                        Debug.WriteLine(exception);
                        throw new CDKException(error, exception);
                    }
                    // parse index atom 1
                    try
                    {
                        tokenizer.MoveNext();
                        string indexAtom1String = tokenizer.Current;
                        int    indexAtom1       = int.Parse(indexAtom1String, NumberFormatInfo.InvariantInfo);
                        IAtom  atom1            = readData.Atoms[indexAtom1 - 1];
                        bond.Atoms.Add(atom1);  // bond.Atoms[0]
                    }
                    catch (Exception exception)
                    {
                        string error = "Error while parsing index atom 1 in bond";
                        Trace.TraceError(error);
                        Debug.WriteLine(exception);
                        throw new CDKException(error, exception);
                    }
                    // parse index atom 2
                    try
                    {
                        tokenizer.MoveNext();
                        string indexAtom2String = tokenizer.Current;
                        int    indexAtom2       = int.Parse(indexAtom2String, NumberFormatInfo.InvariantInfo);
                        IAtom  atom2            = readData.Atoms[indexAtom2 - 1];
                        bond.Atoms.Add(atom2); // bond.Atoms[1]
                    }
                    catch (Exception exception)
                    {
                        string error = "Error while parsing index atom 2 in bond";
                        Trace.TraceError(error);
                        Debug.WriteLine(exception);
                        throw new CDKException(error, exception);
                    }

                    var    endpts = new List <IAtom>();
                    string attach = null;

                    // the rest are key=value fields
                    if (command.IndexOf('=') != -1)
                    {
                        var options = ParseOptions(ExhaustStringTokenizer(tokenizer));
                        foreach (var key in options.Keys)
                        {
                            string value = options[key];
                            try
                            {
                                switch (key)
                                {
                                case "CFG":
                                    int configuration = int.Parse(value, NumberFormatInfo.InvariantInfo);
                                    if (configuration == 0)
                                    {
                                        bond.Stereo = BondStereo.None;
                                    }
                                    else if (configuration == 1)
                                    {
                                        bond.Stereo = BondStereo.Up;
                                    }
                                    else if (configuration == 2)
                                    {
                                        bond.Stereo = BondStereo.None;
                                    }
                                    else if (configuration == 3)
                                    {
                                        bond.Stereo = BondStereo.Down;
                                    }
                                    break;

                                case "ENDPTS":
                                    string[] endptStr = value.Split(' ');
                                    // skip first value that is count
                                    for (int i = 1; i < endptStr.Length; i++)
                                    {
                                        endpts.Add(readData.Atoms[int.Parse(endptStr[i], NumberFormatInfo.InvariantInfo) - 1]);
                                    }
                                    break;

                                case "ATTACH":
                                    attach = value;
                                    break;

                                default:
                                    Trace.TraceWarning("Not parsing key: " + key);
                                    break;
                                }
                            }
                            catch (Exception exception)
                            {
                                string error = "Error while parsing key/value " + key + "=" + value + ": "
                                               + exception.Message;
                                Trace.TraceError(error);
                                Debug.WriteLine(exception);
                                throw new CDKException(error, exception);
                            }
                        }
                    }

                    // storing bond
                    readData.Bonds.Add(bond);

                    // storing positional variation
                    if (string.Equals("ANY", attach, StringComparison.Ordinal))
                    {
                        Sgroup sgroup = new Sgroup {
                            Type = SgroupType.ExtMulticenter
                        };
                        sgroup.Atoms.Add(bond.Begin); // could be other end?
                        sgroup.Bonds.Add(bond);
                        foreach (var endpt in endpts)
                        {
                            sgroup.Atoms.Add(endpt);
                        }

                        var sgroups = readData.GetCtabSgroups();
                        if (sgroups == null)
                        {
                            readData.SetCtabSgroups(sgroups = new List <Sgroup>(4));
                        }
                        sgroups.Add(sgroup);
                    }

                    Debug.WriteLine($"Added bond: {bond}");
                }
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Find all enabled abbreviations in the provided molecule. They are not
        /// added to the existing Sgroups and may need filtering.
        /// </summary>
        /// <param name="mol">molecule</param>
        /// <returns>list of new abbreviation Sgroups</returns>
        public IList <Sgroup> Generate(IAtomContainer mol)
        {
            // mark which atoms have already been abbreviated or are
            // part of an existing Sgroup
            var usedAtoms = new HashSet <IAtom>();
            var sgroups   = mol.GetCtabSgroups();

            if (sgroups != null)
            {
                foreach (var sgroup in sgroups)
                {
                    foreach (var atom in sgroup.Atoms)
                    {
                        usedAtoms.Add(atom);
                    }
                }
            }

            var newSgroups = new List <Sgroup>();

            // disconnected abbreviations, salts, common reagents, large compounds
            if (!usedAtoms.Any())
            {
                try
                {
                    var    copy   = AtomContainerManipulator.CopyAndSuppressedHydrogens(mol);
                    string cansmi = usmigen.Create(copy);
                    if (disconnectedAbbreviations.TryGetValue(cansmi, out string label) && !disabled.Contains(label) && ContractToSingleLabel)
                    {
                        var sgroup = new Sgroup
                        {
                            Type      = SgroupType.CtabAbbreviation,
                            Subscript = label
                        };
                        foreach (var atom in mol.Atoms)
                        {
                            sgroup.Atoms.Add(atom);
                        }
                        return(new[] { sgroup });
                    }
                    else if (cansmi.Contains("."))
                    {
                        var parts = ConnectivityChecker.PartitionIntoMolecules(mol);

                        // leave one out
                        Sgroup best = null;
                        for (int i = 0; i < parts.Count; i++)
                        {
                            var a = parts[i];
                            var b = a.Builder.NewAtomContainer();
                            for (int j = 0; j < parts.Count; j++)
                            {
                                if (j != i)
                                {
                                    b.Add(parts[j]);
                                }
                            }
                            var sgroup1 = GetAbbr(a);
                            var sgroup2 = GetAbbr(b);
                            if (sgroup1 != null && sgroup2 != null && ContractToSingleLabel)
                            {
                                var combined = new Sgroup();
                                label = null;
                                foreach (var atom in sgroup1.Atoms)
                                {
                                    combined.Atoms.Add(atom);
                                }
                                foreach (var atom in sgroup2.Atoms)
                                {
                                    combined.Atoms.Add(atom);
                                }
                                if (sgroup1.Subscript.Length > sgroup2.Subscript.Length)
                                {
                                    combined.Subscript = sgroup1.Subscript + String_Interpunct + sgroup2.Subscript;
                                }
                                else
                                {
                                    combined.Subscript = sgroup2.Subscript + String_Interpunct + sgroup1.Subscript;
                                }
                                combined.Type = SgroupType.CtabAbbreviation;
                                return(new[] { combined });
                            }
                            if (sgroup1 != null && (best == null || sgroup1.Atoms.Count > best.Atoms.Count))
                            {
                                best = sgroup1;
                            }
                            if (sgroup2 != null && (best == null || sgroup2.Atoms.Count < best.Atoms.Count))
                            {
                                best = sgroup2;
                            }
                        }
                        if (best != null)
                        {
                            newSgroups.Add(best);
                            foreach (var atom in best.Atoms)
                            {
                                usedAtoms.Add(atom);
                            }
                        }
                    }
                }
                catch (CDKException)
                {
                }
            }

            var fragments  = GenerateFragments(mol);
            var sgroupAdjs = new MultiDictionary <IAtom, Sgroup>();

            foreach (var frag in fragments)
            {
                try
                {
                    var smi = usmigen.Create(AtomContainerManipulator.CopyAndSuppressedHydrogens(frag));
                    if (!connectedAbbreviations.TryGetValue(smi, out string label) || disabled.Contains(label))
                    {
                        continue;
                    }

                    bool overlap = false;

                    // note: first atom is '*'
                    var numAtoms = frag.Atoms.Count;
                    var numBonds = frag.Bonds.Count;
                    for (int i = 1; i < numAtoms; i++)
                    {
                        if (usedAtoms.Contains(frag.Atoms[i]))
                        {
                            overlap = true;
                            break;
                        }
                    }

                    // overlaps with previous assignment
                    if (overlap)
                    {
                        continue;
                    }

                    // create new abbreviation Sgroup
                    var sgroup = new Sgroup
                    {
                        Type      = SgroupType.CtabAbbreviation,
                        Subscript = label
                    };

                    var   attachBond = frag.Bonds[0].GetProperty <IBond>(PropertyName_CutBond);
                    IAtom attachAtom = null;
                    sgroup.Bonds.Add(attachBond);
                    for (int i = 1; i < numAtoms; i++)
                    {
                        var atom = frag.Atoms[i];
                        usedAtoms.Add(atom);
                        sgroup.Atoms.Add(atom);
                        if (attachBond.Begin.Equals(atom))
                        {
                            attachAtom = attachBond.End;
                        }
                        else if (attachBond.End.Equals(atom))
                        {
                            attachAtom = attachBond.Begin;
                        }
                    }

                    if (attachAtom != null)
                    {
                        sgroupAdjs.Add(attachAtom, sgroup);
                    }
                    newSgroups.Add(sgroup);
                }
                catch (CDKException)
                {
                    // ignore
                }
            }

            if (!ContractOnHetero)
            {
                return(newSgroups);
            }

            // now collapse
            foreach (var attach in mol.Atoms)
            {
                if (usedAtoms.Contains(attach))
                {
                    continue;
                }

                // skip charged or isotopic labelled, C or R/*, H, He
                if ((attach.FormalCharge != null && attach.FormalCharge != 0) ||
                    attach.MassNumber != null ||
                    attach.AtomicNumber == 6 ||
                    attach.AtomicNumber < 2)
                {
                    continue;
                }

                var hcount   = attach.ImplicitHydrogenCount.Value;
                var xatoms   = new HashSet <IAtom>();
                var xbonds   = new HashSet <IBond>();
                var newbonds = new HashSet <IBond>();
                xatoms.Add(attach);

                var nbrSymbols = new List <string>();
                var todelete   = new HashSet <Sgroup>();
                foreach (var sgroup in sgroupAdjs[attach])
                {
                    if (ContainsChargeChar(sgroup.Subscript))
                    {
                        continue;
                    }
                    if (sgroup.Bonds.Count != 1)
                    {
                        continue;
                    }
                    var xbond = sgroup.Bonds.First();
                    xbonds.Add(xbond);
                    foreach (var a in sgroup.Atoms)
                    {
                        xatoms.Add(a);
                    }
                    if (attach.Symbol.Length == 1 &&
                        char.IsLower(sgroup.Subscript[0]))
                    {
                        if (ChemicalElement.OfSymbol(attach.Symbol + sgroup.Subscript[0]) != ChemicalElement.R)
                        {
                            goto continue_collapse;
                        }
                    }
                    nbrSymbols.Add(sgroup.Subscript);
                    todelete.Add(sgroup);
                }
                int numSGrpNbrs = nbrSymbols.Count;
                foreach (var bond in mol.GetConnectedBonds(attach))
                {
                    if (!xbonds.Contains(bond))
                    {
                        var nbr = bond.GetOther(attach);
                        // contract terminal bonds
                        if (mol.GetConnectedBonds(nbr).Count() == 1)
                        {
                            if (nbr.MassNumber != null ||
                                (nbr.FormalCharge != null && nbr.FormalCharge != 0))
                            {
                                newbonds.Add(bond);
                            }
                            else if (nbr.AtomicNumber == 1)
                            {
                                hcount++;
                                xatoms.Add(nbr);
                            }
                            else if (nbr.AtomicNumber > 0)
                            {
                                nbrSymbols.Add(NewSymbol(nbr.AtomicNumber, nbr.ImplicitHydrogenCount.Value, false));
                                xatoms.Add(nbr);
                            }
                        }
                        else
                        {
                            newbonds.Add(bond);
                        }
                    }
                }

                // reject if no symbols
                // reject if no bonds (<1), except if all symbols are identical... (HashSet.size==1)
                // reject if more that 2 bonds
                if (!nbrSymbols.Any() ||
                    newbonds.Count < 1 && (new HashSet <string>(nbrSymbols).Count != 1) ||
                    newbonds.Count > 2)
                {
                    continue;
                }

                // create the symbol
                var sb = new StringBuilder();
                sb.Append(NewSymbol(attach.AtomicNumber, hcount, newbonds.Count == 0));
                string prev  = null;
                int    count = 0;
                nbrSymbols.Sort((o1, o2) =>
                {
                    int cmp = o1.Length.CompareTo(o2.Length);
                    if (cmp != 0)
                    {
                        return(cmp);
                    }
                    return(o1.CompareTo(o2));
                });
                foreach (string nbrSymbol in nbrSymbols)
                {
                    if (nbrSymbol.Equals(prev))
                    {
                        count++;
                    }
                    else
                    {
                        bool useParen = count == 0 || CountUpper(prev) > 1 || (prev != null && nbrSymbol.StartsWith(prev));
                        AppendGroup(sb, prev, count, useParen);
                        prev  = nbrSymbol;
                        count = 1;
                    }
                }
                AppendGroup(sb, prev, count, false);

                // remove existing
                foreach (var e in todelete)
                {
                    newSgroups.Remove(e);
                }

                // create new
                var newSgroup = new Sgroup
                {
                    Type      = SgroupType.CtabAbbreviation,
                    Subscript = sb.ToString()
                };
                foreach (var bond in newbonds)
                {
                    newSgroup.Bonds.Add(bond);
                }
                foreach (var atom in xatoms)
                {
                    newSgroup.Atoms.Add(atom);
                }

                newSgroups.Add(newSgroup);
                foreach (var a in xatoms)
                {
                    usedAtoms.Add(a);
                }
continue_collapse:
                ;
            }

            return(newSgroups);
        }
Ejemplo n.º 11
0
        // Creates a CxSmilesState from a molecule with atom labels, repeat units, multi-center bonds etc
        private static CxSmilesState GetCxSmilesState(SmiFlavors flavour, IAtomContainer mol)
        {
            CxSmilesState state = new CxSmilesState
            {
                atomCoords = new List <double[]>(),
                coordFlag  = false
            };

            // set the atom labels, values, and coordinates,
            // and build the atom->idx map required by other parts
            var atomidx = new Dictionary <IAtom, int>();

            for (int idx = 0; idx < mol.Atoms.Count; idx++)
            {
                IAtom atom = mol.Atoms[idx];
                if (atom is IPseudoAtom)
                {
                    if (state.atomLabels == null)
                    {
                        state.atomLabels = new SortedDictionary <int, string>();
                    }

                    IPseudoAtom pseudo = (IPseudoAtom)atom;
                    if (pseudo.AttachPointNum > 0)
                    {
                        state.atomLabels[idx] = "_AP" + pseudo.AttachPointNum;
                    }
                    else
                    {
                        if (!"*".Equals(pseudo.Label, StringComparison.Ordinal))
                        {
                            state.atomLabels[idx] = pseudo.Label;
                        }
                    }
                }
                object comment = atom.GetProperty <object>(CDKPropertyName.Comment);
                if (comment != null)
                {
                    if (state.atomValues == null)
                    {
                        state.atomValues = new SortedDictionary <int, string>();
                    }
                    state.atomValues[idx] = comment.ToString();
                }
                atomidx[atom] = idx;

                var p2 = atom.Point2D;
                var p3 = atom.Point3D;

                if (SmiFlavorTool.IsSet(flavour, SmiFlavors.Cx2dCoordinates) && p2 != null)
                {
                    state.atomCoords.Add(new double[] { p2.Value.X, p2.Value.Y, 0 });
                    state.coordFlag = true;
                }
                else if (SmiFlavorTool.IsSet(flavour, SmiFlavors.Cx3dCoordinates) && p3 != null)
                {
                    state.atomCoords.Add(new double[] { p3.Value.X, p3.Value.Y, p3.Value.Z });
                    state.coordFlag = true;
                }
                else if (SmiFlavorTool.IsSet(flavour, SmiFlavors.CxCoordinates))
                {
                    state.atomCoords.Add(new double[3]);
                }
            }

            if (!state.coordFlag)
            {
                state.atomCoords = null;
            }

            // radicals
            if (mol.SingleElectrons.Count > 0)
            {
                state.atomRads = new SortedDictionary <int, CxSmilesState.Radical>();
                foreach (ISingleElectron radical in mol.SingleElectrons)
                {
                    // 0->1, 1->2, 2->3
                    if (!state.atomRads.TryGetValue(EnsureNotNull(atomidx[radical.Atom]), out CxSmilesState.Radical val))
                    {
                        val = CxSmilesState.Radical.Monovalent;
                    }
                    else if (val == CxSmilesState.Radical.Monovalent)
                    {
                        val = CxSmilesState.Radical.Divalent;
                    }
                    else if (val == CxSmilesState.Radical.Divalent)
                    {
                        val = CxSmilesState.Radical.Trivalent;
                    }
                    else if (val == CxSmilesState.Radical.Trivalent)
                    {
                        throw new ArgumentException("Invalid radical state, can not be more than trivalent");
                    }

                    state.atomRads[atomidx[radical.Atom]] = val;
                }
            }

            var sgroups = mol.GetCtabSgroups();

            if (sgroups != null)
            {
                state.sgroups     = new List <CxSmilesState.PolymerSgroup>();
                state.positionVar = new SortedDictionary <int, IList <int> >();
                foreach (Sgroup sgroup in sgroups)
                {
                    switch (sgroup.Type)
                    {
                    // polymer SRU
                    case SgroupType.CtabStructureRepeatUnit:
                    case SgroupType.CtabMonomer:
                    case SgroupType.CtabMer:
                    case SgroupType.CtabCopolymer:
                    case SgroupType.CtabCrossLink:
                    case SgroupType.CtabModified:
                    case SgroupType.CtabMixture:
                    case SgroupType.CtabFormulation:
                    case SgroupType.CtabAnyPolymer:
                    case SgroupType.CtabGeneric:
                    case SgroupType.CtabComponent:
                    case SgroupType.CtabGraft:
                        string supscript = (string)sgroup.GetValue(SgroupKey.CtabConnectivity);
                        state.sgroups.Add(new CxSmilesState.PolymerSgroup(GetSgroupPolymerKey(sgroup),
                                                                          ToAtomIdxs(sgroup.Atoms, atomidx),
                                                                          sgroup.Subscript,
                                                                          supscript));
                        break;

                    case SgroupType.ExtMulticenter:
                        IAtom        beg   = null;
                        List <IAtom> ends  = new List <IAtom>();
                        ISet <IBond> bonds = sgroup.Bonds;
                        if (bonds.Count != 1)
                        {
                            throw new ArgumentException("Multicenter Sgroup in inconsistent state!");
                        }
                        IBond bond = bonds.First();
                        foreach (IAtom atom in sgroup.Atoms)
                        {
                            if (bond.Contains(atom))
                            {
                                if (beg != null)
                                {
                                    throw new ArgumentException("Multicenter Sgroup in inconsistent state!");
                                }
                                beg = atom;
                            }
                            else
                            {
                                ends.Add(atom);
                            }
                        }
                        state.positionVar[EnsureNotNull(atomidx[beg])] =
                            ToAtomIdxs(ends, atomidx);
                        break;

                    case SgroupType.CtabAbbreviation:
                    case SgroupType.CtabMultipleGroup:
                        // display shortcuts are not output
                        break;

                    case SgroupType.CtabData:
                        // can be generated but currently ignored
                        break;

                    default:
                        throw new NotSupportedException("Unsupported Sgroup Polymer");
                    }
                }
            }

            return(state);
        }