예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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.");
        }
예제 #4
0
        /// <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));
        }
예제 #5
0
        /// <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);
        }
예제 #6
0
 private static bool UnsaturateByDecreasingBondOrder(IBond bond)
 {
     if (bond.Order != BondOrder.Single)
     {
         bond.Order = BondManipulator.DecreaseBondOrder(bond.Order);
         return(true);
     }
     else
     {
         return(false);
     }
 }
예제 #7
0
        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);
        }
예제 #9
0
        /// <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!");
         }
     }
 }
예제 #13
0
        /// <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);
        }
예제 #14
0
        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);
        }
예제 #15
0
        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());
        }
예제 #16
0
        /// <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);
        }
예제 #17
0
        /// <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");
                        }
                    }
                }
            }
        }
예제 #18
0
 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
     }
 }
예제 #19
0
        /// <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);
        }
예제 #20
0
        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);
        }
예제 #21
0
        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);
            }
        }
예제 #22
0
        /// <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;
        }
예제 #23
0
        /// <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);
        }
예제 #24
0
        /// <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);
        }
예제 #25
0
        /// <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);
        }
예제 #26
0
        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);
        }
예제 #27
0
        /// <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));
        }
예제 #28
0
        /// <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));
        }
예제 #29
0
        /// <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);
        }
예제 #30
0
        /// <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}");
        }