/// <summary> /// <p>Converts a reaction to an 'inlined' reaction stored as a molecule. All /// reactants, agents, products are added to the molecule as disconnected /// components with atoms flagged as to their role <see cref="ReactionRole"/> and /// component group.</p> /// <p> /// The inlined reaction, stored in a molecule can be converted back to an explicit /// reaction with <see cref="ToReaction"/>. Data stored on the individual components (e.g. /// titles is lost in the conversion). /// </p> /// </summary> /// <param name="rxn">reaction to convert</param> /// <returns>inlined reaction stored in a molecule</returns> /// <seealso cref="ToReaction"/> public static IAtomContainer ToMolecule(IReaction rxn) { if (rxn == null) { throw new ArgumentNullException(nameof(rxn), "Null reaction provided"); } IChemObjectBuilder bldr = rxn.Builder; IAtomContainer mol = bldr.NewAtomContainer(); mol.SetProperties(rxn.GetProperties()); mol.Id = rxn.Id; int grpId = 0; foreach (IAtomContainer comp in rxn.Reactants) { AssignRoleAndGrp(comp, ReactionRole.Reactant, ++grpId); mol.Add(comp); } foreach (IAtomContainer comp in rxn.Agents) { AssignRoleAndGrp(comp, ReactionRole.Agent, ++grpId); mol.Add(comp); } foreach (IAtomContainer comp in rxn.Products) { AssignRoleAndGrp(comp, ReactionRole.Product, ++grpId); mol.Add(comp); } return(mol); }
/// <summary> /// Search and place branches of a chain or ring. /// </summary> /// <param name="chain">AtomContainer if atoms in an aliphatic chain or ring system</param> private void SearchAndPlaceBranches(IAtomContainer molecule, IAtomContainer chain, AtomPlacer3D ap3d, AtomTetrahedralLigandPlacer3D atlp3d, AtomPlacer atomPlacer) { //Debug.WriteLine("****** SEARCH AND PLACE ****** Chain length: "+chain.Atoms.Count); IAtomContainer branchAtoms = molecule.Builder.NewAtomContainer(); IAtomContainer connectedAtoms = molecule.Builder.NewAtomContainer(); for (int i = 0; i < chain.Atoms.Count; i++) { var atoms = molecule.GetConnectedAtoms(chain.Atoms[i]); foreach (var atom in atoms) { if (!atom.AtomicNumber.Equals(AtomicNumbers.H) & !atom.IsPlaced & !atom.IsInRing) { connectedAtoms.Add(ap3d.GetPlacedHeavyAtoms(molecule, chain.Atoms[i])); try { SetBranchAtom(molecule, atom, chain.Atoms[i], connectedAtoms, ap3d, atlp3d); } catch (CDKException ex2) { Trace.TraceError($"SearchAndPlaceBranchERROR: Cannot find enough neighbour atoms due to {ex2.ToString()}"); throw new CDKException($"SearchAndPlaceBranchERROR: Cannot find enough neighbour atoms: {ex2.Message}", ex2); } branchAtoms.Atoms.Add(atom); connectedAtoms.RemoveAllElements(); } } }//for ac.getAtomCount PlaceLinearChains3D(molecule, branchAtoms, ap3d, atlp3d, atomPlacer); }
/// <summary> /// Add <paramref name="element"/> as <see cref="IAtom"/> to <paramref name="mol"/>. /// </summary> /// <param name="mol">The molecular to add atom.</param> /// <param name="element"><see cref="ChemicalElement"/> to add.</param> /// <returns><see cref="IAtom"/> added.</returns> public static IAtom Add(this IAtomContainer mol, ChemicalElement element) { var atom = mol.Builder.NewAtom(element); mol.Add(atom); return(atom); }
public static IAtom AddAtom(this IAtomContainer mol, string elementSymbol) { var atom = mol.Builder.NewAtom(elementSymbol); mol.Add(atom); return(atom); }
/// <summary> /// Puts all rings of a ringSet in a single atomContainer /// </summary> /// <param name="ringSet">The ringSet to use</param> /// <returns>The produced atomContainer</returns> public static IAtomContainer GetAllInOneContainer(IRingSet ringSet) { IAtomContainer resultContainer = ringSet.Builder.NewAtomContainer(); IEnumerator <IAtomContainer> containers = RingSetManipulator.GetAllAtomContainers(ringSet).GetEnumerator(); while (containers.MoveNext()) { resultContainer.Add(containers.Current); } return(resultContainer); }
/// <summary> /// Utility method to add an <see cref="IChemObject"/> to an <see cref="IAtomContainer"/>. /// </summary> /// <param name="ac">the <see cref="IAtomContainer"/> to add to</param> /// <param name="item">the <see cref="IChemObject"/> to add</param> protected void AddToAtomContainer(IAtomContainer ac, IChemObject item) { if (item is IAtomContainer) { ac.Add((IAtomContainer)item); } else if (item is IAtom) { ac.Atoms.Add((IAtom)item); } else if (item is IBond) { ac.Bonds.Add((IBond)item); } }
public IAtomContainer Read(IAtomContainer o) { IAtomContainer result = o; // do the actual parsing IGraph model = new Graph(); TurtleParser parser = new TurtleParser(); parser.Load(model, input); var convertor = new Convertor(model); IAtomContainer mol = convertor.Model2Molecule(o.Builder); result.Add(mol); return(result); }
/// <summary> /// Positions the aliphatic substituents of a ring system /// </summary> /// <param name="rs">The RingSystem for which the substituents are to be laid out</param> /// <returns>A list of atoms that where laid out</returns> public IAtomContainer PlaceRingSubstituents(IRingSet rs, double bondLength) { Debug.WriteLine("RingPlacer.PlaceRingSubstituents() start"); IRing ring = null; IAtom atom = null; IAtomContainer unplacedPartners = rs.Builder.NewAtomContainer(); IAtomContainer sharedAtoms = rs.Builder.NewAtomContainer(); IAtomContainer primaryAtoms = rs.Builder.NewAtomContainer(); IAtomContainer treatedAtoms = rs.Builder.NewAtomContainer(); for (int j = 0; j < rs.Count; j++) { ring = (IRing)rs[j]; // Get the j-th Ring in RingSet rs for (int k = 0; k < ring.Atoms.Count; k++) { unplacedPartners.RemoveAllElements(); sharedAtoms.RemoveAllElements(); primaryAtoms.RemoveAllElements(); atom = ring.Atoms[k]; var rings = rs.GetRings(atom); var centerOfRingGravity = GeometryUtil.Get2DCenter(rings); AtomPlacer.PartitionPartners(atom, unplacedPartners, sharedAtoms); AtomPlacer.MarkNotPlaced(unplacedPartners); try { for (int f = 0; f < unplacedPartners.Atoms.Count; f++) { Debug.WriteLine("placeRingSubstituents->unplacedPartners: " + (Molecule.Atoms.IndexOf(unplacedPartners.Atoms[f]) + 1)); } } catch (Exception) { } treatedAtoms.Add(unplacedPartners); if (unplacedPartners.Atoms.Count > 0) { AtomPlacer.DistributePartners(atom, sharedAtoms, centerOfRingGravity, unplacedPartners, bondLength); } } } Debug.WriteLine("RingPlacer.PlaceRingSubstituents() end"); return(treatedAtoms); }
/// <summary> /// Layout all aliphatic chains with ZMatrix. /// </summary> /// <param name="startAtoms">AtomContainer of possible start atoms for a chain</param> private void PlaceLinearChains3D(IAtomContainer molecule, IAtomContainer startAtoms, AtomPlacer3D ap3d, AtomTetrahedralLigandPlacer3D atlp3d, AtomPlacer atomPlacer) { //Debug.WriteLine("****** PLACE LINEAR CHAINS ******"); IAtom dihPlacedAtom = null; IAtom thirdPlacedAtom = null; IAtomContainer longestUnplacedChain = molecule.Builder.NewAtomContainer(); if (startAtoms.Atoms.Count == 0) { //no branch points ->linear chain //Debug.WriteLine("------ LINEAR CHAIN - FINISH ------"); } else { for (int i = 0; i < startAtoms.Atoms.Count; i++) { //Debug.WriteLine("FOUND BRANCHED ALKAN"); //Debug.WriteLine("Atom NOT NULL:" + molecule.Atoms.IndexOf(startAtoms.GetAtomAt(i))); thirdPlacedAtom = ap3d.GetPlacedHeavyAtom(molecule, startAtoms.Atoms[i]); dihPlacedAtom = ap3d.GetPlacedHeavyAtom(molecule, thirdPlacedAtom, startAtoms.Atoms[i]); longestUnplacedChain.Atoms.Add(dihPlacedAtom); longestUnplacedChain.Atoms.Add(thirdPlacedAtom); longestUnplacedChain.Atoms.Add(startAtoms.Atoms[i]); longestUnplacedChain.Add(AtomPlacer.GetLongestUnplacedChain(molecule, startAtoms.Atoms[i])); SetAtomsToUnVisited(molecule); if (longestUnplacedChain.Atoms.Count < 4) { //di,third,sec //Debug.WriteLine("------ Single BRANCH METHYLTYP ------"); //break; } else { //Debug.WriteLine("LongestUnchainLength:"+longestUnplacedChain.Atoms.Count); ap3d.PlaceAliphaticHeavyChain(molecule, longestUnplacedChain); ap3d.ZMatrixChainToCartesian(molecule, true); SearchAndPlaceBranches(molecule, longestUnplacedChain, ap3d, atlp3d, atomPlacer); } longestUnplacedChain.RemoveAllElements(); }//for } //Debug.WriteLine("****** HANDLE ALIPHATICS END ******"); }
static bool JoinMmpFragments( IAtomContainer mol, string commonFragSmiles, int attachmentNo) { IAtomContainer cfMol = SmilesToAtomContainer(commonFragSmiles); //AtomContainerManipulator.removeHydrogens(cfMol); mol.Add(cfMol); List <IAtom> atoms = GetAttachmentAtoms(mol, attachmentNo); if (atoms.Count != 2) { return(false); } Bond b = new Bond(atoms[0], atoms[1], BondOrder.Single); mol.Bonds.Add(b); return(true); }
public static void ExtractUniqueRingSystemsFromFile(string dataFile) { Console.Out.WriteLine("****** EXTRACT UNIQUE RING SYSTEMS ******"); Console.Out.WriteLine($"From file: {dataFile}"); Dictionary <string, string> hashRingSystems = new Dictionary <string, string>(); SmilesGenerator smilesGenerator = new SmilesGenerator(); int counterRings = 0; int counterMolecules = 0; int counterUniqueRings = 0; IRingSet ringSet = null; string key = ""; IAtomContainer ac = null; string molfile = dataFile + "_UniqueRings"; try { using (var fout = new FileStream(molfile, FileMode.Create)) using (var mdlw = new MDLV2000Writer(fout)) { try { Console.Out.WriteLine("Start..."); using (var fin = new StreamReader(dataFile)) using (var imdl = new EnumerableSDFReader(fin, builder)) { Console.Out.WriteLine("Read File in.."); foreach (var m in imdl) { counterMolecules = counterMolecules + 1; IRingSet ringSetM = Cycles.FindSSSR(m).ToRingSet(); if (counterMolecules % 1000 == 0) { Console.Out.WriteLine("Molecules:" + counterMolecules); } if (ringSetM.Count > 0) { var ringSystems = RingPartitioner.PartitionRings(ringSetM); for (int i = 0; i < ringSystems.Count; i++) { ringSet = (IRingSet)ringSystems[i]; ac = builder.NewAtomContainer(); var containers = RingSetManipulator.GetAllAtomContainers(ringSet); foreach (var container in containers) { ac.Add(container); } counterRings = counterRings + 1; // Only connection is important for (int j = 0; j < ac.Atoms.Count; j++) { (ac.Atoms[j]).Symbol = "C"; } try { key = smilesGenerator.Create(builder.NewAtomContainer(ac)); } catch (CDKException e) { Trace.TraceError(e.Message); return; } if (hashRingSystems.ContainsKey(key)) { } else { counterUniqueRings = counterUniqueRings + 1; hashRingSystems[key] = "1"; try { mdlw.Write(builder.NewAtomContainer(ac)); } catch (Exception emdl) { if (!(emdl is ArgumentException || emdl is CDKException)) { throw; } } } } } } } } catch (Exception exc) { Console.Out.WriteLine($"Could not read Molecules from file {dataFile} due to: {exc.Message}"); } } } catch (Exception ex2) { Console.Out.WriteLine($"IOError:cannot write file due to: {ex2.ToString()}"); } Console.Out.WriteLine($"READY Molecules:{counterMolecules} RingSystems:{counterRings} UniqueRingsSystem:{counterUniqueRings}"); Console.Out.WriteLine($"HashtableKeys:{hashRingSystems.Count}"); }
/// <summary> /// Recursive function to produce valid configurations for <see cref="GetAllConfigurations"/>. /// </summary> private void FindConfigurationsRecursively(IReadOnlyList <int> rGroupNumbers, IReadOnlyList <IReadOnlyList <int> > occurrences, IList <int> occurIndexes, List <int[]> distributions, List <IReadOnlyList <RGroup> > substitutes, int level, IList <IAtomContainer> result) { if (level == rGroupNumbers.Count) { if (!CheckIfThenConditionsMet(rGroupNumbers, distributions)) { return; } // Clone the root to get a scaffold to plug the substitutes into. IAtomContainer root = this.RootStructure; IAtomContainer rootClone = null; try { rootClone = (IAtomContainer)root.Clone(); } catch (Exception) { //Abort with CDK exception throw new CDKException("Clone() failed; could not perform R-group substitution."); } for (int rgpIdx = 0; rgpIdx < rGroupNumbers.Count; rgpIdx++) { int rNum = rGroupNumbers[rgpIdx]; int pos = 0; var mapped = substitutes[rgpIdx]; foreach (var substitute in mapped) { IAtom rAtom = this.GetRgroupQueryAtoms(rNum)[pos]; if (substitute != null) { IAtomContainer rgrpClone = null; try { rgrpClone = (IAtomContainer)(substitute.Group.Clone()); } catch (Exception) { throw new CDKException("Clone() failed; could not perform R-group substitution."); } //root cloned, substitute cloned. These now need to be attached to each other.. rootClone.Add(rgrpClone); if (this.RootAttachmentPoints.TryGetValue(rAtom, out IReadOnlyDictionary <int, IBond> rAttachmentPoints)) { // Loop over attachment points of the R# atom for (int apo = 0; apo < rAttachmentPoints.Count; apo++) { IBond bond = rAttachmentPoints[apo + 1]; //Check how R# is attached to bond int whichAtomInBond = 0; if (bond.End.Equals(rAtom)) { whichAtomInBond = 1; } IAtom subsAt = null; if (apo == 0) { subsAt = substitute.FirstAttachmentPoint; } else { subsAt = substitute.SecondAttachmentPoint; } //Do substitution with the clones IBond cloneBond = rootClone.Bonds[GetBondPosition(bond, root)]; if (subsAt != null) { IAtom subsCloneAtom = rgrpClone.Atoms[GetAtomPosition(subsAt, substitute.Group)]; cloneBond.Atoms[whichAtomInBond] = subsCloneAtom; } } } //Optional: shift substitutes 2D for easier visual checking if (rAtom.Point2D != null && substitute != null && substitute.FirstAttachmentPoint != null && substitute.FirstAttachmentPoint.Point2D != null) { Vector2 pointR = rAtom.Point2D.Value; Vector2 pointC = substitute.FirstAttachmentPoint.Point2D.Value; double xDiff = pointC.X - pointR.X; double yDiff = pointC.Y - pointR.Y; foreach (var subAt in rgrpClone.Atoms) { if (subAt.Point2D != null) { subAt.Point2D = new Vector2((subAt.Point2D.Value.X - xDiff), (subAt.Point2D.Value.Y - yDiff)); } } } } else { //Distribution flag is 0, this means the R# group will not be substituted. //Any atom connected to this group should be given the defined IsRestH value. IAtom discarded = rootClone.Atoms[GetAtomPosition(rAtom, root)]; foreach (var r0Bond in rootClone.Bonds) { if (r0Bond.Contains(discarded)) { foreach (var atInBond in r0Bond.Atoms) { atInBond.SetProperty(CDKPropertyName.RestH, this.RGroupDefinitions[rNum] .IsRestH); } } } } pos++; } } //Remove R# remnants from the clone, bonds and atoms that may linger. bool confHasRGroupBonds = true; while (confHasRGroupBonds) { foreach (var cloneBond in rootClone.Bonds) { bool removeBond = false; if (cloneBond.Begin is IPseudoAtom && IsValidRgroupQueryLabel(((IPseudoAtom)cloneBond.Begin).Label)) { removeBond = true; } else if (cloneBond.End is IPseudoAtom && IsValidRgroupQueryLabel(((IPseudoAtom)cloneBond.End).Label)) { removeBond = true; } if (removeBond) { rootClone.Bonds.Remove(cloneBond); confHasRGroupBonds = true; break; } confHasRGroupBonds = false; } } bool confHasRGroupAtoms = true; while (confHasRGroupAtoms) { foreach (var cloneAt in rootClone.Atoms) { if (cloneAt is IPseudoAtom) { if (IsValidRgroupQueryLabel(((IPseudoAtom)cloneAt).Label)) { rootClone.Atoms.Remove(cloneAt); confHasRGroupAtoms = true; break; } } confHasRGroupAtoms = false; } } //Add to result list result.Add(rootClone); } else { for (int idx = 0; idx < occurrences[level].Count; idx++) { occurIndexes[level] = idx; //With an occurrence picked 0..n for this level's R-group, now find //all possible distributions (positional alternatives). int occurrence = occurrences[level][idx]; int positions = this.GetRgroupQueryAtoms(rGroupNumbers[level]).Count; int[] candidate = new int[positions]; for (int j = 0; j < candidate.Length; j++) { candidate[j] = 0; } var rgrpDistributions = new List <int[]>(); FindDistributions(occurrence, candidate, rgrpDistributions, 0); foreach (var distribution in rgrpDistributions) { distributions[level] = distribution; var mapping = new RGroup[distribution.Length]; var mappedSubstitutes = new List <List <RGroup> >(); MapSubstitutes(this.RGroupDefinitions[rGroupNumbers[level]], 0, distribution, mapping, mappedSubstitutes); foreach (var mappings in mappedSubstitutes) { substitutes[level] = mappings; FindConfigurationsRecursively(rGroupNumbers, occurrences, occurIndexes, distributions, substitutes, level + 1, result); } } } } }
/// <summary> /// Read a Reaction from a file in MDL RXN format /// </summary> /// <returns>The Reaction that was read from the MDL file.</returns> private IReaction ReadReaction(IChemObjectBuilder builder) { IReaction reaction = builder.NewReaction(); try { input.ReadLine(); // first line should be $RXN input.ReadLine(); // second line input.ReadLine(); // third line input.ReadLine(); // fourth line } catch (IOException exception) { Debug.WriteLine(exception); throw new CDKException("Error while reading header of RXN file", exception); } int reactantCount = 0; int productCount = 0; int agentCount = 0; try { string countsLine = input.ReadLine(); // this line contains the number of reactants and products var tokenizer = Strings.Tokenize(countsLine).GetEnumerator(); tokenizer.MoveNext(); reactantCount = int.Parse(tokenizer.Current, NumberFormatInfo.InvariantInfo); Trace.TraceInformation("Expecting " + reactantCount + " reactants in file"); tokenizer.MoveNext(); productCount = int.Parse(tokenizer.Current, NumberFormatInfo.InvariantInfo); if (tokenizer.MoveNext()) { agentCount = int.Parse(tokenizer.Current, NumberFormatInfo.InvariantInfo); // ChemAxon extension, technically BIOVIA now support this but // not documented yet if (ReaderMode == ChemObjectReaderMode.Strict && agentCount > 0) { throw new CDKException("RXN files uses agent count extension"); } } Trace.TraceInformation("Expecting " + productCount + " products in file"); } catch (Exception exception) { if (exception is IOException | exception is FormatException) { Debug.WriteLine(exception); throw new CDKException("Error while counts line of RXN file", exception); } throw; } // now read the reactants try { for (int i = 1; i <= reactantCount; i++) { var molFile = new StringBuilder(); input.ReadLine(); // announceMDLFileLine string molFileLine = ""; do { molFileLine = input.ReadLine(); molFile.Append(molFileLine); molFile.Append('\n'); } while (!string.Equals(molFileLine, "M END", StringComparison.Ordinal)); // read MDL molfile content // Changed this to mdlv2000 reader MDLV2000Reader reader = new MDLV2000Reader(new StringReader(molFile.ToString()), base.ReaderMode); IAtomContainer reactant = (IAtomContainer)reader.Read(builder.NewAtomContainer()); reader.Close(); // add reactant reaction.Reactants.Add(reactant); } } catch (CDKException) { // rethrow exception from MDLReader throw; } catch (Exception exception) { if (exception is IOException | exception is ArgumentException) { Debug.WriteLine(exception); throw new CDKException("Error while reading products", exception); } throw; } // now read the products try { for (int i = 1; i <= agentCount; i++) { var molFile = new StringBuilder(); input.ReadLine(); // String announceMDLFileLine = string molFileLine = ""; do { molFileLine = input.ReadLine(); molFile.Append(molFileLine); molFile.Append('\n'); } while (!string.Equals(molFileLine, "M END", StringComparison.Ordinal)); // read MDL molfile content MDLV2000Reader reader = new MDLV2000Reader(new StringReader(molFile.ToString())); IAtomContainer product = (IAtomContainer)reader.Read(builder.NewAtomContainer()); reader.Close(); // add reactant reaction.Agents.Add(product); } } catch (CDKException) { // rethrow exception from MDLReader throw; } catch (Exception exception) { if (exception is IOException | exception is ArgumentException) { Debug.WriteLine(exception); throw new CDKException("Error while reading reactant", exception); } throw; } // now read the products try { for (int i = 1; i <= productCount; i++) { var molFile = new StringBuilder(); input.ReadLine(); // string announceMDLFileLine = string molFileLine = ""; do { molFileLine = input.ReadLine(); molFile.Append(molFileLine); molFile.Append('\n'); } while (!string.Equals(molFileLine, "M END", StringComparison.Ordinal)); // read MDL molfile content MDLV2000Reader reader = new MDLV2000Reader(new StringReader(molFile.ToString())); IAtomContainer product = (IAtomContainer)reader.Read(builder.NewAtomContainer()); reader.Close(); // add reactant reaction.Products.Add(product); } } catch (CDKException) { // rethrow exception from MDLReader throw; } catch (Exception exception) { if (exception is IOException | exception is ArgumentException) { Debug.WriteLine(exception); throw new CDKException("Error while reading products", exception); } throw; } // now try to map things, if wanted Trace.TraceInformation("Reading atom-atom mapping from file"); // distribute all atoms over two AtomContainer's IAtomContainer reactingSide = builder.NewAtomContainer(); foreach (var molecule in reaction.Reactants) { reactingSide.Add(molecule); } IAtomContainer producedSide = builder.NewAtomContainer(); foreach (var molecule in reaction.Products) { producedSide.Add(molecule); } // map the atoms int mappingCount = 0; // IAtom[] reactantAtoms = reactingSide.GetAtoms(); // IAtom[] producedAtoms = producedSide.GetAtoms(); for (int i = 0; i < reactingSide.Atoms.Count; i++) { for (int j = 0; j < producedSide.Atoms.Count; j++) { IAtom eductAtom = reactingSide.Atoms[i]; IAtom productAtom = producedSide.Atoms[j]; if (eductAtom.GetProperty <object>(CDKPropertyName.AtomAtomMapping) != null && eductAtom.GetProperty <object>(CDKPropertyName.AtomAtomMapping).Equals( productAtom.GetProperty <object>(CDKPropertyName.AtomAtomMapping))) { reaction.Mappings.Add(builder.NewMapping(eductAtom, productAtom)); mappingCount++; break; } } } Trace.TraceInformation("Mapped atom pairs: " + mappingCount); return(reaction); }
private TestResults TestFile(string dir, string filename, Type readerType) { var matcher = CDK.AtomTypeMatcher; var ins = ResourceLoader.GetAsStream(dir + filename); var reader = (ISimpleChemObjectReader)readerType.GetConstructor(new Type[] { typeof(Stream) }).Invoke(new object[] { ins }); IAtomContainer mol = null; if (reader.Accepts(typeof(IAtomContainer))) { mol = reader.Read(new Silent.AtomContainer()); } else if (reader.Accepts(typeof(IChemFile))) { var chemFile = reader.Read(builder.NewChemFile()); mol = builder.NewAtomContainer(); var containers = ChemFileManipulator.GetAllAtomContainers(chemFile); foreach (var container in containers) { mol.Add(container); } } Assert.IsNotNull(mol, "Could not read the file into a IAtomContainer: " + filename); TestResults results = new TestResults(); Trace.Assert(mol != null); foreach (var atom in mol.Atoms) { results.tested++; IAtomType matched = matcher.FindMatchingAtomType(mol, atom); if (matched == null) { results.failed++; Console.Out.WriteLine("Could not match atom: " + results.tested + " in file " + filename); } else // OK, the matcher did find something. Now, let's see of the // atom type properties are consistent with those of the atom if (!atom.Symbol.Equals(matched.Symbol)) { // OK, OK, that's very basic indeed, but why not results.failed++; Console.Out.WriteLine("Symbol does not match: " + results.tested + " in file " + filename); Console.Out.WriteLine("Found: " + atom.Symbol + ", expected: " + matched.Symbol); } else if (!atom.Hybridization.IsUnset() && atom.Hybridization != matched.Hybridization) { results.failed++; Console.Out.WriteLine("Hybridization does not match: " + results.tested + " in file " + filename); Console.Out.WriteLine("Found: " + atom.Hybridization + ", expected: " + matched.Hybridization + " (" + matched.AtomTypeName + ")"); } else if (atom.FormalCharge.Value != matched.FormalCharge.Value) { results.failed++; Console.Out.WriteLine("Formal charge does not match: " + results.tested + " in file " + filename); Console.Out.WriteLine("Found: " + atom.FormalCharge + ", expected: " + matched.FormalCharge + " (" + matched.AtomTypeName + ")"); } else { var connections = mol.GetConnectedBonds(atom); int connectionCount = connections.Count(); // int piBondsFound = (int)mol.GetBondOrderSum(atom) - connectionCount; // there might be missing hydrogens, so: found <= expected if (matched.FormalNeighbourCount != null && connectionCount > matched.FormalNeighbourCount && !"X".Equals(matched.AtomTypeName)) { results.failed++; Console.Out.WriteLine("Number of neighbors is too high: " + results.tested + " in file " + filename); Console.Out.WriteLine("Found: " + connectionCount + ", expected (max): " + matched.FormalNeighbourCount + " (" + matched.AtomTypeName + ")"); } // there might be missing double bonds, so: found <= expected // if (piBondsFound > matched.GetXXXX()) { // results.failed++; // Console.Out.WriteLine("Number of neighbors is too high: " + results.tested + " in file " + filename); // Console.Out.WriteLine("Found: " + atom.FormalNeighbourCount + // ", expected (max): " + matched.FormalNeighbourCount); // } } } return(results); }