/// <summary> /// The method is a proton descriptor that evaluate if a proton is bonded to an aromatic system or if there is distance of 2 bonds. /// It is needed to call the addExplicitHydrogensToSatisfyValency method from the class tools.HydrogenAdder. /// </summary> /// <param name="atom">The <see cref="IAtom"/> for which the <see cref="Result"/> is requested</param> /// <returns>true if the proton is bonded to an aromatic atom.</returns> public Result Calculate(IAtom atom) { var clonedAtom = clonedAtomContainer.Atoms[container.Atoms.IndexOf(atom)]; var neighboor = clonedAtomContainer.GetConnectedAtoms(clonedAtom); var neighbour0 = neighboor.First(); int isProtonInAromaticSystem = 0; if (atom.AtomicNumber.Equals(AtomicNumbers.H)) { if (neighbour0.IsAromatic) { isProtonInAromaticSystem = 1; } else { var betaAtom = clonedAtomContainer.GetConnectedAtoms(neighbour0).LastOrDefault(); if (betaAtom != null) { if (betaAtom.IsAromatic) { isProtonInAromaticSystem = 2; } else { isProtonInAromaticSystem = 0; } } } } else { isProtonInAromaticSystem = 0; } return(new Result(isProtonInAromaticSystem)); }
/// <summary> /// The method returns if two atoms have pi-contact. /// </summary> /// <returns><see langword="true"/> if the atoms have pi-contact</returns> /// <param name="first">The first atom</param> /// <param name="second">The second atom</param> public Result Calculate(IAtom first, IAtom second) { var clonedFirst = clonedContainer.Atoms[container.Atoms.IndexOf(first)]; var clonedSecond = clonedContainer.Atoms[container.Atoms.IndexOf(second)]; bool piContact = false; int counter = 0; var detected = acSet; var neighboorsFirst = mol.GetConnectedAtoms(clonedFirst); var neighboorsSecond = mol.GetConnectedAtoms(clonedSecond); foreach (var detectedAC in detected) { if (detectedAC.Contains(clonedFirst) && detectedAC.Contains(clonedSecond)) { counter += 1; break; } if (IsANeighboorsInAnAtomContainer(neighboorsFirst, detectedAC) && IsANeighboorsInAnAtomContainer(neighboorsSecond, detectedAC)) { counter += 1; break; } } if (counter > 0) { piContact = true; } return(new Result(piContact)); }
/// <summary> /// Says if an atom is the end of a double bond configuration /// </summary> /// <param name="atom">The atom which is the end of configuration</param> /// <param name="container">The atomContainer the atom is in</param> /// <param name="parent">The atom we came from</param> /// <param name="doubleBondConfiguration">The array indicating where double bond /// configurations are specified (this method ensures that there is /// actually the possibility of a double bond configuration)</param> /// <returns>false=is not end of configuration, true=is</returns> private static bool IsEndOfDoubleBond(IAtomContainer container, IAtom atom, IAtom parent, bool[] doubleBondConfiguration) { var bondNumber = container.Bonds.IndexOf(container.GetBond(atom, parent)); if (bondNumber == -1 || doubleBondConfiguration.Length <= bondNumber || !doubleBondConfiguration[bondNumber]) { return(false); } int hcount = atom.ImplicitHydrogenCount ?? 0; int lengthAtom = container.GetConnectedAtoms(atom).Count() + hcount; hcount = parent.ImplicitHydrogenCount ?? 0; int lengthParent = container.GetConnectedAtoms(parent).Count() + hcount; if (container.GetBond(atom, parent) != null) { if (container.GetBond(atom, parent).Order == BondOrder.Double && (lengthAtom == 3 || (lengthAtom == 2 && atom.AtomicNumber.Equals(AtomicNumbers.N))) && (lengthParent == 3 || (lengthParent == 2 && parent.AtomicNumber.Equals(AtomicNumbers.N)))) { var atoms = container.GetConnectedAtoms(atom); IAtom one = null; IAtom two = null; foreach (var conAtom in atoms) { if (conAtom != parent && one == null) { one = conAtom; } else if (conAtom != parent && one != null) { two = conAtom; } } string[] morgannumbers = MorganNumbersTools.GetMorganNumbersWithElementSymbol(container); if ((one != null && two == null && atom.AtomicNumber.Equals(AtomicNumbers.N) && Math.Abs(GiveAngleBothMethods(parent, atom, one, true)) > Math.PI / 10) || (!atom.AtomicNumber.Equals(AtomicNumbers.N) && one != null && two != null && !morgannumbers[container.Atoms.IndexOf(one)].Equals(morgannumbers[container.Atoms.IndexOf(two)], StringComparison.Ordinal))) { return(true); } else { return(false); } } } return(false); }
/// <summary> /// Says if an atom is the start of a double bond configuration /// </summary> /// <param name="a">The atom which is the start of configuration</param> /// <param name="container">The atomContainer the atom is in</param> /// <param name="parent">The atom we came from</param> /// <param name="doubleBondConfiguration">The array indicating where double bond /// configurations are specified (this method ensures that there is /// actually the possibility of a double bond configuration)</param> /// <returns>false=is not start of configuration, true=is</returns> private static bool IsStartOfDoubleBond(IAtomContainer container, IAtom a, IAtom parent, bool[] doubleBondConfiguration) { int hcount; hcount = a.ImplicitHydrogenCount ?? 0; int lengthAtom = container.GetConnectedAtoms(a).Count() + hcount; if (lengthAtom != 3 && (lengthAtom != 2 && !(a.AtomicNumber.Equals(AtomicNumbers.N)))) { return(false); } var atoms = container.GetConnectedAtoms(a); IAtom one = null; IAtom two = null; bool doubleBond = false; IAtom nextAtom = null; foreach (var atom in atoms) { if (atom != parent && container.GetBond(atom, a).Order == BondOrder.Double && IsEndOfDoubleBond(container, atom, a, doubleBondConfiguration)) { doubleBond = true; nextAtom = atom; } if (atom != nextAtom && one == null) { one = atom; } else if (atom != nextAtom && one != null) { two = atom; } } string[] morgannumbers = MorganNumbersTools.GetMorganNumbersWithElementSymbol(container); if (one != null && ((!a.AtomicNumber.Equals(AtomicNumbers.N) && two != null && !morgannumbers[container.Atoms.IndexOf(one)].Equals(morgannumbers[container.Atoms.IndexOf(two)], StringComparison.Ordinal) && doubleBond && doubleBondConfiguration[container.Bonds.IndexOf(container.GetBond(a, nextAtom))]) || (doubleBond && a.AtomicNumber.Equals(AtomicNumbers.N) && Math.Abs(GiveAngleBothMethods(nextAtom, a, parent, true)) > Math.PI / 10))) { return(true); } else { return(false); } }
/// <summary> /// Prepares for a breadth first search within the <see cref="IAtomContainer"/>. The actual /// recursion is done in <see cref="NextSphere"/>. /// </summary> /// <param name="root">The atom at which we start the search</param> /// <param name="addTreeNode"></param> /// <exception cref="CDKException"> If something goes wrong.</exception> private void BreadthFirstSearch(IAtom root, bool addTreeNode) { sphere = 0; TreeNode tempNode = null; var conAtoms = atomContainer.GetConnectedAtoms(root); IBond bond = null; sphereNodes.Clear(); sphereNodesWithAtoms.Clear(); foreach (var atom in conAtoms) { try { if (atom.AtomicNumber.Equals(AtomicNumbers.H)) { continue; } bond = atomContainer.GetBond(root, atom); // In the first sphere the atoms are labeled with their own atom // atom as source if (bond.IsAromatic) { tempNode = new TreeNode(this, atom.Symbol, new TreeNode(this, root.Symbol, null, root, (double)0, 0, (long)0), atom, 4, atomContainer.GetConnectedBonds(atom).Count(), 0); } else { tempNode = new TreeNode( this, atom.Symbol, new TreeNode(this, root.Symbol, null, root, (double)0, 0, (long)0), atom, bond.Order.Numeric(), atomContainer.GetConnectedBonds(atom).Count(), 0); } sphereNodes.Add(tempNode); if (!addTreeNode) { sphereNodesWithAtoms.Add(atom); } // rootNode.childs.AddElement(tempNode); atom.IsVisited = true; } catch (Exception exc) { throw new CDKException("Error in HOSECodeGenerator->breadthFirstSearch.", exc); } } sphereNodes.Sort(new TreeNodeComparator()); NextSphere(sphereNodes); }
/// <summary> /// Get all the paths starting from an atom of length 0 up to the specified length. /// <para>This method returns a set of paths. Each path is a <see cref="IList{IAtom}"/> of atoms that make up the path (i.e. they are sequentially connected).</para> /// </summary> /// <param name="atomContainer">The molecule to consider</param> /// <param name="start">The starting atom</param> /// <param name="length">The maximum length of paths to look for</param> /// <returns>A <see cref="IList{T}"/> of <see cref="IList{T}"/> of <see cref="IAtom"/> containing the paths found</returns> public static IList <IList <IAtom> > GetPathsOfLengthUpto(IAtomContainer atomContainer, IAtom start, int length) { IList <IAtom> curPath = new List <IAtom>(); List <IList <IAtom> > paths = new List <IList <IAtom> >(); List <IList <IAtom> > allpaths = new List <IList <IAtom> >(); curPath.Add(start); paths.Add(curPath); allpaths.Add(curPath); for (int i = 0; i < length; i++) { IList <IList <IAtom> > tmpList = new List <IList <IAtom> >(); foreach (var path in paths) { curPath = path; IAtom lastVertex = curPath[curPath.Count - 1]; var neighbors = atomContainer.GetConnectedAtoms(lastVertex); foreach (var neighbor in neighbors) { List <IAtom> newPath = new List <IAtom>(curPath); if (newPath.Contains(neighbor)) { continue; } newPath.Add(neighbor); tmpList.Add(newPath); } } paths.Clear(); paths.AddRange(tmpList); allpaths.AddRange(tmpList); } return(allpaths); }
/// <summary> /// get the electrostatic potential of the neighbours of a atom. /// </summary> /// <param name="ac">The IAtomContainer to study</param> /// <param name="atom1">The position of the IAtom to study</param> /// <param name="ds"></param> /// <returns>The sum of electrostatic potential of the neighbours</returns> private double GetElectrostaticPotentialN(IAtomContainer ac, int atom1, double[] ds) { // double CoulombForceConstant = 1/(4*Math.PI*8.81/*Math.Pow(10, -12)*/); double CoulombForceConstant = 0.048; double sum = 0.0; try { var atoms = ac.GetConnectedAtoms(ac.Atoms[atom1]); foreach (var atom in atoms) { double covalentradius = 0; string symbol = atom.Symbol; IAtomType type = factory.GetAtomType(symbol); covalentradius = type.CovalentRadius.Value; double charge = ds[StepSize * atom1 + atom1 + 5]; Debug.WriteLine($"sum_({sum}) = CFC({CoulombForceConstant})*Charge({charge}/ret({covalentradius}"); sum += CoulombForceConstant * charge / (covalentradius * covalentradius); } } catch (CDKException e) { Debug.WriteLine(e); } return(sum); }
private static List <List <int> > LabelAtoms(IAtomContainer atomCont) { List <List <int> > labelList = new List <List <int> >(); for (int i = 0; i < atomCont.Atoms.Count; i++) { LabelContainer labelContainer = LabelContainer.Instance; List <int> label = new List <int>(7); // label.SetSize(7); for (int a = 0; a < 7; a++) { label.Insert(a, 0); } IAtom refAtom = atomCont.Atoms[i]; string atom1Type = refAtom.Symbol; label[0] = labelContainer.GetLabelID(atom1Type); int countNeighbors = 1; var connAtoms = atomCont.GetConnectedAtoms(refAtom); foreach (var negAtom in connAtoms) { string atom2Type = negAtom.Symbol; label[countNeighbors++] = labelContainer.GetLabelID(atom2Type); } BubbleSort(label); labelList.Add(label); } return(labelList); }
/// <summary> /// Create initial invariant labeling corresponds to step 1 /// </summary> /// <returns>List containing the</returns> private static List <InvPair> CreateInvarLabel(IAtomContainer atomContainer) { var atoms = atomContainer.Atoms; StringBuilder inv; var vect = new List <InvPair>(); foreach (var a in atoms) { inv = new StringBuilder(); var connectedAtoms = atomContainer.GetConnectedAtoms(a).ToReadOnlyList(); inv.Append(connectedAtoms.Count + (a.ImplicitHydrogenCount ?? 0)); //Num connections inv.Append(connectedAtoms.Count); //Num of non H bonds inv.Append(PeriodicTable.GetAtomicNumber(a.Symbol)); double charge = a.Charge ?? 0; if (charge < 0) //Sign of charge { inv.Append(1); } else { inv.Append(0); //Absolute charge } inv.Append((int)Math.Abs((a.FormalCharge ?? 0))); //Hydrogen count inv.Append((a.ImplicitHydrogenCount ?? 0)); vect.Add(new InvPair(long.Parse(inv.ToString(), NumberFormatInfo.InvariantInfo), a)); } return(vect); }
// FIXME: class JavaDoc should use <token>cdk-cite-BLA</token> for the CDK News article /// <summary> /// Tells if a certain bond is center of a valid double bond configuration. /// </summary> /// <param name="container">The atom container.</param> /// <param name="bond">The bond.</param> /// <returns>true=is a potential configuration, false=is not.</returns> public static bool IsValidDoubleBondConfiguration(IAtomContainer container, IBond bond) { //IAtom[] atoms = bond.GetAtoms(); var connectedAtoms = container.GetConnectedAtoms(bond.Begin); IAtom from = null; foreach (var connectedAtom in connectedAtoms) { if (connectedAtom != bond.End) { from = connectedAtom; } } bool[] array = new bool[container.Bonds.Count]; for (int i = 0; i < array.Length; i++) { array[i] = true; } if (IsStartOfDoubleBond(container, bond.Begin, from, array) && IsEndOfDoubleBond(container, bond.End, bond.Begin, array) && !bond.IsAromatic) { return(true); } else { return(false); } }
/// <summary> /// Gets a randomly selected unsaturated atom from the set. If there are any, it will be from another /// container than exclusionAtom. /// </summary> /// <returns>The unsaturated atom.</returns> private IAtom GetAnotherUnsaturatedNode(IAtom exclusionAtom, IAtomContainer exclusionAtomContainer, IChemObjectSet <IAtomContainer> atomContainers) { foreach (var ac in atomContainers) { if (ac != exclusionAtomContainer) { int next = 0;//(int) (Math.Random() * ac.Atoms.Count); for (int f = next; f < ac.Atoms.Count; f++) { var atom = ac.Atoms[f]; if (!satCheck.IsSaturated(atom, ac) && exclusionAtom != atom) { return(atom); } } } } { var next = exclusionAtomContainer.Atoms.Count;//(int) (Math.random() * ac.getAtomCount()); for (int f = 0; f < next; f++) { var atom = exclusionAtomContainer.Atoms[f]; if (!satCheck.IsSaturated(atom, exclusionAtomContainer) && exclusionAtom != atom && !exclusionAtomContainer.GetConnectedAtoms(exclusionAtom).Contains(atom)) { return(atom); } } } return(null); }
private static IAtomContainer RecomputeHydrogens(IAtomContainer mol, IAtomContainer atomContainer, List <IAtom> remove, CDKObjectMap map) { // Recompute hydrogen counts of neighbours of removed Hydrogens. foreach (var aRemove in remove) { // Process neighbours. foreach (var iAtom in atomContainer.GetConnectedAtoms(aRemove)) { if (!map.TryGetValue(iAtom, out IAtom neighb)) { continue; // since for the case of H2, neight H has atom heavy atom neighbor } //Added by Asad if (!(neighb is IPseudoAtom)) { neighb.ImplicitHydrogenCount = (neighb.ImplicitHydrogenCount ?? 0) + 1; } else { neighb.ImplicitHydrogenCount = 0; } } } return(mol); }
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> /// Search and place branches of a chain or ring. /// </summary> /// <param name="chain">AtomContainer if atoms in an aliphatic chain or ring system</param> private void SearchAndPlaceBranches(IAtomContainer molecule, IAtomContainer chain, AtomPlacer3D ap3d, AtomTetrahedralLigandPlacer3D atlp3d, AtomPlacer atomPlacer) { //Debug.WriteLine("****** SEARCH AND PLACE ****** Chain length: "+chain.Atoms.Count); IAtomContainer branchAtoms = molecule.Builder.NewAtomContainer(); IAtomContainer connectedAtoms = molecule.Builder.NewAtomContainer(); for (int i = 0; i < chain.Atoms.Count; i++) { var atoms = molecule.GetConnectedAtoms(chain.Atoms[i]); foreach (var atom in atoms) { if (!atom.AtomicNumber.Equals(AtomicNumbers.H) & !atom.IsPlaced & !atom.IsInRing) { connectedAtoms.Add(ap3d.GetPlacedHeavyAtoms(molecule, chain.Atoms[i])); try { SetBranchAtom(molecule, atom, chain.Atoms[i], connectedAtoms, ap3d, atlp3d); } catch (CDKException ex2) { Trace.TraceError($"SearchAndPlaceBranchERROR: Cannot find enough neighbour atoms due to {ex2.ToString()}"); throw new CDKException($"SearchAndPlaceBranchERROR: Cannot find enough neighbour atoms: {ex2.Message}", ex2); } branchAtoms.Atoms.Add(atom); connectedAtoms.RemoveAllElements(); } } }//for ac.getAtomCount PlaceLinearChains3D(molecule, branchAtoms, ap3d, atlp3d, atomPlacer); }
private static void FixPyridineNOxides(IAtomContainer atomContainer, IRingSet ringSet) { //convert n(=O) to [n+][O-] for (int i = 0; i < atomContainer.Atoms.Count; i++) { var ai = atomContainer.Atoms[i]; if (ai.AtomicNumber.Equals(AtomicNumbers.N) && (ai.FormalCharge == null || ai.FormalCharge == 0)) { if (InRingSet(ai, ringSet)) { var ca = atomContainer.GetConnectedAtoms(ai); foreach (var caj in ca) { if (caj.AtomicNumber.Equals(AtomicNumbers.O) && atomContainer.GetBond(ai, caj).Order == BondOrder.Double) { ai.FormalCharge = 1; caj.FormalCharge = -1; atomContainer.GetBond(ai, caj).Order = BondOrder.Single; } } // end for (int j=0;j<ca.Count;j++) } // end if (InRingSet(ai,ringSet)) { } // end if (ai.Symbol.Equals("N") && ai.FormalCharge==0) } // end for (int i=0;i<atomContainer.Atoms.Count;i++) }
/// <summary> /// Is the {@code atom} a suppressible hydrogen and can be represented as /// implicit. A hydrogen is suppressible if it is not an ion, not the major /// isotope (i.e. it is a deuterium or tritium atom) and is not molecular /// hydrogen. /// </summary> /// <param name="container"> the structure </param> /// <param name="atom"> an atom in the structure </param> /// <returns> the atom is a hydrogen and it can be suppressed (implicit) </returns> private static bool suppressibleHydrogen(IAtomContainer container, IAtom atom) { // is the atom a hydrogen if (!"H".Equals(atom.Symbol)) { return(false); } // is the hydrogen an ion? if (GetFormalCharge(atom) != 0) { return(false); } // is the hydrogen deuterium / tritium? if (GetMassNumber(atom) != 1) { return(false); } // molecule hydrogen with implicit H? if (atom.ImplicitHydrogenCount != null && (int)atom.ImplicitHydrogenCount != 0) { return(false); } // molecule hydrogen List <IAtom> neighbors = container.GetConnectedAtoms(atom) as List <IAtom>; if (neighbors.Count == 1 && neighbors[0].Symbol.Equals("H")) { return(false); } // what about bridging hydrogens? // hydrogens with atom-atom mapping? return(true); }
/// <summary> /// Constructor /// <param name="queryContainer">query atom container</param> /// <param name="template">query atom</param> /// <param name="blockedPositions">/// <param name="shouldMatchBonds">bond matching flag</param></param> /// </summary> public DefaultVFAtomMatcher(IAtomContainer queryContainer, IAtom template, int blockedPositions, bool shouldMatchBonds) : this(queryContainer, template, shouldMatchBonds) { this.maximumNeighbors = CountImplicitHydrogens(template) + queryContainer.GetConnectedAtoms(template).Count() - blockedPositions; }
/// <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> /// The method is a proton descriptor that evaluates if a proton is joined to a conjugated system. /// </summary> /// <param name="atom">The <see cref="IAtom"/> for which the <see cref="Result"/> is requested</param> /// <returns><see langword="true"/> if the proton is bonded to a conjugated system</returns> public Result Calculate(IAtom atom) { var clonedAtom = clonedAtomContainer.Atoms[container.Atoms.IndexOf(atom)]; bool isProtonInPiSystem = false; if (atom.AtomicNumber.Equals(AtomicNumbers.H)) { var detected = acSet.GetEnumerator(); var neighboors = clonedAtomContainer.GetConnectedAtoms(clonedAtom); foreach (var neighboor in neighboors) { while (detected.MoveNext()) { var detectedAC = detected.Current; if (detectedAC != null && detectedAC.Contains(neighboor)) { isProtonInPiSystem = true; break; } } } } return(new Result(isProtonInPiSystem)); }
/// <summary> /// Checks whether the P atom is in a PO environment. /// </summary> /// <remarks> /// This environment is noted in Kier & Hall (1986), page 20 /// </remarks> /// <param name="atom">The P atom in question</param> /// <param name="atomContainer">The molecule containing the P atom</param> /// <returns>The empirical delta V if present in the above environment, -1 otherwise</returns> private static double DeltavPhosphorous(IAtom atom, IAtomContainer atomContainer) { if (!atom.AtomicNumber.Equals(AtomicNumbers.P)) { return(-1); } var connected = atomContainer.GetConnectedAtoms(atom); int conditions = 0; if (connected.Count() == 4) { conditions++; } foreach (var connectedAtom in connected) { if (connectedAtom.AtomicNumber.Equals(AtomicNumbers.O) && atomContainer.GetBond(atom, connectedAtom).Order == BondOrder.Double) { conditions++; } if (atomContainer.GetBond(atom, connectedAtom).Order == BondOrder.Single) { conditions++; } } if (conditions == 5) { return(2.22); } return(-1); }
/// <summary> /// Generate coordinates for all atoms which are singly bonded and have /// no coordinates. This is useful when hydrogens are present but have /// no coordinates. It knows about C, O, N, S only and will give tetrahedral or /// trigonal geometry elsewhere. Bond lengths are computed from covalent radii /// if available. Angles are tetrahedral or trigonal /// </summary> /// <param name="atomContainer">the set of atoms involved</param> // @cdk.keyword coordinate calculation // @cdk.keyword 3D model public static void Add3DCoordinates1(IAtomContainer atomContainer) { // atoms without coordinates var noCoords = atomContainer.Builder.NewAtomContainer(); // get vector of possible referenceAtoms? var refAtoms = atomContainer.Builder.NewAtomContainer(); foreach (var atom in atomContainer.Atoms) { // is this atom without 3D coords, and has only one ligand? if (atom.Point3D == null) { var connectedAtoms = atomContainer.GetConnectedAtoms(atom).ToReadOnlyList(); if (connectedAtoms.Count == 1) { var refAtom = connectedAtoms[0]; if (refAtom.Point3D != null) { refAtoms.Atoms.Add(refAtom); // store atoms with no coords and ref atoms in a // single container noCoords.Atoms.Add(atom); noCoords.Atoms.Add(refAtom); // bond is required to extract ligands noCoords.Bonds.Add(atomContainer.Builder.NewBond(atom, refAtom, BondOrder.Single)); } } } } // now add coordinates to ligands of reference atoms // use default length of 1.0, which can be adjusted later double length = 1; var angle = TypicalTetrahedralAngle; foreach (var refAtom in refAtoms.Atoms) { var noCoordLigands = noCoords.GetConnectedAtoms(refAtom).ToReadOnlyList(); var nLigands = noCoordLigands.Count; var nwanted = nLigands; var elementType = refAtom.Symbol; // try to deal with lone pairs on small hetero switch (refAtom.AtomicNumber) { case AtomicNumbers.N: case AtomicNumbers.O: case AtomicNumbers.S: nwanted = 3; break; } var newPoints = Calculate3DCoordinatesForLigands(atomContainer, refAtom, nwanted, length, angle); for (int j = 0; j < nLigands; j++) { var ligand = noCoordLigands[j]; var newPoint = RescaleBondLength(refAtom, ligand, newPoints[j].Value); ligand.Point3D = newPoint; } } }
/// <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); }
/// <summary> /// Place hydrogens connected to the provided atom <paramref name="atom"/> using the /// specified <paramref name="bondLength"/>. /// </summary> /// <param name="container">atom container</param> /// <param name="atom"></param> /// <param name="bondLength">bond length to user</param> /// <exception cref="ArgumentException">thrown if the <paramref name="atom"/> or /// <i>container</i> was null or the atom has connected atoms which have not been placed.</exception> public void PlaceHydrogens2D(IAtomContainer container, IAtom atom, double bondLength) { if (atom.Point2D == null) { throw new ArgumentException("cannot place hydrogens on atom without coordinates"); } Debug.WriteLine("placing hydrogens connected to atom ", atom.Symbol, ": ", atom.Point2D); Debug.WriteLine($"bond length{bondLength}"); AtomPlacer atomPlacer = new AtomPlacer { Molecule = container ?? throw new ArgumentException("cannot place hydrogens, no container provided") }; var connected = container.GetConnectedAtoms(atom); IAtomContainer placed = container.Builder.NewAtomContainer(); IAtomContainer unplaced = container.Builder.NewAtomContainer(); // divide connected atoms into those which are have and haven't been placed foreach (var conAtom in connected) { if (conAtom.Point2D == null) { if (conAtom.AtomicNumber.Equals(AtomicNumbers.H)) { unplaced.Atoms.Add(conAtom); } else { throw new ArgumentException("cannot place hydrogens, atom has connected non-hydrogens without coordinates"); } } else { placed.Atoms.Add(conAtom); } } Debug.WriteLine("Atom placement before procedure:"); Debug.WriteLine("Centre atom ", atom.Symbol, ": ", atom.Point2D); for (int i = 0; i < unplaced.Atoms.Count; i++) { Debug.WriteLine("H-" + i, ": ", unplaced.Atoms[i].Point2D); } Vector2 centerPlacedAtoms = GeometryUtil.Get2DCenter(placed); atomPlacer.DistributePartners(atom, placed, centerPlacedAtoms, unplaced, bondLength); Debug.WriteLine("Atom placement after procedure:"); Debug.WriteLine($"Centre atom {atom.Symbol}: {atom.Point2D}"); for (int i = 0; i < unplaced.Atoms.Count; i++) { Debug.WriteLine($"H-{i}: {unplaced.Atoms[i].Point2D}"); } } }
/// <summary> /// Obtain the ligands connected to the 'atom' excluding 'exclude'. This is /// mainly meant as a utility for double-bond labelling. /// </summary> /// <param name="atom">an atom</param> /// <param name="container">a structure to which 'atom' belongs</param> /// <param name="exclude">exclude this atom - can not be null</param> /// <returns>the ligands</returns> private static IEnumerable <ILigand> GetLigands(IAtom atom, IAtomContainer container, IAtom exclude) { var neighbors = container.GetConnectedAtoms(atom); var ligands = neighbors .Where(neighbor => neighbor != exclude) .Select(neighbor => new Ligand(container, new VisitedAtoms(), atom, neighbor)); return(ligands); }
private static double[] GetPathWeights(List <IList <IAtom> > pathList, IAtomContainer atomContainer) { var pathWts = new double[pathList.Count]; for (int i = 0; i < pathList.Count; i++) { var p = pathList[i]; pathWts[i] = 1.0; for (int j = 0; j < p.Count - 1; j++) { var a = p[j]; var b = p[j + 1]; var n1 = atomContainer.GetConnectedAtoms(a).Count(); var n2 = atomContainer.GetConnectedAtoms(b).Count(); pathWts[i] /= Math.Sqrt(n1 * n2); } } return(pathWts); }
private bool MatchMaximumNeighbors(IAtomContainer targetContainer, IAtom targetAtom) { if (maximumNeighbors == -1 || !IsBondMatchFlag) { return(true); } int maximumTargetNeighbors = targetContainer.GetConnectedAtoms(targetAtom).Count(); return(maximumTargetNeighbors >= maximumNeighbors); }
/// <summary> /// Finds an neighbor connected to 'atom' which is not 'exclude1' /// or 'exclude2'. If no neighbor exists - null is returned. /// </summary> /// <param name="container"> structure </param> /// <param name="atom"> atom to find a neighbor of </param> /// <param name="exclude1"> the neighbor should not be this atom </param> /// <param name="exclude2"> the neighbor should also not be this atom </param> /// <returns> a neighbor of 'atom', null if not found </returns> private static IAtom findOther(IAtomContainer container, IAtom atom, IAtom exclude1, IAtom exclude2) { foreach (IAtom neighbor in container.GetConnectedAtoms(atom) as List <IAtom> ) { if (neighbor != exclude1 && neighbor != exclude2) { return(neighbor); } } return(null); }
private static bool HasUnsetNeighbour(IAtom atom, IAtomContainer ac) { var atoms = ac.GetConnectedAtoms(atom); foreach (var curAtom in atoms) { if (!curAtom.IsPlaced) {//&& atoms[i].Point3D == null) { return(true); } } return(false); }
public static void FixSulphurH(IAtomContainer m) { // removes extra H's attached to sulphurs for (int i = 0; i <= m.Atoms.Count - 1; i++) { var a = m.Atoms[i]; if (a.AtomicNumber.Equals(AtomicNumbers.S)) { var connectedAtoms = m.GetConnectedAtoms(a); int bondOrderSum = 0; foreach (var conAtom in connectedAtoms) { if (!conAtom.AtomicNumber.Equals(AtomicNumbers.H)) { IBond bond = m.GetBond(a, conAtom); if (bond.Order == BondOrder.Single) { bondOrderSum += 1; } else if (bond.Order == BondOrder.Double) { bondOrderSum += 2; } else if (bond.Order == BondOrder.Triple) { bondOrderSum += 3; } else if (bond.Order == BondOrder.Quadruple) { bondOrderSum += 4; } } } if (bondOrderSum > 1) { foreach (var conAtom in connectedAtoms) { if (conAtom.AtomicNumber.Equals(AtomicNumbers.H)) { m.RemoveAtom(conAtom); } } } } } }
/// <summary> /// Returns a placed neighbouring atom of a central atom atomA, which is not atomB. /// </summary> /// <param name="atomA">central atom (Atom)</param> /// <param name="atomB">atom connected to atomA (Atom)</param> /// <param name="ac">molecule</param> /// <returns>returns a connected atom (Atom)</returns> private static IAtom GetPlacedHeavyAtomInAtomContainer(IAtom atomA, IAtom atomB, IAtomContainer ac) { var atoms = ac.GetConnectedAtoms(atomA); IAtom atom = null; foreach (var curAtom in atoms) { if (curAtom.IsPlaced && !curAtom.AtomicNumber.Equals(AtomicNumbers.H) && curAtom != atomB) { return(curAtom); } } return(atom); }