/// <summary> /// Verify the tetrahedral stereochemistry (clockwise/anticlockwise) of atom /// <paramref name="u"/> is preserved in the target when the <paramref name="mapping"/> is used. /// </summary> /// <param name="u">tetrahedral index in the target</param> /// <param name="mapping">mapping of vertices</param> /// <returns>the tetrahedral configuration is preserved</returns> private bool CheckTetrahedral(int u, int[] mapping) { int v = mapping[u]; if (targetTypes[v] != StereoType.Unset && targetTypes[v] != StereoType.Tetrahedral) { return(false); } ITetrahedralChirality queryElement = (ITetrahedralChirality)queryElements[u]; ITetrahedralChirality targetElement = (ITetrahedralChirality)targetElements[v]; SMARTSAtom queryAtom = (SMARTSAtom)query.Atoms[u]; IAtom targetAtom = target.Atoms[v]; int[] us = Neighbors(queryElement, queryMap); us = Map(u, v, us, mapping); int p = PermutationParity(us); // check if unspecified was allowed if (targetTypes[v] == StereoType.Unset) { if (queryAtom is SMARTSAtom) { return(((SMARTSAtom)queryAtom).ChiralityMatches(targetAtom, 0, p)); } else { return(((QueryAtom)queryAtom).Expression.Matches(targetAtom, 0)); } } // target was non-tetrahedral if (targetTypes[v] != StereoType.Tetrahedral) { return(false); } int[] vs = Neighbors(targetElement, targetMap); int q = PermutationParity(vs) * Parity(targetElement.Stereo); if (queryAtom is SMARTSAtom) { return(((SMARTSAtom)queryAtom).ChiralityMatches(targetAtom, q, p)); } else { q *= p; if (q < 0) { return(((QueryAtom)queryAtom).Expression.Matches(targetAtom, (int)StereoConfigurations.Left)); } else if (q > 0) { return(((QueryAtom)queryAtom).Expression.Matches(targetAtom, (int)StereoConfigurations.Right)); } else { return(((QueryAtom)queryAtom).Expression.Matches(targetAtom, 0)); } } }
public object Visit(ASTSmarts node, object data) { SMARTSAtom atom = null; SMARTSBond bond = null; ASTAtom first = (ASTAtom)node.JjtGetChild(0); atom = (SMARTSAtom)first.JjtAccept(this, null); if (data != null) { // this is a sub smarts bond = (SMARTSBond)((object[])data)[1]; IAtom prev = (SMARTSAtom)((object[])data)[0]; if (bond == null) { // since no bond was specified it could be aromatic or single bond = new AromaticOrSingleQueryBond(builder); bond.SetAtoms(new[] { prev, atom }); } else { bond.SetAtoms(new[] { prev, atom }); } if (neighbors.ContainsKey(prev)) { neighbors[prev].Add(atom); } query.Bonds.Add(bond); bond = null; } // first ATOM in expression query.Atoms.Add(atom); if (BitArrays.GetValue(tetrahedral, query.Atoms.Count - 1)) { List <IAtom> localNeighbors = new List <IAtom>(query.GetConnectedAtoms(atom)) { atom }; neighbors[atom] = localNeighbors; } // now process the rest of the bonds/atoms for (int i = 1; i < node.JjtGetNumChildren(); i++) { INode child = node.JjtGetChild(i); if (child is ASTLowAndBond) { bond = (SMARTSBond)child.JjtAccept(this, data); } else if (child is ASTAtom) { SMARTSAtom newAtom = (SMARTSAtom)child.JjtAccept(this, null); if (bond == null) { // since no bond was specified it could be aromatic or single bond = new AromaticOrSingleQueryBond(builder); } bond.SetAtoms(new[] { atom, newAtom }); query.Bonds.Add(bond); query.Atoms.Add(newAtom); if (neighbors.ContainsKey(atom)) { neighbors[atom].Add(newAtom); } if (BitArrays.GetValue(tetrahedral, query.Atoms.Count - 1)) { List <IAtom> localNeighbors = new List <IAtom>(query.GetConnectedAtoms(newAtom)) { newAtom }; neighbors[newAtom] = localNeighbors; } atom = newAtom; bond = null; } else if (child is ASTSmarts) { // another smarts child.JjtAccept(this, new object[] { atom, bond }); bond = null; } else if (child is ASTRingIdentifier) { HandleRingClosure(atom, (ASTRingIdentifier)child); } else { throw new InvalidOperationException("Unhandled node type: " + child.GetType()); } } return(query); }