/// <summary> /// Determines if the atom can be of atom type. That is, it sees if this /// atom type only differs in bond orders, or implicit hydrogen count. /// </summary> private static bool CouldMatchAtomType(IAtom atom, double bondOrderSum, BondOrder maxBondOrder, IAtomType type) { Debug.WriteLine($"{nameof(CouldMatchAtomType)}: ... matching atom {atom} vs {type}"); var hcount = atom.ImplicitHydrogenCount.Value; var charge = atom.FormalCharge.Value; if (charge == type.FormalCharge) { Debug.WriteLine($"{nameof(CouldMatchAtomType)}e: formal charge matches..."); if (bondOrderSum + hcount <= type.BondOrderSum) { Debug.WriteLine($"{nameof(CouldMatchAtomType)}: bond order sum is OK..."); if (!BondManipulator.IsHigherOrder(maxBondOrder, type.MaxBondOrder)) { Debug.WriteLine($"{nameof(CouldMatchAtomType)}: max bond order is OK... We have a match!"); return(true); } } else { Debug.WriteLine($"{nameof(CouldMatchAtomType)}: no match {(bondOrderSum + hcount)} > {type.BondOrderSum}"); } } else { Debug.WriteLine($"{nameof(CouldMatchAtomType)}: formal charge does NOT match..."); } Debug.WriteLine($"{nameof(CouldMatchAtomType)}e: No Match"); return(false); }
/// <summary> /// Checks whether an atom is saturated by comparing it with known atom types. /// </summary> /// <returns><see langword="true"/> if the atom is an pseudo atom and when the element is not in the list.</returns> public bool IsSaturated(IAtom atom, IAtomContainer container) { if (atom is IPseudoAtom) { Debug.WriteLine("don't figure it out... it simply does not lack H's"); return(true); } var atomTypes = structgenATF.GetAtomTypes(atom.Symbol); if (atomTypes.Any()) { Trace.TraceWarning($"Missing entry in atom type list for {atom.Symbol}"); return(true); } var bondOrderSum = container.GetBondOrderSum(atom); var maxBondOrder = container.GetMaximumBondOrder(atom); var hcount = atom.ImplicitHydrogenCount.Value; var charge = atom.FormalCharge.Value; Debug.WriteLine($"Checking saturation of atom {atom.Symbol}"); Debug.WriteLine($"bondOrderSum: {bondOrderSum}"); Debug.WriteLine($"maxBondOrder: {maxBondOrder}"); Debug.WriteLine($"hcount: {hcount}"); Debug.WriteLine($"charge: {charge}"); bool elementPlusChargeMatches = false; foreach (var type in atomTypes) { if (CouldMatchAtomType(atom, bondOrderSum, maxBondOrder, type)) { if (bondOrderSum + hcount == type.BondOrderSum && !BondManipulator.IsHigherOrder(maxBondOrder, type.MaxBondOrder)) { Debug.WriteLine($"We have a match: {type}"); Debug.WriteLine($"Atom is saturated: {atom.Symbol}"); return(true); } else { // ok, the element and charge matche, but unfulfilled elementPlusChargeMatches = true; } } // else: formal charges don't match } if (elementPlusChargeMatches) { Debug.WriteLine("No, atom is not saturated."); return(false); } // ok, the found atom was not in the list Trace.TraceError("Could not find atom type!"); throw new CDKException($"The atom with element {atom.Symbol} and charge {charge} is not found."); }
private static ValidationReport ValidateMaxBondOrder(IBond bond) { var report = new ValidationReport(); var maxBO = new ValidationTest(bond, "Bond order exceeds the maximum for one of its atoms."); try { var structgenATF = CDK.CdkAtomTypeFactory; for (int i = 0; i < bond.Atoms.Count; i++) { var atom = bond.Atoms[i]; if (atom is IPseudoAtom) { // ok, all is fine; we don't know the properties of pseudo atoms break; } var atomTypes = structgenATF.GetAtomTypes(atom.Symbol); IAtomType failedOn = null; bool foundMatchingAtomType = false; foreach (var atomType in atomTypes) { if (!BondManipulator.IsHigherOrder(bond.Order, atomType.MaxBondOrder)) { foundMatchingAtomType = true; } else { failedOn = atomType; } } if (foundMatchingAtomType) { report.OKs.Add(maxBO); } else { if (failedOn != null) { maxBO.Details = $"Bond order exceeds the one allowed for atom {atom.Symbol} for which the maximum bond order is {failedOn.MaxBondOrder}"; } report.Errors.Add(maxBO); } } } catch (Exception exception) { Trace.TraceError("Error while performing atom bos validation"); Debug.WriteLine(exception); maxBO.Details = $"Error while performing atom bos validation: {exception.ToString()}"; report.CDKErrors.Add(maxBO); } return(report); }
private static BondOrder GetHighestBondOrder(IAtomContainer container, IAtom atom) { var bonds = container.GetConnectedBonds(atom); var maxOrder = BondOrder.Single; foreach (var bond in bonds) { if (BondManipulator.IsHigherOrder(bond.Order, maxOrder)) { maxOrder = bond.Order; } } return(maxOrder); }
/// <summary> /// Method that tests if the matched <see cref="IAtomType"/> and the <see cref="IAtom"/> are /// consistent. For example, it tests if hybridization states and formal charges are equal. /// // @cdk.bug 1897589 /// </summary> private void AssertConsistentProperties(IAtomContainer mol, IAtom atom, IAtomType matched) { // X has no properties; nothing to match if (string.Equals("X", matched.AtomTypeName, StringComparison.Ordinal)) { return; } if (!atom.Hybridization.IsUnset() && !matched.Hybridization.IsUnset()) { Assert.AreEqual(atom.Hybridization, matched.Hybridization, "Hybridization does not match"); } if (atom.FormalCharge != null && matched.FormalCharge != null) { Assert.AreEqual(atom.FormalCharge, matched.FormalCharge, "Formal charge does not match"); } var connections = mol.GetConnectedBonds(atom); int connectionCount = connections.Count(); if (matched.FormalNeighbourCount != null) { Assert.IsFalse(connectionCount > matched.FormalNeighbourCount, "Number of neighbors is too high"); } if (!matched.MaxBondOrder.IsUnset()) { BondOrder expectedMax = matched.MaxBondOrder; foreach (var bond in connections) { BondOrder order = bond.Order; if (!order.IsUnset()) { if (BondManipulator.IsHigherOrder(order, expectedMax)) { Assert.Fail("At least one bond order exceeds the maximum for the atom type"); } } else if (bond.IsSingleOrDouble) { if (expectedMax != BondOrder.Single && expectedMax != BondOrder.Double) { Assert.Fail("A single or double flagged bond does not match the bond order of the atom type"); } } } } }
/// <summary> /// Checks whether an atom is saturated by comparing it with known atom types. /// </summary> public bool IsSaturated(IAtom atom, IAtomContainer ac) { var atomTypes = structgenATF.GetAtomTypes(atom.Symbol); if (!atomTypes.Any()) { return(true); } double bondOrderSum = 0; var maxBondOrder = BondOrder.Unset; int hcount = 0; int charge = 0; bool isInited = false; foreach (var atomType in atomTypes) { if (!isInited) { isInited = true; bondOrderSum = ac.GetBondOrderSum(atom); maxBondOrder = ac.GetMaximumBondOrder(atom); hcount = atom.ImplicitHydrogenCount ?? 0; charge = atom.FormalCharge ?? 0; try { Debug.WriteLine($"*** Checking saturation of atom {atom.Symbol} {ac.Atoms.IndexOf(atom)} ***"); Debug.WriteLine($"bondOrderSum: {bondOrderSum}"); Debug.WriteLine($"maxBondOrder: {maxBondOrder}"); Debug.WriteLine($"hcount: {hcount}"); } catch (Exception exc) { Debug.WriteLine(exc); } } if (bondOrderSum - charge + hcount == atomType.BondOrderSum && !BondManipulator.IsHigherOrder(maxBondOrder, atomType.MaxBondOrder)) { Debug.WriteLine("*** Good ! ***"); return(true); } } Debug.WriteLine("*** Bad ! ***"); return(false); }
/// <summary> /// Finds the AtomType matching the Atom's element symbol, formal charge and /// hybridization state. /// </summary> /// <param name="atomContainer">AtomContainer</param> /// <param name="atom">the target atom</param> /// <exception cref="CDKException">Exception thrown if something goes wrong</exception> /// <returns>the matching AtomType</returns> public IEnumerable <IAtomType> PossibleAtomTypes(IAtomContainer atomContainer, IAtom atom) { var bondOrderSum = atomContainer.GetBondOrderSum(atom); var maxBondOrder = atomContainer.GetMaximumBondOrder(atom); var charge = atom.FormalCharge.Value; var hcount = atom.ImplicitHydrogenCount.Value; var types = factory.GetAtomTypes(atom.Symbol); foreach (var type in types) { Debug.WriteLine(" ... matching atom ", atom, " vs ", type); if (bondOrderSum - charge + hcount <= type.BondOrderSum && !BondManipulator.IsHigherOrder(maxBondOrder, type.MaxBondOrder)) { yield return(type); } } Debug.WriteLine(" No Match"); yield break; }