示例#1
0
        /// <summary>
        /// RemovePseudoAtoms
        /// </summary>
        /// <param name="mol"></param>
        /// <returns>Pseudo atom count</returns>

        public static int RemovePseudoAtoms(IAtomContainer mol)
        {
            List <IAtom> pseudoAtoms = new List <IAtom>();

            for (int ai = 0; ai < mol.getAtomCount(); ai++)
            {
                IAtom atom = mol.getAtom(ai);
                if (atom is IPseudoAtom)
                {
                    pseudoAtoms.Add(atom);
                }
            }

            if (pseudoAtoms.Count == 0)
            {
                return(0);
            }

            foreach (IAtom atom in pseudoAtoms)
            {
                mol.removeAtomAndConnectedElectronContainers(atom);
            }

            AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(mol);
            mol = AtomContainerManipulator.suppressHydrogens(mol);
            GetHydrogenAdder().addImplicitHydrogens(mol);

            return(pseudoAtoms.Count);
        }
示例#2
0
        /// <summary>
        /// MolfileV3000ToAtomContainer
        /// </summary>
        /// <param name="molfile"></param>
        /// <returns></returns>
        public static IAtomContainer MolfileV3000ToAtomContainer(string molfile)
        {
            // Extract any mass info before conversion to avoid losing our custom info in conversion
            Dictionary <int, int> map = new Dictionary <int, int>();

            if (molfile.Contains(" MASS="))
            {
                map = ExtractMassAttributes(ref molfile);
            }

            cdk.io.DefaultChemObjectReader cor;
            java.io.StringReader           sr = new java.io.StringReader(molfile);
            cor = new MDLV3000Reader(sr);
            cor.setReaderMode(IChemObjectReader.Mode.RELAXED);

            IAtomContainer mol = (IAtomContainer)cor.read(new AtomContainer());

            cor.close();

            for (int ai = 0; ai < mol.getAtomCount(); ai++)
            {
                IAtom a = mol.getAtom(ai);
                if (map.ContainsKey(ai + 1))
                {
                    a.setMassNumber(new java.lang.Integer(map[ai + 1]));
                }
                else
                {
                    a.setMassNumber(null);
                }
            }

            ConfigureAtomContainer(mol);
            return(mol);
        }
示例#3
0
        public static string CanonicalizeSmiles(
            string smiles,
            SmilesGeneratorType smiGenFlags)
        {
            IAtomContainer mol = SmilesToAtomContainer(smiles);

            if (mol.getAtomCount() == 0)
            {
                return("");
            }
            else
            {
                string smiles2 = AtomContainerToSmiles(mol, smiGenFlags);
                return(smiles2);
            }
        }
示例#4
0
        /// <summary>
        /// Remove the following features from a molecule
        ///  - Atom non-standard mass
        ///  - Stereo chemistry
        ///  - explicit hydrogens
        /// </summary>
        /// <param name="src"></param>
        /// <returns>Modified mol</returns>

        public static IAtomContainer RemoveIsotopesStereoExplicitHydrogens(
            IAtomContainer src)
        {
            IAtom[] atoms = new IAtom[src.getAtomCount()];
            IBond[] bonds = new IBond[src.getBondCount()];

            IChemObjectBuilder builder = src.getBuilder();

            for (int i = 0; i < atoms.Length; i++)
            {
                IAtom atom  = src.getAtom(i);
                IAtom atom2 = (IAtom)builder.newInstance(typeof(IAtom), atom.getSymbol());
                SetImplicitHydrogenCount(atom2, GetImplicitHydrogenCount(atom));
                atom2.setPoint2d(atom.getPoint2d());
                atoms[i] = atom2;
            }

            for (int i = 0; i < bonds.Length; i++)
            {
                IBond bond = src.getBond(i);

                int   u     = src.getAtomNumber(bond.getAtom(0));
                int   v     = src.getAtomNumber(bond.getAtom(1));
                IBond bond2 = (IBond)builder.newInstance(typeof(IBond), atoms[u], atoms[v]);

                bond2.setIsAromatic(bond.isAromatic());
                bond2.setIsInRing(bond.isInRing());
                bond2.setOrder(bond.getOrder());

                bond2.setFlag(CDKConstants.ISAROMATIC, bond.getFlag(CDKConstants.ISAROMATIC));
                bond2.setFlag(CDKConstants.SINGLE_OR_DOUBLE, bond.getFlag(CDKConstants.SINGLE_OR_DOUBLE));

                bonds[i] = bond2;
            }

            IAtomContainer dest = (IAtomContainer)builder.newInstance(typeof(IAtomContainer));

            dest.setAtoms(atoms);
            dest.setBonds(bonds);

            AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(dest);
            dest = AtomContainerManipulator.suppressHydrogens(dest);
            GetHydrogenAdder().addImplicitHydrogens(dest);

            return(dest);
        }
示例#5
0
        /// <summary>
        /// Convert molfile to Smiles
        /// </summary>
        /// <param name="molfile"></param>
        /// <returns></returns>

        public string MolfileStringToSmilesString(string molfile)
        {
            if (Lex.IsUndefined(molfile))
            {
                return("");
            }

            IAtomContainer mol = MolfileToAtomContainer(molfile);

            if (mol.getAtomCount() == 0)
            {
                return("");
            }

            string smiles = AtomContainerToSmiles(mol);

            return(smiles);
        }
示例#6
0
        /// <summary>
        /// Convert SmilesToMolfile
        /// </summary>
        /// <param name="smiles"></param>
        /// <returns></returns>

        public string SmilesStringToMolfileString(string smiles)
        {
            if (Lex.IsUndefined(smiles))
            {
                return("");
            }

            IAtomContainer mol = SmilesToAtomContainer(smiles);

            if (mol.getAtomCount() == 0)
            {
                return("");
            }

            string molfile = AtomContainerToMolfile(mol);

            return(molfile);
        }
示例#7
0
        static List <IAtom> GetAttachmentAtoms(
            IAtomContainer mol,
            int attachmentNo)
        {
            List <IAtom> atoms = new List <IAtom>();

            for (int ai = 0; ai < mol.getAtomCount(); ai++)
            {
                IAtom atom   = mol.getAtom(ai);
                int   massNo = Math.Abs(GetMassNumber(atom));
                if (massNo == attachmentNo || massNo == 12 || massNo == 21)                 // 12 & 21 values occur at atoms with two attachments
                {
                    //SetMassNumber(atom, 0); // clear attachment number (isotope) (can't may need later, e.g.12 value for two attachements to same atom)
                    atoms.Add(atom);
                }
            }

            return(atoms);
        }
示例#8
0
        /// <summary>
        /// Fragment a molecule
        /// </summary>
        /// <param name="mol"></param>
        /// <returns></returns>

        public static List <KeyValuePair <string, IAtomContainer> > FragmentMoleculeAndCanonicalizeSmiles(
            IAtomContainer mol,
            bool filterOutCommonCounterIons)
        {
            int aci, fi, i1;

            KeyValuePair <string, IAtomContainer>         kvp;
            List <KeyValuePair <string, IAtomContainer> > frags = new List <KeyValuePair <string, IAtomContainer> >();

            AtomContainerSet acs = (AtomContainerSet)ConnectivityChecker.partitionIntoMolecules(mol);

            int acc = acs.getAtomContainerCount();

            for (aci = 0; aci < acc; aci++)
            {
                IAtomContainer fragMol    = acs.getAtomContainer(aci);
                string         fragSmiles = AtomContainerToSmiles(fragMol);
                if (filterOutCommonCounterIons)
                {
                    if (CommonSmallFragments.Contains(fragSmiles) ||
                        GetHeavyAtomCount(fragMol) <= 6)
                    {
                        continue;
                    }
                }

                kvp = new KeyValuePair <string, IAtomContainer>(fragSmiles, fragMol);

                int ac = fragMol.getAtomCount();

                for (fi = frags.Count - 1; fi >= 0; fi--)                 // insert into list so that fragments are ordered largest to smallest
                {
                    if (frags[fi].Value.getAtomCount() >= ac)
                    {
                        break;
                    }
                }
                frags.Insert(fi + 1, kvp);
            }

            return(frags);
        }
示例#9
0
        /// <summary>
        /// GetHeavyAtomCount
        /// </summary>
        /// <param name="mol"></param>
        /// <returns></returns>

        public static int GetHeavyAtomCount(IAtomContainer mol)
        {
            int haCnt = 0;

            for (int ai = 0; ai < mol.getAtomCount(); ai++)
            {
                IAtom atom = mol.getAtom(ai);
                if (atom.getAtomicNumber().intValue() == 1 ||                  // do not count hydrogens
                    atom.getSymbol().Equals("H"))
                {
                    continue;
                }
                else
                {
                    haCnt++;
                }
            }

            return(haCnt);
        }
示例#10
0
		/**
		 * Very quick and easy isomorphism check.
		 * 
		 * @param molecule1 the molecule1
		 * @param fragsToCompare the frags to compare
		 * 
		 * @return true, if successful
		 */

		private bool identicalAtoms(IAtomContainer molecule1, List<IAtomContainer> fragsToCompare)
		{
			var molFormula = MolecularFormulaTools.GetMolecularFormula(molecule1);
			var molFormulaString = MolecularFormulaTools.GetString(molFormula);

			for (var i = 0; i < fragsToCompare.Count; i++)
			{
				//no match
				if (molecule1.getBondCount() != fragsToCompare[i].getBondCount() && molecule1.getAtomCount() != fragsToCompare[i].getAtomCount())
				{
					continue;
				}

				//Molecular Formula redundancy check
				var molFormulaFrag = MolecularFormulaTools.GetMolecularFormula(fragsToCompare[i]);
				var molFormulaFragString = MolecularFormulaTools.GetString(molFormulaFrag);
				if (molFormulaString.Equals(molFormulaFragString))
				{
					return true;
				}
			}

			//no match found
			return false;
		}
示例#11
0
		public IAtomContainer markAllBonds(IAtomContainer original)
		{
			MoleculeTools.MoleculeNumbering(original);
			atomsContained = original.getAtomCount();
			return original;
		}
示例#12
0
		private IEnumerable<IAtomContainer> splitMolecule(IAtomContainer atomContainer, IBond bond, IDictionary<IAtom, IList<IBond>> atomBonds)
		{
			//if this bond is in a ring we have to split another bond in this ring where at least one 
			//bond is in between. Otherwise we wont have two fragments. Else normal split.

			var ret = new List<IAtomContainer>();

			//get bond energy for splitting this bond
			var currentBondEnergy = BondEnergies.Lookup(bond);			

			//bond is in a ring....so we have to split up another bond to break it
			var rings = allRings.getRings(bond);
			if (rings.getAtomContainerCount() != 0)
			{
				foreach (var bondInRing in rings.getAtomContainer(0).bonds().ToWindowsEnumerable<IBond>())
				{
					//if the bonds are the same...this wont split up the ring
					if (bondInRing == bond)
					{
						continue;
					}

					//check for already tried bonds
					var check = new BondPair(bond, bondInRing);
					if (knownBonds.Contains(check))
					{
						continue;
					}
					knownBonds.Add(new BondPair(bond, bondInRing));


					var set = new List<IAtomContainer>();
					var bondListList = new List<List<IBond>>();
					var fragWeightList = new List<Double>();

					foreach (var currentAtom in bond.atoms().ToWindowsEnumerable<IAtom>())
					{
						//List with bonds in Ring
						var partRing = new List<IBond>();
						//reset the weight because it is computed inside the traverse
						currentFragWeight = 0.0;
						//initialize new atom list
						atomList = new List<IAtom>();

						//clone current atom because a single electron is being added...homolytic cleavage
						partRing = traverse(atomBonds, currentAtom, partRing, bond, bondInRing);

						bondListList.Add(partRing);
						fragWeightList.Add(currentFragWeight);

						var temp = makeAtomContainer(currentAtom, partRing);
						//set the properties again!
						var properties = atomContainer.getProperties();
						temp.setProperties(properties);


						//*********************************************************
						//BOND ENERGY CALCULATION
						//calculate bond energy
						var currentBondEnergyRing = BondEnergies.Lookup(bondInRing);

						//*********************************************************

						//now set property
						temp = setBondEnergy(temp, (currentBondEnergyRing + currentBondEnergy));
						set.Add(temp);
					}

					//now maybe add the fragments to the list
					for (var j = 0; j < set.Count; j++)
					{
						//Render.Draw(set.getAtomContainer(j), "");
						if (set[j].getAtomCount() > 0 && set[j].getBondCount() > 0 && set[j].getAtomCount() != atomContainer.getAtomCount())
						{
							//now check the current mass
							var fragMass = getFragmentMass(set[j], fragWeightList[j]);
							//check the weight of the current fragment
							if (!isHeavyEnough(fragMass))
							{
								continue;
							}

							//returns true if isomorph
							//set the current sum formula
							var fragmentFormula = MolecularFormulaTools.GetMolecularFormula(set[j]);
							var currentSumFormula = MolecularFormulaTools.GetString(fragmentFormula);

							if (isIdentical(set[j], currentSumFormula))
							{
								continue;
							}

							//add the fragment to the return list
							ret.Add(set[j]);
						}
					}
				}
			}
			else
			{
				var set = new List<IAtomContainer>();
				var bondListList = new List<List<IBond>>();
				var fragWeightList = new List<Double>();

				//get the atoms from the splitting bond --> create 2 fragments
				foreach (var currentAtom in bond.atoms().ToWindowsEnumerable<IAtom>())
				{
					var part = new List<IBond>();
					//reset the weight because it is computed inside the traverse
					currentFragWeight = 0.0;
					//initialize new atom list
					atomList = new List<IAtom>();
					part = traverse(atomBonds, currentAtom, part, bond);
					bondListList.Add(part);

					//create Atomcontainer out of bondList        		
					var temp = makeAtomContainer(currentAtom, part);
					//set the properties again!
					var properties = atomContainer.getProperties();
					temp.setProperties(properties);
					//now calculate the correct weight subtrating the possible neutral loss mass

					fragWeightList.Add(currentFragWeight);


					//now set property: BondEnergy!
					temp = setBondEnergy(temp, currentBondEnergy);
					set.Add(temp);
				}


				//at most 2 new molecules
				for (var i = 0; i < set.Count; i++)
				{
					if (set[i].getAtomCount() > 0 && set[i].getBondCount() > 0 && set[i].getAtomCount() != atomContainer.getAtomCount())
					{
						//now check the current mass
						var fragMass = getFragmentMass(set[i], fragWeightList[i]);
						//check the weight of the current fragment
						if (!isHeavyEnough(fragMass))
						{
							continue;
						}

						//set the current sum formula
						var fragmentFormula = MolecularFormulaTools.GetMolecularFormula(set[i]);
						var currentSumFormula = MolecularFormulaTools.GetString(fragmentFormula);
						//returns true if isomorph (fast isomorph check)
						if (isIdentical(set[i], currentSumFormula))
						{
							continue;
						}

						ret.Add(set[i]);
					}
				}
			}

			return ret;
		}
示例#13
0
        /// <summary>
        /// (Converted from Java to C# for possible later modification)
        /// Suppress any explicit hydrogens in the provided container. Only hydrogens
        /// that can be represented as a hydrogen count value on the atom are
        /// suppressed. The container is updated and no elements are copied, please
        /// use either <seealso cref="#copyAndSuppressedHydrogens"/> if you would to preserve
        /// the old instance.
        /// </summary>
        /// <param name="org"> the container from which to remove hydrogens </param>
        /// <returns> the input for convenience </returns>
        /// <seealso cref= #copyAndSuppressedHydrogens </seealso>
        public IAtomContainer suppressHydrogens(IAtomContainer org)
        {
            bool anyHydrogenPresent = false;

            for (int ai = 0; ai < org.getAtomCount(); ai++)
            {
                IAtom atom = org.getAtom(ai);
                if ("H".Equals(atom.getSymbol()))
                {
                    anyHydrogenPresent = true;
                    break;
                }
            }

            if (!anyHydrogenPresent)
            {
                return(org);
            }

            // we need fast adjacency checks (to check for suppression and
            // update hydrogen counts)
            int[][] graph = GraphUtil.toAdjList(org);

            int nOrgAtoms = org.getAtomCount();
            int nOrgBonds = org.getBondCount();

            int nCpyAtoms = 0;
            int nCpyBonds = 0;

            ISet <IAtom> hydrogens = new HashSet <IAtom>();

            IAtom[] cpyAtoms = new IAtom[nOrgAtoms];

            // filter the original container atoms for those that can/can't
            // be suppressed
            for (int v = 0; v < nOrgAtoms; v++)
            {
                IAtom atom = org.getAtom(v);
                if (suppressibleHydrogen(org, graph, v))
                {
                    hydrogens.Add(atom);
                    incrementImplHydrogenCount(org.getAtom(graph[v][0]));
                }
                else
                {
                    cpyAtoms[nCpyAtoms++] = atom;
                }
            }

            // none of the hydrogens could be suppressed - no changes need to be made
            if (hydrogens.Count == 0)
            {
                return(org);
            }

            org.setAtoms(cpyAtoms);

            // we now update the bonds - we have auxiliary variable remaining that
            // bypasses the set membership checks if all suppressed bonds are found
            IBond[] cpyBonds  = new IBond[nOrgBonds - hydrogens.Count];
            int     remaining = hydrogens.Count;

            for (int bi = 0; bi < org.getBondCount(); bi++)
            {
                IBond bond = org.getBond(bi);
                if (remaining > 0 && (hydrogens.Contains(bond.getAtom(0)) || hydrogens.Contains(bond.getAtom(1))))
                {
                    remaining--;
                    continue;
                }
                cpyBonds[nCpyBonds++] = bond;
            }

            // we know how many hydrogens we removed and we should have removed the
            // same number of bonds otherwise the container is strange
            if (nCpyBonds != cpyBonds.Length)
            {
                throw new System.ArgumentException("number of removed bonds was less than the number of removed hydrogens");
            }

            org.setBonds(cpyBonds);

            return(org);
        }
示例#14
0
        /// <summary>
        /// Convert isotope labels to hilighting.
        /// </summary>
        /// <param name="mol"></param>
        /// <returns></returns>

        public string ConvertIsotopeValuesToHilighting(
            IAtomContainer mol)
        {
            bool   hilight;
            string molfile2 = "";
            bool   clearAttachmentPointLabels = true;
            bool   hilightAttachmentBond      = true;

            List <int> atomSet = new List <int>();
            List <int> bondSet = new List <int>();

            for (int bi = 0; bi < mol.getBondCount(); bi++)
            {
                IBond b = mol.getBond(bi);
                if (b.getAtomCount() != 2)
                {
                    continue;
                }

                IAtom a1 = b.getAtom(0);
                IAtom a2 = b.getAtom(1);

                if (hilightAttachmentBond)
                {
                    hilight = (GetMassNumber(a1) != 0 && GetMassNumber(a2) != 0);
                }
                else
                {
                    hilight = (GetMassNumber(a1) < 0 && GetMassNumber(a2) < 0);
                }
                if (hilight)
                {
                    bondSet.Add(bi);
                }
            }

            //String posMap = ""; // debug (note that hydrogens can get repositioned)
            for (int ai = 0; ai < mol.getAtomCount(); ai++)             // scan atoms for hilighting and reset isotope values
            {
                IAtom a = mol.getAtom(ai);

                hilight = GetMassNumber(a) < 0;
                if (hilight)
                {
                    atomSet.Add(ai);
                }

                //posMap += ai.ToString() + ", " + a.getSymbol() + ", " + hilight + "\r\n"; // debug

                int massNo = GetMassNumber(a);
                if (massNo == hilightIsotopeValue)
                {
                    a.setMassNumber(null);                     // set back to original value
                }
                else if (massNo < 0)
                {
                    if (clearAttachmentPointLabels)
                    {
                        a.setMassNumber(null);
                    }

                    else
                    {
                        SetMassNumber(a, -massNo);                      // set back to positive
                    }
                }
            }

            //mol = GenerateCoordinates(mol); // (should already be done)

            try { molfile2 = AtomContainerToMolFileV3000(mol); }
            catch (Exception ex) { ex = ex; }

            if (Lex.IsUndefined(molfile2))             // couldn't convert to v3000, just return unhilighted v2000 file
            {
                molfile2 = AtomContainerToMolfile(mol);
                return(molfile2);
            }

            string txt = "MDLV30/HILITE";

            if (atomSet.Count > 0)
            {
                txt += " " + BuildV3000KeywordList("ATOMS", atomSet);
            }

            if (bondSet.Count > 0)
            {
                txt += " " + BuildV3000KeywordList("BONDS", bondSet);
            }

            txt = BuildV3000Lines(txt);

            bool hasCollection = Lex.Contains(molfile2, "M  V30 END COLLECTION");

            if (hasCollection)             // already have collection begin and end
            {
                txt = txt +
                      "M  V30 END COLLECTION";
                molfile2 = Lex.Replace(molfile2, "M  V30 END COLLECTION", txt);
            }

            else             // add collection begin & end
            {
                txt =
                    "M  V30 BEGIN COLLECTION\n" +
                    txt +
                    "M  V30 END COLLECTION\n" +
                    "M  V30 END CTAB";
                molfile2 = Lex.Replace(molfile2, "M  V30 END CTAB", txt);
            }

            return(molfile2);
        }
示例#15
0
        /// <summary>
        /// Remove explicit and implicit hydrogens bonded to positive nitrogens
        /// </summary>
        /// <param name="org"></param>
        /// <returns></returns>
        public int RemoveHydrogensBondedToPositiveNitrogens(IAtomContainer org)
        {
            int chg, impHydCnt;
            int implicitHydRemoved = 0;

            HashSet <IAtom> atomsToRemove = new HashSet <IAtom>();
            HashSet <IBond> bondsToRemove = new HashSet <IBond>();
            int             nOrgAtoms     = org.getAtomCount();
            int             nOrgBonds     = org.getBondCount();

            // Get H atoms and their bonds to pos-charged Nitrogen, adjusting charge

            for (int bi = 0; bi < org.getBondCount(); bi++)
            {
                IBond bond = org.getBond(bi);
                if (bond.getAtomCount() != 2)
                {
                    continue;
                }

                IAtom a1 = bond.getAtom(0);
                IAtom a2 = bond.getAtom(1);
                if (a1.getSymbol() == "H" && a2.getSymbol() == "N" && GetFormalCharge(a2) > 0)
                {
                    chg = GetFormalCharge(a2) - 1;
                    SetFormalCharge(a2, chg);
                    atomsToRemove.Add(a1);
                    bondsToRemove.Add(bond);
                }

                else if (a2.getSymbol() == "H" && a1.getSymbol() == "N" && GetFormalCharge(a1) > 0)
                {
                    chg = GetFormalCharge(a1) - 1;
                    SetFormalCharge(a1, chg);
                    atomsToRemove.Add(a2);
                    bondsToRemove.Add(bond);
                }
            }

            // Check for implicit H attached to pos-charged N

            for (int ai = 0; ai < nOrgAtoms; ai++)
            {
                IAtom a = org.getAtom(ai);
                if (a.getSymbol() == "N" && GetFormalCharge(a) > 0 && GetImplicitHydrogenCount(a) > 0)
                {
                    chg = GetFormalCharge(a) - 1;
                    SetFormalCharge(a, chg);

                    impHydCnt = GetImplicitHydrogenCount(a) - 1;
                    SetImplicitHydrogenCount(a, impHydCnt);
                    implicitHydRemoved++;
                }
            }

            if (implicitHydRemoved > 0)
            {
                implicitHydRemoved = implicitHydRemoved;                                     // debug
            }
            if (atomsToRemove.Count == 0)
            {
                return(implicitHydRemoved);                                      // just return if no explicit H to remove
            }
            // Get list of atoms to keep

            IAtom[] cpyAtoms  = new IAtom[nOrgAtoms - atomsToRemove.Count];
            int     nCpyAtoms = 0;

            for (int ai = 0; ai < nOrgAtoms; ai++)
            {
                IAtom atom = org.getAtom(ai);
                if (!atomsToRemove.Contains(atom))
                {
                    cpyAtoms[nCpyAtoms++] = atom;
                }
            }

            org.setAtoms(cpyAtoms);

            // Get list of bonds to keep

            IBond[] cpyBonds  = new IBond[nOrgBonds - bondsToRemove.Count];
            int     nCpyBonds = 0;

            for (int bi = 0; bi < org.getBondCount(); bi++)
            {
                IBond bond = org.getBond(bi);
                if (!bondsToRemove.Contains(bond))
                {
                    cpyBonds[nCpyBonds++] = bond;
                }
            }

            org.setBonds(cpyBonds);

            return(atomsToRemove.Count + implicitHydRemoved);
        }
示例#16
0
        static ICdkMol CdkMolUtil => StaticCdkMol.I;         // static molecule shortcut for utility methods

        /// <summary>
        /// Build UniChem Data
        /// Note that this routine takes about 14 secs the first time it's called, faster thereafter.
        /// </summary>
        /// <param name="mol"></param>
        /// <returns></returns>

        public static UniChemData BuildUniChemData(
            IAtomContainer mol)
        {
            IAtomContainer mol2;
            InChIGenerator ig = null;
            string         molSmiles, fragSmiles = "", molFile = "";
            int            acc, fi, ci;

            //if (Lex.StartsWith(molString, "InChI="))
            //{
            //	sourceInchi = molString;
            //	mol = CdkMol.InChIToAtomContainer(sourceInchi);
            //}

            //else // assume molfile otherwise
            //{
            //	molfile = molString;
            //	mol = CdkMol.MolfileToAtomContainer(molfile);
            //}

            if (mol.getAtomCount() <= 1)
            {
                throw new Exception("Atom count <= 1");
            }

            int pseudoCount = CdkMol.RemovePseudoAtoms(mol);

            mol = CdkMol.AtomContainerToSmilesAndBack(mol, out molSmiles);

            InChIGeneratorFactory igf = InChIGeneratorFactory.getInstance();

            try
            {
                //string options = "/KET /15T"; // options to include keto-enol and 1,5-tautomerism (not recognized by CDK)
                ig = igf.getInChIGenerator(mol);                 //, options);
            }

            catch (Exception ex)             // may fail for some complex mols (e.g. CorpId 12345, a MDL V3000 mol with a CF3 Sgroup/alias)
            {
                throw new Exception(ex.Message, ex);
            }

            //{
            //	try // try to simplify the molfile so that InChI can handle it
            //	{
            //		//if (Lex.IsUndefined(molfile)) throw ex;
            //		string molfile2 = SimplifyMolfileForInChIGeneration(molile);
            //		mol = CdkMol.MolfileToAtomContainer(molfile2);
            //		mol = CdkMol.AtomContainerToSmilesAndBack(mol, out molSmiles);
            //		ig = igf.getInChIGenerator(mol);
            //	}
            //	catch (Exception ex2)
            //	{
            //		throw new Exception(ex2.Message, ex);
            //	}
            //}

            if (!IsAcceptableInchiStatus(ig))
            {
                string errMsg = "InChI generation " + ig.getReturnStatus() + ": " + ig.getMessage();
                molFile = CdkMol.AtomContainerToMolfile(mol);                 // debug
                throw new Exception(errMsg);
            }

            // Populate the UniChem object

            UniChemData icd = new UniChemData();

            //icd.Molfile = molfile;
            icd.AtomContainer = mol;
            icd.InChIString   = ig.getInchi();
            icd.InChIKey      = ig.getInchiKey();
            icd.CanonSmiles   = molSmiles;

            // Build and store fingerprint

            mol = CdkMol.InChIToAtomContainer(icd.InChIString);

            //int hydRemovedCnt = CdkMol.RemoveHydrogensBondedToPositiveNitrogens(mol);
            mol = CdkMol.RemoveIsotopesStereoExplicitHydrogens(mol); // additional normalization for fingerprint

            BitSetFingerprint fp =                                   // generate a fingerprint
                                   CdkFingerprint.BuildBitSetFingerprint(mol, FingerprintType.MACCS, -1, -1);

            icd.Fingerprint = fp;

            if (ConnectivityChecker.isConnected(mol))
            {
                return(icd);                                                  // single fragment
            }
            //string mf = CdkMol.GetMolecularFormula(mol);

            //AtomContainerSet acs = (AtomContainerSet)ConnectivityChecker.partitionIntoMolecules(mol);
            List <IAtomContainer> frags = CdkMol.FragmentMolecule(mol, true);            // get fragments filtering out small and common frags

            for (fi = 0; fi < frags.Count; fi++)
            {
                mol2 = frags[fi];

                int atomCnt = mol2.getAtomCount();
                if (atomCnt <= 1)
                {
                    continue;
                }

                try
                {
                    mol2 = CdkMol.AtomContainerToSmilesAndBack(mol2, out fragSmiles);
                }
                catch (Exception ex)
                {
                    AtomContainerToSmilesAndBackErrorCount++;                     // just count error and ignore
                }

                ig = igf.getInChIGenerator(mol2);
                if (!IsAcceptableInchiStatus(ig))
                {
                    continue;
                }

                string childInChIString = ig.getInchi();
                string childInChIKey    = ig.getInchiKey();
                string childFIKHB       = UniChemUtil.GetFIKHB(childInChIKey);

                mol2 = CdkMol.InChIToAtomContainer(childInChIString);      // convert from inchi
                mol2 = CdkMol.RemoveIsotopesStereoExplicitHydrogens(mol2); // additional normalization for fingerprint

                fp =                                                       // generate a fingerprint for the fragment
                     CdkFingerprint.BuildBitSetFingerprint(mol2, FingerprintType.MACCS, -1, -1);

                for (ci = 0; ci < icd.Children.Count; ci++)                 // see if a dup child
                {
                    if (icd.Children[ci].ChildFIKHB == childFIKHB)
                    {
                        break;
                    }
                }
                if (ci < icd.Children.Count)
                {
                    continue;                                          // skip if dup
                }
                UniChemFIKHBHierarchy icdChild = new UniChemFIKHBHierarchy();
                icdChild.ParentFIKHB = icd.GetFIKHB();
                icdChild.ChildFIKHB  = childFIKHB;
                icdChild.InChIString = childInChIString;
                icdChild.CanonSmiles = fragSmiles;

                icdChild.Fingerprint = fp;

                icd.Children.Add(icdChild);
            }

            return(icd);
        }