Revision: 21659
          http://sourceforge.net/p/jmol/code/21659
Author:   hansonr
Date:     2017-07-14 00:01:09 +0000 (Fri, 14 Jul 2017)
Log Message:
-----------
better spiro testing

Modified Paths:
--------------
    trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java

Modified: trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java
===================================================================
--- trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java  2017-07-10 00:51:36 UTC 
(rev 21658)
+++ trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java  2017-07-14 00:01:09 UTC 
(rev 21659)
@@ -115,7 +115,7 @@
  * CIP-System, MATCH, 21, 1986, 3-31
  * http://match.pmf.kg.ac.rs/electronic_versions/Match21/match21_3-31.pdf
  * 
- * Mata(1993a) Paulina Mata, Ana M. Lobo, Chris Marshall, A.Peter Johnson The
+ * Mata(1993) Paulina Mata, Ana M. Lobo, Chris Marshall, A.Peter Johnson The
  * CIP sequence rules: Analysis and proposal for a revision, Tetrahedron:
  * Asymmetry, Volume 4, Issue 4, April 1993, Pages 657-668
  * 
@@ -140,6 +140,7 @@
  * 
  * code history:
  * 
+ * 7/10/17 Jmol 14.20.2 adding check for C3 and double spiran (CIP 1966 #32 
and #33)
  * 7/8/17 Jmol 14.20.2 adding presort for Rules 4a and 4c (test12.mol; 828 
lines) 
  * 
  * 7/7/17 Jmol 14.20.1 minor coding efficiencies (833 lines)
@@ -1504,7 +1505,9 @@
      * pointer to this branch's spiro end atom if it is found to be spiro
      */
 
-    private CIPAtom spiroEnd;
+    private CIPAtom spiroEnd, spiroEnd1;
+    
+    private int nSpiro;
 
     /**
      * Rule 1b hash table that maintains distance of the associated
@@ -1687,7 +1690,15 @@
         // pointing to original atom
         isDuplicate = true;
         rootDistance = 0;
-        rootSubstituent.spiroEnd = parent;
+        root.nSpiro++;
+        if (rootSubstituent.spiroEnd == null) {
+          rootSubstituent.spiroEnd = parent;
+        } else if (rootSubstituent.spiroEnd.sphere > parent.sphere) {
+          rootSubstituent.spiroEnd1 = rootSubstituent.spiroEnd;
+          rootSubstituent.spiroEnd = parent;
+        } else if (rootSubstituent.spiroEnd1 == null || 
rootSubstituent.spiroEnd1.sphere > parent.sphere){
+          rootSubstituent.spiroEnd1 = parent;
+        }
       } else if (bsPath.get(atomIndex)) {
         isDuplicate = true;
         rootDistance = (isParentBond ? parent.sphere : htPathPoints.get(
@@ -1882,7 +1893,8 @@
         if (isTerminal)
           return false;
         for (int i = 0; i < 4; i++)
-          if (rule4List[i] != null && atoms[i].atom != null && 
!atoms[i].isTerminal)
+          if (rule4List[i] != null && atoms[i].atom != null
+              && !atoms[i].isTerminal)
             atoms[i].sortSubstituents(Integer.MIN_VALUE);
         if (!canBePseudo)
           return false;
@@ -1973,52 +1985,11 @@
 
         // We do the spiro test first, as it may inform the pseudoasymmetric 
test.
 
-        if (nPriorities == 2 && priorities[3] == 2) {
-          //
-          // We have priorities [0 0 2 2], possibly being spiro
-          //
-          int end0, end1;
-          if ((end0 = getSpiroType(0)) >= 2 && (end1 = getSpiroType(1)) >= 2
-              && end0 != end1) {
-            //
-            // We are done, because the two spiro ends set both of these ties.
-            //                     a a'b b' (order is already OK)
-            //                     a a'b'b  (needs switching)
-            //
-            // P-93.2.3.2
-            //
-            // We have priorities [0 0 2 2], possibly being spiro
-            //
-            //     b                            b
-            //    /-                            -\
-            //   / -                            - \
-            //  a--C--a'    R                a--C--a'    S
-            //     - /                        \ - 
-            //     -/                          \-
-            //     b'                           b'
-            // 
-            // a==a' and b==b'; order of precedence is set to a > a' > b > b'
-            //
-            // Note that this is really a case of axial chirality. It is the 
same as:
-            // 
-            //     b'                          a'
-            //     -                           -
-            //     -                           - 
-            //  a--C--b    M                a--C--b    P
-            //     -                           - 
-            //     -                           -
-            //     a'                          b'
-
+        if (nSpiro > 0) {
+          int nprev = checkSpiro();
+          if (nprev == 2)
             nPrioritiesPrev = 2;
-            nPriorities = 4;
-            if (end1 == 2) {
-              CIPAtom a = atoms[2];
-              atoms[2] = atoms[3];
-              atoms[3] = a;
-            }
-          }
         }
-
         if (currentRule == RULE_5 && nPriorities == 4 && nPrioritiesPrev == 2) 
{
 
           // Rule 5 has decided the issue, but how many decisions did we make?
@@ -2063,6 +2034,96 @@
       return (nPriorities == bondCount);
     }
 
+    private int checkSpiro() {
+      if (nSpiro >= 42)
+        return -1; // disallow O_h-cubane, which has 42 root termination 
pathways
+      boolean swap23 = false;
+      int nPrev = 0;
+      if (nPriorities == 1) {
+        // CIP Helv Chim. Acta 1966 #33 -- double spiran
+        // 0-1,2-3 or 0-1,3-2
+        // 0-2,1-3 or 
+        // 0-3,1-2
+        int a2, a3;
+        if ((getSpiroType(0, false)) >= 0 && (a2 = getSpiroType(0, true)) >= 0
+            && (getSpiroType(1, false)) >= 0
+            && (a3 = getSpiroType(1, true)) >= 0
+            && (getSpiroType(2, false)) >= 0 && (getSpiroType(2, true)) >= 0
+            && (getSpiroType(3, false)) >= 0 && (getSpiroType(3, true)) >= 0) {
+          nPriorities = 4;
+          swap23 = (a2 < a3);
+        }
+      } else if (nPriorities == 2) {
+        swap23 = false;
+        switch (priorities[3]) {
+        case 1:
+        case 3:
+          // CIP Helv. Chim. Acta 1966 #32 
+          // [0 1 1 1] or [0 0 0 3]
+          int first = (priorities[3] == 1 ? 1 : 0);
+          int a1 = getSpiroType(first, false);
+          if (a1 >= 0) {
+            // BH64_069, BH64_070
+            int a2 = getSpiroType(a1, false);
+            int a3 = getSpiroType(a2, false);
+            if (a1 != a2 && a2 != a3 && a3 != a1) {
+              nPriorities = 4;
+              swap23 = (a2 > a1);
+            }
+          }
+          break;
+        case 2:
+          //
+          // We have priorities [0 0 2 2], possibly being spiro
+          //
+          int end0,
+          end1;
+          if ((end0 = getSpiroType(0, false)) >= 2
+              && (end1 = getSpiroType(1, false)) >= 2 && end0 != end1) {
+            //
+            // We are done, because the two spiro ends set both of these ties.
+            //                     a a'b b' (order is already OK)
+            //                     a a'b'b  (needs switching)
+            //
+            // P-93.2.3.2
+            //
+            // We have priorities [0 0 2 2], possibly being spiro
+            //
+            //     b                            b
+            //    /-                            -\
+            //   / -                            - \
+            //  a--C--a'    R                a--C--a'    S
+            //     - /                        \ - 
+            //     -/                          \-
+            //     b'                           b'
+            // 
+            // a==a' and b==b'; order of precedence is set to a > a' > b > b'
+            //
+            // Note that this is really a case of axial chirality. It is the 
same as:
+            // 
+            //     b'                          a'
+            //     -                           -
+            //     -                           - 
+            //  a--C--b    M                a--C--b    P
+            //     -                           - 
+            //     -                           -
+            //     a'                          b'
+
+            nPrev = 2;
+            nPriorities = 4;
+            swap23 = (end1 == 2);
+          }
+          break;
+        }
+      }
+      if (swap23) {
+        CIPAtom a = atoms[2];
+        atoms[2] = atoms[3];
+        atoms[3] = a;
+      }
+      return nPrev;
+    }
+
     /**
      * Find the other end of a loop to root.
      * 
@@ -2070,10 +2131,11 @@
      * @return pointer to spiro end of atoms[0] -- either 0 (not spiro), 1, 2,
      *         or 3
      */
-    private int getSpiroType(int i0) {
-      if (atoms[i0].spiroEnd != null)
+    private int getSpiroType(int i0, boolean checkEnd1) {
+      CIPAtom a = (i0 < 0 ? null : checkEnd1 ? atoms[i0].spiroEnd1 : 
atoms[i0].spiroEnd);
+      if (a != null)
         for (int i = 0; i < 4; i++)
-          if (i != i0 && atoms[i0].spiroEnd.atom == atoms[i].atom)
+          if (i != i0 && a.atom == atoms[i].atom)
             return i;
       return -1;
     }
@@ -2551,7 +2613,7 @@
 
       a.generateRule4Paths(this);
       b.generateRule4Paths(this);
-      
+
       boolean isRule5 = (currentRule == RULE_5);
       char aref = (isRule5 ? 'R' : a.getRule4ReferenceDescriptor());
       char bref = (isRule5 ? 'R' : b.getRule4ReferenceDescriptor());
@@ -2561,67 +2623,57 @@
 
       int score = TIED;
       String reason = "Rule 4b"; // Logger
-      
+
       while (true) {
 
         // check for RS on only one side
         if ((aref == '?') != (bref == '?')) {
           score = (haveRSOptions ? B_WINS : A_WINS);
-          reason += " RS on only one side";  // Logger
+          reason += " RS on only one side"; // Logger
           break;
         }
 
-        String aStr = (haveRSOptions ? a.flattenRule4Paths('R', isRule5) + "|"
-            + a.flattenRule4Paths('S', isRule5) : a.flattenRule4Paths(
-            aref, isRule5));
-        String bStr = (haveRSOptions ? b.flattenRule4Paths('R', isRule5) + "|"
-            + b.flattenRule4Paths('S', isRule5) : b.flattenRule4Paths(
-            bref, isRule5));
+        String aStr = (haveRSOptions ? a.flattenRule4Paths('R') : a
+            .flattenRule4Paths(aref));
+        String aStr2 = (haveRSOptions ? a.flattenRule4Paths('S') : "");
+        String bStr = (haveRSOptions ? b.flattenRule4Paths('R') : b
+            .flattenRule4Paths(bref));
+        String bStr2 = (haveRSOptions ? b.flattenRule4Paths('S') : "");
 
         // just return string comparison if Rule 5
         if (isRule5) {
           // note that these two strings cannot be different lengths
-          score = sign(aStr.compareTo(bStr));
-          reason = "Rule 5";  // Logger
+          score = sign(haveRSOptions ? (aStr + aStr2).compareTo(bStr + bStr2)
+              : aStr.compareTo(bStr));
+          reason = "Rule 5"; // Logger
           break;
         }
 
-        // check for 
         aStr = cleanRule4Str(aStr);
         bStr = cleanRule4Str(bStr);
+
         if (haveRSOptions) {
-          
-          // Mata(2005) Figure 9
-          // We are trying to ascertain that
-          // R lull                  R luuu
-          // S luuu   is the same as S lull
-          // 
-          // Solution is to SUM all winners. If that is 0, then they are the 
same.
-          
-          String[] aList = PT.split(aStr, "|"), bList = PT.split(bStr, "|");
-          int minScore = Integer.MAX_VALUE, sumScore = 0;
-          for (int i = aList.length; --i >= 0;) {
-            for (int j = bList.length; --j >= 0;) {
-              score = compareRule4PairStr(aList[i], bList[j], true);
-              sumScore += score;
-              if (score != TIED && Math.abs(score) <= Math.abs(minScore)) {
-                minScore = score;
-              }
-            }
-          }
-          score = (sumScore == TIED ? TIED : minScore < 0 ? A_WINS : B_WINS);
-          break;
+
+          // first find the better of A(R)/A(S) and the better of B(R)/B(S)
+
+          if (compareRule4PairStr(aStr, aStr2 = cleanRule4Str(aStr2), true) > 
0)
+            aStr = aStr2;
+          if (compareRule4PairStr(bStr, bStr2 = cleanRule4Str(bStr2), true) > 
0)
+            bStr = bStr2;
+
+          // then continue as before
         }
         score = compareRule4PairStr(aStr, bStr, false);
         break;
-        
+
       }
-      
+
       if (Logger.debugging && (score == A_WINS || score == B_WINS))
-        Logger.info((score == A_WINS ? a : b) + " > " + (score == A_WINS ? b : 
a) + " by " + reason + "\n"); // Logger
+        Logger.info((score == A_WINS ? a : b) + " > "
+            + (score == A_WINS ? b : a) + " by " + reason + "\n"); // Logger
 
       // no tie-breaking for Rules 4b or 5
-      
+
       return (score == TIED ? IGNORE : score);
     }
 
@@ -2747,10 +2799,9 @@
      * lowest ASCII characater "A" (65).
      * 
      * @param ref
-     * @param isRule5
      * @return a string that can be compared with another using like/unlike
      */ 
-    private String flattenRule4Paths(char ref, boolean isRule5) {
+    private String flattenRule4Paths(char ref) {
       int nPaths = rootRule4Paths.size();
       String[] paths = new String[nPaths];      
       int nMax = 0;

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Jmol-commits mailing list
Jmol-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jmol-commits

Reply via email to