Revision: 21648
          http://sourceforge.net/p/jmol/code/21648
Author:   hansonr
Date:     2017-07-05 02:10:59 +0000 (Wed, 05 Jul 2017)
Log Message:
-----------
logic clean-up 908 lines

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-03 15:12:15 UTC 
(rev 21647)
+++ trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java  2017-07-05 02:10:59 UTC 
(rev 21648)
@@ -1,3 +1,28 @@
+/* $RCSfile$
+ * $Author$
+ * $Date$
+ * $Revision$
+ *
+ * Copyright (C) 2017  The Jmol Development Team
+ *
+ * Contact: jmol-develop...@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
 package org.jmol.symmetry;
 
 import java.util.Arrays;
@@ -115,8 +140,8 @@
  * 
  * code history:
  * 
- * 7/3/17 Jmol 14.20.1 major rewrite to correct and simplify logic; full 
validation
- *  for 433 structures (many duplicates) in AY236, BH64, MV64, MV116, JM, and 
L (949 lines)
+ * 7/4/17 Jmol 14.20.1 major rewrite to correct and simplify logic; full 
validation
+ *  for 433 structures (many duplicates) in AY236, BH64, MV64, MV116, JM, and 
L (908 lines)
  * 
  * 6/30/17 Jmol 14.20.1 major rewrite of Rule 4b (999 lines)
  * 
@@ -394,7 +419,7 @@
   static final int ENANTIOMERIC_A_WINS = -3;
   static final int ENANTIOMERIC_B_WINS = 3;
 static final int IGNORE = Integer.MIN_VALUE;
-  static final int NOT_RELEVANT = Integer.MIN_VALUE;
+  static final int CHECK_BRANCH = Integer.MIN_VALUE;
 
   static final int STEREO_UNDETERMINED = -1;
 
@@ -1706,8 +1731,6 @@
           return !(isTerminal = true);
         }
       }
-      // don't think this can happen
-      isTerminal = (pt == 0);
       nAtoms = pt;
       for (; pt < atoms.length; pt++)
         atoms[pt] = new CIPAtom().create(null, this, false, true, false);
@@ -1766,6 +1789,8 @@
       return atoms[i] = new CIPAtom()
           .create(other, this, isAlkene, isDuplicate, isParentBond);
     }
+    
+    private BS bsTemp = new BS();
 
     /**
      * Deep-Sort the substituents of an atom, setting the node's atoms[] and
@@ -1778,6 +1803,8 @@
      * 
      */
     boolean sortSubstituents(int sphere) {
+      
+      // Note that this method calls breakTie and is called recursively from 
breakTie.
 
       int[] indices = new int[4], prevPrior = new int[4];
       int nPrioritiesPrev = nPriorities;
@@ -1796,75 +1823,48 @@
       }
 
       // if this is Rule 4 or 5, then we do a check of the forward-based 
stereochemical path
+      
       boolean checkRule4List = (rule4List != null && (currentRule == RULE_4b 
|| currentRule == RULE_5));
+
+      int loser, score;
       for (int i = 0; i < 4; i++) {
         CIPAtom a = atoms[i];
         for (int j = i + 1; j < 4; j++) {
-          CIPAtom b = atoms[j];
-          boolean logger_debugHigh = Logger.debuggingHigh && b.isHeavy()
-              && a.isHeavy();
-          int score = (a.atom == null ? B_WINS : b.atom == null ? A_WINS
-              : prevPrior[i] == prevPrior[j] ? TIED
-                  : prevPrior[j] < prevPrior[i] ? B_WINS : A_WINS);
-          // note that a.compareTo(b) also down-scores duplicated atoms 
relative to actual atoms.
-          if (score == TIED)
-            score = (checkRule4List ? checkRule4And5(i, j) : 
a.checkPriority(b));
-          if (logger_debugHigh)
-            Logger.info(dots() + "ordering " + this.id + "." + i + "." + j
-                + " " + this + "-" + a + " vs " + b + " = " + score); // Logger
-          switch (score) {
-          case IGNORE:
-            // just increment the index and go on to the next rule -- no 
breaking of the tie
-            indices[i]++;
-            if (logger_debugHigh)
-              Logger.info(dots() + atom + "." + b + " ends up with tie with "
-                  + a);
-            break;
+          CIPAtom b = atoms[loser = j];
+
+          // Check:
+
+          // (a) if one of the atoms is a phantom atom (P-92.1.4.1); if not, 
then
+          // (b) if the prioritiy has already been set; if not, then
+          // (c) if the current rule decides; if not, then
+          // (d) if the tie can be broken in the next sphere
+
+          switch (a.atom == null ? B_WINS : b.atom == null ? A_WINS
+              : prevPrior[i] < prevPrior[j] ? A_WINS
+                  : prevPrior[j] < prevPrior[i] ? B_WINS
+                      : (score = (checkRule4List ? checkRule4And5(i, j) : 
+                          a.checkPriority(b))) != TIED ? score : 
+                            sign(a.breakTie(b, sphere + 1))) {
+          case B_WINS:
+            loser = i;
+            //$FALL-THROUGH$
           case A_WINS:
-            indices[j]++;
-            priorities[j]++;
-            if (logger_debugHigh)
-              Logger.info(dots() + this + "." + a + " A-beats " + b);
+            priorities[loser]++;
             break;
-          case B_WINS:
-            indices[i]++;
-            priorities[i]++;
-            if (logger_debugHigh)
-              Logger.info(dots() + this + "." + b + " B-beats " + a);
-            break;
           case TIED:
-            switch (score = sign(a.breakTie(b, sphere + 1))) {
-            case A_WINS:
-              indices[j]++;
-              priorities[j]++;
-              if (logger_debugHigh)
-                Logger.info(dots() + this + "." + a + " wins in tie with " + 
b);
-              break;
-            case B_WINS:
-              indices[i]++;
-              priorities[i]++;
-              if (logger_debugHigh)
-                Logger.info(dots() + this + "." + b + " wins in tie with " + 
a);
-              break;
-            case TIED:
-              indices[j]++;
-              if (logger_debugHigh)
-                Logger.info(dots() + this + "." + b + " ends up with tie with "
-                    + a);
-              break;
-            }
+          case IGNORE:
             break;
           }
+          indices[loser]++;
         }
       }
 
-      // update the atoms[] and priorities[] arrays
+      // update nPriorities and all arrays
 
       CIPAtom[] newAtoms = new CIPAtom[4];
       int[] newPriorities = new int[4];
       String[] newRule4List = (rule4List == null ? null : new String[4]);
-
-      BS bs = new BS();
+      bsTemp.clearAll(); // track number of priorities
       for (int i = 0; i < 4; i++) {
         int pt = indices[i];
         CIPAtom a = newAtoms[pt] = atoms[i];
@@ -1872,22 +1872,23 @@
         if (rule4List != null)
           newRule4List[pt] = rule4List[i];
         if (a.atom != null)
-          bs.set(priorities[i]);
+          bsTemp.set(priorities[i]);
       }
       atoms = newAtoms;
       priorities = newPriorities;
       rule4List = newRule4List;
-      nPriorities = bs.cardinality();
+      nPriorities = bsTemp.cardinality();
 
       if (parent == null) {
+
+        // Check for special root-only cases:
         
-        // Check for special root-only cases:
-        //
         //  P-92.2.1.1(c) pseudoasymmetric centers must have 
         //                two and only two enantiomorphic ligands
         //
         //  P-33.5.3.1 spiro compounds have increased constraints
-        //
+        
+
         // We do the spiro test first, as it may inform the pseudoasymmetric 
test.
 
         if (nPriorities == 2 && priorities[3] == 2) {
@@ -1927,7 +1928,7 @@
             //     a'                          b'
 
             nPrioritiesPrev = 2;
-            nPriorities = 4; 
+            nPriorities = 4;
             if (end1 == 2) {
               CIPAtom a = atoms[2];
               atoms[2] = atoms[3];
@@ -1935,9 +1936,9 @@
             }
           }
         }
-        
+
         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 [1 2 3 4] then
           // we have two Rule-5 decisions -- R,S,R',S'.
@@ -1964,19 +1965,20 @@
           canBePseudo = false;
         }
 
-
       }
       if ((Logger.debuggingHigh) && atoms[2].atom != null
-          && atoms[2].elemNo != 1) {
+          && atoms[2].elemNo != 1) { // Logger
         Logger.info(dots() + atom + " nPriorities = " + nPriorities);
         for (int i = 0; i < 4; i++) { // Logger
           Logger.info(dots() + myPath + "[" + i + "]=" + atoms[i] + " "
-              + priorities[i] + " " + Integer.toHexString(priorities[i])
-              + " new"); // Logger
+              + priorities[i] + " " + Integer.toHexString(priorities[i])); // 
Logger
         }
         Logger.info(dots() + "-------");
       }
-      return (nPriorities >= bondCount);
+      
+      // We are done if the number of priorities equals the bond count.
+      
+      return (nPriorities == bondCount);
     }
 
     /**
@@ -2000,7 +2002,7 @@
      * @return a string of dots based on the value of atom.sphere.
      */
     private String dots() {
-      return ".....................".substring(0, Math.min(20, sphere));
+      return ".....................".substring(0, Math.min(20, sphere)); // 
Logger
     }
 
     /**
@@ -2010,36 +2012,39 @@
      * @param b
      * @param sphere
      *        current working sphere
-     * @return [0 (TIED), -1 (A_WINS), or 1 (B_WINS)] * sphere where broken
+     * @return [0 (TIED), -1 (A_WINS), or 1 (B_WINS)] * (sphere where broken)
      */
     private int breakTie(CIPAtom b, int sphere) {
-      if (Logger.debugging && isHeavy() && b.isHeavy())
-          Logger.info(dots() + "tie for " + this + " and " + b + " at sphere " 
+ sphere);
 
-      // Two duplicates of the same atom are always tied, if they have the 
same root distance.
-      if (isDuplicate && b.isDuplicate && atom == b.atom && rootDistance == 
b.rootDistance)
+      // Two duplicates of the same atom are always tied
+      // if they have the same root distance.
+
+      if (isDuplicate && b.isDuplicate && atom == b.atom
+          && rootDistance == b.rootDistance)
         return TIED;
 
       // Do a duplicate check -- if that is not a TIE we do not have to go any 
further.
-      // NOTE THAT THIS IS NOT EXPLICIT IN THE RULES
-      // BECAUSE DUPLICATES LOSE IN THE NEXT SPHERE, NOT THIS.
+
+      // NOTE THAT THIS CHECK IS NOT EXPLICIT IN THE RULES
+      // BECAUSE DUPLICATES LOSE IN THE NEXT SPHERE, NOT THIS ONE.
       // THE NEED FOR (sphere+1) in AY236.53, 163, 173, 192 SHOWS THAT 
       // SUBRULE 1a MUST BE COMPLETED EXHAUSTIVELY PRIOR TO SUBRULE 1b.
 
       int score = checkIsDuplicate(b);
       if (score != TIED)
-        return score * (sphere + 1);  // COUNT_LINE
+        return score * (sphere + 1); // COUNT_LINE
 
-      // return NO_CHIRALITY/TIED if:
-      //  a) one or the other can't be set (because it has too many 
connections)
-      //  b) or both are terminal or both are duplicates
+      // return TIED if:
 
+      //  a) one or the other can't be set (because it has too many 
connections), or
+      //  b) both are terminal or both are duplicates
+
       if (!setNode() || !b.setNode() || isTerminal && b.isTerminal
           || isDuplicate && b.isDuplicate)
         return TIED;
 
-      // We are done -- again, for the next sphere, actually -- if one of these
-      // is terminal.
+      // We are done if one of these is terminal (for the next sphere, 
actually).
+
       if (isTerminal != b.isTerminal)
         return (isTerminal ? B_WINS : A_WINS) * (sphere + 1); // COUNT_LINE
 
@@ -2057,7 +2062,7 @@
       if ((score = compareShallowly(b, sphere)) != TIED)
         return score;
 
-      // Phase II -- deep check using breakTie
+      // Phase II -- check deeply using breakTie
       //
       // OK, so all three are nominally the same.
       // Now iteratively deep-sort each list based on substituents
@@ -2065,19 +2070,21 @@
 
       sortSubstituents(sphere);
       b.sortSubstituents(sphere);
-      return compareDeeply(b, sphere);
+      int finalScore = (nAtoms == 0 ? B_WINS : TIED), absScore = 
Integer.MAX_VALUE;
+      for (int i = 0; i < nAtoms; i++) {
+        CIPAtom ai = atoms[i], bi = b.atoms[i];
+        if ((score = ai.breakTie(bi, sphere + 1)) != TIED) {
+          int abs = Math.abs(score);
+          if (abs < absScore) {
+            absScore = abs;
+            finalScore = score;
+          }
+        }
+      }
+      return finalScore;
     }
 
     /**
-     * Just checking for hydrogen.
-     * 
-     * @return true if not hydrogen.
-     */
-    private boolean isHeavy() {
-      return massNo > 1;
-    }
-
-    /**
      * The first part of breaking a tie at the current level. Compare only in
      * the current substitutent sphere; a preliminary check using the current
      * rule.
@@ -2093,49 +2100,12 @@
         CIPAtom bi = b.atoms[i];
         int score = ai.checkCurrentRule(bi);
         // checkCurrentRule can return IGNORE, but we ignore that here.
-        if (score == IGNORE)
-          score = TIED;
-        if (score != TIED) {
-          if (Logger.debugging && ai.isHeavy() && bi.isHeavy())
-            Logger.info(ai.dots() + "compareShallow " + i + " " + this + "."
-                + ai + "/" + b + "." + bi + ": " + score * (sphere + 1));  // 
Logger
+        if (score != IGNORE && score != TIED)
           return score * (sphere + 1);  // COUNT_LINE
-        }
       }
       return TIED;
     }
 
-    /**
-     * Continue to break ties in each substituent in a and b, as we now know
-     * that all of them are tied. This take us to the next sphere.
-     * 
-     * @param b
-     * @param sphere
-     *        current working sphere
-     * @return 0 (TIED) or [-1 (A_WINS), or 1 (B_WINS)]*n, where n is the 
lowest
-     *         sphere of a win
-     */
-    private int compareDeeply(CIPAtom b, int sphere) {
-      int finalScore = (nAtoms == 0 ? B_WINS : TIED), absScore = 
Integer.MAX_VALUE;
-      for (int i = 0; i < nAtoms; i++) {
-        CIPAtom ai = atoms[i], bi = b.atoms[i];
-        if (Logger.debuggingHigh && ai.isHeavy() && bi.isHeavy())
-          Logger.info(ai.dots() + "compareDeep sub " + this + "." + ai + " " + 
b + "." + bi);
-        int score = ai.breakTie(bi, sphere + 1);
-        if (score == TIED)
-          continue;
-        int abs = Math.abs(score);
-        if (abs < absScore) {
-          absScore = abs;
-          finalScore = score;
-          if (Logger.debugging && ai.isHeavy() && bi.isHeavy())
-            Logger.info(ai.dots() + "compareDeep sub " + ai + " " + bi + ": " 
+ score);
-        }
-      }
-      if (Logger.debuggingHigh)
-        Logger.info(dots() + "compareDeep " + this + " " + b + ": " + 
finalScore);
-      return finalScore;
-    }
 
     /**
      * Used in Array.sort when an atom is set; includes a preliminary check for
@@ -2163,8 +2133,7 @@
      */
     private int checkPriority(CIPAtom b) {
       int score;
-      return (b == null ? A_WINS
-          : (atom == null) != (b.atom == null) ? (atom == null ? B_WINS
+      return ((atom == null) != (b.atom == null) ? (atom == null ? B_WINS
               : A_WINS) : (score = checkCurrentRule(b)) == IGNORE ? TIED
               : score);
     }
@@ -2197,13 +2166,6 @@
       switch (currentRule) {
       default:
       case RULE_1a:
-        //        // Checking what happens if you do 1a and 1b together
-        //        // note a fix is also required 
-        //        int score = checkRule1a(b);
-        //        if (score == TIED) {
-        //          score = checkRule1b(b);
-        //        }
-        //        return score;
         return checkRule1a(b);
       case RULE_1b:
         return checkRule1b(b);
@@ -2463,7 +2425,7 @@
      * @return 0 (TIED), -1 (A_WINS), 1 (B_WINS), Integer.MIN_VALUE (IGNORE)
      */
     private int checkRule4And5(int i, int j) {
-      return (rule4List[i] == null && rule4List[j] == null ? TIED
+      return (rule4List[i] == null && rule4List[j] == null ? IGNORE
           : rule4List[j] == null ? A_WINS : rule4List[i] == null ? B_WINS
               : compareMataPair(atoms[i], atoms[j]));
     }
@@ -2501,15 +2463,16 @@
 
       a.generateRule4Paths();
       b.generateRule4Paths();
-      // 
+      
       boolean isRule5 = (currentRule == RULE_5);
       String aref = (isRule5 ? "R" : a.getRule4ReferenceDescriptor());
       String bref = (isRule5 ? "R" : b.getRule4ReferenceDescriptor());
       boolean haveRSOptions = (aref == "RS");
-      System.out.println("reference descriptors are " + aref + " and " + bref);
+      if (Logger.debugging)
+        Logger.info("reference descriptors are " + aref + " and " + bref);
 
       int score = TIED;
-      String reason = "Rule 4b";
+      String reason = "Rule 4b"; // Logger
       String aStr = aref, bStr = bref;
       
       while (true) {
@@ -2517,7 +2480,7 @@
         // check for RS on only one side
         if (aref.length() != bref.length()) {
           score = (haveRSOptions ? B_WINS : A_WINS);
-          reason += " RS on only one side";
+          reason += " RS on only one side";  // Logger
           break;
         }
 
@@ -2528,15 +2491,11 @@
             + b.flattenRule4Paths('S', isRule5) : b.flattenRule4Paths(
             bref.charAt(0), isRule5));
 
-        if (Logger.debugging)
-          Logger.info(dots() + this + " comparing " + a + " " + aStr + " to "
-              + b + " " + bStr); // Logger
-        
         // 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";
+          reason = "Rule 5";  // Logger
           break;
         }
 
@@ -2544,12 +2503,14 @@
         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
+          // 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;) {
@@ -2570,10 +2531,12 @@
       }
       
       Logger.info(a
-          + (score == A_WINS ? " > " : score == B_WINS ? " < " : " = ")
-          + b + " by " + reason + "\n");
+          + (score == A_WINS ? " > " : score == B_WINS ? " < " : " = ") // 
Logger
+          + b + " by " + reason + "\n"); // Logger
 
-      return score;
+      // no tie-breaking for Rules 4b or 5
+      
+      return (score == TIED ? IGNORE : score);
     }
 
     /**
@@ -2703,7 +2666,8 @@
       // now remove the priorities
       for (int i = 0; i < nPaths; i++) {
         paths[i] = PT.replaceAllCharacters(paths[i], "1234", "").replace('A', 
ref);
-        System.out.println("Flattened[" + i + "]=" + paths[i]);
+        if (Logger.debugging)
+          Logger.info("Flattened[" + i + "]=" + paths[i]);
       }
       SB sb = new SB();
       String s;
@@ -2754,29 +2718,6 @@
       return (isRSTest ? TIED : IGNORE);
     }
 
-//    /**
-//     * Sort Mata list of ["RS...", "SR..."] by temporarily assigning the
-//     * reference atom chirality the letter "A" and then sorting
-//     * lexicographically.
-//     * 
-//     * @param lst
-//     * @param aref
-//     * @return sorted list
-//     */
-//    private String[] getMataSortedList(String[] lst, String aref) {
-//      int n = lst.length;
-//      String[] sorted = new String[n];
-//      for (int i = 0; i < n; i++)
-//        sorted[i] = PT.rep(lst[i], aref, "A");
-//      Arrays.sort(sorted);
-//      for (int i = 0; i < n; i++)
-//        sorted[i] = PT.rep(sorted[i], "A", aref);
-//      if (Logger.debuggingHigh)
-//        for (int i = 0; i < n; i++) // Logger
-//          Logger.info("Sorted Mata list " + i + " " + aref + ": " + 
sorted[i]);
-//      return sorted;
-//    }
-
     /**
      * This critical method creates a list of downstream (higher-sphere)
      * auxiliary chirality designators (R or S) in the correct order specified
@@ -2795,218 +2736,231 @@
       String subRS = "", s = (node1 == null ? "" : "~");
       boolean isBranch = false, noPseudo = false;
       int nRS = 0;
-      if (atom != null) {
-        rule4List = new String[4]; // full list based on atoms[]
-        int[] mataList = new int[4]; //sequential pointers into rule4List
-        CIPAtom[] ret1 = new CIPAtom[1];
-        for (int i = 0; i < 4; i++) {
-          CIPAtom a = atoms[i];
-          if (a != null)
-            a.setNode();
-          if (a != null && !a.isDuplicate && !a.isTerminal) {
-            a.priority = priorities[i];
-            ret1[0] = null;
-            String ssub = a.createRule4AuxiliaryData(node1 == null ? a : 
node1, ret1);
-            if (ret1[0] != null) {
-              a.nextChiralBranch = ret1[0];
-              if (ret != null)
-                ret[0] = ret1[0];
-            }
-            rule4List[i] = ssub;
-            if (a.nextChiralBranch != null || 
-                ssub.indexOf("R") >= 0 || ssub.indexOf("S") >= 0
-                || ssub.indexOf("r") >= 0 || ssub.indexOf("s") >= 0) {
-              mataList[nRS] = i;
-              nRS++;
-              subRS += ssub;
-            } else {
-              rule4List[i] = null;
-            }
+      if (atom == null)
+        return s;
+      rule4List = new String[4]; // full list based on atoms[]
+      int[] mataList = new int[4]; //sequential pointers into rule4List
+      CIPAtom[] ret1 = new CIPAtom[1];
+      for (int i = 0; i < 4; i++) {
+        CIPAtom a = atoms[i];
+        if (a != null)
+          a.setNode();
+        if (a != null && !a.isDuplicate && !a.isTerminal) {
+          a.priority = priorities[i];
+          ret1[0] = null;
+          String ssub = a.createRule4AuxiliaryData(node1 == null ? a : node1,
+              ret1);
+          if (ret1[0] != null) {
+            a.nextChiralBranch = ret1[0];
+            if (ret != null)
+              ret[0] = ret1[0];
           }
+          rule4List[i] = ssub;
+          if (a.nextChiralBranch != null || ssub.indexOf("R") >= 0
+              || ssub.indexOf("S") >= 0 || ssub.indexOf("r") >= 0
+              || ssub.indexOf("s") >= 0) {
+            mataList[nRS] = i;
+            nRS++;
+            subRS += ssub;
+          } else {
+            rule4List[i] = null;
+          }
         }
-        int adj = TIED;
-        switch (nRS) {
-        case 0:
-          subRS = "";
-          break;
-        case 1:
-          break;
-        case 2:
-          if (node1 != null) {
-            // we want to now if these two are enantiomorphic, identical, or 
diastereomorphic.
-            adj = (compareRule4Isomers(mataList[0], mataList[1]));
-            switch (adj) {
-            case TIED:
-              // identical
-              isBranch = true;
-              s = "~";
-              subRS = "";
-              break;
-            case NOT_RELEVANT:
-              // a and b are different priorities - we need to check to see if 
we have a chiral branch node
-              isBranch = true;
-              break;
-            case DIASTEREOMERIC_A_WINS:
-            case DIASTEREOMERIC_B_WINS:
-              adj -= sign(adj);
-              subRS = "r";
-              //$FALL-THROUGH$
+      }
+      int adj = TIED;
+      switch (nRS) {
+      case 0:
+        subRS = "";
+        //$FALL-THROUGH$
+      case 1:
+        break;
+      case 2:
+        if (node1 != null) {
+          // we want to now if these two are enantiomorphic, identical, or 
diastereomorphic.
+          switch (adj = (compareRule4Isomers(mataList[0], mataList[1]))) {
+          case TIED:
+            // identical
+            isBranch = true;
+            s = "~";
+            subRS = "";
+            break;
+          case DIASTEREOMERIC_A_WINS:
+          case DIASTEREOMERIC_B_WINS:
+            noPseudo = true;
+            adj -= sign(adj); // change to A_WINS or B_WINS
+            //$FALL-THROUGH$
+          case A_WINS:
+          case B_WINS:
+            // enantiomers -- we have an r/s situation
+            // process to determine chirality, but then set ret[0] to be null
+            subRS = "";
+            //$FALL-THROUGH$
+          case CHECK_BRANCH:
+            // a and b are different priorities - we need to check to see if 
we have a chiral branch node
+            isBranch = true;
+            break;
+          }
+        }
+        break;
+      case 3:
+        // We have three different chiral ligands.
+        // Check for exactly one enantiomeric pair among the three groups.
+        //
+        // If we have C{RRS SSR SSR}  
+        //
+        //    {RRS}    e      d     
+        //           {SSR}    d
+        //                  {SRS}  two enantiomers and a diastereomer (r/s)
+        //
+        // AY236.52 (tris-cyclopropyl), AY236.54 (Mata), AY236.148 (PR3)
+        //
+        //TODO:  not fully tested AY236.23?? 192??
+        //
+        // compareRule4Isomers can return TIED for:
+        //
+        //     R            S
+        //    /            /
+        // --~    and   --~
+        //    \            \ 
+        //     R            S
+
+        int irs = 0,
+        jrs = 0,
+        adj0 = TIED;
+        for (int i = 0; i < 2; i++) {
+          for (int j = i + 1; j < 3; j++) {
+            adj0 = (compareRule4Isomers(mataList[i], mataList[j]));
+            switch (adj0) {
             case A_WINS:
             case B_WINS:
-              isBranch = true;
-              noPseudo = (subRS.indexOf("r") >= 0);
-              // enantiomers -- we have an r/s situation
-              // process to determine chirality, but then set ret[0] to be null
-              subRS = "";
+              if (adj == TIED) {
+                adj = adj0;
+                irs = i;
+                jrs = j;
+                continue;
+              }
+              i = j = 3;
+              adj = TIED;
               break;
+            default:
+              break;
             }
           }
-          break;
-        case 3:
-          // 
-          // check for exactly one enantiomeric pair among the three groups
-          //
-          //    {RRS}    e      d     
-          //           {SSR}    d
-          //                  {SRS}  two enantiomers and a diastereomer (r/s)
-          //
-          //
-          int irs = 0,
-          jrs = 0,
-          adj0 = TIED;
-          for (int i = 0; i < 2; i++) {
-            for (int j = i + 1; j < 3; j++) {
-              adj0 = (compareRule4Isomers(mataList[i], mataList[j]));
-              switch (adj0) {
-              case A_WINS:
-              case B_WINS:
-                if (adj == TIED) {
-                  adj = adj0;
-                  irs = i;
-                  jrs = j;
-                  continue;
-                }
-                i = j = 3;
-                adj = TIED;
+        }
+        if (adj != TIED) {
+          mataList[0] = mataList[irs];
+          mataList[1] = mataList[jrs];
+        }
+        //$FALL-THROUGH$
+      case 4:
+        s = "";
+        isBranch = true;
+        break;
+      }
+      if (isBranch) {
+        subRS = "";
+        if (ret != null)
+          ret[0] = this;
+      }
+      if (!isBranch || adj == A_WINS || adj == B_WINS || adj == CHECK_BRANCH) {
+        if (isAlkene) {
+          if (!isBranch && alkeneChild != null) {
+            // must be alkeneParent -- first C of an alkene -- this is where 
C/T is recorded 
+            boolean isSeqCT = (ret != null && ret[0] == alkeneChild);
+            // All odd cumulenes need to be checked.
+            // If it is an alkene or even cumulene, we must do an auxiliary 
check 
+            // only if it is not already a defined stereochemistry, because in 
that
+            // 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 == STEREO_UNDETERMINED)
+                && alkeneChild.bondCount >= 2 && !isKekuleAmbiguous) {
+              rs = getAuxEneWinnerChirality(this, alkeneChild, !isEvenEne,
+                  RULE_5);
+              //
+              // Note that we can have C/T (rule4Type = R/S):
+              // 
+              //    R      x
+              //     \    /
+              //       ==
+              //     /    \
+              //    S      root
+              //
+              // flips sense upon planar inversion; determination was Rule 5.
+              //
+              // Normalize M/P and E/Z to R/S
+              switch (rs) {
+              case STEREO_M:
+              case STEREO_Z:
+                rs = STEREO_R;
+                s = "R";
                 break;
-              default:
+              case STEREO_P:
+              case STEREO_E:
+                rs = STEREO_S;
+                s = "S";
                 break;
               }
-            }
-          }
-          if (adj != TIED) {
-            mataList[0] = mataList[irs];
-            mataList[1] = mataList[jrs];
-          }
-          //$FALL-THROUGH$
-        case 4:
-          s = "";
-          isBranch = true;
-          break;
-        }
-        if (isBranch) {
-          subRS = "";
-          if (ret != null)
-            ret[0] = this;
-        }
-        if (!isBranch || adj == A_WINS || adj == B_WINS || adj == 
NOT_RELEVANT) {
-          if (isAlkene) {
-            if (!isBranch && alkeneChild != null) {
-              // must be alkeneParent -- first C of an alkene -- this is where 
C/T is recorded 
-              boolean isSeqCT = (ret != null && ret[0] == alkeneChild);
-              // All odd cumulenes need to be checked.
-              // If it is an alkene or even cumulene, we must do an auxiliary 
check 
-              // only if it is not already a defined stereochemistry, because 
in that
-              // 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 == 
STEREO_UNDETERMINED)
-                  && alkeneChild.bondCount >= 2 && !isKekuleAmbiguous) {
-                rs = getAuxEneWinnerChirality(this, alkeneChild, !isEvenEne, 
RULE_5);
-                //
-                // Note that we can have C/T (rule4Type = R/S):
-                // 
-                //    R      x
-                //     \    /
-                //       ==
-                //     /    \
-                //    S      root
-                //
-                // flips sense upon planar inversion; determination was Rule 5.
-                //
-                // Normalize M/P and E/Z to R/S
-                switch (rs) {
-                case STEREO_M:
-                case STEREO_Z:
-                  rs = STEREO_R;
-                  s = "R";
-                  break;
-                case STEREO_P:
-                case STEREO_E:
-                  rs = STEREO_S;
-                  s = "S";
-                  break;
+              if (rs != NO_CHIRALITY) {
+                auxChirality = s;
+                rule4Type = rs;
+                subRS = "";
+                if (isSeqCT) {
+                  nextChiralBranch = alkeneChild;
+                  ret[0] = this;
                 }
-                if (rs != NO_CHIRALITY) {
-                  auxChirality = s;
-                  rule4Type = rs;
-                  subRS = "";
-                  if (isSeqCT) {
-                    nextChiralBranch = alkeneChild;
-                    ret[0] = this;
-                  }
 
-                }
               }
             }
-          } else if (node1 != null
-              && (bondCount == 4 && nPriorities >= 3 - Math.abs(adj) || 
isTrigonalPyramidal
-                  && nPriorities >= 2 - Math.abs(adj))) {
-            // if adj is 1 or -1, then we check for one fewer priorities 
because
-            // it means we had two groups that were either enantiomers or 
diasteriomers
+          }
+        } else if (node1 != null
+            && (bondCount == 4 && nPriorities >= 3 - Math.abs(adj) || 
isTrigonalPyramidal
+                && nPriorities >= 2 - Math.abs(adj))) {
+          // if adj is 1 or -1, then we check for one fewer priorities because
+          // it means we had two groups that were either enantiomers or 
diasteriomers
 
-            if (isBranch && adj != NOT_RELEVANT) {
-              // if here, adj is A_WINS (-1), or B_WINS (1) 
-              // we check based on A winning, but then reverse it if B 
actually won
-              switch (rule4CheckPseudoHandedness(mataList)) {
-              case STEREO_R:
-                s = (adj == A_WINS ? "r" : "s");
-                break;
-              case STEREO_S:
-                s = (adj == A_WINS ? "s" : "r");
-                break;
-              }
-              if (noPseudo) {
-                s = s.toUpperCase(); // Rule 4c or diasteriomers // AY-236.148
-                rule4Type = (s.equals("R")  ? STEREO_R : STEREO_S);
-              }
-              subRS = "";
-              //if (ret != null)
-              //ret[0] = null;
-            } else {
-              // if here, adj is TIED (0) or NOT_RELEVANT
-              CIPAtom atom1 = (CIPAtom) clone();
-              if (atom1.setNode()) {
-                atom1.addReturnPath(null, this);
-                atom1.rule4List = rule4List;
-                int rule = atom1.sortToRule(RULE_5);
-                if (rule != TIED) {
-                  rs = atom1.checkHandedness();
-                  s = (rs == STEREO_R ? "R" : rs == STEREO_S ? "S" : "~");
-                  if (rule == RULE_5) {
-                    s = s.toLowerCase();
-                  } else {
-                    rule4Type = rs;
-                  }
+          if (isBranch && adj != CHECK_BRANCH) {
+            // if here, adj is A_WINS (-1), or B_WINS (1) 
+            // we check based on A winning, but then reverse it if B actually 
won
+            switch (rule4CheckPseudoHandedness(mataList)) {
+            case STEREO_R:
+              s = (adj == A_WINS ? "r" : "s");
+              break;
+            case STEREO_S:
+              s = (adj == A_WINS ? "s" : "r");
+              break;
+            }
+            if (noPseudo) {
+              s = s.toUpperCase(); // Rule 4c or diasteriomers // AY-236.148
+              rule4Type = (s.equals("R") ? STEREO_R : STEREO_S);
+            }
+            subRS = "";
+            //if (ret != null)
+            //ret[0] = null;
+          } else {
+            // if here, adj is TIED (0) or NOT_RELEVANT
+            CIPAtom atom1 = (CIPAtom) clone();
+            if (atom1.setNode()) {
+              atom1.addReturnPath(null, this);
+              atom1.rule4List = rule4List;
+              int rule = atom1.sortToRule(RULE_5);
+              if (rule != TIED) {
+                rs = atom1.checkHandedness();
+                s = (rs == STEREO_R ? "R" : rs == STEREO_S ? "S" : "~");
+                if (rule == RULE_5) {
+                  s = s.toLowerCase();
+                } else {
+                  rule4Type = rs;
                 }
               }
             }
-            auxChirality = s;
           }
+          auxChirality = s;
         }
       }
       if (node1 == null)
-        rule4Type = nRS; 
+        rule4Type = nRS;
       s += subRS;
       if (Logger.debugging && !s.equals("~"))
         Logger.info("creating aux " + s + " fofr " + this + " = " + myPath);
@@ -3056,10 +3010,10 @@
     private int compareRule4Isomers(int i1, int i2) {
       String rs1 = rule4List[i1], rs2 = rule4List[i2];
       if (priorities[i1] != priorities[i2] || atoms[i1].nextChiralBranch != 
null)
-        return NOT_RELEVANT;
+        return CHECK_BRANCH;
       int n = rs1.length();
       if (n != rs2.length())
-        return NOT_RELEVANT; // not possible?
+        return CHECK_BRANCH;
       
       if (rs1.equals(rs2)) {
         
@@ -3074,7 +3028,6 @@
         return TIED;
       }
       String rs = rs1 + rs2;
-      //System.out.println("compareRule4Isomers:" + rs1 + " vs. " + rs2);
       boolean haveRS = (rs.indexOf("R") >= 0 || rs.indexOf("S") >= 0);
       rs = (haveRS ? "~RS" : "~rs");
       if (haveRS) {
@@ -3114,12 +3067,12 @@
         // any other score indicates diasteriomeric
         int i1 = rs.indexOf(rs1.charAt(i));
         int score = i1 + rs.indexOf(rs2.charAt(i));
-        if (score == 0)
-          continue;
-        if (score != STEREO_BOTH_RS)
-          return DIASTEREOMERIC;
-        if (finalScore == TIED)
-          finalScore = (i1 == STEREO_R ? A_WINS : B_WINS);
+        if (score != 0) {
+          if (score != STEREO_BOTH_RS)
+            return DIASTEREOMERIC;
+          if (finalScore == TIED)
+            finalScore = (i1 == STEREO_R ? A_WINS : B_WINS);
+        }
       }
       return finalScore;
     }

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