/// <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> /// Tries to saturate a bond by increasing its bond orders by 1.0. /// </summary> /// <returns>true if the bond could be increased</returns> public bool SaturateByIncreasingBondOrder(IBond bond, IAtomContainer atomContainer) { var atoms = BondManipulator.GetAtomArray(bond); var atom = atoms[0]; var partner = atoms[1]; Debug.WriteLine(" saturating bond: ", atom.Symbol, "-", partner.Symbol); var atomTypes1 = structgenATF.GetAtomTypes(atom.Symbol); var atomTypes2 = structgenATF.GetAtomTypes(partner.Symbol); foreach (var aType1 in atomTypes1) { Debug.WriteLine($" considering atom type: {aType1}"); if (CouldMatchAtomType(atomContainer, atom, aType1)) { Debug.WriteLine($" trying atom type: {aType1}"); foreach (var aType2 in atomTypes2) { Debug.WriteLine($" considering partner type: {aType1}"); if (CouldMatchAtomType(atomContainer, partner, aType2)) { Debug.WriteLine($" with atom type: {aType2}"); if (BondManipulator.IsLowerOrder(bond.Order, aType2.MaxBondOrder) && BondManipulator.IsLowerOrder(bond.Order, aType1.MaxBondOrder)) { bond.Order = BondManipulator.IncreaseBondOrder(bond.Order); Debug.WriteLine($"Bond order now {bond.Order}"); return(true); } } } } } 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."); }
/// <summary> /// Saturate atom by adjusting its bond orders. /// This method is known to fail, especially on pyrrole-like compounds. /// Consider using <see cref="Smiles.DeduceBondSystemTool"/>, which should work better /// </summary> public bool NewSaturate(IBond bond, IAtomContainer atomContainer) { var atoms = BondManipulator.GetAtomArray(bond); var atom = atoms[0]; var partner = atoms[1]; Debug.WriteLine($" saturating bond: {atom.Symbol}-{partner.Symbol}"); var atomTypes1 = structgenATF.GetAtomTypes(atom.Symbol); var atomTypes2 = structgenATF.GetAtomTypes(partner.Symbol); bool bondOrderIncreased = true; while (bondOrderIncreased && !IsSaturated(bond, atomContainer)) { Debug.WriteLine("Can increase bond order"); bondOrderIncreased = false; foreach (var aType1 in atomTypes1) { if (bondOrderIncreased) { break; } Debug.WriteLine($" considering atom type: {aType1}"); if (CouldMatchAtomType(atomContainer, atom, aType1)) { Debug.WriteLine($" trying atom type: {aType1}"); foreach (var aType2 in atomTypes2) { if (bondOrderIncreased) { break; } Debug.WriteLine($" considering partner type: {aType1}"); if (CouldMatchAtomType(atomContainer, partner, aType2)) { Debug.WriteLine($" with atom type: {aType2}"); if (!BondManipulator.IsLowerOrder(bond.Order, aType2.MaxBondOrder) || !BondManipulator.IsLowerOrder(bond.Order, aType1.MaxBondOrder)) { Debug.WriteLine("Bond order not increased: atoms has reached (or exceeded) maximum bond order for this atom type"); } else if (BondManipulator.IsLowerOrder(bond.Order, aType2.MaxBondOrder) && BondManipulator.IsLowerOrder(bond.Order, aType1.MaxBondOrder)) { BondManipulator.IncreaseBondOrder(bond); Debug.WriteLine($"Bond order now {bond.Order}"); bondOrderIncreased = true; } } } } } } return(IsSaturated(bond, atomContainer)); }
/// <summary> /// Returns whether a bond is saturated. A bond is saturated if /// <b>both</b> Atoms in the bond are saturated. /// </summary> public bool IsSaturated(IBond bond, IAtomContainer atomContainer) { var atoms = BondManipulator.GetAtomArray(bond); bool isSaturated = true; for (int i = 0; i < atoms.Length; i++) { isSaturated = isSaturated && IsSaturated(atoms[i], atomContainer); } return(isSaturated); }
private static bool UnsaturateByDecreasingBondOrder(IBond bond) { if (bond.Order != BondOrder.Single) { bond.Order = BondManipulator.DecreaseBondOrder(bond.Order); return(true); } else { return(false); } }
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); }
/// <summary> /// A small help method that count how many bonds an atom has, regarding /// bonds due to its charge and to implicit hydrogens. /// </summary> /// <param name="atom">The atom to check</param> /// <param name="atomContainer">The atomContainer containing the atom</param> /// <returns>The number of bonds that the atom has</returns> private static double BondsUsed(IAtom atom, IAtomContainer atomContainer) { int bondsToAtom = 0; foreach (var bond in atomContainer.Bonds) { if (bond.Contains(atom)) { bondsToAtom += (int)BondManipulator.DestroyBondOrder(bond.Order); } } int implicitHydrogens; if (atom.ImplicitHydrogenCount == null || atom.ImplicitHydrogenCount == null) { // Will probably only work with group 13-18, and not for helium... if (atom.Valency == null || atom.Valency == null) { throw new CDKException($"Atom {atom.AtomTypeName} has not got the valency set."); } if (atom.FormalNeighbourCount == null || atom.FormalNeighbourCount == null) { throw new CDKException($"Atom {atom.AtomTypeName} has not got the formal neighbour count set."); } implicitHydrogens = (8 - atom.Valency.Value) - atom.FormalNeighbourCount.Value; Trace.TraceWarning($"Number of implicit hydrogens not set for atom {atom.AtomTypeName}. Estimated it to: {implicitHydrogens}"); } else { implicitHydrogens = atom.ImplicitHydrogenCount.Value; } double charge; if (atom.Charge == null) { if (atom.FormalCharge == null) { charge = 0; Trace.TraceWarning($"Neither charge nor formal charge is set for atom {atom.AtomTypeName}. Estimate it to: 0"); } else { charge = atom.FormalCharge.Value; } } else { charge = atom.Charge.Value; } return(bondsToAtom - charge + implicitHydrogens); }
/// <summary> /// Returns whether a bond is unsaturated. A bond is unsaturated if /// <b>all</b> Atoms in the bond are unsaturated. /// </summary> public bool IsUnsaturated(IBond bond, IAtomContainer atomContainer) { Debug.WriteLine($"isBondUnsaturated?: {bond}"); var atoms = BondManipulator.GetAtomArray(bond); var isUnsaturated = true; for (int i = 0; i < atoms.Length && isUnsaturated; i++) { isUnsaturated = isUnsaturated && !IsSaturated(atoms[i], atomContainer); } Debug.WriteLine($"Bond is unsaturated?: {isUnsaturated}"); return(isUnsaturated); }
public Result Calculate(IBond bond) { if (bond.Atoms.Count != 2) { throw new CDKException("Only 2-center bonds are considered"); } var atoms = BondManipulator.GetAtomArray(bond); var factory = CDK.IsotopeFactory; return(new Result(Math.Abs(bond.Begin.AtomicNumber - bond.End.AtomicNumber))); }
/// <summary> /// This method is used if, by some reason, the bond order sum is not set /// for an atom. /// </summary> /// <param name="atom">The atom in question</param> /// <param name="mol">The molecule that the atom belongs to</param> /// <returns>The bond order sum</returns> private static double GetAtomBondOrderSum(IAtom atom, IAtomContainer mol) { double sum = 0; foreach (var bond in mol.Bonds) { if (bond.Contains(atom)) { sum += BondManipulator.DestroyBondOrder(bond.Order); } } return(sum); }
/// <summary> /// This method decides the highest bond order that the bond can have and set /// it to that. /// </summary> /// <param name="bond">The bond to be investigated</param> /// <param name="atomContainer">The <see cref="IAtomContainer"/> that contains the bond</param> /// <exception cref="CDKException">when the bond cannot be further increased</exception> private void SetMaxBondOrder(IBond bond, IAtomContainer atomContainer) { if (BondOrderCanBeIncreased(bond, atomContainer)) { if (bond.Order != BondOrder.Quadruple) { bond.Order = BondManipulator.IncreaseBondOrder(bond.Order); } else { throw new CDKException("Can't increase a quadruple bond!"); } } }
/// <summary> /// Returns whether a bond is saturated. A bond is saturated if /// <b>both</b> Atoms in the bond are saturated. /// </summary> public bool IsSaturated(IBond bond, IAtomContainer atomContainer) { Debug.WriteLine($"isBondSaturated?: {bond}"); var atoms = BondManipulator.GetAtomArray(bond); bool isSaturated = true; for (int i = 0; i < atoms.Length; i++) { Debug.WriteLine($"IsSaturated(Bond, AC): atom I={i}"); isSaturated = isSaturated && IsSaturated(atoms[i], atomContainer); } Debug.WriteLine($"IsSaturated(Bond, AC): result={isSaturated}"); return(isSaturated); }
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); }
public virtual void TestGetBondOrderSum() { IChemObject obj = NewChemObject(); IRing r = obj.Builder.NewRing(5, "C"); Assert.AreEqual(5, r.GetBondOrderSum()); BondManipulator.IncreaseBondOrder(r.Bonds[0]); Assert.AreEqual(6, r.GetBondOrderSum()); BondManipulator.IncreaseBondOrder(r.Bonds[0]); Assert.AreEqual(7, r.GetBondOrderSum()); BondManipulator.IncreaseBondOrder(r.Bonds[4]); Assert.AreEqual(8, r.GetBondOrderSum()); }
/// <summary> /// Returns the connection matrix representation of this <see cref="IAtomContainer"/>. /// </summary> /// <param name="container">The <see cref="IAtomContainer"/> for which the matrix is calculated</param> /// <returns>A connection matrix representing this <see cref="IAtomContainer"/></returns> public static double[][] GetMatrix(IAtomContainer container) { IBond bond = null; int indexAtom1; int indexAtom2; double[][] conMat = Arrays.CreateJagged <double>(container.Atoms.Count, container.Atoms.Count); for (int f = 0; f < container.Bonds.Count; f++) { bond = container.Bonds[f]; indexAtom1 = container.Atoms.IndexOf(bond.Begin); indexAtom2 = container.Atoms.IndexOf(bond.End); conMat[indexAtom1][indexAtom2] = BondManipulator.DestroyBondOrder(bond.Order); conMat[indexAtom2][indexAtom1] = BondManipulator.DestroyBondOrder(bond.Order); } return(conMat); }
/// <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"); } } } } }
private void ProcessBondsBlock(int lineCount, IAtomContainer container) { for (int i = 0; i < lineCount; i++) { string line = input.ReadLine(); int atom1 = int.Parse(line.Substring(10, 3).Trim(), NumberFormatInfo.InvariantInfo) - 1; int atom2 = int.Parse(line.Substring(16, 3).Trim(), NumberFormatInfo.InvariantInfo) - 1; if (container.GetBond(container.Atoms[atom1], container.Atoms[atom2]) == null) { IBond bond = container.Builder.NewBond(container.Atoms[atom1], container.Atoms[atom2]); int order = int.Parse(line.Substring(23).Trim(), NumberFormatInfo.InvariantInfo); bond.Order = BondManipulator.CreateBondOrder((double)order); container.Bonds.Add(bond); } // else: bond already present; CTX store the bonds twice } }
/// <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); }
public void TestAromaticity() { IAtomContainer molecule = TestMoleculeFactory.MakeBenzene(); foreach (var bond in molecule.Bonds) { bond.IsAromatic = true; } IAtomContainer roundTrippedMol = CMLRoundTripTool.RoundTripMolecule(convertor, molecule); var bonds = roundTrippedMol.Bonds; double orderSum = BondManipulator.GetSingleBondEquivalentSum(bonds); foreach (var bond in bonds) { Assert.IsTrue(bond.IsAromatic); } Assert.AreEqual(9.0, orderSum, 0.001); }
public override void CharacterData(CMLStack xpath, XElement element) { string s = element.Value; if (isBond) { Debug.WriteLine($"CharData (bond): {s}"); var st = Strings.Tokenize(s); foreach (var border in st) { Debug.WriteLine($"new bond order: {border}"); // assume cdk bond object has already started // cdo.SetObjectProperty("Bond", "order", border); CurrentBond.Order = BondManipulator.CreateBondOrder(double.Parse(border, NumberFormatInfo.InvariantInfo)); } } else { base.CharacterData(xpath, element); } }
/// <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; }
/// <summary> /// Initiates the process for the given mechanism. The atoms and bonds to apply are mapped between /// reactants and products. /// </summary> /// <param name="atomContainerSet"></param> /// <param name="atomList">The list of atoms taking part in the mechanism. Only allowed three atoms</param> /// <param name="bondList">The list of bonds taking part in the mechanism. Only allowed one bond</param> /// <returns>The Reaction mechanism</returns> public IReaction Initiate(IChemObjectSet <IAtomContainer> atomContainerSet, IList <IAtom> atomList, IList <IBond> bondList) { var atMatcher = CDK.AtomTypeMatcher; if (atomContainerSet.Count != 2) { throw new CDKException("AdductionPBMechanism expects two IAtomContainer's"); } if (atomList.Count != 3) { throw new CDKException("AdductionPBMechanism expects two atoms in the List"); } if (bondList.Count != 1) { throw new CDKException("AdductionPBMechanism don't expect bonds in the List"); } IAtomContainer molecule1 = atomContainerSet[0]; IAtomContainer molecule2 = atomContainerSet[1]; IAtomContainer reactantCloned; reactantCloned = (IAtomContainer)atomContainerSet[0].Clone(); reactantCloned.Add((IAtomContainer)atomContainerSet[1].Clone()); IAtom atom1 = atomList[0]; // Atom 1: to be deficient in charge IAtom atom1C = reactantCloned.Atoms[molecule1.Atoms.IndexOf(atom1)]; IAtom atom2 = atomList[1]; // Atom 2: receive the adduct IAtom atom2C = reactantCloned.Atoms[molecule1.Atoms.IndexOf(atom2)]; IAtom atom3 = atomList[2]; // Atom 2: deficient in charge IAtom atom3C = reactantCloned.Atoms[molecule1.Atoms.Count + molecule2.Atoms.IndexOf(atom3)]; IBond bond1 = bondList[0]; int posBond1 = atomContainerSet[0].Bonds.IndexOf(bond1); BondManipulator.DecreaseBondOrder(reactantCloned.Bonds[posBond1]); IBond newBond = molecule1.Builder.NewBond(atom2C, atom3C, BondOrder.Single); reactantCloned.Bonds.Add(newBond); int charge = atom1C.FormalCharge.Value; atom1C.FormalCharge = charge + 1; atom1C.Hybridization = Hybridization.Unset; AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(reactantCloned); IAtomType type = atMatcher.FindMatchingAtomType(reactantCloned, atom1C); if (type == null || type.AtomTypeName.Equals("X", StringComparison.Ordinal)) { return(null); } atom2C.Hybridization = Hybridization.Unset; AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(reactantCloned); type = atMatcher.FindMatchingAtomType(reactantCloned, atom2C); if (type == null || type.AtomTypeName.Equals("X", StringComparison.Ordinal)) { return(null); } charge = atom3C.FormalCharge.Value; atom3C.FormalCharge = charge - 1; atom3C.Hybridization = Hybridization.Unset; AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(reactantCloned); type = atMatcher.FindMatchingAtomType(reactantCloned, atom3C); if (type == null || type.AtomTypeName.Equals("X", StringComparison.Ordinal)) { return(null); } IReaction reaction = atom1C.Builder.NewReaction(); reaction.Reactants.Add(molecule1); /* mapping */ foreach (var atom in molecule1.Atoms) { IMapping mapping = atom1C.Builder.NewMapping(atom, reactantCloned.Atoms[molecule1.Atoms.IndexOf(atom)]); reaction.Mappings.Add(mapping); } foreach (var atom in molecule2.Atoms) { IMapping mapping = atom1C.Builder.NewMapping(atom, reactantCloned.Atoms[molecule2.Atoms.IndexOf(atom)]); reaction.Mappings.Add(mapping); } reaction.Products.Add(reactantCloned); return(reaction); }
/// <summary> /// Initiates the process for the given mechanism. The atoms to apply are mapped between /// reactants and products. /// </summary> /// <param name="atomContainerSet"></param> /// <param name="atomList"> /// The list of atoms taking part in the mechanism. Only allowed two atoms. /// The first atom is the atom which contains the ISingleElectron and the second /// third is the atom which will be removed /// the first atom</param> /// <param name="bondList">The list of bonds taking part in the mechanism. Only allowed one bond. /// It is the bond which is moved</param> /// <returns>The Reaction mechanism</returns> public IReaction Initiate(IChemObjectSet <IAtomContainer> atomContainerSet, IList <IAtom> atomList, IList <IBond> bondList) { var atMatcher = CDK.AtomTypeMatcher; if (atomContainerSet.Count != 1) { throw new CDKException("RadicalSiteIonizationMechanism only expects one IAtomContainer"); } if (atomList.Count != 3) { throw new CDKException("RadicalSiteIonizationMechanism expects three atoms in the List"); } if (bondList.Count != 2) { throw new CDKException("RadicalSiteIonizationMechanism only expect one bond in the List"); } IAtomContainer molecule = atomContainerSet[0]; IAtomContainer reactantCloned; reactantCloned = (IAtomContainer)molecule.Clone(); IAtom atom1 = atomList[0]; // Atom containing the ISingleElectron IAtom atom1C = reactantCloned.Atoms[molecule.Atoms.IndexOf(atom1)]; IAtom atom2 = atomList[1]; // Atom IAtom atom2C = reactantCloned.Atoms[molecule.Atoms.IndexOf(atom2)]; IAtom atom3 = atomList[2]; // Atom to be saved IAtom atom3C = reactantCloned.Atoms[molecule.Atoms.IndexOf(atom3)]; IBond bond1 = bondList[0]; // Bond to increase the order int posBond1 = molecule.Bonds.IndexOf(bond1); IBond bond2 = bondList[1]; // Bond to remove int posBond2 = molecule.Bonds.IndexOf(bond2); BondManipulator.IncreaseBondOrder(reactantCloned.Bonds[posBond1]); reactantCloned.Bonds.Remove(reactantCloned.Bonds[posBond2]); var selectron = reactantCloned.GetConnectedSingleElectrons(atom1C); reactantCloned.SingleElectrons.Remove(selectron.Last()); atom1C.Hybridization = Hybridization.Unset; AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(reactantCloned); IAtomType type = atMatcher.FindMatchingAtomType(reactantCloned, atom1C); if (type == null || type.AtomTypeName.Equals("X", StringComparison.Ordinal)) { return(null); } atom2C.Hybridization = Hybridization.Unset; AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(reactantCloned); type = atMatcher.FindMatchingAtomType(reactantCloned, atom2C); if (type == null || type.AtomTypeName.Equals("X", StringComparison.Ordinal)) { return(null); } reactantCloned.SingleElectrons.Add(atom2C.Builder.NewSingleElectron(atom3C)); atom3C.Hybridization = Hybridization.Unset; AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(reactantCloned); type = atMatcher.FindMatchingAtomType(reactantCloned, atom3C); if (type == null || type.AtomTypeName.Equals("X", StringComparison.Ordinal)) { return(null); } IReaction reaction = atom2C.Builder.NewReaction(); reaction.Reactants.Add(molecule); /* mapping */ foreach (var atom in molecule.Atoms) { IMapping mapping = atom2C.Builder.NewMapping(atom, reactantCloned.Atoms[molecule.Atoms.IndexOf(atom)]); reaction.Mappings.Add(mapping); } var moleculeSetP = ConnectivityChecker.PartitionIntoMolecules(reactantCloned); foreach (var moleculeP in moleculeSetP) { reaction.Products.Add(moleculeP); } return(reaction); }
/// <summary> /// Initiates the process for the given mechanism. The atoms to apply are mapped between /// reactants and products. /// </summary> /// <param name="atomContainerSet"></param> /// <param name="atomList">The list of atoms taking part in the mechanism. Only allowed two atoms. The first atom receives the charge and the second the single electron</param> /// <param name="bondList">The list of bonds taking part in the mechanism. Only allowed one bond</param> /// <returns>The Reaction mechanism</returns> public IReaction Initiate(IChemObjectSet <IAtomContainer> atomContainerSet, IList <IAtom> atomList, IList <IBond> bondList) { var atMatcher = CDKAtomTypeMatcher.GetInstance(CDKAtomTypeMatcher.Mode.RequireExplicitHydrogens); if (atomContainerSet.Count != 1) { throw new CDKException("RemovingSEofBMechanism only expects one IAtomContainer"); } if (atomList.Count != 2) { throw new CDKException("RemovingSEofBMechanism expects two atoms in the List"); } if (bondList.Count != 1) { throw new CDKException("RemovingSEofBMechanism only expects one bond in the List"); } var molecule = atomContainerSet[0]; var reactantCloned = (IAtomContainer)molecule.Clone(); var atom1 = atomList[0]; var atom1C = reactantCloned.Atoms[molecule.Atoms.IndexOf(atom1)]; var atom2 = atomList[1]; var atom2C = reactantCloned.Atoms[molecule.Atoms.IndexOf(atom2)]; var bond1 = bondList[0]; var posBond1 = molecule.Bonds.IndexOf(bond1); if (bond1.Order == BondOrder.Single) { reactantCloned.Bonds.Remove(reactantCloned.Bonds[posBond1]); } else { BondManipulator.DecreaseBondOrder(reactantCloned.Bonds[posBond1]); } var charge = atom1C.FormalCharge.Value; atom1C.FormalCharge = charge + 1; reactantCloned.SingleElectrons.Add(atom1C.Builder.NewSingleElectron(atom2C)); // check if resulting atom type is reasonable atom1C.Hybridization = Hybridization.Unset; AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(reactantCloned); var type = atMatcher.FindMatchingAtomType(reactantCloned, atom1C); if (type == null || type.AtomTypeName.Equals("X", StringComparison.Ordinal)) { return(null); } atom2C.Hybridization = Hybridization.Unset; AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(reactantCloned); type = atMatcher.FindMatchingAtomType(reactantCloned, atom2C); if (type == null || type.AtomTypeName.Equals("X", StringComparison.Ordinal)) { return(null); } var reaction = atom1C.Builder.NewReaction(); reaction.Reactants.Add(molecule); /* mapping */ foreach (var atom in molecule.Atoms) { IMapping mapping = atom1C.Builder.NewMapping(atom, reactantCloned.Atoms[molecule.Atoms.IndexOf(atom)]); reaction.Mappings.Add(mapping); } if (bond1.Order != BondOrder.Single) { reaction.Products.Add(reactantCloned); } else { var moleculeSetP = ConnectivityChecker.PartitionIntoMolecules(reactantCloned); foreach (var moleculeP in moleculeSetP) { reaction.Products.Add(moleculeP); } } return(reaction); }
public IReadOnlyList <IAtomType> ReadAtomTypes() { var ret = new List <IAtomType>(); var doc = XElement.Load(input); foreach (var atomTypeElm in doc.Elements(XName_AtomType)) { var anAtomType = builder.NewAtomType("H"); anAtomType.AtomicNumber = 0; anAtomType.AtomTypeName = atomTypeElm.Attribute(XName_ID)?.Value; int piBondCount = 0; int neighborCount = 0; BondOrder maxBondOrder = BondOrder.Unset; double bondOrderSum = 0.0; foreach (var elm in atomTypeElm.Elements()) { if (elm.Name == XName_hasElement) { var aa = elm.Attribute(XName_rdf_resource)?.Value; anAtomType.Symbol = aa.Substring(aa.IndexOf('#') + 1); } else if (elm.Name == XName_formalBondType) { neighborCount++; var aa = elm.Attribute(XName_rdf_resource)?.Value; var bondType = aa.Substring(aa.IndexOf('#') + 1); int bondOrder = 0; switch (bondType) { case "single": bondOrder = 1; break; case "double": bondOrder = 2; break; case "triple": bondOrder = 3; break; case "quadruple": bondOrder = 4; break; default: throw new Exception(); } maxBondOrder = BondManipulator.GetMaximumBondOrder(maxBondOrder, (BondOrder)bondOrder); piBondCount += (bondOrder - 1); bondOrderSum += bondOrder; } else if (elm.Name == XName_hybridization) { var aa = elm.Attribute(XName_rdf_resource)?.Value; var hybridization = aa.Substring(aa.IndexOf('#') + 1); anAtomType.Hybridization = HybridizationTools.ToHybridization(hybridization); } else if (elm.Name == XName_formalCharge) { anAtomType.FormalCharge = int.Parse(elm.Value, NumberFormatInfo.InvariantInfo); } else if (elm.Name == XName_formalNeighbourCount) { neighborCount = int.Parse(elm.Value, NumberFormatInfo.InvariantInfo); } else if (elm.Name == XName_lonePairCount) { anAtomType.SetProperty(CDKPropertyName.LonePairCount, int.Parse(elm.Value, NumberFormatInfo.InvariantInfo)); } else if (elm.Name == XName_singleElectronCount) { anAtomType.SetProperty(CDKPropertyName.SingleElectronCount, int.Parse(elm.Value, NumberFormatInfo.InvariantInfo)); } else if (elm.Name == XName_piBondCount) { piBondCount = int.Parse(elm.Value, NumberFormatInfo.InvariantInfo); } } anAtomType.SetProperty(CDKPropertyName.PiBondCount, piBondCount); anAtomType.FormalNeighbourCount = neighborCount; if (maxBondOrder != BondOrder.Unset) { anAtomType.MaxBondOrder = maxBondOrder; } if (bondOrderSum > 0.1) { anAtomType.BondOrderSum = bondOrderSum; } ret.Add(anAtomType); } return(ret); }
/// <summary> /// The method calculates the number of rotatable bonds of an atom container. /// If the boolean parameter is set to <see langword="true"/>, terminal bonds are included. /// </summary> /// <returns>number of rotatable bonds</returns> /// <param name="includeTerminals"><see langword="true"/> if terminal bonds are included</param> /// <param name="excludeAmides"><see langword="true"/> if amide C-N bonds should be excluded</param> public Result Calculate(IAtomContainer container, bool includeTerminals = false, bool excludeAmides = false) { container = (IAtomContainer)container.Clone(); IRingSet ringSet; try { ringSet = new SpanningTree(container).GetBasicRings(); } catch (NoSuchAtomException) { return(new Result(0)); } foreach (var bond in container.Bonds) { if (ringSet.GetRings(bond).Count() > 0) { bond.IsInRing = true; } } int rotatableBondsCount = 0; foreach (var bond in container.Bonds) { var atom0 = bond.Atoms[0]; var atom1 = bond.Atoms[1]; if (atom0.AtomicNumber.Equals(AtomicNumbers.H) || atom1.AtomicNumber.Equals(AtomicNumbers.H)) { continue; } if (bond.Order == BondOrder.Single) { if (BondManipulator.IsLowerOrder(container.GetMaximumBondOrder(atom0), BondOrder.Triple) && BondManipulator.IsLowerOrder(container.GetMaximumBondOrder(atom1), BondOrder.Triple)) { if (!bond.IsInRing) { if (excludeAmides && (IsAmide(atom0, atom1, container) || IsAmide(atom1, atom0, container))) { continue; } // if there are explicit H's we should ignore those bonds var degree0 = container.GetConnectedBonds(atom0).Count() - GetConnectedHCount(container, atom0); var degree1 = container.GetConnectedBonds(atom1).Count() - GetConnectedHCount(container, atom1); if ((degree0 == 1) || (degree1 == 1)) { if (includeTerminals) { rotatableBondsCount += 1; } } else { rotatableBondsCount += 1; } } } } } return(new Result(rotatableBondsCount)); }
/// <summary> /// Generates a random structure based on the atoms in the given <see cref="IAtomContainer"/>. /// </summary> public IAtomContainer Generate() { int iteration = 0; bool structureFound = false; do { iteration++; atomContainer.RemoveAllElectronContainers(); bool bondFormed; do { bondFormed = false; foreach (var atom in atomContainer.Atoms) { if (!satCheck.IsSaturated(atom, atomContainer)) { var partner = GetAnotherUnsaturatedNode(atom); if (partner != null) { var cmax1 = satCheck.GetCurrentMaxBondOrder(atom, atomContainer); var cmax2 = satCheck.GetCurrentMaxBondOrder(partner, atomContainer); var max = Math.Min(cmax1, cmax2); var order = Math.Min(Math.Max(1.0, random.NextInt((int)Math.Round(max))), 3.0); Debug.WriteLine($"Forming bond of order {order}"); atomContainer.Bonds.Add(atomContainer.Builder.NewBond(atom, partner, BondManipulator.CreateBondOrder(order))); bondFormed = true; } } } } while (bondFormed); if (ConnectivityChecker.IsConnected(atomContainer) && satCheck.IsSaturated(atomContainer)) { structureFound = true; } } while (!structureFound && iteration < 20); Debug.WriteLine($"Structure found after #iterations: {iteration}"); return(atomContainer.Builder.NewAtomContainer(atomContainer)); }
/// <summary> /// Initiates the process for the given mechanism. The atoms to apply are mapped between /// reactants and products. /// </summary> /// <param name="atomContainerSet"></param> /// <param name="atomList"> The list of atoms taking part in the mechanism. Only allowed two atoms</param> /// <param name="bondList">The list of bonds taking part in the mechanism. Only allowed one bond</param> /// <returns>The Reaction mechanism</returns> public IReaction Initiate(IChemObjectSet <IAtomContainer> atomContainerSet, IList <IAtom> atomList, IList <IBond> bondList) { var atMatcher = CDK.AtomTypeMatcher; if (atomContainerSet.Count != 1) { throw new CDKException("SharingElectronMechanism only expects one IAtomContainer"); } if (atomList.Count != 2) { throw new CDKException("SharingElectronMechanism expects two atoms in the List"); } if (bondList.Count != 1) { throw new CDKException("SharingElectronMechanism only expect one bond in the List"); } IAtomContainer molecule = atomContainerSet[0]; IAtomContainer reactantCloned; reactantCloned = (IAtomContainer)molecule.Clone(); IAtom atom1 = atomList[0]; // Atom containing the lone pair to share IAtom atom1C = reactantCloned.Atoms[molecule.Atoms.IndexOf(atom1)]; IAtom atom2 = atomList[1]; // Atom to neutralize the deficiency of charge IAtom atom2C = reactantCloned.Atoms[molecule.Atoms.IndexOf(atom2)]; IBond bond1 = bondList[0]; int posBond1 = molecule.Bonds.IndexOf(bond1); BondManipulator.IncreaseBondOrder(reactantCloned.Bonds[posBond1]); var lonePair = reactantCloned.GetConnectedLonePairs(atom1C); reactantCloned.LonePairs.Remove(lonePair.Last()); int charge = atom1C.FormalCharge.Value; atom1C.FormalCharge = charge + 1; charge = atom2C.FormalCharge.Value; atom2C.FormalCharge = charge - 1; atom1C.Hybridization = Hybridization.Unset; AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(reactantCloned); IAtomType type = atMatcher.FindMatchingAtomType(reactantCloned, atom1C); if (type == null || type.AtomTypeName.Equals("X", StringComparison.Ordinal)) { return(null); } atom2C.Hybridization = Hybridization.Unset; AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(reactantCloned); type = atMatcher.FindMatchingAtomType(reactantCloned, atom2C); if (type == null || type.AtomTypeName.Equals("X", StringComparison.Ordinal)) { return(null); } IReaction reaction = atom2C.Builder.NewReaction(); reaction.Reactants.Add(molecule); /* mapping */ foreach (var atom in molecule.Atoms) { IMapping mapping = atom2C.Builder.NewMapping(atom, reactantCloned.Atoms[molecule.Atoms.IndexOf(atom)]); reaction.Mappings.Add(mapping); } reaction.Products.Add(reactantCloned); return(reaction); }
/// <summary> /// Randomly chooses four atoms and alters the bonding /// pattern between them according to rules described /// in "Faulon, JCICS 1996, 36, 731". /// </summary> public virtual void Mutate(IAtomContainer ac) { Debug.WriteLine("RandomGenerator->Mutate() Start"); int nrOfAtoms = ac.Atoms.Count; int x1 = 0, x2 = 0, y1 = 0, y2 = 0; double a11 = 0, a12 = 0, a22 = 0, a21 = 0; double b11 = 0, lowerborder = 0, upperborder = 0; IAtom ax1 = null, ax2 = null, ay1 = null, ay2 = null; IBond b1 = null, b2 = null, b3 = null, b4 = null; int[] choices = new int[3]; int choiceCounter = 0; /* We need at least two non-zero bonds in order to be successful */ int nonZeroBondsCounter = 0; do { do { nonZeroBondsCounter = 0; /* Randomly choose four distinct atoms */ do { // this yields numbers between 0 and (nrOfAtoms - 1) x1 = (int)(random.NextDouble() * nrOfAtoms); x2 = (int)(random.NextDouble() * nrOfAtoms); y1 = (int)(random.NextDouble() * nrOfAtoms); y2 = (int)(random.NextDouble() * nrOfAtoms); Debug.WriteLine($"RandomGenerator->Mutate(): x1, x2, y1, y2: {x1}, {x2}, {y1}, {y2}"); } while (!(x1 != x2 && x1 != y1 && x1 != y2 && x2 != y1 && x2 != y2 && y1 != y2)); ax1 = ac.Atoms[x1]; ay1 = ac.Atoms[y1]; ax2 = ac.Atoms[x2]; ay2 = ac.Atoms[y2]; /* Get four bonds for these four atoms */ b1 = ac.GetBond(ax1, ay1); if (b1 != null) { a11 = BondManipulator.DestroyBondOrder(b1.Order); nonZeroBondsCounter++; } else { a11 = 0; } b2 = ac.GetBond(ax1, ay2); if (b2 != null) { a12 = BondManipulator.DestroyBondOrder(b2.Order); nonZeroBondsCounter++; } else { a12 = 0; } b3 = ac.GetBond(ax2, ay1); if (b3 != null) { a21 = BondManipulator.DestroyBondOrder(b3.Order); nonZeroBondsCounter++; } else { a21 = 0; } b4 = ac.GetBond(ax2, ay2); if (b4 != null) { a22 = BondManipulator.DestroyBondOrder(b4.Order); nonZeroBondsCounter++; } else { a22 = 0; } Debug.WriteLine($"RandomGenerator->Mutate()->The old bond orders: a11, a12, a21, a22: {a11}, {a12}, {a21}, {a22}"); } while (nonZeroBondsCounter < 2); /* Compute the range for b11 (see Faulons formulae for details) */ double[] cmax = { 0, a11 - a22, a11 + a12 - 3, a11 + a21 - 3 }; double[] cmin = { 3, a11 + a12, a11 + a21, a11 - a22 + 3 }; lowerborder = MathTools.Max(cmax); upperborder = MathTools.Min(cmin); /* Randomly choose b11 != a11 in the range max > r > min */ Debug.WriteLine("*** New Try ***"); Debug.WriteLine($"a11 = {a11}"); Debug.WriteLine($"upperborder = {upperborder}"); Debug.WriteLine($"lowerborder = {lowerborder}"); choiceCounter = 0; for (double f = lowerborder; f <= upperborder; f++) { if (f != a11) { choices[choiceCounter] = (int)f; choiceCounter++; } } if (choiceCounter > 0) { b11 = choices[(int)(random.NextDouble() * choiceCounter)]; } Debug.WriteLine($"b11 = {b11}"); } while (!(b11 != a11 && (b11 >= lowerborder && b11 <= upperborder))); var b12 = a11 + a12 - b11; var b21 = a11 + a21 - b11; var b22 = a22 - a11 + b11; if (b11 > 0) { if (b1 == null) { b1 = ac.Builder.NewBond(ax1, ay1, BondManipulator.CreateBondOrder(b11)); ac.Bonds.Add(b1); } else { b1.Order = BondManipulator.CreateBondOrder(b11); } } else if (b1 != null) { ac.Bonds.Remove(b1); } if (b12 > 0) { if (b2 == null) { b2 = ac.Builder.NewBond(ax1, ay2, BondManipulator.CreateBondOrder(b12)); ac.Bonds.Add(b2); } else { b2.Order = BondManipulator.CreateBondOrder(b12); } } else if (b2 != null) { ac.Bonds.Remove(b2); } if (b21 > 0) { if (b3 == null) { b3 = ac.Builder.NewBond(ax2, ay1, BondManipulator.CreateBondOrder(b21)); ac.Bonds.Add(b3); } else { b3.Order = BondManipulator.CreateBondOrder(b21); } } else if (b3 != null) { ac.Bonds.Remove(b3); } if (b22 > 0) { if (b4 == null) { b4 = ac.Builder.NewBond(ax2, ay2, BondManipulator.CreateBondOrder(b22)); ac.Bonds.Add(b4); } else { b4.Order = BondManipulator.CreateBondOrder(b22); } } else if (b4 != null) { ac.Bonds.Remove(b4); } Debug.WriteLine($"a11 a12 a21 a22: {a11} {a12} {a21} {a22}"); Debug.WriteLine($"b11 b12 b21 b22: {b11} {b12} {b21} {b22}"); }