public static IAtomContainer GetLargestMoleculeFragment( IAtomContainer mol, out int acc) { IAtomContainer mol2, molMain = null; acc = 0; if (mol == null) { return(null); } if (ConnectivityChecker.IsConnected(mol)) { acc = 1; return(mol); } IReadOnlyList <IAtomContainer> acs = ConnectivityChecker.PartitionIntoMolecules(mol); int largestAc = -1; acc = acs.Count; for (int aci = 0; aci < acc; aci++) { mol2 = acs[aci]; int ac2 = mol2.Atoms.Count; if (ac2 > largestAc) { largestAc = mol2.Atoms.Count; molMain = mol2; } } return(molMain); }
public void TestPartialFilledStructureMerger2() { var sp = CDK.SmilesParser; var acs = ChemObjectBuilder.Instance.NewAtomContainerSet(); acs.Add(sp.ParseSmiles("[C]=[C]CC[CH2]")); acs.Add(sp.ParseSmiles("[C]([CH2])=C1CC1")); var pfsm = new PartialFilledStructureMerger(); var result = pfsm.Generate(acs); Assert.IsTrue(ConnectivityChecker.IsConnected(result)); Assert.IsTrue(CDK.SaturationChecker.IsSaturated(result)); }
/// <summary> /// Proposes a structure which can be accepted or rejected by an external /// entity. If rejected, the structure is not used as a starting point /// for the next random move in structure space. /// </summary> /// <returns>A proposed molecule</returns> public IAtomContainer ProposeStructure() { Debug.WriteLine("RandomGenerator->ProposeStructure() Start"); do { trial = (IAtomContainer)Molecule.Clone(); Mutate(trial); Debug.WriteLine("BondCounts: " + string.Join(" ", trial.Atoms.Select(n => trial.GetConnectedBonds(n).Count()))); Debug.WriteLine("BondOrderSums: " + string.Join(" ", trial.Atoms.Select(n => trial.GetBondOrderSum(n)))); } while (trial == null || !ConnectivityChecker.IsConnected(trial)); proposedStructure = trial; return(proposedStructure); }
/// <summary> /// Modules for cleaning a molecule /// </summary> /// <param name="molecule"></param> /// <returns>cleaned AtomContainer</returns> public static IAtomContainer CheckAndCleanMolecule(IAtomContainer molecule) { bool isMarkush = false; foreach (var atom in molecule.Atoms) { if (atom.Symbol.Equals("R", StringComparison.Ordinal)) { isMarkush = true; break; } } if (isMarkush) { Console.Error.WriteLine("Skipping Markush structure for sanity check"); } // Check for salts and such if (!ConnectivityChecker.IsConnected(molecule)) { // lets see if we have just two parts if so, we assume its a salt and just work // on the larger part. Ideally we should have a check to ensure that the smaller // part is a metal/halogen etc. var fragments = ConnectivityChecker.PartitionIntoMolecules(molecule).ToReadOnlyList(); if (fragments.Count > 2) { Console.Error.WriteLine("More than 2 components. Skipped"); } else { var frag1 = fragments[0]; var frag2 = fragments[1]; if (frag1.Atoms.Count > frag2.Atoms.Count) { molecule = frag1; } else { molecule = frag2; } } } Configure(molecule); return(molecule); }
// @cdk.bug 1632610 public void TestCycloButene() { var mol = parser.ParseSmiles("C=CC=C"); BODRIsotopeFactory.Instance.ConfigureAtoms(mol); AddImplicitHydrogens(mol); var structures = VicinitySampler.Sample(mol); var count = 0; foreach (var temp in structures) { Assert.IsNotNull(temp); Assert.IsTrue(ConnectivityChecker.IsConnected(temp)); Assert.AreEqual(mol.Atoms.Count, temp.Atoms.Count); count++; } Assert.AreEqual(1, count); }
public void TestVicinitySampler_sample() { IAtomContainer mol = TestMoleculeFactory.MakeEthylPropylPhenantren(); BODRIsotopeFactory.Instance.ConfigureAtoms(mol); AddImplicitHydrogens(mol); var structures = VicinitySampler.Sample(mol); var count = 0; foreach (var temp in structures) { Assert.IsNotNull(temp); Assert.IsTrue(ConnectivityChecker.IsConnected(temp)); Assert.AreEqual(mol.Atoms.Count, temp.Atoms.Count); count++; } Assert.AreEqual(37, count); }
private static int GetFragmentCount(IAtomContainer molecule) { bool fragmentFlag = true; var fragmentMolSet = ChemObjectBuilder.Instance.NewAtomContainerSet(); int countFrag = 0; if (molecule.Atoms.Count > 0) { fragmentFlag = ConnectivityChecker.IsConnected(molecule); if (!fragmentFlag) { fragmentMolSet.AddRange(ConnectivityChecker.PartitionIntoMolecules(molecule)); } else { fragmentMolSet.Add(molecule); } countFrag = fragmentMolSet.Count; } return(countFrag); }
/// <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> /// Generates a shortest path based BitArray fingerprint for the given AtomContainer. /// </summary> /// <param name="ac">The AtomContainer for which a fingerprint is generated</param> /// <exception cref="CDKException">if there error in aromaticity perception or other CDK functions</exception> /// <returns>A <see cref="BitArray"/> representing the fingerprint</returns> public override IBitFingerprint GetBitFingerprint(IAtomContainer ac) { IAtomContainer atomContainer = null; atomContainer = (IAtomContainer)ac.Clone(); Aromaticity.CDKLegacy.Apply(atomContainer); var bitSet = new BitArray(fingerprintLength); if (!ConnectivityChecker.IsConnected(atomContainer)) { var partitionedMolecules = ConnectivityChecker.PartitionIntoMolecules(atomContainer); foreach (var container in partitionedMolecules) { AddUniquePath(container, bitSet); } } else { AddUniquePath(atomContainer, bitSet); } return(new BitSetFingerprint(bitSet)); }
/// <summary> /// Generate 3D coordinates with force field information. /// </summary> public IAtomContainer Generate3DCoordinates(IAtomContainer molecule, bool clone) { var originalAtomTypeNames = molecule.Atoms.Select(n => n.AtomTypeName).ToArray(); Debug.WriteLine("******** GENERATE COORDINATES ********"); foreach (var atom in molecule.Atoms) { atom.IsPlaced = false; atom.IsVisited = false; } //CHECK FOR CONNECTIVITY! Debug.WriteLine($"#atoms>{molecule.Atoms.Count}"); if (!ConnectivityChecker.IsConnected(molecule)) { throw new CDKException("Molecule is NOT connected, could not layout."); } // setup helper classes AtomPlacer atomPlacer = new AtomPlacer(); AtomPlacer3D ap3d = new AtomPlacer3D(parameterSet); AtomTetrahedralLigandPlacer3D atlp3d = new AtomTetrahedralLigandPlacer3D(parameterSet); if (clone) { molecule = (IAtomContainer)molecule.Clone(); } atomPlacer.Molecule = molecule; if (ap3d.NumberOfUnplacedHeavyAtoms(molecule) == 1) { Debug.WriteLine("Only one Heavy Atom"); ap3d.GetUnplacedHeavyAtom(molecule).Point3D = new Vector3(0.0, 0.0, 0.0); try { atlp3d.Add3DCoordinatesForSinglyBondedLigands(molecule); } catch (CDKException ex3) { Trace.TraceError($"PlaceSubstitutensERROR: Cannot place substitutents due to:{ex3.Message}"); Debug.WriteLine(ex3); throw new CDKException("PlaceSubstitutensERROR: Cannot place substitutents due to:" + ex3.Message, ex3); } return(molecule); } //Assing Atoms to Rings,Aliphatic and Atomtype IRingSet ringSetMolecule = ffc.AssignAtomTyps(molecule); IRingSet largestRingSet = null; int numberOfRingAtoms = 0; IReadOnlyList <IRingSet> ringSystems = null; if (ringSetMolecule.Count > 0) { if (templateHandler == null) { throw new CDKException("You are trying to generate coordinates for a molecule with rings, but you have no template handler set. Please do SetTemplateHandler() before generation!"); } ringSystems = RingPartitioner.PartitionRings(ringSetMolecule); largestRingSet = RingSetManipulator.GetLargestRingSet(ringSystems); IAtomContainer largestRingSetContainer = RingSetManipulator.GetAllInOneContainer(largestRingSet); numberOfRingAtoms = largestRingSetContainer.Atoms.Count; templateHandler.MapTemplates(largestRingSetContainer, numberOfRingAtoms); if (!CheckAllRingAtomsHasCoordinates(largestRingSetContainer)) { throw new CDKException("RingAtomLayoutError: Not every ring atom is placed! Molecule cannot be layout."); } SetAtomsToPlace(largestRingSetContainer); SearchAndPlaceBranches(molecule, largestRingSetContainer, ap3d, atlp3d, atomPlacer); largestRingSet = null; } else { //Debug.WriteLine("****** Start of handling aliphatic molecule ******"); IAtomContainer ac = AtomPlacer.GetInitialLongestChain(molecule); SetAtomsToUnVisited(molecule); SetAtomsToUnplaced(molecule); ap3d.PlaceAliphaticHeavyChain(molecule, ac); //ZMatrixApproach ap3d.ZMatrixChainToCartesian(molecule, false); SearchAndPlaceBranches(molecule, ac, ap3d, atlp3d, atomPlacer); } LayoutMolecule(ringSystems, molecule, ap3d, atlp3d, atomPlacer); //Debug.WriteLine("******* PLACE SUBSTITUENTS ******"); try { atlp3d.Add3DCoordinatesForSinglyBondedLigands(molecule); } catch (CDKException ex3) { Trace.TraceError($"PlaceSubstitutensERROR: Cannot place substitutents due to:{ex3.Message}"); Debug.WriteLine(ex3); throw new CDKException("PlaceSubstitutensERROR: Cannot place substitutents due to:" + ex3.Message, ex3); } // restore the original atom type names for (int i = 0; i < originalAtomTypeNames.Length; i++) { molecule.Atoms[i].AtomTypeName = originalAtomTypeNames[i]; } return(molecule); }
static INativeMolMx CdkMolUtil => StaticCdkMol.I; // static molecule shortcut for utility methods /// <summary> /// Build UniChem Data /// Note that this routine takes about 14 secs the first time it's called, faster thereafter. /// </summary> /// <param name="mol"></param> /// <returns></returns> public static UniChemData BuildUniChemData( IAtomContainer mol) { IAtomContainer mol2; InChIGenerator ig = null; string molSmiles, fragSmiles = "", molFile = ""; int acc, fi, ci; //if (Lex.StartsWith(molString, "InChI=")) //{ // sourceInchi = molString; // mol = CdkMol.InChIToAtomContainer(sourceInchi); //} //else // assume molfile otherwise //{ // molfile = molString; // mol = CdkMol.MolfileToAtomContainer(molfile); //} if (mol.Atoms.Count <= 1) { throw new Exception("Atom count <= 1"); } int pseudoCount = CdkMol.RemovePseudoAtoms(mol); mol = CdkMol.AtomContainerToSmilesAndBack(mol, out molSmiles); InChIGeneratorFactory igf = InChIGeneratorFactory.Instance; try { //string options = "/KET /15T"; // options to include keto-enol and 1,5-tautomerism (not recognized by CDK) ig = igf.GetInChIGenerator(mol); //, options); } catch (Exception ex) // may fail for some complex mols (e.g. CorpId 12345, a MDL V3000 mol with a CF3 Sgroup/alias) { throw new Exception(ex.Message, ex); } //{ // try // try to simplify the molfile so that InChI can handle it // { // //if (Lex.IsUndefined(molfile)) throw ex; // string molfile2 = SimplifyMolfileForInChIGeneration(molile); // mol = CdkMol.MolfileToAtomContainer(molfile2); // mol = CdkMol.AtomContainerToSmilesAndBack(mol, out molSmiles); // ig = igf.getInChIGenerator(mol); // } // catch (Exception ex2) // { // throw new Exception(ex2.Message, ex); // } //} if (!IsAcceptableInchiStatus(ig)) { string errMsg = "InChI generation " + ig.ReturnStatus + ": " + ig.Message; molFile = CdkMol.AtomContainerToMolfile(mol); // debug throw new Exception(errMsg); } // Populate the UniChem object UniChemData icd = new UniChemData(); //icd.Molfile = molfile; icd.AtomContainer = mol; icd.InChIString = ig.InChI; icd.InChIKey = ig.GetInChIKey(); icd.CanonSmiles = molSmiles; // Build and store fingerprint mol = CdkMol.InChIToAtomContainer(icd.InChIString); //int hydRemovedCnt = CdkMol.RemoveHydrogensBondedToPositiveNitrogens(mol); mol = CdkMol.RemoveIsotopesStereoExplicitHydrogens(mol); // additional normalization for fingerprint BitSetFingerprint fp = // generate a fingerprint CdkFingerprint.BuildBitSetFingerprint(mol, FingerprintType.MACCS, -1, -1); icd.Fingerprint = fp; if (ConnectivityChecker.IsConnected(mol)) { return(icd); // single fragment } //string mf = CdkMol.GetMolecularFormula(mol); //AtomContainerSet acs = (AtomContainerSet)ConnectivityChecker.partitionIntoMolecules(mol); List <IAtomContainer> frags = CdkMol.FragmentMolecule(mol, true); // get fragments filtering out small and common frags for (fi = 0; fi < frags.Count; fi++) { mol2 = frags[fi]; int atomCnt = mol2.Atoms.Count; if (atomCnt <= 1) { continue; } try { mol2 = CdkMol.AtomContainerToSmilesAndBack(mol2, out fragSmiles); } catch (Exception ex) { AtomContainerToSmilesAndBackErrorCount++; // just count error and ignore } ig = igf.GetInChIGenerator(mol2); if (!IsAcceptableInchiStatus(ig)) { continue; } string childInChIString = ig.InChI; string childInChIKey = ig.GetInChIKey(); string childFIKHB = UniChemUtil.GetFIKHB(childInChIKey); mol2 = CdkMol.InChIToAtomContainer(childInChIString); // convert from inchi mol2 = CdkMol.RemoveIsotopesStereoExplicitHydrogens(mol2); // additional normalization for fingerprint fp = // generate a fingerprint for the fragment CdkFingerprint.BuildBitSetFingerprint(mol2, FingerprintType.MACCS, -1, -1); for (ci = 0; ci < icd.Children.Count; ci++) // see if a dup child { if (icd.Children[ci].ChildFIKHB == childFIKHB) { break; } } if (ci < icd.Children.Count) { continue; // skip if dup } UniChemFIKHBHierarchy icdChild = new UniChemFIKHBHierarchy(); icdChild.ParentFIKHB = icd.GetFIKHB(); icdChild.ChildFIKHB = childFIKHB; icdChild.InChIString = childInChIString; icdChild.CanonSmiles = fragSmiles; icdChild.Fingerprint = fp; icd.Children.Add(icdChild); } return(icd); }
/// <summary> /// BuildFingerprints /// </summary> public static void BuildFingerprints( UniChemData icd) { IAtomContainer mol, mol2; InChIGenerator ig = null; int acc, aci, ci; icd.Children.Clear(); string parentFIKHB = icd.GetFIKHB(); DateTime t0 = DateTime.Now; mol = CdkMol.InChIToAtomContainer(icd.InChIString); icd.CanonSmiles = CdkMol.AtomContainerToSmiles(mol); InChIToAtomContainerTime += TimeOfDay.Delta(ref t0); BitSetFingerprint fp = // generate a fingerprint CdkFingerprint.BuildBitSetFingerprint(mol, FingerprintType.MACCS, -1, -1); BuildFinterprintTime1 += TimeOfDay.Delta(ref t0); icd.Fingerprint = fp; if (ConnectivityChecker.IsConnected(mol)) { return; // single fragment } InChIGeneratorFactory igf = InChIGeneratorFactory.Instance; AtomContainerSet acs = (AtomContainerSet)ConnectivityChecker.PartitionIntoMolecules(mol); PartitionIntoMoleculesTime += TimeOfDay.Delta(ref t0); acc = acs.Count; for (aci = 0; aci < acc; aci++) { mol2 = acs[aci]; GetAtomContainerTime += TimeOfDay.Delta(ref t0); ig = igf.GetInChIGenerator(mol2); if (!IsAcceptableInchiStatus(ig)) { continue; } string childKey = ig.GetInChIKey(); string childFIKHB = UniChemUtil.GetFIKHB(childKey); InChIGeneratorTime += TimeOfDay.Delta(ref t0); fp = // generate a fingerprint for the fragment CdkFingerprint.BuildBitSetFingerprint(mol2, FingerprintType.MACCS, -1, -1); BuildFinterprintTime2 += TimeOfDay.Delta(ref t0); for (ci = 0; ci < icd.Children.Count; ci++) // see if a dup child { if (icd.Children[ci].ChildFIKHB == childFIKHB) { break; } } if (ci < icd.Children.Count) { continue; // skip if dup } UniChemFIKHBHierarchy fikhbHier = new UniChemFIKHBHierarchy(); fikhbHier.ParentFIKHB = parentFIKHB; fikhbHier.ChildFIKHB = childFIKHB; fikhbHier.CanonSmiles = CdkMol.AtomContainerToSmiles(mol2); fikhbHier.Fingerprint = fp; icd.Children.Add(fikhbHier); } return; }
/// <summary> /// Performs the n point crossover of two <see cref="IAtomContainer"/>. /// </summary> /// <remarks> /// Precondition: The atoms in the molecules are ordered by properties to /// preserve (e. g. atom symbol). Due to its randomized nature, this method /// fails in around 3% of all cases. A <see cref="CDKException"/> with message "Could not /// mate these properly" will then be thrown. /// </remarks> /// <returns>The children.</returns> /// <exception cref="CDKException">if it was not possible to form off springs.</exception> public IReadOnlyList <IAtomContainer> DoCrossover(IAtomContainer dad, IAtomContainer mom) { int tries = 0; while (true) { int dim = dad.Atoms.Count; var redChild = new IAtomContainer[2]; var blueChild = new IAtomContainer[2]; var redAtoms = new List <int>(); var blueAtoms = new List <int>(); // randomly divide atoms into two parts: redAtoms and blueAtoms. if (splitMode == SplitMode.Random) { // better way to randomly divide atoms into two parts: redAtoms // and blueAtoms. for (int i = 0; i < dim; i++) { redAtoms.Add(i); } for (int i = 0; i < (dim - numatoms); i++) { int ranInt = RandomNumbersTool.RandomInt(0, redAtoms.Count - 1); redAtoms.RemoveAt(ranInt); blueAtoms.Add(ranInt); } } else { // split graph using depth/breadth first traverse var graph = new ChemGraph(dad) { NumAtoms = numatoms }; if (splitMode == SplitMode.DepthFirst) { redAtoms = graph.PickDFGraph().ToList(); } else { //this is SPLIT_MODE_BREADTH_FIRST redAtoms = graph.PickBFGraph().ToList(); } for (int i = 0; i < dim; i++) { int element = i; if (!(redAtoms.Contains(element))) { blueAtoms.Add(element); } } } /* * dividing over ** */ redChild[0] = dad.Builder.NewAtomContainer(dad); blueChild[0] = dad.Builder.NewAtomContainer(dad); redChild[1] = dad.Builder.NewAtomContainer(mom); blueChild[1] = dad.Builder.NewAtomContainer(mom); var blueAtomsInRedChild0 = new List <IAtom>(); for (int j = 0; j < blueAtoms.Count; j++) { blueAtomsInRedChild0.Add(redChild[0].Atoms[(int)blueAtoms[j]]); } for (int j = 0; j < blueAtomsInRedChild0.Count; j++) { redChild[0].RemoveAtom(blueAtomsInRedChild0[j]); } var blueAtomsInRedChild1 = new List <IAtom>(); for (int j = 0; j < blueAtoms.Count; j++) { blueAtomsInRedChild1.Add(redChild[1].Atoms[(int)blueAtoms[j]]); } for (int j = 0; j < blueAtomsInRedChild1.Count; j++) { redChild[1].RemoveAtom(blueAtomsInRedChild1[j]); } var redAtomsInBlueChild0 = new List <IAtom>(); for (int j = 0; j < redAtoms.Count; j++) { redAtomsInBlueChild0.Add(blueChild[0].Atoms[(int)redAtoms[j]]); } for (int j = 0; j < redAtomsInBlueChild0.Count; j++) { blueChild[0].RemoveAtom(redAtomsInBlueChild0[j]); } var redAtomsInBlueChild1 = new List <IAtom>(); for (int j = 0; j < redAtoms.Count; j++) { redAtomsInBlueChild1.Add(blueChild[1].Atoms[(int)redAtoms[j]]); } for (int j = 0; j < redAtomsInBlueChild1.Count; j++) { blueChild[1].RemoveAtom(redAtomsInBlueChild1[j]); } //if the two fragments of one and only one parent have an uneven number //of attachment points, we need to rearrange them var satCheck = CDK.SaturationChecker; double red1attachpoints = 0; for (int i = 0; i < redChild[0].Atoms.Count; i++) { red1attachpoints += satCheck.GetCurrentMaxBondOrder(redChild[0].Atoms[i], redChild[0]); } double red2attachpoints = 0; for (int i = 0; i < redChild[1].Atoms.Count; i++) { red2attachpoints += satCheck.GetCurrentMaxBondOrder(redChild[1].Atoms[i], redChild[1]); } bool isok = true; if (red1attachpoints % 2 == 1 ^ red2attachpoints % 2 == 1) { isok = false; var firstToBalance = redChild[1]; var secondToBalance = blueChild[0]; if (red1attachpoints % 2 == 1) { firstToBalance = redChild[0]; secondToBalance = blueChild[1]; } //we need an atom which has //- an uneven number of "attachment points" and //- an even number of outgoing bonds foreach (var atom in firstToBalance.Atoms) { if (satCheck.GetCurrentMaxBondOrder(atom, firstToBalance) % 2 == 1 && firstToBalance.GetBondOrderSum(atom) % 2 == 0) { //we remove this from it's current container and add it to the other one firstToBalance.RemoveAtom(atom); secondToBalance.Atoms.Add(atom); isok = true; break; } } } //if we have combinable fragments if (isok) { //combine the fragments crosswise var newstrucs = new IChemObjectSet <IAtomContainer> [2]; newstrucs[0] = dad.Builder.NewAtomContainerSet(); newstrucs[0].AddRange(ConnectivityChecker.PartitionIntoMolecules(redChild[0])); newstrucs[0].AddRange(ConnectivityChecker.PartitionIntoMolecules(blueChild[1])); newstrucs[1] = dad.Builder.NewAtomContainerSet(); newstrucs[1].AddRange(ConnectivityChecker.PartitionIntoMolecules(redChild[1])); newstrucs[1].AddRange(ConnectivityChecker.PartitionIntoMolecules(blueChild[0])); //and merge var children = new List <IAtomContainer>(2); for (int f = 0; f < 2; f++) { var structrue = pfsm.Generate2(newstrucs[f]); if (structrue != null) { //if children are not correct, the outer loop will repeat, //so we ignore this children.Add(structrue); } } if (children.Count == 2 && ConnectivityChecker.IsConnected(children[0]) && ConnectivityChecker.IsConnected(children[1])) { return(children); } } tries++; if (tries > 20) { throw new CDKException("Could not mate these properly"); } } }
/// <summary> /// Choose any possible quadruple of the set of atoms /// in ac and establish all of the possible bonding schemes according to /// Faulon's equations. /// </summary> public static IEnumerable <IAtomContainer> Sample(IAtomContainer ac) { Debug.WriteLine("RandomGenerator->Mutate() Start"); int nrOfAtoms = ac.Atoms.Count; double a11 = 0, a12 = 0, a22 = 0, a21 = 0; double b11 = 0, lowerborder = 0, upperborder = 0; double b12 = 0; double b21 = 0; double b22 = 0; double[] cmax = new double[4]; double[] cmin = new double[4]; IAtomContainer newAc = null; IAtom ax1 = null, ax2 = null, ay1 = null, ay2 = null; IBond b1 = null, b2 = null, b3 = null, b4 = null; //int[] choices = new int[3]; /* We need at least two non-zero bonds in order to be successful */ int nonZeroBondsCounter = 0; for (int x1 = 0; x1 < nrOfAtoms; x1++) { for (int x2 = x1 + 1; x2 < nrOfAtoms; x2++) { for (int y1 = x2 + 1; y1 < nrOfAtoms; y1++) { for (int y2 = y1 + 1; y2 < nrOfAtoms; y2++) { nonZeroBondsCounter = 0; 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; } if (nonZeroBondsCounter > 1) { // Compute the range for b11 (see Faulons formulae for details) cmax[0] = 0; cmax[1] = a11 - a22; cmax[2] = a11 + a12 - 3; cmax[3] = a11 + a21 - 3; cmin[0] = 3; cmin[1] = a11 + a12; cmin[2] = a11 + a21; cmin[3] = a11 - a22 + 3; lowerborder = MathTools.Max(cmax); upperborder = MathTools.Min(cmin); for (b11 = lowerborder; b11 <= upperborder; b11++) { if (b11 != a11) { b12 = a11 + a12 - b11; b21 = a11 + a21 - b11; b22 = a22 - a11 + b11; Debug.WriteLine("Trying atom combination : " + x1 + ":" + x2 + ":" + y1 + ":" + y2); newAc = (IAtomContainer)ac.Clone(); Change(newAc, x1, y1, x2, y2, b11, b12, b21, b22); if (ConnectivityChecker.IsConnected(newAc)) { yield return(newAc); } else { Debug.WriteLine("not connected"); } } } } } } } } yield break; }
[TestCategory("VerySlowTest")] // structgen is slow... a single method here currently takes ~6 seconds public void TestDoCrossover_IAtomContainer() { IChemObjectSet <IAtomContainer> som; var filename = "NCDK.Data.Smiles.c10h16isomers.smi"; using (var ins = ResourceLoader.GetAsStream(filename)) using (SMILESReader reader = new SMILESReader(ins)) { som = reader.Read(CDK.Builder.NewAtomContainerSet()); Assert.AreEqual(99, som.Count, "We must have read 99 structures"); } // Comment out next line to enable time seed random. RandomNumbersTool.RandomSeed = 0L; CrossoverMachine cm = new CrossoverMachine(); string correctFormula = "C10H16"; int errorcount = 0; for (int i = 0; i < som.Count; i++) { int[] hydrogencount1 = new int[4]; foreach (var atom in som[i].Atoms) { hydrogencount1[atom.ImplicitHydrogenCount.Value]++; } for (int k = i + 1; k < som.Count; k++) { try { var result = cm.DoCrossover(som[i], som[k]); int[] hydrogencount2 = new int[4]; foreach (var atom in som[k].Atoms) { hydrogencount2[atom.ImplicitHydrogenCount.Value]++; } Assert.AreEqual(2, result.Count, "Result size must be 2"); for (int l = 0; l < 2; l++) { IAtomContainer ac = result[l]; Assert.IsTrue(ConnectivityChecker.IsConnected(ac), "Result must be connected"); Assert.AreEqual( MolecularFormulaManipulator.GetString(MolecularFormulaManipulator.GetMolecularFormula(ac)), correctFormula, "Molecular formula must be the same as" + "of the input"); int[] hydrogencountresult = new int[4]; int hcounttotal = 0; foreach (var atom in result[l].Atoms) { hydrogencountresult[atom.ImplicitHydrogenCount.Value]++; hcounttotal += atom.ImplicitHydrogenCount.Value; } if (hydrogencount1[0] == hydrogencount2[0]) { Assert.AreEqual( hydrogencount1[0], hydrogencountresult[0], "Hydrogen count of the result must" + " be same as of input"); } if (hydrogencount1[1] == hydrogencount2[1]) { Assert.AreEqual( hydrogencount1[1], hydrogencountresult[1], "Hydrogen count of the result must" + " be same as of input"); } if (hydrogencount1[2] == hydrogencount2[2]) { Assert.AreEqual( hydrogencount1[2], hydrogencountresult[2], "Hydrogen count of the result must" + " be same as of input"); } if (hydrogencount1[3] == hydrogencount2[3]) { Assert.AreEqual( hydrogencount1[3], hydrogencountresult[3], "Hydrogen count of the result must" + " be same as of input"); } Assert.AreEqual(16, hcounttotal); } } catch (CDKException) { errorcount++; } } } Assert.IsTrue(errorcount < 300, "We tolerate up to 300 errors"); }