/// <summary> /// Add double-bond stereo configuration to the Beam GraphBuilder. /// </summary> /// <param name="dbs">stereo element specifying double-bond configuration</param> /// <param name="gb">the current graph builder</param> /// <param name="indices">atom indices</param> private static void AddGeometricConfiguration(IDoubleBondStereochemistry dbs, SmiFlavors flavour, GraphBuilder gb, Dictionary <IAtom, int> indices) { var db = dbs.StereoBond; var bs = dbs.Bonds; // don't try to set a configuration on aromatic bonds if (SmiFlavorTool.IsSet(flavour, SmiFlavors.UseAromaticSymbols) && db.IsAromatic) { return; } var u = indices[db.Begin]; var v = indices[db.End]; // is bs[0] always connected to db.Atom(0)? var x = indices[bs[0].GetOther(db.Begin)]; var y = indices[bs[1].GetOther(db.End)]; if (dbs.Stereo == DoubleBondConformation.Together) { gb.Geometric(u, v).Together(x, y); } else { gb.Geometric(u, v).Opposite(x, y); } }
/// <summary> /// Adjust the configuration of the <paramref name="dbs"/> element (if required). /// </summary> /// <param name="dbs">double-bond stereochemistry element</param> private void Adjust(IDoubleBondStereochemistry dbs) { var db = dbs.StereoBond; var bonds = dbs.Bonds; var left = db.Begin; var right = db.End; var p = Parity(dbs.Configure); var q = Parity(GetAtoms(left, bonds[0].GetOther(left), right)) * Parity(GetAtoms(right, bonds[1].GetOther(right), left)); // configuration is unspecified? then we add an unspecified bond. // note: IDoubleBondStereochemistry doesn't indicate this yet if (p == 0) { foreach (var bond in container.GetConnectedBonds(left)) { bond.Stereo = BondStereo.None; } foreach (var bond in container.GetConnectedBonds(right)) { bond.Stereo = BondStereo.None; } bonds[0].Stereo = BondStereo.UpOrDown; return; } // configuration is already correct if (p == q) { return; } Arrays.Fill(visited, false); visited[atomToIndex[left]] = true; if (ringSearch.Cyclic(atomToIndex[left], atomToIndex[right])) { db.Stereo = BondStereo.EOrZ; return; } foreach (var w in graph[atomToIndex[right]]) { if (!visited[w]) { Reflect(w, db); } } }
public void Z_1_2_difluroethene() { IAtomContainer ac = Convert("F/C=C\\F"); var se = ac.StereoElements.First(); Assert.IsInstanceOfType(se, typeof(IDoubleBondStereochemistry)); IDoubleBondStereochemistry dbs = (IDoubleBondStereochemistry)se; Assert.AreEqual(ac.GetBond(ac.Atoms[1], ac.Atoms[2]), dbs.StereoBond); Assert.IsTrue(Compares.AreDeepEqual(new IBond[] { ac.GetBond(ac.Atoms[0], ac.Atoms[1]), ac.GetBond(ac.Atoms[2], ac.Atoms[3]) }, dbs.Bonds)); Assert.AreEqual(DoubleBondConformation.Together, dbs.Stereo); }
public void Z_1_2_difluroethene_explicit() { IAtomContainer ac = Convert("FC(\\[H])=C([H])/F"); var se = ac.StereoElements.First(); Assert.IsInstanceOfType(se, typeof(IDoubleBondStereochemistry)); IDoubleBondStereochemistry dbs = (IDoubleBondStereochemistry)se; Assert.AreEqual(ac.GetBond(ac.Atoms[1], ac.Atoms[3]), dbs.StereoBond); Assert.IsTrue(Compares.AreDeepEqual(new IBond[] { ac.GetBond(ac.Atoms[1], ac.Atoms[2]), ac.GetBond(ac.Atoms[3], ac.Atoms[5]) }, dbs.Bonds)); // the two 'F' are together but we use a H so they are 'opposite' Assert.AreEqual(DoubleBondConformation.Opposite, dbs.Stereo); }
public void TestMap_Map_Map_EmptyMapping() { IChemObjectBuilder builder = ChemObjectBuilder.Instance; IAtom c1 = builder.NewAtom("C"); IAtom c2 = builder.NewAtom("C"); IAtom o3 = builder.NewAtom("O"); IAtom o4 = builder.NewAtom("O"); IBond c1c2 = builder.NewBond(c1, c2, BondOrder.Double); IBond c1o3 = builder.NewBond(c1, o3, BondOrder.Single); IBond c2o4 = builder.NewBond(c2, o4, BondOrder.Single); // new stereo element IDoubleBondStereochemistry original = new DoubleBondStereochemistry(c1c2, new IBond[] { c1o3, c2o4 }, DoubleBondConformation.Opposite); // map the existing element a new element - should through an ArgumentException IDoubleBondStereochemistry mapped = (IDoubleBondStereochemistry)original.Clone(new CDKObjectMap()); Assert.AreSame(original, mapped); }
/// <summary> /// Create an encoder for the <see cref="IDoubleBondStereochemistry"/> element. /// </summary> /// <param name="dbs">stereo element from an atom container</param> /// <param name="atomToIndex">map of atoms to indices</param> /// <param name="graph">adjacency list of connected vertices</param> /// <returns>a new geometry encoder</returns> private static GeometryEncoder GetEncoder(IDoubleBondStereochemistry dbs, IDictionary <IAtom, int> atomToIndex, int[][] graph) { var db = dbs.StereoBond; var u = atomToIndex[db.Begin]; var v = atomToIndex[db.End]; // we now need to expand our view of the environment - the vertex arrays // 'us' and <paramref name="vs"/> hold the neighbors of each end point of the double bond // (<paramref name="u"/> or 'v'). The first neighbor is always the one stored in the // stereo element. The second is the other non-double bonded vertex // which we must find from the neighbors list (findOther). If there is // no additional atom attached (or perhaps it is an implicit Hydrogen) // we use either double bond end point. var bs = dbs.Bonds; var us = new int[2]; var vs = new int[2]; us[0] = atomToIndex[bs[0].GetOther(db.Begin)]; us[1] = graph[u].Length == 2 ? u : FindOther(graph[u], v, us[0]); vs[0] = atomToIndex[bs[1].GetOther(db.End)]; vs[1] = graph[v].Length == 2 ? v : FindOther(graph[v], u, vs[0]); var parity = dbs.Stereo == DoubleBondConformation.Opposite ? +1 : -1; var geomParity = GeometricParity.ValueOf(parity); // the permutation parity is combined - but note we only use this if we // haven't used <paramref name="u"/> or 'v' as place holders (i.e. implicit hydrogens) // otherwise there is only '1' and the parity is just '1' (identity) PermutationParity permParity = new CombinedPermutationParity(us[1] == u ? BasicPermutationParity.Identity : new BasicPermutationParity(us), vs[1] == v ? BasicPermutationParity.Identity : new BasicPermutationParity(vs)); return(new GeometryEncoder(new int[] { u, v }, permParity, geomParity)); }
/// <summary> /// Given an index of an atom in the query get the index of the other atom in /// the double bond. /// </summary> /// <param name="i">query atom index</param> /// <returns>the other atom index involved in a double bond</returns> private int OtherIndex(int i) { IDoubleBondStereochemistry element = (IDoubleBondStereochemistry)queryElements[i]; return(queryMap[element.StereoBond.GetOther(query.Atoms[i])]); }
/// <summary> /// Verify the geometric stereochemistry (cis/trans) of the double bond /// <c><paramref name="u1"/>=<paramref name="u2"/></c> is preserved in the target when the <paramref name="mapping"/> is /// used. /// </summary> /// <param name="u1">one index of the double bond</param> /// <param name="u2">other index of the double bond</param> /// <param name="mapping">mapping of vertices</param> /// <returns>the geometric configuration is preserved</returns> private bool CheckGeometric(int u1, int u2, int[] mapping) { int v1 = mapping[u1]; int v2 = mapping[u2]; if (targetTypes[v1] != StereoType.Unset && targetTypes[v1] != StereoType.Geometric) { return(false); } if (targetTypes[v2] != StereoType.Unset && targetTypes[v2] != StereoType.Geometric) { return(false); } IDoubleBondStereochemistry queryElement = (IDoubleBondStereochemistry)queryElements[u1]; var queryBonds = queryElement.Bonds; bool unspecified = ((StereoBond)queryBonds[0]).IsUnspecified || ((StereoBond)queryBonds[1]).IsUnspecified; if (unspecified && (targetTypes[v1] == StereoType.Unset || targetTypes[v2] == StereoType.Unset)) { return(true); } // no configuration in target if (targetTypes[v1] != StereoType.Geometric || targetTypes[v2] != StereoType.Geometric) { return(false); } IDoubleBondStereochemistry targetElement = (IDoubleBondStereochemistry)targetElements[v1]; // although the atoms were mapped and 'v1' and 'v2' are bond in double-bond // elements they are not in the same element if (!targetElement.StereoBond.Contains(target.Atoms[v1]) || !targetElement.StereoBond.Contains(target.Atoms[v2])) { return(false); } // bond is undirected so we need to ensure v1 is the first atom in the bond // we also need to to swap the substituents later bool swap = false; if (targetElement.StereoBond.Begin != target.Atoms[v1]) { int tmp = v1; v1 = v2; v2 = tmp; swap = true; } var targetBonds = targetElement.Bonds; int p = Parity(queryElement.Stereo); int q = Parity(targetElement.Stereo); int uLeft = queryMap[queryBonds[0].GetOther(query.Atoms[u1])]; int uRight = queryMap[queryBonds[1].GetOther(query.Atoms[u2])]; int vLeft = targetMap[targetBonds[0].GetOther(target.Atoms[v1])]; int vRight = targetMap[targetBonds[1].GetOther(target.Atoms[v2])]; if (swap) { int tmp = vLeft; vLeft = vRight; vRight = tmp; } if (mapping[uLeft] != vLeft) { p *= -1; } if (mapping[uRight] != vRight) { p *= -1; } return(p == q); }
public static CIPChirality GetCIPChirality(IAtomContainer container, IDoubleBondStereochemistry stereoCenter) { IBond stereoBond = stereoCenter.StereoBond; IBond leftBond = stereoCenter.Bonds[0]; IBond rightBond = stereoCenter.Bonds[1]; // the following variables are usd to label the atoms - makes things // a little more concise // // x y x // \ / \ // u = v or u = v // \ // y // var u = stereoBond.Begin; var v = stereoBond.End; var x = leftBond.GetOther(u); var y = rightBond.GetOther(v); var conformation = stereoCenter.Stereo; var leftLigands = GetLigands(u, container, v).ToList(); var rightLigands = GetLigands(v, container, u).ToList(); if (leftLigands.Count > 2 || rightLigands.Count > 2) { return(CIPChirality.None); } // invert if x/y aren't in the first position if (leftLigands[0].LigandAtom != x) { conformation = conformation.Invert(); } if (rightLigands[0].LigandAtom != y) { conformation = conformation.Invert(); } int p = PermParity(leftLigands) * PermParity(rightLigands); if (p == 0) { return(CIPChirality.None); } else if (p < 0) { conformation = conformation.Invert(); } switch (conformation) { case DoubleBondConformation.Together: return(CIPChirality.Z); case DoubleBondConformation.Opposite: return(CIPChirality.E); default: return(CIPChirality.None); } }
void Main() { IAtomContainer someMolecule = null; StereoElementFactory someFactory = null; { #region IAtomContainer container = someMolecule; StereoElementFactory stereo = StereoElementFactory.Using2DCoordinates(container).InterpretProjections(Projection.Haworth); // set the elements replacing any existing elements container.SetStereoElements(stereo.CreateAll()); // adding elements individually is also possible but existing elements are // are not removed foreach (var element in stereo.CreateAll()) { container.StereoElements.Add(element); } #endregion } { #region CreateTetrahedral_int StereoElementFactory factory = someFactory; // 2D/3D IAtomContainer container = someMolecule; // container for (int v = 0; v < container.Atoms.Count; v++) { // ... verify v is a stereo atom ... ITetrahedralChirality element = factory.CreateTetrahedral(v, null); if (element != null) { container.StereoElements.Add(element); } } #endregion } { #region CreateTetrahedral_IAtom StereoElementFactory factory = someFactory; // 2D/3D IAtomContainer container = someMolecule; // container foreach (var atom in container.Atoms) { // ... verify atom is a stereo atom ... ITetrahedralChirality element = factory.CreateTetrahedral(atom, null); if (element != null) { container.StereoElements.Add(element); } } #endregion } { #region CreateGeometric_IBond StereoElementFactory factory = someFactory; // 2D/3D IAtomContainer container = someMolecule; // container foreach (var bond in container.Bonds) { if (bond.Order != BondOrder.Double) { continue; } // ... verify bond is a stereo bond... IDoubleBondStereochemistry element = factory.CreateGeometric(bond, null); if (element != null) { container.StereoElements.Add(element); } } #endregion } { #region CreateExtendedTetrahedral StereoElementFactory factory = someFactory; // 2D/3D IAtomContainer container = someMolecule; // container for (int v = 0; v < container.Atoms.Count; v++) { // ... verify v is a stereo atom ... ExtendedTetrahedral element = factory.CreateExtendedTetrahedral(v, null); if (element != null) { container.StereoElements.Add(element); } } #endregion } { IAtomContainer container = someMolecule; // container #region InterpretProjections StereoElementFactory factory = StereoElementFactory.Using2DCoordinates(container) .InterpretProjections(Projection.Fischer, Projection.Haworth); #endregion } }