/// <summary> /// A compound with one sulfur atom joined to three oxygen /// atoms total in which two of the three are double-bound /// while the third is single bound and, in addition, said /// third oxygen atom is, itself, bound to a hydrogen atom. /// </summary> public static bool IsSulphonic(this IAtomContainer mol) { if (mol == null) { return(false); } foreach (var bond in mol.Bonds) { if (bond.Begin.Symbol != "S" && bond.End.Symbol != "S") { continue; } var sulfur = bond.Begin.Symbol == "S" ? bond.Begin : bond.End; var sulfurBonds = mol.GetConnectedBonds(sulfur)?.ToList(); if (sulfurBonds == null || !sulfurBonds.Any()) { continue; } if (sulfurBonds.Count < 4) { continue; } if (sulfurBonds.Count(b => b.Order == BondOrder.Double && (b.Begin.IsOxygenAtom() || b.End.IsOxygenAtom())) != 2) { continue; } var sulfur2OxygenSingle = sulfurBonds.FirstOrDefault(b => b.Order == BondOrder.Single && (b.Begin.IsOxygenAtom() || b.End.IsOxygenAtom())); if (sulfur2OxygenSingle == null) { continue; } var singleBoundOxygen = sulfur2OxygenSingle.Begin.IsOxygenAtom() ? sulfur2OxygenSingle.Begin : sulfur2OxygenSingle.End; var singleBoundOxygenBonds = mol.GetConnectedBonds(singleBoundOxygen)?.ToList(); if (singleBoundOxygenBonds == null || !singleBoundOxygenBonds.Any()) { continue; } if (singleBoundOxygenBonds.Count(b => b.Order == BondOrder.Single && (b.Begin.IsHydrogenAtom() || b.End.IsHydrogenAtom())) != 1) { continue; } return(true); } return(false); }
/// <summary> /// set the active center for this molecule. /// The active center will be those which correspond with X=Y-Z-H. /// <pre> /// X: Atom /// =: bond /// Y: Atom /// -: bond /// Z: Atom /// -: bond /// H: Atom /// </pre> /// </summary> /// <param name="reactant">The molecule to set the activity</param> private static void SetActiveCenters(IAtomContainer reactant) { foreach (var atomi in reactant.Atoms) { if ((atomi.FormalCharge ?? 0) == 0 && !reactant.GetConnectedSingleElectrons(atomi).Any()) { foreach (var bondi in reactant.GetConnectedBonds(atomi)) { if (bondi.Order == BondOrder.Double) { IAtom atomj = bondi.GetOther(atomi); if ((atomj.FormalCharge ?? 0) == 0 && !reactant.GetConnectedSingleElectrons(atomj).Any()) { foreach (var bondj in reactant.GetConnectedBonds(atomj)) { if (bondj.Equals(bondi)) { continue; } if (bondj.Order == BondOrder.Single) { IAtom atomk = bondj.GetOther(atomj); if ((atomk.FormalCharge ?? 0) == 0 && !reactant.GetConnectedSingleElectrons(atomk).Any() ) { foreach (var bondk in reactant.GetConnectedBonds(atomk)) { if (bondk.Equals(bondj)) { continue; } if (bondk.Order == BondOrder.Single) { IAtom atoml = bondk.GetOther(atomk); // Atom pos 4 if (atoml.AtomicNumber.Equals(AtomicNumbers.H)) { atomi.IsReactiveCenter = true; atomj.IsReactiveCenter = true; atomk.IsReactiveCenter = true; atoml.IsReactiveCenter = true; bondi.IsReactiveCenter = true; bondj.IsReactiveCenter = true; bondk.IsReactiveCenter = true; } } } } } } } } } } } }
private void CreateCenterCode(IAtom root, IAtomContainer ac, bool ringsize) { int partnerCount = 0; partnerCount = atomContainer.GetConnectedBonds(root).Count() + (root.ImplicitHydrogenCount ?? 0); centerCode = root.Symbol + "-" + partnerCount + CreateChargeCode(root) + (ringsize ? GetRingcode(root, ac) : "") + ";"; }
/// <summary> /// Adjust the configuration of the <paramref name="dbs"/> element (if required). /// </summary> /// <param name="dbs">double-bond stereochemistry element</param> private void Adjust(IDoubleBondStereochemistry dbs) { var db = dbs.StereoBond; var bonds = dbs.Bonds; var left = db.Begin; var right = db.End; var p = Parity(dbs.Configure); var q = Parity(GetAtoms(left, bonds[0].GetOther(left), right)) * Parity(GetAtoms(right, bonds[1].GetOther(right), left)); // configuration is unspecified? then we add an unspecified bond. // note: IDoubleBondStereochemistry doesn't indicate this yet if (p == 0) { foreach (var bond in container.GetConnectedBonds(left)) { bond.Stereo = BondStereo.None; } foreach (var bond in container.GetConnectedBonds(right)) { bond.Stereo = BondStereo.None; } bonds[0].Stereo = BondStereo.UpOrDown; return; } // configuration is already correct if (p == q) { return; } Arrays.Fill(visited, false); visited[atomToIndex[left]] = true; if (ringSearch.Cyclic(atomToIndex[left], atomToIndex[right])) { db.Stereo = BondStereo.EOrZ; return; } foreach (var w in graph[atomToIndex[right]]) { if (!visited[w]) { Reflect(w, db); } } }
/// <summary> /// Performs a breadthFirstSearch in an AtomContainer starting with a /// particular sphere, which usually consists of one start atom, and searches /// for the longest aliphatic chain which is yet unplaced. If the search /// encounters an unplaced ring atom, it is also appended to the chain so that /// this last bond of the chain can also be laid out. This gives us the /// orientation for the attachment of the ring system. /// </summary> /// <param name="ac">The AtomContainer to be searched</param> /// <param name="sphere">A sphere of atoms to start the search with</param> /// <param name="pathes">A vector of N paths (N = no of heavy atoms).</param> /// <exception cref="CDKException"> Description of the Exception</exception> public static void BreadthFirstSearch(IAtomContainer ac, IList <IAtom> sphere, IAtomContainer[] pathes) { IAtom nextAtom = null; int atomNr; int nextAtomNr; //IAtomContainer path = null; var newSphere = new List <IAtom>(); Debug.WriteLine("Start of breadthFirstSearch"); foreach (var atom in sphere) { if (!atom.IsInRing) { atomNr = ac.Atoms.IndexOf(atom); Debug.WriteLine($"{nameof(BreadthFirstSearch)} around atom {atomNr + 1}"); var bonds = ac.GetConnectedBonds(atom); foreach (var curBond in bonds) { nextAtom = curBond.GetOther(atom); if (!nextAtom.IsVisited && !nextAtom.IsPlaced) { nextAtomNr = ac.Atoms.IndexOf(nextAtom); Debug.WriteLine("BreadthFirstSearch is meeting new atom " + (nextAtomNr + 1)); pathes[nextAtomNr] = ac.Builder.NewAtomContainer(pathes[atomNr]); Debug.WriteLine("Making copy of path " + (atomNr + 1) + " to form new path " + (nextAtomNr + 1)); pathes[nextAtomNr].Atoms.Add(nextAtom); Debug.WriteLine("Adding atom " + (nextAtomNr + 1) + " to path " + (nextAtomNr + 1)); pathes[nextAtomNr].Bonds.Add(curBond); if (ac.GetConnectedBonds(nextAtom).Count() > 1) { newSphere.Add(nextAtom); } } } } } if (newSphere.Count > 0) { for (int f = 0; f < newSphere.Count; f++) { newSphere[f].IsVisited = true; } BreadthFirstSearch(ac, newSphere, pathes); } Debug.WriteLine("End of breadthFirstSearch"); }
/// <inheritdoc/> public void AddImplicitHydrogens(IAtomContainer container, IAtom atom) { if (atom.AtomTypeName == null) { throw new CDKException("IAtom is not typed! " + atom.Symbol); } if (string.Equals("X", atom.AtomTypeName, StringComparison.Ordinal)) { if (atom.ImplicitHydrogenCount == null) { atom.ImplicitHydrogenCount = 0; } return; } var type = atomTypeList.GetAtomType(atom.AtomTypeName); if (type == null) { throw new CDKException("Atom type is not a recognized CDK atom type: " + atom.AtomTypeName); } if (type.FormalNeighbourCount == null) { throw new CDKException($"Atom type is too general; cannot decide the number of implicit hydrogen to add for: {atom.AtomTypeName}"); } // very simply counting: each missing explicit neighbor is a missing hydrogen atom.ImplicitHydrogenCount = type.FormalNeighbourCount - container.GetConnectedBonds(atom).Count(); }
private static int CountAttachedBonds(IAtomContainer container, IAtom atom, BondOrder order, string symbol) { var neighbors = container.GetConnectedBonds(atom).ToReadOnlyList(); int neighborcount = neighbors.Count; int doubleBondedAtoms = 0; for (int i = neighborcount - 1; i >= 0; i--) { var bond = neighbors[i]; if (bond.Order == order) { if (bond.Atoms.Count == 2 && bond.Contains(atom)) { if (symbol != null) { var neighbor = bond.GetOther(atom); if (string.Equals(neighbor.Symbol, symbol, StringComparison.Ordinal)) { doubleBondedAtoms++; } } else { doubleBondedAtoms++; } } } } return(doubleBondedAtoms); }
private static bool IsCarbonyl(IAtomContainer atomContainer, IAtom atom) { var neighbors = atomContainer.GetConnectedBonds(atom).ToReadOnlyList(); if (neighbors.Count != 1) { return(false); } var neighbor = neighbors[0]; var neighborAtom = neighbor.GetOther(atom); if (neighborAtom.AtomicNumber.Equals(AtomicNumbers.C)) { if (neighbor.Order == BondOrder.Single) { if (CountAttachedBonds(atomContainer, neighborAtom, BondOrder.Double, "O") == 1) { return(true); } } else if (neighbor.Order == BondOrder.Double) { if (CountAttachedBonds(atomContainer, neighborAtom, BondOrder.Single, "O") == 1) { return(true); } } } return(false); }
internal static bool TestIsAlcoholEther(IAtomContainer mol, Func <IAtom, IAtom, bool> expr) { if (mol == null || expr == null) { return(false); } foreach (var atom in mol.Atoms) { if (!atom.IsOxygenAtom()) { continue; } var bonds = mol.GetConnectedBonds(atom)?.ToList(); if (bonds == null || bonds.Count != 2) { continue; } var end0 = bonds[0].Atoms.FirstOrDefault(a => !a.IsOxygenAtom()); var end1 = bonds[1].Atoms.FirstOrDefault(a => !a.IsOxygenAtom()); if (expr(end0, end1)) { return(true); } } return(false); }
/// <summary> /// Compounds that contain one or more halogens /// </summary> public static bool IsHalide(this IAtomContainer mol) { if (mol == null) { return(false); } foreach (var atom in mol.Atoms) { if (!atom.IsCarbonAtom()) { continue; } var bonds = mol.GetConnectedBonds(atom)?.ToList(); if (bonds == null || bonds.Count != 4) { continue; } foreach (var cBond in bonds) { var connected = cBond.Atoms.FirstOrDefault(a => !a.IsCarbonAtom()); if (connected.ToNfAtom() is IHalogens) { return(true); } } } return(false); }
/// <summary> /// set the active center for this molecule. /// The active center will be those which correspond with [A+]=B. /// <pre> /// A: Atom with positive charge /// =: Double bond /// B: Atom /// </pre> /// </summary> /// <param name="reactant">The molecule to set the activity</param> private static void SetActiveCenters(IAtomContainer reactant) { foreach (var atomi in reactant.Atoms) { if (atomi.FormalCharge == 1) { foreach (var bondi in reactant.GetConnectedBonds(atomi)) { if (bondi.Order != BondOrder.Single) { IAtom atomj = bondi.GetOther(atomi); if (atomj.FormalCharge == 0) { if (!reactant.GetConnectedSingleElectrons(atomj).Any()) { atomi.IsReactiveCenter = true; bondi.IsReactiveCenter = true; atomj.IsReactiveCenter = true; } } } } } } }
/// <summary> /// Produces a HOSE code for Atom <paramref name="root"/> in the <see cref="IAtomContainer"/> <paramref name="ac"/>. The HOSE /// code is produced for the number of spheres given by <paramref name="noOfSpheres"/>. /// </summary> /// <remarks> /// <note type="important"> /// If you want aromaticity to be included in the code, you need /// to apply <see cref="Aromaticities.Aromaticity.Apply(IAtomContainer)"/> to <paramref name="ac"/> prior to /// using <see cref="GetHOSECode(IAtomContainer, IAtom, int, bool)"/>. This method only gives proper results if the molecule is /// fully saturated (if not, the order of the HOSE code might depend on atoms in higher spheres). /// This method is known to fail for protons sometimes. /// </note> /// <note type="important"> /// Your molecule must contain implicit or explicit hydrogens /// for this method to work properly. /// </note> /// </remarks> /// <param name="ac">The IAtomContainer with the molecular skeleton in which the root atom resides</param> /// <param name="root">The root atom for which to produce the HOSE code</param> /// <param name="noOfSpheres">The number of spheres to look at</param> /// <param name="ringsize">The size of the Ring(s) it is in is included in center atom code</param> /// <returns>The HOSECode value</returns> /// <exception cref="CDKException">Thrown if something is wrong</exception> public string GetHOSECode(IAtomContainer ac, IAtom root, int noOfSpheres, bool ringsize) { var canLabler = new CanonicalLabeler(); canLabler.CanonLabel(ac); centerCode = ""; this.atomContainer = ac; maxSphere = noOfSpheres; spheres = new List <TreeNode> [noOfSpheres + 1]; for (int i = 0; i < ac.Atoms.Count; i++) { ac.Atoms[i].IsVisited = false; } root.IsVisited = true; rootNode = new TreeNode(this, root.Symbol, null, root, (double)0, atomContainer.GetConnectedBonds(root).Count(), 0); // All we need to observe is how the ranking of substituents in the // subsequent spheres of the root nodes influences the ranking of the // first sphere, since the order of a node in a sphere depends on the // order the preceding node in its branch HOSECode = new StringBuilder(); CreateCenterCode(root, ac, ringsize); BreadthFirstSearch(root, true); CreateCode(); FillUpSphereDelimiters(); Debug.WriteLine($"HOSECodeGenerator -> HOSECode: {HOSECode}"); return(HOSECode.ToString()); }
public TargetProperties(IAtomContainer container) { int i = 0; atoms = new Dictionary <IAtom, int>(); atomsIndex = new Dictionary <int, IAtom>(); connectedTargetAtomCountMap = new Dictionary <IAtom, int>(); connectedTargetAtomListMap = new Dictionary <IAtom, IReadOnlyList <IAtom> >(); map = Arrays.CreateJagged <IBond>(container.Atoms.Count, container.Atoms.Count); foreach (var atom in container.Atoms) { int count = container.GetConnectedBonds(atom).Count(); connectedTargetAtomCountMap[atom] = count; var list = container.GetConnectedAtoms(atom); if (list != null) { connectedTargetAtomListMap[atom] = list.ToReadOnlyList(); } else { connectedTargetAtomListMap[atom] = new List <IAtom>(); } atoms[atom] = i; atomsIndex[i] = atom; i++; } foreach (var bond in container.Bonds) { map[atoms[bond.Begin]][atoms[bond.End]] = bond; map[atoms[bond.End]][atoms[bond.Begin]] = bond; } }
/// <summary> /// Helper method to locate two terminal atoms in a container for a given /// focus. /// </summary> /// <param name="container">structure representation</param> /// <param name="focus">cumulated atom</param> /// <returns>the terminal atoms (unordered)</returns> public static IAtom[] FindTerminalAtoms(IAtomContainer container, IAtom focus) { var focusBonds = container.GetConnectedBonds(focus); if (focusBonds.Count() != 2) { throw new ArgumentException("focus must have exactly 2 neighbors"); } var leftPrev = focus; var rightPrev = focus; var left = focusBonds.ElementAt(0).GetOther(focus); var right = focusBonds.ElementAt(1).GetOther(focus); IAtom tmp; while (left != null && right != null) { tmp = GetOtherNbr(container, left, leftPrev); leftPrev = left; left = tmp; tmp = GetOtherNbr(container, right, rightPrev); rightPrev = right; right = tmp; } return(new IAtom[] { leftPrev, rightPrev }); }
/// <summary> /// Says if an atom as a center of a square planar chirality. /// This method uses wedge bonds. 3D coordinates are not taken into account. If there /// are no wedge bonds around a potential stereo center, it will not be found. /// </summary> /// <param name="atom">The atom which is the center</param> /// <param name="container">The atomContainer the atom is in</param> /// <returns>true=is square planar, false=is not</returns> public static bool IsSquarePlanar(IAtomContainer container, IAtom atom) { var atoms = container.GetConnectedAtoms(atom); if (atoms.Count() != 4) { return(false); } var bonds = container.GetConnectedBonds(atom); int up = 0; int down = 0; foreach (var bond in bonds) { switch (bond.Stereo) { case BondStereo.None: break; case BondStereo.Up: up++; break; case BondStereo.Down: down++; break; } } return(up == 2 && down == 2 && !StereosAreOpposite(container, atom)); }
/// <summary> /// Make a query atom that matches atomic number, h count, valence, and /// connectivity. This effectively provides an exact match for that atom /// type. /// </summary> /// <param name="mol">molecule</param> /// <param name="atom">atom of molecule</param> /// <returns>the query atom (null if attachment point)</returns> private static IQueryAtom MatchExact(IAtomContainer mol, IAtom atom) { var bldr = atom.Builder; var elem = atom.AtomicNumber; // attach atom skipped if (elem == 0) { return(null); } var hcnt = atom.ImplicitHydrogenCount.Value; var val = hcnt; var con = hcnt; foreach (var bond in mol.GetConnectedBonds(atom)) { val += bond.Order.Numeric(); con++; if (bond.GetOther(atom).AtomicNumber == 1) { hcnt++; } } var expr = new Expr(ExprType.Element, elem) .And(new Expr(ExprType.TotalDegree, con)) .And(new Expr(ExprType.TotalHCount, hcnt)) .And(new Expr(ExprType.Valence, val)); return(new QueryAtom(expr)); }
private string EncodePath(IAtomContainer mol, Dictionary <IAtom, List <IBond> > cache, List <IAtom> path, StringBuilder buffer) { buffer.Clear(); var prev = path[0]; buffer.Append(GetAtomSymbol(prev)); for (int i = 1; i < path.Count; i++) { var next = path[i]; var bonds = cache[prev]; if (bonds == null) { bonds = mol.GetConnectedBonds(prev).ToList(); cache[prev] = bonds; } var bond = FindBond(bonds, next, prev); if (bond == null) { throw new InvalidOperationException("FATAL - Atoms in patch were connected?"); } buffer.Append(GetBondSymbol(bond)); buffer.Append(GetAtomSymbol(next)); prev = next; } return(buffer.ToString()); }
public void SaturateRingSystems(IAtomContainer atomContainer) { var rs0 = Cycles.FindSSSR(atomContainer.Builder.NewAtomContainer(atomContainer)).ToRingSet(); var ringSets = RingPartitioner.PartitionRings(rs0); IAtom atom = null; foreach (var rs in ringSets) { var containers = RingSetManipulator.GetAllAtomContainers(rs); foreach (var ac in containers) { var temp = new int[ac.Atoms.Count]; for (int g = 0; g < ac.Atoms.Count; g++) { atom = ac.Atoms[g]; temp[g] = atom.ImplicitHydrogenCount.Value; atom.ImplicitHydrogenCount = (atomContainer.GetConnectedBonds(atom).Count() - ac.GetConnectedBonds(atom).Count() - temp[g]); } Saturate(ac); for (int g = 0; g < ac.Atoms.Count; g++) { atom = ac.Atoms[g]; atom.ImplicitHydrogenCount = temp[g]; } } } }
/// <summary> /// Calculates the eccentric connectivity /// </summary> /// <returns>A <see cref="Result"/> value representing the eccentric connectivity index</returns> public Result Calculate(IAtomContainer container) { container = AtomContainerManipulator.RemoveHydrogens(container); var natom = container.Atoms.Count; var admat = AdjacencyMatrix.GetMatrix(container); var distmat = PathTools.ComputeFloydAPSP(admat); int eccenindex = 0; for (int i = 0; i < natom; i++) { int max = -1; for (int j = 0; j < natom; j++) { if (distmat[i][j] > max) { max = distmat[i][j]; } } var degree = container.GetConnectedBonds(container.Atoms[i]).Count(); eccenindex += max * degree; } return(new Result(eccenindex)); }
private static void SetActiveCenters(IAtomContainer reactant, CheckReactant checkReatant, CheckReactantAtom checkReatantAtom, CheckAtom checkAtom) { if (checkReatant != null && !checkReatant(reactant)) { return; } foreach (var atomi in reactant.Atoms) { if (checkReatantAtom(reactant, atomi)) { foreach (var bondi in reactant.GetConnectedBonds(atomi)) { if (bondi.Order == BondOrder.Single) { IAtom atomj = bondi.GetOther(atomi); if ((atomj.FormalCharge ?? 0) == 0 && !reactant.GetConnectedSingleElectrons(atomj).Any()) { foreach (var bondj in reactant.GetConnectedBonds(atomj)) { if (bondj.Equals(bondi)) { continue; } if (bondj.Order == BondOrder.Double) { IAtom atomk = bondj.GetOther(atomj); if (checkAtom(atomk) && !reactant.GetConnectedSingleElectrons(atomk).Any()) { atomi.IsReactiveCenter = true; atomj.IsReactiveCenter = true; atomk.IsReactiveCenter = true; bondi.IsReactiveCenter = true; bondj.IsReactiveCenter = true; } } } } } } } } }
/// <summary> /// Says if an atom as a center of a tetrahedral chirality. /// This method uses wedge bonds. 3D coordinates are not taken into account. If there /// are no wedge bonds around a potential stereo center, it will not be found. /// </summary> /// <param name="atom">The atom which is the center</param> /// <param name="container">The atomContainer the atom is in</param> /// <param name="strict"></param> /// <returns>0=is not tetrahedral; >1 is a certain depiction of /// tetrahedrality (evaluated in parse chain)</returns> public static int IsTetrahedral(IAtomContainer container, IAtom atom, bool strict) { var atoms = container.GetConnectedAtoms(atom); if (atoms.Count() != 4) { return(0); } var bonds = container.GetConnectedBonds(atom); int up = 0; int down = 0; foreach (var bond in bonds) { switch (bond.Stereo) { case BondStereo.None: break; case BondStereo.Up: up++; break; case BondStereo.Down: down++; break; } } if (up == 1 && down == 1) { return(1); } if (up == 2 && down == 2) { if (StereosAreOpposite(container, atom)) { return(2); } return(0); } if (up == 1 && down == 0 && !strict) { return(3); } if (down == 1 && up == 0 && !strict) { return(4); } if (down == 2 && up == 1 && !strict) { return(5); } if (down == 1 && up == 2 && !strict) { return(6); } return(0); }
internal IReactionSet Initiate(IChemObjectSet <IAtomContainer> reactants, IChemObjectSet <IAtomContainer> agents, bool isReverse, CheckReactantAtom checkReactantAtom, CheckAtom checkAtom, CheckBond checkBond) { CheckInitiateParams(reactants, agents); IReactionSet setOfReactions = reactants.Builder.NewReactionSet(); IAtomContainer reactant = reactants[0]; // if the parameter hasActiveCenter is not fixed yet, set the active centers IParameterReaction ipr = base.GetParameterClass(typeof(SetReactionCenter)); if (ipr != null && !ipr.IsSetParameter) { SetActiveCenters(reactant, checkReactantAtom, checkAtom, checkBond); } foreach (var atomi in reactant.Atoms) { if (atomi.IsReactiveCenter && checkReactantAtom(reactant, atomi)) { foreach (var bondi in reactant.GetConnectedBonds(atomi)) { if (bondi.IsReactiveCenter && checkBond(bondi)) { IAtom atomj = bondi.GetOther(atomi); if (atomj.IsReactiveCenter && checkAtom(atomj) && !reactant.GetConnectedSingleElectrons(atomj).Any()) { IAtom[] atomList; if (isReverse) { atomList = new[] { atomj, atomi } } ; else { atomList = new[] { atomi, atomj } }; var bondList = new[] { bondi }; IChemObjectSet <IAtomContainer> moleculeSet = reactant.Builder.NewChemObjectSet <IAtomContainer>(); moleculeSet.Add(reactant); IReaction reaction = Mechanism.Initiate(moleculeSet, atomList, bondList); if (reaction == null) { continue; } else { setOfReactions.Add(reaction); } } } } } } return(setOfReactions); }
internal List <IBond> GetBonds(IAtom atom) { if (!cache.TryGetValue(atom, out List <IBond> bonds)) { bonds = mol.GetConnectedBonds(atom).ToList(); cache[atom] = bonds; } return(bonds); }
/// <summary> /// Calculates the volume for the given <see cref="IAtomContainer"/>. This methods assumes /// that atom types have been perceived. /// </summary> /// <param name="molecule"><see cref="IAtomContainer"/> to calculate the volume of.</param> /// <returns>the volume in cubic Ångström.</returns> public static double Calculate(IAtomContainer molecule) { double sum = 0.0; int totalHCount = 0; foreach (var atom in molecule.Atoms) { if (!bondiiVolumes.TryGetValue(atom.Symbol, out double bondiiVolume)) { throw new CDKException("Unsupported element."); } sum += bondiiVolume; // add volumes of implicit hydrogens? var type = atomTypeList.GetAtomType(atom.AtomTypeName); if (type == null) { throw new CDKException($"Unknown atom type for atom: {atom.Symbol}"); } if (type.FormalNeighbourCount == null) { throw new CDKException($"Formal neighbor count not given for : {type.AtomTypeName}"); } int hCount = type.FormalNeighbourCount.Value - molecule.GetConnectedBonds(atom).Count(); sum += hCount * bondiiVolumes["H"]; totalHCount += hCount; } sum -= 5.92 * (molecule.Bonds.Count + totalHCount); Aromaticity.CDKLegacy.Apply(molecule); var ringSet = Cycles.FindSSSR(molecule).ToRingSet(); if (ringSet.Count() > 0) { int aromRingCount = 0; int nonAromRingCount = 0; foreach (var ring in ringSet) { if (RingIsAromatic(ring)) { aromRingCount++; } else { nonAromRingCount++; } } sum -= 14.7 * aromRingCount; sum -= 3.8 * nonAromRingCount; } return(sum); }
internal static List <IBond> Traverse(IAtomContainer atomContainer, IAtom atom, List <IBond> bondList) { var connectedBonds = atomContainer.GetConnectedBonds(atom); foreach (var aBond in connectedBonds) { if (bondList.Contains(aBond)) { continue; } bondList.Add(aBond); IAtom nextAtom = aBond.GetOther(atom); if (atomContainer.GetConnectedBonds(nextAtom).Count() == 1) { continue; } Traverse(atomContainer, nextAtom, bondList); } return(bondList); }
/// <summary> /// Sums up the degrees of atoms in an atomcontainer /// </summary> /// <param name="ac">The atomcontainer to be processed</param> /// <param name="superAC">The superAtomContainer from which the former has been derived</param> /// <returns>sum of degrees</returns> static int GetDegreeSum(IAtomContainer ac, IAtomContainer superAC) { int degreeSum = 0; for (int f = 0; f < ac.Atoms.Count; f++) { degreeSum += superAC.GetConnectedBonds(ac.Atoms[f]).Count(); degreeSum += ac.Atoms[f].ImplicitHydrogenCount ?? 0; } return(degreeSum); }
/// <summary> /// Finds a neighbor attached to 'atom' that is singley bonded and isn't 'exclude'. If no such atom exists, the 'atom' is returned. /// </summary> /// <param name="container">a molecule container</param> /// <param name="atom">the atom to find the neighbor or</param> /// <param name="exclude">don't find this atom</param> /// <returns>the other atom (or 'atom')</returns> private static IAtom FindOtherSinglyBonded(IAtomContainer container, IAtom atom, IAtom exclude) { foreach (var bond in container.GetConnectedBonds(atom)) { if (!BondOrder.Single.Equals(bond.Order) || bond.Contains(exclude)) { continue; } return(bond.GetOther(atom)); } return(atom); }
/// <summary> /// Create an encoder for axial 2D stereochemistry for the given start and /// end atoms. /// </summary> /// <param name="container">the molecule</param> /// <param name="start">start of the cumulated system</param> /// <param name="end">end of the cumulated system</param> /// <returns>an encoder or null if there are no coordinated</returns> internal static IStereoEncoder AxialEncoder(IAtomContainer container, IAtom start, IAtom end) { var startBonds = container.GetConnectedBonds(start); var endBonds = container.GetConnectedBonds(end); if (startBonds.Count() < 2 || endBonds.Count() < 2) { return(null); } if (Has2DCoordinates(startBonds) && Has2DCoordinates(endBonds)) { return(Axial2DEncoder(container, start, startBonds, end, endBonds)); } else if (Has3DCoordinates(startBonds) && Has3DCoordinates(endBonds)) { return(Axial3DEncoder(container, start, startBonds, end, endBonds)); } return(null); }
/// <summary> /// Recursively performs a depth first search in a molecular graphs contained in /// the AtomContainer molecule, starting at the root atom and returning when it /// hits the target atom. /// <para> /// CAUTION: This recursive method sets the VISITED flag of each atom /// does not reset it after finishing the search. If you want to do the /// operation on the same collection of atoms more than once, you have /// to set all the VISITED flags to false before each operation /// by looping of the atoms and doing a /// "atom.Flag = (CDKConstants.VISITED, false);" /// </para> /// <para> /// Note that the path generated by the search will not contain the root atom, /// but will contain the target atom /// </para> /// </summary> /// <param name="molecule">The AtomContainer to be searched</param> /// <param name="root">The root atom to start the search at</param> /// <param name="target">The target</param> /// <param name="path">An AtomContainer to be filled with the path</param> /// <returns><see langword="true"/> if the target atom was found during this function call</returns> public static bool DepthFirstTargetSearch(IAtomContainer molecule, IAtom root, IAtom target, IAtomContainer path) { var bonds = molecule.GetConnectedBonds(root); IAtom nextAtom; root.IsVisited = true; bool first = path.IsEmpty(); if (first) { path.Atoms.Add(root); } foreach (var bond in bonds) { nextAtom = bond.GetOther(root); if (!nextAtom.IsVisited) { path.Atoms.Add(nextAtom); path.Bonds.Add(bond); if (nextAtom.Equals(target)) { if (first) { path.Atoms.Remove(root); } return(true); } else { if (!DepthFirstTargetSearch(molecule, nextAtom, target, path)) { // we did not find the target path.Atoms.Remove(nextAtom); path.Bonds.Remove(bond); } else { if (first) { path.Atoms.Remove(root); } return(true); } } } } if (first) { path.Atoms.Remove(root); } return(false); }
private static void SetActiveCenters(IAtomContainer reactant, string atomSymbol, int charge) { foreach (var atomi in reactant.Atoms) { if (reactant.GetConnectedSingleElectrons(atomi).Count() == 1 && atomi.FormalCharge == charge) { foreach (var bondi in reactant.GetConnectedBonds(atomi)) { if (bondi.Order == BondOrder.Single) { IAtom atomj = bondi.GetOther(atomi); if (atomj.FormalCharge == 0) { foreach (var bondj in reactant.GetConnectedBonds(atomj)) { if (bondj.Equals(bondi)) { continue; } if (bondj.Order == BondOrder.Single) { IAtom atomk = bondj.GetOther(atomj); if (atomk.Symbol.Equals(atomSymbol, StringComparison.Ordinal) && atomk.FormalCharge == 0) { atomi.IsReactiveCenter = true; atomj.IsReactiveCenter = true; atomk.IsReactiveCenter = true; bondi.IsReactiveCenter = true; bondj.IsReactiveCenter = true; } } } } } } } } }