private static ValidationReport ValidateChargeConservation(IReaction reaction, IAtomContainer reactants, IAtomContainer products) { var report = new ValidationReport(); var chargeConservation = new ValidationTest(reaction, "Total formal charge is not preserved during the reaction"); var atoms1 = reactants.Atoms; int totalCharge1 = 0; foreach (var atom1 in atoms1) { totalCharge1 = +atom1.FormalCharge.Value; } var atoms2 = products.Atoms; int totalCharge2 = 0; foreach (var atom2 in atoms2) { totalCharge2 = +atom2.FormalCharge.Value; } if (totalCharge1 != totalCharge2) { report.Errors.Add(chargeConservation); } else { report.OKs.Add(chargeConservation); } return(report); }
// the Molecule tests private static ValidationReport ValidateBondOrderSum(IAtom atom, IAtomContainer molecule) { var report = new ValidationReport(); var checkBondSum = new ValidationTest(atom, "The atom's total bond order is too high."); try { var structgenATF = CDK.CdkAtomTypeFactory; int bos = (int)molecule.GetBondOrderSum(atom); var atomTypes = structgenATF.GetAtomTypes(atom.Symbol).ToReadOnlyList(); if (atomTypes.Count == 0) { checkBondSum.Details = $"Cannot validate bond order sum for atom not in valency atom type list: {atom.Symbol}"; report.Warnings.Add(checkBondSum); } else { IAtomType failedOn = null; bool foundMatchingAtomType = false; foreach (var type in atomTypes) { if (atom.FormalCharge == type.FormalCharge) { foundMatchingAtomType = true; if (bos == type.BondOrderSum) { // skip this atom type } else { failedOn = type; } } } if (foundMatchingAtomType) { report.OKs.Add(checkBondSum); } else { if (failedOn != null) { checkBondSum.Details = $"Bond order exceeds the one allowed for atom {atom.Symbol} for which the total bond order is {failedOn.BondOrderSum}"; } else { } report.Errors.Add(checkBondSum); } } } catch (Exception exception) { Trace.TraceError($"Error while performing atom bos validation: {exception.Message}"); Debug.WriteLine(exception); } return(report); }
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 ValidationReport ValidateAtomCountConservation(IReaction reaction, IAtomContainer reactants, IAtomContainer products) { var report = new ValidationReport(); var atomCount = new ValidationTest(reaction, "Atom count mismatch for reaction: the product side has a different atom count than the reactant side."); if (reactants.Atoms.Count != products.Atoms.Count) { report.Errors.Add(atomCount); } else { report.OKs.Add(atomCount); } return(report); }
// the Bond tests private static ValidationReport ValidateStereoChemistry(IBond bond) { var report = new ValidationReport(); var bondStereo = new ValidationTest(bond, "Defining stereochemistry on bonds is not safe.", "Use atom based stereochemistry."); if (bond.Stereo != BondStereo.None) { report.Warnings.Add(bondStereo); } else { report.OKs.Add(bondStereo); } return(report); }
// assumes 1 unit in the coordinate system is one angstrom public override ValidationReport ValidateBond(IBond subject) { var report = new ValidationReport(); // only consider two atom bonds if (subject.Atoms.Count == 2) { var distance = Vector3.Distance(subject.Begin.Point3D.Value, subject.End.Point3D.Value); if (distance > 3.0) { // should really depend on the elements var badBondLengthError = new ValidationTest(subject, "Bond length cannot exceed 3 Angstroms.", "A bond length typically is between 0.5 and 3.0 Angstroms."); report.Errors.Add(badBondLengthError); } } return(report); }
private static ValidationReport ValidateHydrogenCount(IAtom atom) { var report = new ValidationReport(); var negativeHydrogenCount = new ValidationTest(atom, "An Atom cannot have a negative number of hydrogens attached."); if (atom.ImplicitHydrogenCount == null) { report.Warnings.Add(new ValidationTest(atom, "An atom had unset (null) implicit hydrogen count")); } else if (atom.ImplicitHydrogenCount < 0) { negativeHydrogenCount.Details = $"Atom has {atom.ImplicitHydrogenCount} hydrogens."; report.Errors.Add(negativeHydrogenCount); } else { report.OKs.Add(negativeHydrogenCount); } return(report); }
public override ValidationReport ValidateMolecule(IAtomContainer subject) { var report = new ValidationReport(); var emptyMolecule = new ValidationTest(subject, "Molecule does not contain any atom"); if (subject.Atoms.Count == 0) { report.Errors.Add(emptyMolecule); } else { report.OKs.Add(emptyMolecule); var massCalcProblem = new ValidationTest(subject, "Molecule contains PseudoAtom's. Won't be able to calculate some properties, like molecular mass."); bool foundMassCalcProblem = false; for (int i = 0; i < subject.Atoms.Count; i++) { if (subject.Atoms[i] is IPseudoAtom) { foundMassCalcProblem = true; } else { report.Add(ValidateBondOrderSum(subject.Atoms[i], subject)); } } if (foundMassCalcProblem) { report.Warnings.Add(massCalcProblem); } else { report.OKs.Add(massCalcProblem); } } return(report); }
// the Isotope tests public static ValidationReport ValidateIsotopeExistence(IIsotope isotope) { var report = new ValidationReport(); var isotopeExists = new ValidationTest(isotope, "Isotope with this mass number is not known for this element."); try { var isotopeFac = CDK.IsotopeFactory; var isotopes = isotopeFac.GetIsotopes(isotope.Symbol); bool foundKnownIsotope = false; if (isotope.MassNumber != null && isotope.MassNumber != 0) { foreach (var facIsotope in isotopes) { if (facIsotope.MassNumber == isotope.MassNumber) { foundKnownIsotope = true; } } } if (!foundKnownIsotope) { report.Errors.Add(isotopeExists); } else { // isotopic is unspecified report.OKs.Add(isotopeExists); } } catch (Exception) { // too bad... } return(report); }
private static ValidationReport ValidatePseudoAtom(IAtom atom) { var report = new ValidationReport(); var isElementOrPseudo = new ValidationTest(atom, "Non-element atom must be of class PseudoAtom."); if (atom is IPseudoAtom) { // that's fine report.OKs.Add(isElementOrPseudo); } else { // check whether atom is really an element try { var isotopeFactory = CDK.IsotopeFactory; var element = isotopeFactory.GetElement(atom.Symbol); if (element == null) { isElementOrPseudo.Details = $"Element {atom.Symbol} does not exist."; report.Errors.Add(isElementOrPseudo); } else { report.OKs.Add(isElementOrPseudo); } } catch (Exception exception) { // well... don't throw an error then. isElementOrPseudo.Details = exception.ToString(); report.CDKErrors.Add(isElementOrPseudo); } } return(report); }
// the Atom tests private static ValidationReport ValidateCharge(IAtom atom) { var report = new ValidationReport(); var tooCharged = new ValidationTest(atom, "Atom has an unlikely large positive or negative charge"); switch (atom.AtomicNumber) { case AtomicNumbers.O: case AtomicNumbers.N: case AtomicNumbers.C: case AtomicNumbers.H: if (atom.FormalCharge == 0) { report.OKs.Add(tooCharged); } else { tooCharged.Details = $"Atom {atom.Symbol} has charge {atom.FormalCharge}"; if (atom.FormalCharge < -3) { report.Errors.Add(tooCharged); } else if (atom.FormalCharge < -1) { report.Warnings.Add(tooCharged); } else if (atom.FormalCharge > 3) { report.Errors.Add(tooCharged); } else if (atom.FormalCharge > 1) { report.Warnings.Add(tooCharged); } } break; default: if (atom.FormalCharge == 0) { report.OKs.Add(tooCharged); } else { tooCharged.Details = $"Atom {atom.Symbol} has charge {atom.FormalCharge}"; if (atom.FormalCharge < -4) { report.Errors.Add(tooCharged); } else if (atom.FormalCharge < -3) { report.Warnings.Add(tooCharged); } else if (atom.FormalCharge > 4) { report.Errors.Add(tooCharged); } else if (atom.FormalCharge > 3) { report.Warnings.Add(tooCharged); } } break; } return(report); }
public override ValidationReport ValidateChemObject(IChemObject subject) { var report = new ValidationReport(); var properties = subject.GetProperties(); var iter = properties.Keys; var noNamespace = new ValidationTest(subject,"Dictionary Reference lacks a namespace indicating the dictionary."); var noDict = new ValidationTest(subject, "The referenced dictionary does not exist."); var noEntry = new ValidationTest(subject, "The referenced entry does not exist in the dictionary."); foreach (var key in iter) { if (key is string keyName) { if (keyName.StartsWith(DictionaryDatabase.DictRefPropertyName, StringComparison.Ordinal)) { string dictRef = (string)properties[keyName]; string details = "Dictref being anaylyzed: " + dictRef + ". "; noNamespace.Details = details; noDict.Details = details; noEntry.Details = details; int index = dictRef.IndexOf(':'); if (index != -1) { report.OKs.Add(noNamespace); string dict = dictRef.Substring(0, index); Debug.WriteLine($"Looking for dictionary:{dict}"); if (db.HasDictionary(dict)) { report.OKs.Add(noDict); if (dictRef.Length > index + 1) { string entry = dictRef.Substring(index + 1); Debug.WriteLine($"Looking for entry:{entry}"); if (db.HasEntry(dict, entry)) { report.OKs.Add(noEntry); } else { report.Errors.Add(noEntry); } } else { report.Errors.Add(noEntry); } } else { details += "The dictionary searched: " + dict + "."; noDict.Details = details; report.Errors.Add(noDict); report.Errors.Add(noEntry); } } else { // The dictRef has no namespace details += "There is not a namespace given."; noNamespace.Details = details; report.Errors.Add(noNamespace); report.Errors.Add(noDict); report.Errors.Add(noEntry); } } else { // not a dictref } } else { // not a dictref } } return report; }