예제 #1
0
        public virtual void TestContains_IAtom()
        {
            IBond b = (IBond)NewChemObject();
            IAtom c = b.Builder.NewAtom("C");
            IAtom o = b.Builder.NewAtom("O");

            b.SetAtoms(new[] { c, o });
            b.Order = BondOrder.Single;

            Assert.IsTrue(b.Contains(c));
            Assert.IsTrue(b.Contains(o));
        }
예제 #2
0
        public virtual void TestMultiCenterContains()
        {
            IChemObject obj   = NewChemObject();
            IAtom       atom1 = obj.Builder.NewAtom("C");
            IAtom       atom2 = obj.Builder.NewAtom("O");
            IAtom       atom3 = obj.Builder.NewAtom("C");
            IAtom       atom4 = obj.Builder.NewAtom("C");

            IBond bond1 = obj.Builder.NewBond(new IAtom[] { atom1, atom2, atom3 });

            Assert.IsTrue(bond1.Contains(atom1));
            Assert.IsTrue(bond1.Contains(atom2));
            Assert.IsTrue(bond1.Contains(atom3));
            Assert.IsFalse(bond1.Contains(atom4));
        }
예제 #3
0
        /// <summary>
        /// Access the common atom shared by two bonds.
        /// </summary>
        /// <param name="bndA">first bond</param>
        /// <param name="bndB">second bond</param>
        /// <returns>common atom or null if non exists</returns>
        private static IAtom GetCommon(IBond bndA, IBond bndB)
        {
            var beg = bndA.Begin;
            var end = bndA.End;

            if (bndB.Contains(beg))
            {
                return(beg);
            }
            else if (bndB.Contains(end))
            {
                return(end);
            }
            else
            {
                return(null);
            }
        }
 /// <summary>
 /// Look if any atoms in <paramref name="bond1"/> also are in <paramref name="bond2"/>
 /// and if so it conceder the bonds connected.
 /// </summary>
 /// <param name="bond1">The first bond</param>
 /// <param name="bond2">The other bond</param>
 /// <returns>True if any of the atoms in <paramref name="bond1"/> also are in <paramref name="bond2"/></returns>
 private static bool IsConnected(IBond bond1, IBond bond2)
 {
     foreach (var atom in bond1.Atoms)
     {
         if (bond2.Contains(atom))
         {
             return(true);
         }
     }
     return(false);
 }
예제 #5
0
        /// <summary>
        /// Reads atoms, bonds etc from atom container and converts to format
        /// InChI library requires, then places call for the library to generate
        /// the InChI.
        /// </summary>
        /// <param name="atomContainer">AtomContainer to generate InChI for.</param>
        /// <param name="ignore"></param>
        private void GenerateInChIFromCDKAtomContainer(IAtomContainer atomContainer, bool ignore)
        {
            this.ReferringAtomContainer = atomContainer;

            // Check for 3d coordinates
            bool all3d = true;
            bool all2d = true;

            foreach (var atom in atomContainer.Atoms)
            {
                if (all3d && atom.Point3D == null)
                {
                    all3d = false;
                }
                if (all2d && atom.Point2D == null)
                {
                    all2d = false;
                }
            }

            var atomMap = new Dictionary <IAtom, NInchiAtom>();

            foreach (var atom in atomContainer.Atoms)
            {
                // Get coordinates
                // Use 3d if possible, otherwise 2d or none
                double x, y, z;
                if (all3d)
                {
                    var p = atom.Point3D.Value;
                    x = p.X;
                    y = p.Y;
                    z = p.Z;
                }
                else if (all2d)
                {
                    var p = atom.Point2D.Value;
                    x = p.X;
                    y = p.Y;
                    z = 0.0;
                }
                else
                {
                    x = 0.0;
                    y = 0.0;
                    z = 0.0;
                }

                // Chemical element symbol
                var el = atom.Symbol;

                // Generate InChI atom
                var iatom = Input.Add(new NInchiAtom(x, y, z, el));
                atomMap[atom] = iatom;

                // Check if charged
                var charge = atom.FormalCharge.Value;
                if (charge != 0)
                {
                    iatom.Charge = charge;
                }

                // Check whether isotopic
                var isotopeNumber = atom.MassNumber;
                if (isotopeNumber != null)
                {
                    iatom.IsotopicMass = isotopeNumber.Value;
                }

                // Check for implicit hydrogens
                // atom.HydrogenCount returns number of implicit hydrogens, not
                // total number
                // Ref: Posting to cdk-devel list by Egon Willighagen 2005-09-17
                int?implicitH = atom.ImplicitHydrogenCount;

                // set implicit hydrogen count, -1 tells the inchi to determine it
                iatom.ImplicitH = implicitH ?? -1;

                // Check if radical
                int count = atomContainer.GetConnectedSingleElectrons(atom).Count();
                if (count == 0)
                {
                    // TODO - how to check whether singlet or undefined multiplicity
                }
                else if (count == 1)
                {
                    iatom.Radical = INCHI_RADICAL.Doublet;
                }
                else if (count == 2)
                {
                    iatom.Radical = INCHI_RADICAL.Triplet;
                }
                else
                {
                    throw new CDKException("Unrecognised radical type");
                }
            }

            // Process bonds
            var bondMap = new Dictionary <IBond, NInchiBond>();

            foreach (var bond in atomContainer.Bonds)
            {
                // Assumes 2 centre bond
                var at0 = atomMap[bond.Begin];
                var at1 = atomMap[bond.End];

                // Get bond order
                INCHI_BOND_TYPE order;
                var             bo = bond.Order;
                if (!ignore && bond.IsAromatic)
                {
                    order = INCHI_BOND_TYPE.Altern;
                }
                else if (bo == BondOrder.Single)
                {
                    order = INCHI_BOND_TYPE.Single;
                }
                else if (bo == BondOrder.Double)
                {
                    order = INCHI_BOND_TYPE.Double;
                }
                else if (bo == BondOrder.Triple)
                {
                    order = INCHI_BOND_TYPE.Triple;
                }
                else
                {
                    throw new CDKException("Failed to generate InChI: Unsupported bond type");
                }

                // Create InChI bond
                var ibond = new NInchiBond(at0, at1, order);
                bondMap[bond] = ibond;
                Input.Add(ibond);

                // Check for bond stereo definitions
                var stereo = bond.Stereo;
                // No stereo definition
                if (stereo == BondStereo.None)
                {
                    ibond.BondStereo = INCHI_BOND_STEREO.None;
                }
                // Bond ending (fat end of wedge) below the plane
                else if (stereo == BondStereo.Down)
                {
                    ibond.BondStereo = INCHI_BOND_STEREO.Single1Down;
                }
                // Bond ending (fat end of wedge) above the plane
                else if (stereo == BondStereo.Up)
                {
                    ibond.BondStereo = INCHI_BOND_STEREO.Single1Up;
                }
                // Bond starting (pointy end of wedge) below the plane
                else if (stereo == BondStereo.DownInverted)
                {
                    ibond.BondStereo = INCHI_BOND_STEREO.Single2Down;
                }
                // Bond starting (pointy end of wedge) above the plane
                else if (stereo == BondStereo.UpInverted)
                {
                    ibond.BondStereo = INCHI_BOND_STEREO.Single2Up;
                }
                else if (stereo == BondStereo.EOrZ)
                {
                    ibond.BondStereo = INCHI_BOND_STEREO.DoubleEither;
                }
                else if (stereo == BondStereo.UpOrDown)
                {
                    ibond.BondStereo = INCHI_BOND_STEREO.Single1Either;
                }
                else if (stereo == BondStereo.UpOrDownInverted)
                {
                    ibond.BondStereo = INCHI_BOND_STEREO.Single2Either;
                }
                // Bond with undefined stereochemistry
                else if (stereo == BondStereo.None)
                {
                    if (order == INCHI_BOND_TYPE.Single)
                    {
                        ibond.BondStereo = INCHI_BOND_STEREO.Single1Either;
                    }
                    else if (order == INCHI_BOND_TYPE.Double)
                    {
                        ibond.BondStereo = INCHI_BOND_STEREO.DoubleEither;
                    }
                }
            }

            // Process tetrahedral stereo elements
            foreach (var stereoElem in atomContainer.StereoElements)
            {
                if (stereoElem is ITetrahedralChirality chirality)
                {
                    var stereoType = chirality.Stereo;

                    var atC = atomMap[chirality.ChiralAtom];
                    var at0 = atomMap[chirality.Ligands[0]];
                    var at1 = atomMap[chirality.Ligands[1]];
                    var at2 = atomMap[chirality.Ligands[2]];
                    var at3 = atomMap[chirality.Ligands[3]];
                    var p   = INCHI_PARITY.Unknown;
                    if (stereoType == TetrahedralStereo.AntiClockwise)
                    {
                        p = INCHI_PARITY.Odd;
                    }
                    else if (stereoType == TetrahedralStereo.Clockwise)
                    {
                        p = INCHI_PARITY.Even;
                    }
                    else
                    {
                        throw new CDKException("Unknown tetrahedral chirality");
                    }

                    var jniStereo = new NInchiStereo0D(atC, at0, at1, at2, at3, INCHI_STEREOTYPE.Tetrahedral, p);
                    Input.Stereos.Add(jniStereo);
                }
                else if (stereoElem is IDoubleBondStereochemistry dbStereo)
                {
                    var surroundingBonds = dbStereo.Bonds;
                    if (surroundingBonds[0] == null || surroundingBonds[1] == null)
                    {
                        throw new CDKException("Cannot generate an InChI with incomplete double bond info");
                    }
                    var stereoType = dbStereo.Stereo;

                    IBond      stereoBond = dbStereo.StereoBond;
                    NInchiAtom at0        = null;
                    NInchiAtom at1        = null;
                    NInchiAtom at2        = null;
                    NInchiAtom at3        = null;
                    // TODO: I should check for two atom bonds... or maybe that should happen when you
                    //    create a double bond stereochemistry
                    if (stereoBond.Contains(surroundingBonds[0].Begin))
                    {
                        // first atom is A
                        at1 = atomMap[surroundingBonds[0].Begin];
                        at0 = atomMap[surroundingBonds[0].End];
                    }
                    else
                    {
                        // first atom is X
                        at0 = atomMap[surroundingBonds[0].Begin];
                        at1 = atomMap[surroundingBonds[0].End];
                    }
                    if (stereoBond.Contains(surroundingBonds[1].Begin))
                    {
                        // first atom is B
                        at2 = atomMap[surroundingBonds[1].Begin];
                        at3 = atomMap[surroundingBonds[1].End];
                    }
                    else
                    {
                        // first atom is Y
                        at2 = atomMap[surroundingBonds[1].End];
                        at3 = atomMap[surroundingBonds[1].Begin];
                    }
                    var p = INCHI_PARITY.Unknown;
                    if (stereoType == DoubleBondConformation.Together)
                    {
                        p = INCHI_PARITY.Odd;
                    }
                    else if (stereoType == DoubleBondConformation.Opposite)
                    {
                        p = INCHI_PARITY.Even;
                    }
                    else
                    {
                        throw new CDKException("Unknown double bond stereochemistry");
                    }

                    var jniStereo = new NInchiStereo0D(null, at0, at1, at2, at3, INCHI_STEREOTYPE.DoubleBond, p);
                    Input.Stereos.Add(jniStereo);
                }
                else if (stereoElem is ExtendedTetrahedral extendedTetrahedral)
                {
                    TetrahedralStereo winding = extendedTetrahedral.Winding;

                    // The peripherals (p<i>) and terminals (t<i>) are referring to
                    // the following atoms. The focus (f) is also shown.
                    //
                    //   p0          p2
                    //    \          /
                    //     t0 = f = t1
                    //    /         \
                    //   p1         p3
                    var terminals   = extendedTetrahedral.FindTerminalAtoms(atomContainer);
                    var peripherals = extendedTetrahedral.Peripherals.ToArray();

                    // InChI API is particular about the input, each terminal atom
                    // needs to be present in the list of neighbors and they must
                    // be at index 1 and 2 (i.e. in the middle). This is true even
                    // of explicit atoms. For the implicit atoms, the terminals may
                    // be in the peripherals already and so we correct the winding
                    // and reposition as needed.

                    var t0Bonds = OnlySingleBonded(atomContainer.GetConnectedBonds(terminals[0]));
                    var t1Bonds = OnlySingleBonded(atomContainer.GetConnectedBonds(terminals[1]));

                    // first if there are two explicit atoms we need to replace one
                    // with the terminal atom - the configuration does not change
                    if (t0Bonds.Count == 2)
                    {
                        var orgBond = t0Bonds[0];
                        t0Bonds.RemoveAt(0);
                        var replace = orgBond.GetOther(terminals[0]);
                        for (int i = 0; i < peripherals.Length; i++)
                        {
                            if (replace == peripherals[i])
                            {
                                peripherals[i] = terminals[0];
                            }
                        }
                    }

                    if (t1Bonds.Count == 2)
                    {
                        var orgBond = t0Bonds[0];
                        t1Bonds.RemoveAt(0);
                        var replace = orgBond.GetOther(terminals[1]);
                        for (int i = 0; i < peripherals.Length; i++)
                        {
                            if (replace == peripherals[i])
                            {
                                peripherals[i] = terminals[1];
                            }
                        }
                    }

                    // the neighbor attached to each terminal atom that we will
                    // define the configuration of
                    var t0Neighbor = t0Bonds[0].GetOther(terminals[0]);
                    var t1Neighbor = t1Bonds[0].GetOther(terminals[1]);

                    // we now need to move all the atoms into the correct positions
                    // everytime we exchange atoms the configuration inverts
                    for (int i = 0; i < peripherals.Length; i++)
                    {
                        if (i != 0 && t0Neighbor == peripherals[i])
                        {
                            Swap(peripherals, i, 0);
                            winding = winding.Invert();
                        }
                        else if (i != 1 && terminals[0] == peripherals[i])
                        {
                            Swap(peripherals, i, 1);
                            winding = winding.Invert();
                        }
                        else if (i != 2 && terminals[1] == peripherals[i])
                        {
                            Swap(peripherals, i, 2);
                            winding = winding.Invert();
                        }
                        else if (i != 3 && t1Neighbor == peripherals[i])
                        {
                            Swap(peripherals, i, 3);
                            winding = winding.Invert();
                        }
                    }

                    var parity = INCHI_PARITY.Unknown;
                    if (winding == TetrahedralStereo.AntiClockwise)
                    {
                        parity = INCHI_PARITY.Odd;
                    }
                    else if (winding == TetrahedralStereo.Clockwise)
                    {
                        parity = INCHI_PARITY.Even;
                    }
                    else
                    {
                        throw new CDKException("Unknown extended tetrahedral chirality");
                    }

                    NInchiStereo0D jniStereo = new NInchiStereo0D(atomMap[extendedTetrahedral.Focus],
                                                                  atomMap[peripherals[0]], atomMap[peripherals[1]], atomMap[peripherals[2]],
                                                                  atomMap[peripherals[3]], INCHI_STEREOTYPE.Allene, parity);
                    Input.Stereos.Add(jniStereo);
                }
            }

            try
            {
                Output = NInchiWrapper.GetInchi(Input);
            }
            catch (NInchiException jie)
            {
                throw new CDKException("Failed to generate InChI: " + jie.Message, jie);
            }
        }
예제 #6
0
파일: BondRef.cs 프로젝트: qize/NCDK
 /// <inheritdoc/>
 public bool Contains(IAtom atom)
 {
     return(bond.Contains(atom));
 }
예제 #7
0
파일: Bond.tt.cs 프로젝트: qize/NCDK
 /// <summary>
 /// Checks whether a bond is connected to another one.
 /// This can only be true if the bonds have an Atom in common.
 /// </summary>
 /// <param name="bond">The bond which is checked to be connect with this one</param>
 /// <returns>true if the bonds share an atom, otherwise false</returns>
 public virtual bool IsConnectedTo(IBond bond)
 {
     return(atoms.Any(atom => bond.Contains(atom)));
 }
예제 #8
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);
        }