public void TestGeometric_3D() { var m_l = new Mock <IAtom>(); var l = m_l.Object; // 0 var m_r = new Mock <IAtom>(); var r = m_r.Object; // 1 var m_l1 = new Mock <IAtom>(); var l1 = m_l1.Object; // 2 var m_l2 = new Mock <IAtom>(); var l2 = m_l2.Object; // 3 var m_r1 = new Mock <IAtom>(); var r1 = m_r1.Object; // 4 var m_r2 = new Mock <IAtom>(); var r2 = m_r2.Object; // 5 var m_m = new Mock <IAtomContainer>(); var m = m_m.Object; m_m.SetupGet(n => n.Atoms[0]).Returns(l); m_m.SetupGet(n => n.Atoms[1]).Returns(r); m_m.SetupGet(n => n.Atoms[2]).Returns(l1); m_m.SetupGet(n => n.Atoms[3]).Returns(l2); m_m.SetupGet(n => n.Atoms[4]).Returns(r1); m_m.SetupGet(n => n.Atoms[5]).Returns(r2); m_l.SetupGet(n => n.Point3D).Returns(new Vector3()); m_r.SetupGet(n => n.Point3D).Returns(new Vector3()); m_l1.SetupGet(n => n.Point3D).Returns(new Vector3()); m_l2.SetupGet(n => n.Point3D).Returns(new Vector3()); m_r1.SetupGet(n => n.Point3D).Returns(new Vector3()); m_r2.SetupGet(n => n.Point3D).Returns(new Vector3()); GeometricParity p = Geometric(m, 0, 1, 2, 3, 4, 5); Assert.IsTrue(p is DoubleBond3DParity); }
public void TestCreate_2D_Implicit() { var m_container = new Mock <IAtomContainer>(); var container = m_container.Object; m_container.SetupGet(n => n.Atoms.Count).Returns(4); var m_c1 = new Mock <IAtom>(); var c1 = m_c1.Object; var m_o2 = new Mock <IAtom>(); var o2 = m_o2.Object; var m_n3 = new Mock <IAtom>(); var n3 = m_n3.Object; var m_c4 = new Mock <IAtom>(); var c4 = m_c4.Object; m_container.SetupGet(n => n.Atoms[0]).Returns(c1); m_container.SetupGet(n => n.Atoms[1]).Returns(o2); m_container.SetupGet(n => n.Atoms[2]).Returns(n3); m_container.SetupGet(n => n.Atoms[3]).Returns(c4); Vector2 p1 = new Vector2(1.23, -0.29); Vector2 p2 = new Vector2(-0.30, -0.29); Vector2 p3 = new Vector2(2.00, -1.63); Vector2 p4 = new Vector2(2.00, 1.03); m_c1.SetupGet(n => n.Point2D).Returns(p1); m_o2.SetupGet(n => n.Point2D).Returns(p2); m_n3.SetupGet(n => n.Point2D).Returns(p3); m_c4.SetupGet(n => n.Point2D).Returns(p4); var m_c1c4 = new Mock <IBond>(); var c1c4 = m_c1c4.Object; var m_c1o2 = new Mock <IBond>(); var c1o2 = m_c1o2.Object; var m_c1n3 = new Mock <IBond>(); var c1n3 = m_c1n3.Object; var m_c1h5 = new Mock <IBond>(); var c1h5 = m_c1h5.Object; int[][] graph = new int[][] { new[] { 1, 2, 3 }, new[] { 0 }, new[] { 0 }, new[] { 0 }, }; m_container.Setup(n => n.GetConnectedBonds(c1)).Returns(new[] { c1c4, c1o2, c1n3 }); // let's say c1 is a chiral carbon m_c1.SetupGet(n => n.Hybridization).Returns(Hybridization.SP3); // with a hatch bond from c1 to n3 m_c1n3.SetupGet(n => n.Stereo).Returns(BondStereo.Down); m_c1n3.SetupGet(n => n.Begin).Returns(c1); m_c1n3.SetupGet(n => n.End).Returns(n3); m_c1o2.SetupGet(n => n.Stereo).Returns(BondStereo.None); m_c1o2.SetupGet(n => n.Begin).Returns(c1); m_c1o2.SetupGet(n => n.End).Returns(o2); m_c1c4.SetupGet(n => n.Stereo).Returns(BondStereo.None); m_c1c4.SetupGet(n => n.Begin).Returns(c1); m_c1c4.SetupGet(n => n.End).Returns(c4); IStereoEncoder encoder = new GeometricTetrahedralEncoderFactory().Create(container, graph); Assert.AreEqual(1, ExtractEncoders(encoder).Count); GeometricParity geometricParity = GetGeometricParity(ExtractEncoders(encoder)[0]); Assert.IsTrue(geometricParity is Tetrahedral2DParity); Assert.IsTrue(Compares.AreDeepEqual( new Vector2[] { p2, p3, p4, p1 // p1 is from central atom }, Coords2D(geometricParity))); }
public void ValueOf() { GeometricParity odd = GeometricParity.ValueOf(-1); GeometricParity even = GeometricParity.ValueOf(1); Assert.AreEqual(-1, odd.Parity); Assert.AreEqual(+1, even.Parity); }
/// <summary> /// Create a new encoder for multiple stereo centres (specified as an array). /// </summary> /// <param name="centres">the stereo centres which will be configured</param> /// <param name="permutation">calculator for permutation parity</param> /// <param name="geometric">geometric calculator</param> /// <exception cref="ArgumentException">if the centres[] were empty</exception> public GeometryEncoder(int[] centres, PermutationParity permutation, GeometricParity geometric) { if (centres.Length == 0) { throw new ArgumentException("no centres[] provided"); } this.permutation = permutation; this.geometric = geometric; this.centres = new int[centres.Length]; Array.Copy(centres, this.centres, centres.Length); }
/// <summary> /// Create an encoder for the <see cref="ITetrahedralChirality"/> element. /// </summary> /// <param name="tc">stereo element from an atom container</param> /// <param name="atomToIndex">map of atoms to indices</param> /// <returns>a new geometry encoder</returns> private static GeometryEncoder Encoder(ITetrahedralChirality tc, IDictionary <IAtom, int> atomToIndex) { var ligands = tc.Ligands; var centre = atomToIndex[tc.ChiralAtom]; var indices = new int[4]; int offset = -1; { int i = 0; foreach (var ligand in ligands) { indices[i] = atomToIndex[ligands[i]]; if (indices[i] == centre) { offset = i; } i++; } } // convert clockwise/anticlockwise to -1/+1 var parity = tc.Stereo == TetrahedralStereo.Clockwise ? -1 : 1; // now if any atom is the centre (indicating an implicit // hydrogen) we need to adjust the indicies and the parity if (offset >= 0) { // remove the 'implicit' central from the first 3 vertices for (int i = offset; i < indices.Length - 1; i++) { indices[i] = indices[i + 1]; } // we now take how many vertices we moved which is // 3 (last index) minus the index where we started. if the // value is odd we invert the parity (odd number of // inversions) if ((3 - offset) % 2 == 1) { parity *= -1; } // trim the array to size we don't include the last (implicit) // vertex when checking the invariants var sindices = new int[indices.Length - 1]; Array.Copy(indices, sindices, indices.Length - 1); indices = sindices; } return(new GeometryEncoder(centre, new BasicPermutationParity(indices), GeometricParity.ValueOf(parity))); }
private static Vector3[] Coords3D(GeometricParity parity) { if (parity is Tetrahedral3DParity) { FieldInfo field = null; field = parity.GetType().GetField("coordinates", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (field == null) { Console.Error.WriteLine("Error on accessing coordinates field."); return(null); } return((Vector3[])field.GetValue(parity)); } return(null); }
/// <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> /// Create a new encoder for the specified left and right atoms. The parent /// is the atom which is connected by a double bond to the left and right /// atom. For simple double bonds the parent of each is the other atom, in /// cumulenes the parents are not the same. /// </summary> /// <param name="container">the molecule</param> /// <param name="left">the left atom</param> /// <param name="leftParent">the left atoms parent (usually <paramref name="right"/>)</param> /// <param name="right">the right atom</param> /// <param name="rightParent">the right atoms parent (usually <paramref name="left"/>)</param> /// <param name="graph">adjacency list representation of the molecule</param> /// <returns>a stereo encoder (or null)</returns> internal static IStereoEncoder NewEncoder(IAtomContainer container, IAtom left, IAtom leftParent, IAtom right, IAtom rightParent, int[][] graph) { var leftBonds = container.GetConnectedBonds(left); var rightBonds = container.GetConnectedBonds(right); // check the left and right bonds are acceptable if (Accept(left, leftBonds) && Accept(right, rightBonds)) { int leftIndex = container.Atoms.IndexOf(left); int rightIndex = container.Atoms.IndexOf(right); int leftParentIndex = container.Atoms.IndexOf(leftParent); int rightParentIndex = container.Atoms.IndexOf(rightParent); // neighbors of u/v with the bonded atoms (left,right) moved // to the back of each array. this is important as we can // drop it when we build the permutation parity int[] leftNeighbors = MoveToBack(graph[leftIndex], leftParentIndex); int[] rightNeighbors = MoveToBack(graph[rightIndex], rightParentIndex); int l1 = leftNeighbors[0]; int l2 = leftNeighbors[1] == leftParentIndex ? leftIndex : leftNeighbors[1]; int r1 = rightNeighbors[0]; int r2 = rightNeighbors[1] == rightParentIndex ? rightIndex : rightNeighbors[1]; // make 2D/3D geometry GeometricParity geometric = Geometric(container, leftIndex, rightIndex, l1, l2, r1, r2); // geometric is null if there were no coordinates if (geometric != null) { return(new GeometryEncoder(new int[] { leftIndex, rightIndex }, new CombinedPermutationParity( Permutation(leftNeighbors), Permutation(rightNeighbors)), geometric)); } } return(null); }
/// <summary> /// Convenience method to create a new encoder for a single stereo centre. /// </summary> /// <param name="centre">a stereo centre which will be configured</param> /// <param name="permutation">calculator for permutation parity</param> /// <param name="geometric">geometric calculator</param> /// <exception cref="ArgumentException">if the centres[] were empty</exception> public GeometryEncoder(int centre, PermutationParity permutation, GeometricParity geometric) : this(new int[] { centre }, permutation, geometric) { }