Revision: 21649
          http://sourceforge.net/p/jmol/code/21649
Author:   hansonr
Date:     2017-07-05 17:43:33 +0000 (Wed, 05 Jul 2017)
Log Message:
-----------
840 line CIPChirality rewrite - streamlined logic

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-05 02:10:59 UTC 
(rev 21648)
+++ trunk/Jmol/src/org/jmol/symmetry/CIPChirality.java  2017-07-05 17:43:33 UTC 
(rev 21649)
@@ -141,7 +141,7 @@
  * code history:
  * 
  * 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)
+ *  for 433 structures (many duplicates) in AY236, BH64, MV64, MV116, JM, and 
L (840 lines)
  * 
  * 6/30/17 Jmol 14.20.1 major rewrite of Rule 4b (999 lines)
  * 
@@ -1627,7 +1627,7 @@
             Integer.valueOf(rootDistance));
       }
       this.isDuplicate = isDuplicate;
-      if (Logger.debugging) {
+      if (Logger.debuggingHigh) {
         if (sphere < MAX_PATH) // Logger
           myPath = (parent != null ? parent.myPath + "-" : "") + this; // 
Logger
         Logger.info("new CIPAtom " + myPath);
@@ -1842,7 +1842,8 @@
           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) : 
+                      : (score = (checkRule4List ? 
+                          checkRule4And5(i, j) : 
                           a.checkPriority(b))) != TIED ? score : 
                             sign(a.breakTie(b, sphere + 1))) {
           case B_WINS:
@@ -2461,8 +2462,8 @@
       // then we build ["SrS" and "SrR"]
       // 
 
-      a.generateRule4Paths();
-      b.generateRule4Paths();
+      a.generateRule4Paths(this);
+      b.generateRule4Paths(this);
       
       boolean isRule5 = (currentRule == RULE_5);
       String aref = (isRule5 ? "R" : a.getRule4ReferenceDescriptor());
@@ -2541,10 +2542,11 @@
 
     /**
      * Combine all subpaths
+     * @param ignore atom to ignore (parent)
      */
-    void generateRule4Paths() {
+    void generateRule4Paths(CIPAtom ignore) {
       
-      getRule4PriorityPaths("");
+      getRule4PriorityPaths("", ignore.atom);
       rootRule4Paths = new Lst<String[]>();
       appendRule4Paths(this, new String[3]);
       getRule4Counts(rule4Count = new Object[] { null, zero, zero, 
Integer.valueOf(10000)});
@@ -2566,12 +2568,13 @@
      * Recursively build paths to stereocenters to estabish the path priority 
lexicographically.
      *  
      * @param path
+     * @param ignore atom to ignore (parent)
      */
-    private void getRule4PriorityPaths(String path) {
+    private void getRule4PriorityPaths(String path, SimpleNode ignore) {
       priorityPath = path + (priority + 1);
       for (int i = 0; i < 4; i++)
-        if (rule4List[i] != null)
-          atoms[i].getRule4PriorityPaths(priorityPath);
+        if (rule4List[i] != null && atoms[i].atom != ignore)
+          atoms[i].getRule4PriorityPaths(priorityPath, null);
     }
     
     private void getRule4Counts(Object[] counts) {
@@ -2732,15 +2735,14 @@
      * @return collective string, with setting of rule4List
      */
     String createRule4AuxiliaryData(CIPAtom node1, CIPAtom[] ret) {
-      int rs = -1;
       String subRS = "", s = (node1 == null ? "" : "~");
-      boolean isBranch = false, noPseudo = false;
-      int nRS = 0;
       if (atom == null)
         return s;
+      int rs = -1, nRS = 0;
       rule4List = new String[4]; // full list based on atoms[]
-      int[] mataList = new int[4]; //sequential pointers into rule4List
       CIPAtom[] ret1 = new CIPAtom[1];
+      int ruleMax = RULE_5;
+      boolean prevIsChiral = false;
       for (int i = 0; i < 4; i++) {
         CIPAtom a = atoms[i];
         if (a != null)
@@ -2759,325 +2761,129 @@
           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;
+            subRS = ssub;
+            prevIsChiral = true;
+          } else if (i > 0 && priorities[i] == priorities[i - 1]
+              && !prevIsChiral) {
+            // two groups have the same priority, and both have no chirality
+            ruleMax = 3;
           } else {
-            rule4List[i] = null;
+            prevIsChiral = false;
           }
         }
       }
-      int adj = TIED;
+      boolean isBranch = false;
       switch (nRS) {
       case 0:
         subRS = "";
         //$FALL-THROUGH$
       case 1:
+        ruleMax = RULE_3;
         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:
-              if (adj == TIED) {
-                adj = adj0;
-                irs = i;
-                jrs = j;
-                continue;
-              }
-              i = j = 3;
-              adj = TIED;
-              break;
-            default:
-              break;
-            }
-          }
-        }
-        if (adj != TIED) {
-          mataList[0] = mataList[irs];
-          mataList[1] = mataList[jrs];
-        }
-        //$FALL-THROUGH$
       case 4:
-        s = "";
+        s = "~";
+        subRS = "";
         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 (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 cumulene s 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);
             //
-            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;
+            // 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
-
-          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;
-                }
+        }
+      } else if (isTrigonalPyramidal || bondCount == 4) {
+        // if here, adj is TIED (0) or NOT_RELEVANT
+        CIPAtom atom1 = (CIPAtom) clone();
+        if (atom1.setNode()) {
+          atom1.addReturnPath(null, this);
+          atom1.rule4List = new String[4];
+          for (int i = 0; i < 4; i++) {
+            for (int j = 0; j < 4; j++) {
+              if (atom1.atoms[i] ==  atoms[j]) {
+                atom1.rule4List[i] = rule4List[j];
+                break;
               }
             }
           }
-          auxChirality = s;
+          //rule4List; //227 needs this commented out; 66 needs this in!
+          int rule = atom1.sortToRule(ruleMax);
+          if (rule == TIED)
+            s = "~";
+          else
+          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;
       }
       if (node1 == null)
         rule4Type = nRS;
       s += subRS;
       if (Logger.debugging && !s.equals("~"))
-        Logger.info("creating aux " + s + " fofr " + this + " = " + myPath);
+        Logger.info("creating aux " + s + " for " + this + " = " + myPath);
       return s;
     }
 
     /**
-     * Reverse the path to the parent and check r/s chirality
-     * 
-     * @param iab
-     * @return STEREO_R or STEREO_S
-     * 
-     */
-    private int rule4CheckPseudoHandedness(int[] iab) {
-      int ia = iab[0];
-      int ib = iab[1];
-      CIPAtom atom1;
-      // critical here that we do NOT include the tied branches
-      atom1 = (CIPAtom) clone();
-      atom1.atoms[ia] = new CIPAtom().create(null, atom1, false, false, false);
-      atom1.atoms[ib] = new CIPAtom().create(null, atom1, false, false, false);
-      atom1.addReturnPath(null, this);
-      // We are guaranteed that only RULE_1a is necessary, because one of our
-      // paths goes all the way back to the root, without a duplicate atom, 
and any
-      // other path reaching that will terminate with a duplicate atom instead.
-      atom1.sortByRule(RULE_1a);
-      // Now add the tied branches at the end; it doesn't matter where they 
-      // go as long as they are together and in order.
-      atom1.atoms[bondCount - 2] = atoms[Math.min(ia, ib)];
-      atom1.atoms[bondCount - 1] = atoms[Math.max(ia, ib)];
-      int rs = atom1.checkHandedness();
-      if (Logger.debugging) {
-        for (int i = 0; i < 4; i++) // Logger
-          Logger.info("pseudo " + rs + " " + priorities[i] + " " + 
atoms[i].myPath);
-      }
-      return rs;
-    }
-
-    /**
-     * Check for strings such as SSR/RRS
-     * 
-     * @param i1
-     * @param i2
-     * @return NOT_RELEVANT if there is no stereochemistry, TIED if they are
-     *         equal, A_WINS for enantiomer Rxxx, B_WINS for Sxxxx, or IGNORE
-     */
-    private int compareRule4Isomers(int i1, int i2) {
-      String rs1 = rule4List[i1], rs2 = rule4List[i2];
-      if (priorities[i1] != priorities[i2] || atoms[i1].nextChiralBranch != 
null)
-        return CHECK_BRANCH;
-      int n = rs1.length();
-      if (n != rs2.length())
-        return CHECK_BRANCH;
-      
-      if (rs1.equals(rs2)) {
-        
-        
-        // this is tricky, because we could have
-        //     R            S
-        //    /            /
-        // --~    and   --~
-        //    \            \ 
-        //     R            S
-        
-        return TIED;
-      }
-      String rs = rs1 + rs2;
-      boolean haveRS = (rs.indexOf("R") >= 0 || rs.indexOf("S") >= 0);
-      rs = (haveRS ? "~RS" : "~rs");
-      if (haveRS) {
-        rs1 = PT.replaceAllCharacters(rs1, "rs", "~");
-        rs2 = PT.replaceAllCharacters(rs2, "rs", "~");
-      }
-      int score = checkEnantiomer(rs1, rs2, 0, n, rs);
-      if (score == DIASTEREOMERIC) {
-        switch (compareMataPair(atoms[i1], atoms[i2])) {
-        case A_WINS:
-          return DIASTEREOMERIC_A_WINS;
-        case B_WINS:
-          return DIASTEREOMERIC_B_WINS;
-        }
-      }
-      return score;
-    }
-
-    /**
-     * Check to see if two RS-strings are enantiomeric or not. If enantiomeric,
-     * returns which has higher priority by Rule 4b. Can be used to compare "r"
-     * and "s" as well as "R" and "S"
-     * 
-     * @param rs1
-     * @param rs2
-     * @param m
-     * @param n
-     * @param rs
-     * @return DIASTEREOMERIC, A_WINS, or B_WINS
-     */
-    private int checkEnantiomer(String rs1, String rs2, int m, int n, String 
rs) {
-      int finalScore = TIED; // not a possible return
-      // "0~~R 0~~S"
-      for (int i = m; i < n; i++) {
-        // a score of 0 means ~ was present for both
-        // a score of 3 means one was R and one was S
-        // any other score indicates diasteriomeric
-        int i1 = rs.indexOf(rs1.charAt(i));
-        int score = i1 + rs.indexOf(rs2.charAt(i));
-        if (score != 0) {
-          if (score != STEREO_BOTH_RS)
-            return DIASTEREOMERIC;
-          if (finalScore == TIED)
-            finalScore = (i1 == STEREO_R ? A_WINS : B_WINS);
-        }
-      }
-      return finalScore;
-    }
-
-    /**
      * Chapter 9 Rules 4a and 4c. This method allows for "RS" to be checked as
      * "either R or S". See AY236.66, AY236.67,
      * AY236.147,148,156,170,171,201,202, etc. (4a)
@@ -3139,9 +2945,10 @@
       a.rule4Count = null;
       a.rule4List = null;
       a.rootRule4Paths = null;
-      a.priority = a.rule4Type = 0;
-      a.auxChirality = "~";
-      a.auxEZ = STEREO_UNDETERMINED;
+      a.priority = 0;
+      //a.rule4Type = 0;
+      //a.auxChirality = "~";
+      //a.auxEZ = STEREO_UNDETERMINED;
       for (int i = 0; i < 4; i++)
         if (atoms[i] != null)
           a.atoms[i] = atoms[i];

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