Revision: 21670
          http://sourceforge.net/p/jmol/code/21670
Author:   hansonr
Date:     2017-07-21 22:22:08 +0000 (Fri, 21 Jul 2017)
Log Message:
-----------
Jmol.___JmolVersion="14.20.4"

bug fix: CIPChirality covers all special spiro cases and C3-symmetry

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

Modified: trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java
===================================================================
--- trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java  2017-07-20 14:37:14 UTC 
(rev 21669)
+++ trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java  2017-07-21 22:22:08 UTC 
(rev 21670)
@@ -540,10 +540,10 @@
   static final int STEREO_BOTH_EZ = STEREO_E | STEREO_Z;
 
   static final int RULE_1a = 1, RULE_1b = 2, RULE_2 = 3, RULE_3 = 4,
-      RULE_4a = 5,
+      RULE_4a = 5, RULE_4bTEST = 6, RULE_4b = 7, RULE_4c = 8, 
+      RULE_5 = 9,
+      RULE_6 = 10;
 
-      RULE_4bTEST = 6, RULE_4b = 7, RULE_4c = 8, RULE_5 = 9;
-
   boolean isRule4TEST = false;
 
   static String prefixString = ".........."; // Logger only
@@ -1557,7 +1557,7 @@
      * pointer to this branch's spiro end atom if it is found to be spiro
      */
 
-    private CIPAtom spiroEnd, spiroEnd1;
+    private CIPAtom spiroEnd;
 
     private int nSpiro;
 
@@ -1681,10 +1681,15 @@
 
     private BS bsTemp = new BS();
 
-    // flag to reverse the ruling for a few isotope types
+    // flag to reverse the Rule 2 result for a few isotope types
 
     private boolean reverseRule2;
 
+    // flag for C3-symmetry checking reference atom index
+    
+    private int c3RefIndex = -1;
+    private int c4RefIndex = -1;
+
     CIPAtom() {
       // had a problem in JavaScript that the constructor of an inner function 
cannot
       // access this.b$ yet. That assignment is made after construction.
@@ -1753,15 +1758,8 @@
         isDuplicate = true;
         rootDistance = 0;
         root.nSpiro++;
-        if (rootSubstituent.spiroEnd == null) {
+        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(
@@ -1998,7 +1996,7 @@
      * pseudochirality is also done here.
      * 
      * @param sphere
-     *        current working sphere
+     *        current working sphere; Integer.MIN_VALUE to not break ties
      * @return all priorities assigned
      * 
      */
@@ -2016,13 +2014,22 @@
         // Just before Rule4a we must sort all substituents without breaking 
ties
         if (isTerminal)
           return false;
-        for (int i = 0; i < 4; i++)
-          if (rule4List[i] != null && atoms[i].atom != null
-              && !atoms[i].isTerminal)
-            atoms[i].sortSubstituents(Integer.MIN_VALUE);
-        if (!canBePseudo)
-          return false;
+        if (currentRule == RULE_6) {
+          for (int i = 0; i < 4; i++)
+            if (atoms[i] != null && !atoms[i].isDuplicate && atoms[i].atom != 
null
+                && atoms[i].setNode())
+              atoms[i].sortSubstituents(Integer.MIN_VALUE);          
+        } else {
+          for (int i = 0; i < 4; i++)
+            if (rule4List[i] != null && atoms[i].atom != null
+                && !atoms[i].isTerminal)
+              atoms[i].sortSubstituents(Integer.MIN_VALUE);
+          if (!canBePseudo)
+            return false;
+        }
       }
+      
+      ignoreTies |= (currentRule == RULE_4b || currentRule == RULE_5);
 
       int[] indices = new int[4], prevPrior = new int[4];
       int nPrioritiesPrev = nPriorities;
@@ -2037,7 +2044,7 @@
           Logger.info(getRuleName() + ": " + this + "[" + i + "]="
               + atoms[i].myPath + " " + Integer.toHexString(prevPrior[i])); // 
Logger
         }
-        Logger.info("---");
+        Logger.info("---" + nPriorities);
       }
 
       int loser, score;
@@ -2059,7 +2066,7 @@
                       : (score = checkPriority(a, b, i, j)) != TIED ? score
                           : ignoreTies ? IGNORE : sign(a
                               .breakTie(b, sphere + 1))) {
-          case B_WINS:
+          case B_WINS:  
             loser = i;
             //$FALL-THROUGH$
           case A_WINS:
@@ -2102,15 +2109,11 @@
         //
         //  P-33.5.3.1 spiro compounds have increased constraints
 
-        // We do the spiro test first, as it may inform the pseudoasymmetric 
test.
+        if (currentRule == RULE_5) {
+          if (nSpiro > 0)
+            checkSpiro();          
+          if (nPriorities == 4 && nPrioritiesPrev == 2) {
 
-        if (nSpiro > 0) {
-          int nprev = checkSpiro();
-          if (nprev == 2)
-            nPrioritiesPrev = 2;
-        }
-        if (currentRule == RULE_5 && nPriorities == 4 && nPrioritiesPrev == 2) 
{
-
           // Rule 5 has decided the issue, but how many decisions did we make?
           // If priorities [0 0 2 2] went to [0 1 2 3] then
           // we have two Rule-5 decisions -- R,S,R',S'.
@@ -2136,7 +2139,7 @@
           // 
           canBePseudo = false;
         }
-
+        }
       }
       if ((Logger.debuggingHigh) && atoms[2].atom != null
           && atoms[2].elemNo != 1) { // Logger
@@ -2145,7 +2148,7 @@
           Logger.info(dots() + myPath + "[" + i + "]=" + atoms[i] + " "
               + priorities[i] + " " + Integer.toHexString(priorities[i])); // 
Logger
         }
-        Logger.info(dots() + "-------");
+        Logger.info(dots() + "-------" + nPriorities);
       }
 
       // We are done if the number of priorities equals the bond count.
@@ -2153,94 +2156,53 @@
       return (nPriorities == bondCount);
     }
 
-    private int checkSpiro() {
-      if (nSpiro >= 42)
-        return -1; // disallow O_h-cubane, which has 42 root termination 
pathways
+    /**
+     * CheckSpiro uses the concept that Mikko Vainio discovered that
+     * covers all spiro, double spiro, C3-, C3-symmetric cases from CIP(1966).
+     * Incredibly simple!
+     * 
+     */
+    private void checkSpiro() {
       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'
+      int a = 0, b = -1;
+      switch (nPriorities * 10 + priorities[3]) {
+      case 10:
+        //      // 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        
 
-            nPrev = 2;
-            nPriorities = 4;
-            swap23 = (end1 == 2);
-          }
-          break;
+        if (atoms[a].spiroEnd == null)
+          return;
+        b = 1;
+        swap23 = true; // just the way it has to be
+        break;
+      case 21:
+      case 23:
+        // CIP Helv. Chim. Acta 1966 #32 
+        // [0 1 1 1] or [0 0 0 3]
+        a = priorities[1];
+        break;
+      case 22:
+        //
+        // We have priorities [0 0 2 2], possibly being spiro
+        //
+        b = getSpiroEnd(0);
+        break;
+      default:
+        return;
+      }
+      c3RefIndex = atoms[a].atomIndex;
+      if (b >= 0)
+        c4RefIndex = atoms[b].atomIndex;
+      if (sortByRule(RULE_6)) {
+        currentRule = RULE_6;
+        if (swap23) {
+          CIPAtom atom = atoms[2];
+          atoms[2] = atoms[3];
+          atoms[3] = atom;
         }
       }
-      if (swap23) {
-        CIPAtom a = atoms[2];
-        atoms[2] = atoms[3];
-        atoms[3] = a;
-      }
-      return nPrev;
     }
 
     /**
@@ -2248,12 +2210,11 @@
      * 
      * @param i0
      *        index of the spiro starting atom
-     * @return pointer to spiro end of atoms[0] -- either 0 (not spiro), 1, 2,
+     * @return pointer to spiro end of atoms[0] -- either -1 (not spiro), 0, 
1, 2,
      *         or 3
      */
-    private int getSpiroType(int i0, boolean checkEnd1) {
-      CIPAtom a = (i0 < 0 ? null : checkEnd1 ? atoms[i0].spiroEnd1
-          : atoms[i0].spiroEnd);
+    private int getSpiroEnd(int i0) {
+      CIPAtom a = atoms[i0].spiroEnd;
       if (a != null)
         for (int i = 0; i < 4; i++)
           if (i != i0 && a.atom == atoms[i].atom)
@@ -2284,7 +2245,6 @@
       // Two duplicates of the same atom are always tied
       // if they have the same root distance.
 
-      //      System.out.println("breaking tie for \n" + this.myPath + "\n" + 
b.myPath);
       if (isDuplicate && b.isDuplicate && atom == b.atom
           && rootDistance == b.rootDistance)
         return TIED;
@@ -2392,10 +2352,12 @@
 
     /**
      * Used in sortSubstituents
-     * 
+     * @param a  
      * @param b
+     * @param i 
+     * @param j 
      * 
-     * @return 0 (TIED), -1 (A_WINS), or 1 (B_WINS)
+     * @return 0 (TIED), -1 (A_WINS), 1 (B_WINS), or Integer.MIN_VALUE (IGNORE)
      */
     private int checkPriority(CIPAtom a, CIPAtom b, int i, int j) {
       switch (currentRule) {
@@ -2449,6 +2411,8 @@
         return false;
       int current = currentRule;
       currentRule = rule;
+      if (rule == RULE_6)
+        sortSubstituents(Integer.MIN_VALUE);
       boolean isChiral = sortSubstituents(0);
       currentRule = current;
       return isChiral;
@@ -2481,13 +2445,21 @@
       case RULE_4c:
         return checkRules4ac(b, " s r p m");
       case RULE_4bTEST:
-        return (checkRule4Test(b));
+        return checkRule4Test(b);
       case RULE_4b:
       case RULE_5:
-        return TIED; // not carried out here because these need access to a 
full list of ligands 
+        return TIED; // not carried out here because these need access to a 
full list of ligands
+      case RULE_6:
+        int score;
+        return ((score = checkRule6(b, root.c3RefIndex)) != TIED ? score : 
root.c4RefIndex >= 0 ? checkRule6(b, root.c4RefIndex) : score);
       }
     }
-
+    
+    private int checkRule6(CIPAtom b, int refIndex) {
+      return ((atomIndex == refIndex) == (b.atomIndex == refIndex) ? TIED : 
+        atomIndex == refIndex ? A_WINS : B_WINS);
+    }
+    
     private int checkRule4Test(CIPAtom b) {
       // TODO
       boolean isNS = (auxChirality == '~');
@@ -2540,9 +2512,6 @@
      * @return 0 (TIED), -1 (A_WINS), or 1 (B_WINS)
      */
     private int checkRule2(CIPAtom b) {
-      System.out.println(getMass() + " vs " + b.getMass() + " " + (b.getMass() 
== getMass() ? TIED : 
-        (reverseRule2 || b.reverseRule2) == (b.mass > mass) ? A_WINS : 
B_WINS));
-      
       return (b.getMass() == getMass() ? TIED : 
         (reverseRule2 || b.reverseRule2) == (b.mass > mass) ? A_WINS : B_WINS);
     }
@@ -2756,6 +2725,9 @@
       String reason = "Rule 4b"; // Logger
 
       while (true) {
+        
+        if (aref == '-' && bref == '-')
+          return IGNORE;
 
         // check for RS on only one side
         if ((aref == '?') != (bref == '?')) {
@@ -2924,7 +2896,7 @@
         return auxChirality;
       int nR = ((Integer) rule4Count[1]).intValue(), nS = ((Integer) 
rule4Count[2])
           .intValue();
-      return (nR > nS ? 'R' : nR < nS ? 'S' : '?');
+      return (nR > nS ? 'R' : nR < nS ? 'S' : nR == 0 ? '-' : '?');
     }
 
     /**
@@ -3000,12 +2972,12 @@
      * @return 0 (TIED), -1 (A_WINS), 1 (B_WINS), Integer.MIN_VALUE (IGNORE)
      */
     private int compareRule4PairStr(String aStr, String bStr, boolean 
isRSTest) {
+      int n = aStr.length();
+      if (n == 0 || n != bStr.length())
+        return TIED;
       if (Logger.debugging)
         Logger.info(dots() + this.myPath + " Rule 4b comparing " + aStr + " "
             + bStr);
-      int n = aStr.length();
-      if (n == 0 || n != bStr.length())
-        return TIED;
       char aref = aStr.charAt(0), bref = bStr.charAt(0);
       for (int c = 1; c < n; c++) {
         boolean alike = (aref == aStr.charAt(c));
@@ -3062,9 +3034,13 @@
             retThread = rsPath;
             prevIsChiral = true;
           } else {
-            if (!prevIsChiral && priorities[i] == priorities[i - 1])
+            if (!prevIsChiral && priorities[i] == priorities[i - 1]) {
+              if (node1 == null)
+                for (; i >= 0; --i)
+                  rule4List[i] = null;
               // two groups have the same priority, and neither has a 
stereocenter
               return "~";
+            }
             prevIsChiral = false;
           }
         }
@@ -3096,8 +3072,7 @@
           // case we have a simple E/Z (c/t), and there is no need to check AND
           // it does not contribute to the Mata sequence (similar to r/s or 
m/p).
           //
-          if (!isEvenEne
-              || (auxEZ == STEREO_BOTH_EZ || auxEZ == UNDETERMINED)
+          if (!isEvenEne || (auxEZ == STEREO_BOTH_EZ || auxEZ == UNDETERMINED)
               && alkeneChild.bondCount >= 2 && !isKekuleAmbiguous) {
             rs = getAuxEneWinnerChirality(this, alkeneChild, !isEvenEne, 
RULE_5);
             //
@@ -3191,7 +3166,11 @@
         return TIED;
       int isRa = test.indexOf(auxChirality), isRb = test
           .indexOf(b.auxChirality);
-      return (isRa > isRb + 1 ? A_WINS : isRb > isRa + 1 ? B_WINS : TIED);
+      return (isRa > isRb + 1 ? 
+          A_WINS : 
+            isRb > isRa + 1 ? 
+                B_WINS 
+                : TIED);
     }
 
     /**

Modified: trunk/Jmol/src/org/jmol/viewer/JC.java
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/JC.java      2017-07-20 14:37:14 UTC (rev 
21669)
+++ trunk/Jmol/src/org/jmol/viewer/JC.java      2017-07-21 22:22:08 UTC (rev 
21670)
@@ -99,7 +99,7 @@
     }
   }
 
-  private static final String[] ruleNames = {"", "1a", "1b", "2", "3", "4a", 
"4b", "4b", "4c", "5"}; 
+  private static final String[] ruleNames = {"", "1a", "1b", "2", "3", "4a", 
"4b", "4b", "4c", "5", "6"}; 
   public static String getCIPRuleName(int i) {
     return ruleNames[i];
   }

Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2017-07-20 14:37:14 UTC 
(rev 21669)
+++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2017-07-21 22:22:08 UTC 
(rev 21670)
@@ -56,8 +56,12 @@
 
 # TODO: fix UNDO
 
-Jmol.___JmolVersion="14.20.3" // 2017.07.20
+Jmol.___JmolVersion="14.20.4"
 
+bug fix: CIPChirality covers all special spiro cases and C3-symmetry
+
+JmolVersion="14.20.3" // 2017.07.20
+
 bug fix: ROTATE should not stop spin if it does not initiate a spin
 bug fix: CIPChirality tests for CIP1966#31,#32 douple spirans and C3 compounds
 bug fix: CIPChirality for Rule 2 using atomic masses and not for duplicate 
atoms

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